select-seat.uvue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <template>
  2. <cl-page>
  3. <view class="p-3 pb-0 w-full">
  4. <view
  5. class="flex flex-row items-center p-2 rounded-lg bg-white w-full dark:!bg-surface-800 mb-3"
  6. >
  7. <cl-icon name="information-2-line" color="warn"></cl-icon>
  8. <cl-text
  9. :pt="{
  10. className: 'text-sm ml-1'
  11. }"
  12. color="warn"
  13. >双指缩放:放大/缩小、单指拖动:移动视图</cl-text
  14. >
  15. </view>
  16. </view>
  17. <view v-if="width > 0">
  18. <view
  19. class="w-full flex flex-col items-center justify-center pt-3"
  20. :style="{
  21. transform: `translateX(${translateX}px)`
  22. }"
  23. >
  24. <image
  25. src="/static/demo/select-seat/screen.png"
  26. mode="widthFix"
  27. class="w-[400rpx]"
  28. />
  29. <cl-text
  30. :pt="{
  31. className: 'text-center w-full text-sm'
  32. }"
  33. >2号激光厅 银幕</cl-text
  34. >
  35. </view>
  36. <cl-select-seat
  37. ref="selectSeatRef"
  38. v-model="selected as ClSelectSeatValue[]"
  39. :rows="rows"
  40. :cols="cols"
  41. :width="width"
  42. :height="300"
  43. :seats="seats"
  44. :seatGap="8"
  45. :borderRadius="6"
  46. :minScale="1"
  47. :maxScale="1.5"
  48. selectedIcon="check-line"
  49. @seat-click="onSeatClick"
  50. @move="onMove"
  51. ></cl-select-seat>
  52. </view>
  53. <cl-footer>
  54. <cl-text>寻秦记</cl-text>
  55. <cl-text
  56. color="info"
  57. :pt="{
  58. className: 'text-sm mb-3 mt-1'
  59. }"
  60. >今日 01月10日 14:20 - 16:16 国语 2D</cl-text
  61. >
  62. <scroll-view direction="horizontal" class="flex flex-row" :show-scrollbar="false">
  63. <view
  64. class="flex p-3 bg-surface-100 dark:!bg-surface-800 rounded-lg mr-2 mb-2"
  65. v-for="(item, index) in selectedSeats"
  66. :key="index"
  67. >
  68. <cl-text
  69. :pt="{
  70. className: 'text-sm'
  71. }"
  72. >{{ item }}</cl-text
  73. >
  74. </view>
  75. </scroll-view>
  76. <view class="mt-2">
  77. <cl-button size="large" :disabled="selectedSeats.length == 0" @tap="confirm"
  78. >确认选座</cl-button
  79. >
  80. </view>
  81. </cl-footer>
  82. </cl-page>
  83. </template>
  84. <script lang="ts" setup>
  85. import { ref, computed } from "vue";
  86. import type { ClSelectSeatItem, ClSelectSeatValue } from "@/uni_modules/cool-ui/types";
  87. import { getColor, isDark } from "@/cool";
  88. import { useUi } from "@/uni_modules/cool-ui";
  89. import { t } from "@/locale";
  90. const selectSeatRef = ref<ClSelectSeatComponentPublicInstance | null>(null);
  91. const ui = useUi();
  92. // 已选中的座位
  93. const selected = ref<ClSelectSeatValue[]>([]);
  94. // 画布偏移横向值
  95. const translateX = ref(0);
  96. // 座位行数
  97. const rows = ref(9);
  98. // 座位列数
  99. const cols = ref(16);
  100. // 生成自定义座位数据
  101. const seats = computed<ClSelectSeatItem[]>(() => {
  102. const seats: ClSelectSeatItem[] = [];
  103. for (let row = 0; row < rows.value; row++) {
  104. for (let col = 0; col < cols.value; col++) {
  105. const seat: ClSelectSeatItem = {
  106. row,
  107. col
  108. };
  109. // 示例:设置一些座位为禁用(不可点击)
  110. if (col < 4 && row > 1 && row < 6) {
  111. seat.disabled = true;
  112. seat.bgColor = isDark.value ? getColor("surface-600") : getColor("surface-200");
  113. seat.color = isDark.value ? getColor("surface-300") : getColor("surface-400");
  114. }
  115. // 示例:VIP座位使用金色边框,选中时金色背景
  116. if (row < 2) {
  117. seat.borderColor = "#ffd700";
  118. }
  119. // 示例:情侣座使用粉色边框,选中时粉色背景
  120. if (row > 7) {
  121. seat.borderColor = "#ff69b4";
  122. seat.icon = "heart-fill";
  123. seat.color = "#ff69b4";
  124. }
  125. // 示例:空座位
  126. if ((col < 2 && row < 8) || (col > 13 && row < 8)) {
  127. seat.empty = true;
  128. }
  129. // 最佳座位
  130. if (col > 4 && col < 11 && row > 1 && row < 6) {
  131. seat.borderColor = "#22c55e";
  132. }
  133. seats.push(seat);
  134. }
  135. }
  136. return seats;
  137. });
  138. // 计算已选座位显示
  139. const selectedSeats = computed<string[]>(() => {
  140. if (selected.value.length == 0) {
  141. return [];
  142. }
  143. return selected.value.map((s) => `${s.row + 1}排${s.col + 1}座`);
  144. });
  145. // 座位点击事件
  146. function onSeatClick(seat: ClSelectSeatItem) {
  147. console.log("点击座位:", seat);
  148. }
  149. // 移动事件
  150. function onMove(data: UTSJSONObject) {
  151. translateX.value = data["screenTranslateX"] as number;
  152. }
  153. function confirm() {
  154. ui.showConfirm({
  155. title: t("提示"),
  156. message: t("确认选座后将无法修改,是否确认?"),
  157. callback(action) {
  158. if (action == "confirm") {
  159. ui.showToast({
  160. message: t("选座成功")
  161. });
  162. }
  163. }
  164. });
  165. }
  166. const width = ref(0);
  167. onReady(() => {
  168. width.value = uni.getWindowInfo().windowWidth;
  169. });
  170. </script>