select-seat.uvue 4.5 KB

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