seat.vue 20 KB

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