select-seat.uvue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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
  63. direction="horizontal"
  64. class="flex flex-row h-[80rpx]"
  65. :show-scrollbar="false"
  66. v-if="selectedSeats.length > 0"
  67. >
  68. <view
  69. class="flex p-3 bg-surface-100 dark:!bg-surface-800 rounded-lg mr-2 mb-2 h-full items-center justify-center"
  70. v-for="(item, index) in selectedSeats"
  71. :key="index"
  72. >
  73. <cl-text
  74. :pt="{
  75. className: 'text-sm'
  76. }"
  77. >{{ item }}</cl-text
  78. >
  79. </view>
  80. </scroll-view>
  81. <view class="mt-2">
  82. <cl-button size="large" :disabled="selectedSeats.length == 0" @tap="confirm"
  83. >确认选座</cl-button
  84. >
  85. </view>
  86. </cl-footer>
  87. </cl-page>
  88. </template>
  89. <script lang="ts" setup>
  90. import { ref, computed } from "vue";
  91. import type { ClSelectSeatItem, ClSelectSeatValue } from "@/uni_modules/cool-ui/types";
  92. import { getColor, isDark } from "@/cool";
  93. import { useUi } from "@/uni_modules/cool-ui";
  94. import { t } from "@/locale";
  95. const selectSeatRef = ref<ClSelectSeatComponentPublicInstance | null>(null);
  96. const ui = useUi();
  97. // 已选中的座位
  98. const selected = ref<ClSelectSeatValue[]>([]);
  99. // 画布偏移横向值
  100. const translateX = ref(0);
  101. // 座位行数
  102. const rows = ref(9);
  103. // 座位列数
  104. const cols = ref(16);
  105. // 生成自定义座位数据
  106. const seats = computed<ClSelectSeatItem[]>(() => {
  107. const seats: ClSelectSeatItem[] = [];
  108. for (let row = 0; row < rows.value; row++) {
  109. for (let col = 0; col < cols.value; col++) {
  110. const seat: ClSelectSeatItem = {
  111. row,
  112. col
  113. };
  114. // 示例:设置一些座位为禁用(不可点击)
  115. if (col < 4 && row > 1 && row < 6) {
  116. seat.disabled = true;
  117. seat.bgColor = isDark.value ? getColor("surface-600") : getColor("surface-200");
  118. seat.color = isDark.value ? getColor("surface-300") : getColor("surface-400");
  119. }
  120. // 示例:VIP座位使用金色边框,选中时金色背景
  121. if (row < 2) {
  122. seat.borderColor = "#ffd700";
  123. }
  124. // 示例:情侣座使用粉色边框,选中时粉色背景
  125. if (row > 7) {
  126. seat.borderColor = "#ff69b4";
  127. seat.icon = "heart-fill";
  128. seat.color = "#ff69b4";
  129. }
  130. // 示例:空座位
  131. if ((col < 2 && row < 8) || (col > 13 && row < 8)) {
  132. seat.empty = true;
  133. }
  134. // 示例:最佳座位
  135. if (col > 4 && col < 11 && row > 1 && row < 6) {
  136. seat.borderColor = "#22c55e";
  137. }
  138. // 示例:图片
  139. if (col == 5 && row == 5) {
  140. seat.image = 'https://unix.cool-js.com/images/demo/avatar.jpg';
  141. }
  142. seats.push(seat);
  143. }
  144. }
  145. return seats;
  146. });
  147. // 计算已选座位显示
  148. const selectedSeats = computed<string[]>(() => {
  149. if (selected.value.length == 0) {
  150. return [];
  151. }
  152. console.log(selected.value.map((s) => `${s.row + 1}排${s.col + 1}座`));
  153. return selected.value.map((s) => `${s.row + 1}排${s.col + 1}座`);
  154. });
  155. // 座位点击事件
  156. function onSeatClick(seat: ClSelectSeatItem) {
  157. console.log("点击座位:", seat);
  158. }
  159. // 移动事件
  160. function onMove(data: UTSJSONObject) {
  161. translateX.value = data["screenTranslateX"] as number;
  162. }
  163. function confirm() {
  164. ui.showConfirm({
  165. title: t("提示"),
  166. message: t("确认选座后将无法修改,是否确认?"),
  167. callback(action) {
  168. if (action == "confirm") {
  169. ui.showToast({
  170. message: t("选座成功")
  171. });
  172. }
  173. }
  174. });
  175. }
  176. const width = ref(0);
  177. onReady(() => {
  178. width.value = uni.getWindowInfo().windowWidth;
  179. });
  180. </script>