anil-seat.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. <template>
  2. <view class="sel-seat" :style="{height}">
  3. <!-- top -->
  4. <view class="seat-head">
  5. <text class="sh-title">{{ title }}</text>
  6. <text class="sh-info">{{ info }}</text>
  7. </view>
  8. <!-- main -->
  9. <view class="seat-main">
  10. <movable-area class="vm-area">
  11. <movable-view :style="'width: 750rpx;height:'+(seatRow*40+350)+'rpx;'" :inertia="true" :scale="true" :scale-min="0.95"
  12. :scale-max="2" direction="all" @change="onMove" @scale="onScale">
  13. <view class="sm-title">
  14. <text class="text">{{ roomName }}</text>
  15. </view>
  16. <view class="sm-screen">
  17. <text class="text">银幕中央</text>
  18. </view>
  19. <view class="sm-line-center"></view>
  20. <!-- seat content -->
  21. <view v-for="(item,index) in seatArray" :key="index"
  22. class="sm-cell" :style="'width:'+boxWidth+'px;height:'+seatSize+'px'">
  23. <view v-for="(seat,col) in item" :key="col" class="dp-ib" :style="'width:'+seatSize+'px;height:'+seatSize+'px'"
  24. @click="handleChooseSeat(index,col)">
  25. <!-- // 情侣左座 -->
  26. <template v-if="seat.flag === 1">
  27. <image v-if="seat.type===0" class="sm-icon" src="/uni_modules/anil-seat/static/unselected-l.png" mode="aspectFit"></image>
  28. <image v-else-if="seat.type===1" class="sm-icon" src="/uni_modules/anil-seat/static/selected-l.png" mode="aspectFit"></image>
  29. <image v-else-if="seat.type===2" class="sm-icon" src="/uni_modules/anil-seat/static/bought.png" mode="aspectFit"></image>
  30. </template>
  31. <!-- // 情侣右座 -->
  32. <template v-else-if="seat.flag === 2">
  33. <image v-if="seat.type===0" class="sm-icon" src="/uni_modules/anil-seat/static/unselected-r.png" mode="aspectFit"></image>
  34. <image v-else-if="seat.type===1" class="sm-icon" src="/uni_modules/anil-seat/static/selected-r.png" mode="aspectFit"></image>
  35. <image v-else-if="seat.type===2" class="sm-icon" src="/uni_modules/anil-seat/static/bought.png" mode="aspectFit"></image>
  36. </template>
  37. <!-- // 普通座位 其他座位 -->
  38. <template v-else>
  39. <image v-if="seat.type===0" class="sm-icon" src="/uni_modules/anil-seat/static/unselected.png" mode="aspectFit"></image>
  40. <image v-else-if="seat.type===1" class="sm-icon" src="/uni_modules/anil-seat/static/selected.png" mode="aspectFit"></image>
  41. <image v-else-if="seat.type===2" class="sm-icon" src="/uni_modules/anil-seat/static/bought.png" mode="aspectFit"></image>
  42. </template>
  43. </view>
  44. </view>
  45. <view class="sm-line-index" :style="'left: '+(10-moveX/scale)+'px;'">
  46. <text class="text" :style="'height:'+seatSize+'px;'" v-for="(m,mindex) in mArr"
  47. :key="mindex">{{m}}</text>
  48. </view>
  49. </movable-view>
  50. </movable-area>
  51. <view class="fix-tips">
  52. <view class="v-tips">
  53. <image :style="'width:'+seatSize+'px;height:'+seatSize+'px'" src="/uni_modules/anil-seat/static/unselected.png" mode="aspectFit"></image>
  54. <text class="text">可选</text>
  55. </view>
  56. <view class="v-tips">
  57. <image :style="'width:'+seatSize+'px;height:'+seatSize+'px'" src="/uni_modules/anil-seat/static/bought.png" mode="aspectFit"></image>
  58. <text class="text">不可选</text>
  59. </view>
  60. <view class="v-tips">
  61. <image :style="'width:'+seatSize+'px;height:'+seatSize+'px'" src="/uni_modules/anil-seat/static/selected.png" mode="aspectFit"></image>
  62. <text class="text">选中</text>
  63. </view>
  64. </view>
  65. </view>
  66. <!-- foot -->
  67. <view class="seat-foot">
  68. <view class="sf-recommend" v-if="SelectNum === 0">
  69. <text class="text">推荐选座</text>
  70. <view class="sfr-tag" v-for="num in Math.min(max, 6)" :key="num"
  71. @click="smartChoose(num+1)">
  72. <text class="text">{{ num+1 }}人</text>
  73. </view>
  74. </view>
  75. <view class="sf-arselect" v-else>
  76. <text class="text">已选</text>
  77. <scroll-view scroll-x="true">
  78. <view class="scr-wrap">
  79. <view class="sfr-selt" v-for="(optItem,optindex) in optArr" :key="optItem.SeatCode"
  80. @click="handleChooseSeat(optItem.rowIndex, optItem.colIndex)">
  81. <!-- <image src="static/close.png" class="sfr-close"></image> -->
  82. <text class="text">{{ optItem.SeatName }}</text>
  83. <text class="price">¥{{ optItem.Price || '' }}</text>
  84. <view class="sfr-close">X</view>
  85. </view>
  86. </view>
  87. </scroll-view>
  88. </view>
  89. <view class="f-btn" :class="{disabled: SelectNum === 0 }" @click="buySeat">
  90. <text class="text">{{SelectNum === 0 ? '请选座位' : `¥ ${aPrice} 确认座位`}}</text>
  91. </view>
  92. </view>
  93. </view>
  94. </template>
  95. <script>
  96. export default {
  97. name:"anil-seat",
  98. props: {
  99. seatData: {
  100. type: Array
  101. },
  102. max: {
  103. type: Number,
  104. default: 4
  105. },
  106. title: {
  107. type: String,
  108. default: ''
  109. },
  110. info: {
  111. type: String,
  112. default: ''
  113. },
  114. roomName: {
  115. type: String,
  116. default: ''
  117. },
  118. height: {
  119. type: String,
  120. // #ifndef MP-WEIXIN
  121. default: 'calc(100vh - 44px)',
  122. // #endif
  123. // #ifdef MP-WEIXIN
  124. default: '100vh',
  125. // #endif
  126. }
  127. },
  128. data() {
  129. return {
  130. scaleMin:1,//h5端为解决1无法缩小问题,设为0.95
  131. boxWidth: 400, //屏幕宽度px
  132. space: ' ', //空格
  133. seatArray: [], //影院座位的二维数组,-1为非座位,0为未购座位,1为已选座位(绿色),2为已购座位(红色),一维行,二维列
  134. seatRow: 0, //影院座位行数
  135. seatCol: 0, //影院座位列数
  136. seatSize: 0, //座位尺寸
  137. SelectNum: 0, //选择座位数
  138. moveX: 0, //水平移动偏移量
  139. scale: 1, //放大倍数
  140. minRow: 0, //从第几行开始排座位
  141. minCol: 0, //从第几列开始排座位
  142. showTis: true, //显示选座提示
  143. seatList: [], //接口获取的原始位置
  144. mArr: [], //排数提示
  145. optArr: [], //选中的座位数组。
  146. isWXAPP:false,
  147. areaHeight: 0
  148. };
  149. },
  150. computed: {
  151. aPrice() {
  152. let totalAmount = ''
  153. if (this.optArr && this.optArr.length) {
  154. totalAmount = this.optArr.map(item => Number(item.Price)).reduce((prev, curr) => prev + curr)
  155. }
  156. return Number(totalAmount).toFixed(2)
  157. },
  158. rpxNum() {
  159. return this.boxWidth / 750
  160. },
  161. pxNum() {
  162. return 750 / this.boxWidth
  163. },
  164. },
  165. created() {
  166. //获取宽度
  167. uni.getSystemInfo({
  168. success: (e) => {
  169. this.boxWidth = e.screenWidth
  170. //#ifdef H5
  171. this.scaleMin = 0.95
  172. //#endif
  173. }
  174. })
  175. // this.initData()
  176. },
  177. methods: {
  178. initData: function(data) {
  179. let arr = data || this.seatData
  180. //假数据说明:SeatCode座位编号,RowNum-行号,ColumnNum-纵号,YCoord-Y坐标,XCoord-X坐标,Status-状态
  181. let row = 0
  182. let col = 0
  183. let minCol = parseInt(arr[0].XCoord)
  184. let minRow = parseInt(arr[0].YCoord)
  185. for (let i of arr) {
  186. minRow = parseInt(i.YCoord) < minRow ? parseInt(i.YCoord) : minRow
  187. minCol = parseInt(i.XCoord) < minCol ? parseInt(i.XCoord) : minCol
  188. row = parseInt(i.YCoord) > row ? parseInt(i.YCoord) : row
  189. col = parseInt(i.XCoord) > col ? parseInt(i.XCoord) : col
  190. }
  191. this.seatList = arr
  192. this.seatRow = row - minRow + 1
  193. this.seatCol = col - minCol + 3
  194. this.minRow = minRow
  195. this.minCol = minCol - 1
  196. this.initSeatArray()
  197. },
  198. //初始座位数组
  199. initSeatArray: function() {
  200. let seatArray = Array(this.seatRow).fill(0).map(() => Array(this.seatCol).fill({
  201. type: -1,
  202. SeatCode: '',
  203. RowNum: '',
  204. ColumnNum: ''
  205. }));
  206. this.seatArray = seatArray
  207. this.seatSize = this.boxWidth > 0 ?
  208. parseInt(parseInt(this.boxWidth, 10) / (this.seatCol + 1), 10) :
  209. parseInt(parseInt(414, 10) / (this.seatCol + 1), 10)
  210. this.initNonSeatPlace();
  211. },
  212. //初始化是座位的地方
  213. initNonSeatPlace: function() {
  214. let seat = this.seatList.slice()
  215. let arr = this.seatArray.slice()
  216. for (let num in seat) {
  217. let status = 2 //-1为非座位,0为未购座位,1为已选座位(绿色),2为已购座位(红色)
  218. switch (seat[num].Status) {
  219. case -2:
  220. status = 2
  221. break;
  222. case -1:
  223. status = -1
  224. break;
  225. case 0:
  226. status = 2
  227. break;
  228. case 1:
  229. status = 0
  230. break;
  231. }
  232. // if (seat[num].Status === 1) {
  233. // status = 0
  234. // } else if (seat[num].Status === -1) {
  235. // status = -1
  236. // }
  237. arr[parseInt(seat[num].YCoord) - this.minRow][parseInt(seat[num].XCoord) - this.minCol] = {
  238. type: status,
  239. SeatCode: seat[num].SeatCode,
  240. RowNum: seat[num].RowNum,
  241. ColumnNum: seat[num].ColumnNum,
  242. Price: seat[num].Price,
  243. SeatName: seat[num].SeatName,
  244. flag: seat[num].flag,
  245. area: seat[num].area
  246. }
  247. }
  248. this.seatArray = arr.slice()
  249. let mArr = []
  250. for (let i in arr) {
  251. let m = ''
  252. for (let n of arr[i]) {
  253. if (n.SeatCode) {
  254. m = n.RowNum
  255. }
  256. }
  257. if (m) {
  258. mArr.push(m)
  259. } else {
  260. mArr.push('')
  261. }
  262. }
  263. this.mArr = mArr
  264. },
  265. //放大缩小事件
  266. onScale: function(e) {
  267. this.showTis = false
  268. // this.moveX=-e.detail.x
  269. let w = this.boxWidth * 0.5
  270. let s = 1 - e.detail.scale
  271. this.moveX = w * s
  272. this.scale = e.detail.scale
  273. if (s > 0 || s === 0) {
  274. this.showTis = true
  275. }
  276. },
  277. //移动事件
  278. onMove: function(e) {
  279. this.showTis = false
  280. this.moveX = e.detail.x
  281. },
  282. //重置座位
  283. resetSeat: function() {
  284. this.SelectNum = 0
  285. this.optArr = []
  286. //将所有已选座位的值变为0
  287. let oldArray = this.seatArray.slice();
  288. for (let i = 0; i < this.seatRow; i++) {
  289. for (let j = 0; j < this.seatCol; j++) {
  290. if (oldArray[i][j].type === 1) {
  291. oldArray[i][j].type = 0
  292. }
  293. }
  294. }
  295. this.seatArray = oldArray;
  296. },
  297. //选定且购买座位
  298. buySeat: function() {
  299. if (this.SelectNum === 0) return;
  300. // let oldArray = [];
  301. // for (let i = 0; i < this.seatRow; i++) {
  302. // for (let j = 0; j < this.seatCol; j++) {
  303. // if (this.seatArray[i][j].type === 1) {
  304. // oldArray.push(this.seatArray[i][j])
  305. // }
  306. // }
  307. // }
  308. this.$emit('confirm', this.optArr)
  309. },
  310. //处理座位选择逻辑
  311. handleChooseSeat: function(row, col, isbreak) {
  312. let newArray = this.seatArray;
  313. let seatValue = newArray[row][col].type;
  314. let flag = newArray[row][col].flag
  315. //如果是已购座位,直接返回
  316. if (seatValue === 2 || seatValue === -1) return
  317. //如果是已选座位点击后变未选
  318. if (seatValue === 1) {
  319. newArray[row][col].type = 0
  320. this.SelectNum--
  321. this.getOptArr(newArray[row][col], 0)
  322. } else if (seatValue === 0) {
  323. if (this.SelectNum >= this.max) {
  324. return uni.showToast({
  325. title: '一次最多选择' + this.max + '张',
  326. icon: 'none'
  327. })
  328. }
  329. newArray[row][col].rowIndex = row
  330. newArray[row][col].colIndex = col
  331. newArray[row][col].type = 1
  332. this.SelectNum++
  333. this.getOptArr(newArray[row][col], 1)
  334. }
  335. switch (flag) {
  336. case 1: // 情侣左座
  337. !isbreak && this.handleChooseSeat(row, col+1, true)
  338. break;
  339. case 2: // 情侣右座
  340. !isbreak && this.handleChooseSeat(row, col-1, true)
  341. break;
  342. }
  343. //必须整体更新二维数组,Vue无法检测到数组某一项更新,必须slice复制一个数组才行
  344. // this.seatArray = newArray.slice();
  345. // this.$forceUpdate()
  346. },
  347. //处理已选座位数组
  348. getOptArr: function(item, type) {
  349. let optArr = this.optArr
  350. if (type === 1) {
  351. optArr.push(item)
  352. } else if (type === 0) {
  353. let arr = []
  354. optArr.forEach(v => {
  355. if (v.SeatCode !== item.SeatCode) {
  356. arr.push(v)
  357. }
  358. })
  359. optArr = arr
  360. }
  361. this.optArr = optArr.slice()
  362. },
  363. //推荐选座,参数是推荐座位数目,
  364. smartChoose: function(num) {
  365. // console.log('num===', num)
  366. // 先重置
  367. this.resetSeat()
  368. //找到影院座位水平垂直中间位置的后一排
  369. let rowStart = parseInt((this.seatRow - 1) / 2, 10) + 1;
  370. //先从中间排往后排搜索
  371. let backResult = this.searchSeatByDirection(rowStart, this.seatRow - 1, num);
  372. if (backResult.length > 0) {
  373. this.chooseSeat(backResult);
  374. this.SelectNum += num
  375. return
  376. }
  377. //再从中间排往前排搜索
  378. let forwardResult = this.searchSeatByDirection(rowStart - 1, 0, num);
  379. if (forwardResult.length > 0) {
  380. this.chooseSeat(forwardResult);
  381. this.SelectNum += num
  382. return
  383. }
  384. //提示用户无合法位置可选
  385. uni.showToast({
  386. title: '无合法位置可选!',
  387. icon: 'none'
  388. })
  389. },
  390. //搜索函数,参数:fromRow起始行,toRow终止行,num推荐座位数
  391. searchSeatByDirection: function(fromRow, toRow, num) {
  392. /*
  393. * 推荐座位规则
  394. * (1)初始状态从座位行数的一半处的后一排的中间开始向左右分别搜索,取离中间最近的,如果满足条件,
  395. * 记录下该结果离座位中轴线的距离,后排搜索完成后取距离最小的那个结果座位最终结果,优先向后排进行搜索,
  396. * 后排都没有才往前排搜,前排逻辑同上
  397. *
  398. * (2)只考虑并排且连续的座位,不能不在一排或者一排中间有分隔
  399. *
  400. * */
  401. /*
  402. * 保存当前方向搜索结果的数组,元素是对象,result是结果数组,offset代表与中轴线的偏移距离
  403. * {
  404. * result:Array([x,y])
  405. * offset:Number
  406. * }
  407. *
  408. */
  409. let currentDirectionSearchResult = [];
  410. let largeRow = fromRow > toRow ? fromRow : toRow,
  411. smallRow = fromRow > toRow ? toRow : fromRow;
  412. for (let i = smallRow; i <= largeRow; i++) {
  413. //每一排的搜索,找出该排里中轴线最近的一组座位
  414. let tempRowResult = [],
  415. minDistanceToMidLine = Infinity;
  416. try{
  417. for (let j = 0; j <= this.seatCol - num; j++) {
  418. //如果有合法位置
  419. if (this.checkRowSeatContinusAndEmpty(i, j, j + num - 1, num)) {
  420. //计算该组位置距离中轴线的距离:该组位置的中间位置到中轴线的距离
  421. let resultMidPos = parseInt((j + num / 2), 10);
  422. let distance = Math.abs(parseInt(this.seatCol / 2) - resultMidPos);
  423. //如果距离较短则更新
  424. if (distance < minDistanceToMidLine) {
  425. minDistanceToMidLine = distance;
  426. //该行的最终结果
  427. tempRowResult = this.generateRowResult(i, j, j + num - 1)
  428. }
  429. }
  430. }
  431. }catch(e){
  432. //TODO handle the exception
  433. uni.showToast({
  434. title: '暂无推荐选座',
  435. icon: 'none'
  436. })
  437. }
  438. //保存该行的最终结果
  439. currentDirectionSearchResult.push({
  440. result: tempRowResult,
  441. offset: minDistanceToMidLine
  442. })
  443. }
  444. //处理后排的搜索结果:找到距离中轴线最短的一个
  445. //注意这里的逻辑需要区分前后排,对于后排是从前往后,前排则是从后往前找
  446. let isBackDir = fromRow < toRow;
  447. let finalReuslt = [],
  448. minDistanceToMid = Infinity;
  449. if (isBackDir) {
  450. //后排情况,从前往后
  451. currentDirectionSearchResult.forEach((item) => {
  452. if (item.offset < minDistanceToMid) {
  453. finalReuslt = item.result;
  454. minDistanceToMid = item.offset;
  455. }
  456. });
  457. } else {
  458. //前排情况,从后往前找
  459. currentDirectionSearchResult.reverse().forEach((item) => {
  460. if (item.offset < minDistanceToMid) {
  461. finalReuslt = item.result;
  462. minDistanceToMid = item.offset;
  463. }
  464. })
  465. }
  466. //直接返回结果
  467. return finalReuslt
  468. },
  469. /*辅助函数,判断每一行座位从i列到j列是否全部空余且连续
  470. *
  471. */
  472. checkRowSeatContinusAndEmpty: function(rowNum, startPos, endPos, num) {
  473. let isValid = true;
  474. for (let i = startPos; i <= endPos; i++) {
  475. if (this.seatArray[rowNum][i].type !== 0) {
  476. isValid = false;
  477. break;
  478. }
  479. // 忽略情侣座
  480. if ([1, 2].includes(this.seatArray[rowNum][i].flag)) {
  481. isValid = false;
  482. break;
  483. }
  484. }
  485. return isValid
  486. },
  487. //辅助函数:返回每一行的某个合理位置的座位数组
  488. generateRowResult: function(row, startPos, endPos) {
  489. let result = [];
  490. for (let i = startPos; i <= endPos; i++) {
  491. result.push([row, i])
  492. }
  493. return result
  494. },
  495. //辅助函数:智能推荐的选座操作
  496. chooseSeat: function(result) {
  497. let opt = this.optArr
  498. let oldArray = this.seatArray.slice();
  499. for (let i = 0; i < result.length; i++) {
  500. //选定座位
  501. oldArray[result[i][0]][result[i][1]].rowIndex = result[i][0]
  502. oldArray[result[i][0]][result[i][1]].colIndex = result[i][1]
  503. oldArray[result[i][0]][result[i][1]].type = 1
  504. this.optArr.push(oldArray[result[i][0]][result[i][1]])
  505. }
  506. this.seatArray = oldArray;
  507. },
  508. }
  509. }
  510. </script>
  511. <style lang="scss">
  512. .sel-seat {
  513. display: flex;
  514. flex-direction: column;
  515. width: 100%;
  516. height: 100vh;
  517. .seat-head {
  518. background-color: #ffffff;
  519. display: flex;
  520. flex-direction: column;
  521. padding: 20rpx 30rpx;
  522. position: relative;
  523. z-index: 5;
  524. .sh-title {
  525. font-size: 32rpx;
  526. font-weight: bold;
  527. color: #333333;
  528. }
  529. .sh-info {
  530. font-size: 24rpx;
  531. color: #999999;
  532. margin-top: 10rpx;
  533. }
  534. }
  535. .seat-main {
  536. width: 100%;
  537. height: 100%;
  538. position: relative;
  539. padding: 10rpx;
  540. .vm-area {
  541. width: 750rpx;
  542. overflow: hidden;
  543. height: calc(100% - 40rpx);
  544. }
  545. .sm-title {
  546. background-color: #dddddd;
  547. width: 380rpx;
  548. height: 34rpx;
  549. transform: perspective(34rpx) rotateX(-10deg);
  550. margin: 0 auto;
  551. display: flex;
  552. align-items: center;
  553. justify-content: center;
  554. position: relative;
  555. z-index: 2;
  556. .text {
  557. font-size: 24rpx;
  558. color: #333333;
  559. }
  560. }
  561. .sm-screen {
  562. width: 100rpx;
  563. height: 30rpx;
  564. border: 1rpx solid #cccccc;
  565. display: flex;
  566. align-items: center;
  567. justify-content: center;
  568. margin: 48rpx auto 0;
  569. border-radius: 4rpx;
  570. position: relative;
  571. z-index: 1;
  572. .text {
  573. font-size: 20rpx;
  574. color: #999999;
  575. }
  576. }
  577. .sm-line-center {
  578. height: 610rpx;
  579. width: 0;
  580. border: 1rpx dashed #e5e5e5;
  581. position: fixed;
  582. left: 50%;
  583. top: 0;
  584. display: block;
  585. z-index: 0;
  586. transform: translateX(-50%);
  587. }
  588. .fix-tips {
  589. display: flex;
  590. align-items: center;
  591. justify-content: center;
  592. font-size: 24rpx;
  593. position: fixed;
  594. bottom: 198rpx;
  595. left: 0;
  596. width: 100%;
  597. z-index: 1;
  598. padding: 20rpx;
  599. .v-tips {
  600. display: flex;
  601. align-items: center;
  602. color: #999;
  603. margin: 0 10rpx;
  604. .text {
  605. margin-left: 10rpx;
  606. }
  607. }
  608. }
  609. // seat style
  610. .sm-cell {
  611. display: flex;
  612. margin-top: 20rpx;
  613. align-items: center;
  614. justify-content: center;
  615. position: relative;
  616. z-index: 2;
  617. .sm-icon {
  618. width: 100%;
  619. height: 100%;
  620. }
  621. }
  622. .sm-line-index {
  623. position: fixed;
  624. top: 114rpx;
  625. left: 20rpx;
  626. border-radius: 14rpx;
  627. overflow: hidden;
  628. background-color: rgba($color: #000000, $alpha: 0.3);
  629. z-index: 3;
  630. display: flex;
  631. flex-direction: column;
  632. align-items: center;
  633. justify-content: center;
  634. padding-bottom: 20rpx;
  635. width: 30rpx;
  636. .text {
  637. font-size: 24rpx;
  638. color: #ffffff;
  639. width: 100%;
  640. text-align: center;
  641. margin-top: 20rpx;
  642. }
  643. }
  644. }
  645. .seat-foot {
  646. margin-top: auto;
  647. background-color: #ffffff;
  648. padding: 20rpx 30rpx;
  649. position: relative;
  650. z-index: 5;
  651. .sf-recommend {
  652. display: flex;
  653. align-items: center;
  654. justify-content: center;
  655. padding-bottom: 20rpx;
  656. .text {
  657. font-size: 28rpx;
  658. color: #666666;
  659. }
  660. .sfr-tag {
  661. width: 110rpx;
  662. height: 60rpx;
  663. border-radius: 4rpx;
  664. border: 1rpx solid #ccc;
  665. display: flex;
  666. align-items: center;
  667. justify-content: center;
  668. margin-left: 20rpx;
  669. }
  670. }
  671. .sf-arselect {
  672. @extend .sf-recommend;
  673. .text {
  674. font-size: 24rpx;
  675. color: #666666;
  676. }
  677. .price {
  678. font-size: 20rpx;
  679. color: red;
  680. }
  681. .scr-wrap {
  682. display: flex;
  683. white-space: nowrap;
  684. }
  685. .sfr-selt {
  686. min-width: 130rpx;
  687. height: 60rpx;
  688. border-radius: 4rpx;
  689. border: 1rpx solid #ccc;
  690. display: flex;
  691. align-items: flex-start;
  692. justify-content: center;
  693. flex-direction: column;
  694. margin-left: 20rpx;
  695. position: relative;
  696. margin-left: 20rpx;
  697. padding-left: 10rpx;
  698. .text {
  699. font-size: 20rpx;
  700. }
  701. .sfr-close {
  702. position: absolute;
  703. right: 6rpx;
  704. top: 10rpx;
  705. font-size: 20rpx;
  706. color: #999;
  707. }
  708. }
  709. }
  710. .f-btn {
  711. background-color: #F45664;
  712. width: 100%;
  713. height: 90rpx;
  714. line-height: 90rpx;
  715. text-align: center;
  716. border-radius: 10rpx;
  717. .text {
  718. color: #ffffff;
  719. font-size: 36rpx;
  720. }
  721. &.disabled {
  722. opacity: .8;
  723. &:active {
  724. background-color: #F45664;
  725. }
  726. }
  727. &:active {
  728. background-color: #de4e5d;
  729. }
  730. }
  731. }
  732. }
  733. </style>