ut-action-sheet.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <template>
  2. <template v-if="mode === 'picker'">
  3. <picker :range="options" range-key="name" @change="selectChange" :disabled="false">
  4. <slot></slot>
  5. </picker>
  6. </template>
  7. <template v-else-if="mode === 'custom'">
  8. <view @click="showModel = true" class="flex1">
  9. <slot></slot>
  10. </view>
  11. <up-popup v-model:show="showModel" mode="center" round="30rpx" closeable @close="showModel = false">
  12. <view class="w-700">
  13. <view class="pd-24">
  14. <view class="f-s-32 c-#333 f-w-500">{{ title }}</view>
  15. </view>
  16. <scroll-view scroll-y style="max-height: 70vh">
  17. <view class="pd3-10-24-24">
  18. <ut-row gap="16rpx">
  19. <template v-for="(item, index) in options" :key="index">
  20. <ut-col :span="item.span">
  21. <view @click="clickCol(item)" class="ut-custom-item-sheet p-rtv" :class="{ active: checkeds[item.value] }"
  22. >{{ item?.name }}
  23. <image v-if="checkeds[item.value]" class="w-40 h-40 checked-icon" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images-lm/price/checked1.png" mode="widthFix" />
  24. </view>
  25. </ut-col>
  26. </template>
  27. </ut-row>
  28. </view>
  29. </scroll-view>
  30. </view>
  31. </up-popup>
  32. </template>
  33. </template>
  34. <script setup lang="ts">
  35. import { ref, watch, computed } from 'vue';
  36. const props = defineProps({
  37. modelValue: {
  38. type: Array,
  39. default: () => [],
  40. },
  41. title: {
  42. type: String,
  43. default: '系统提示',
  44. },
  45. showTitle: {
  46. type: Boolean,
  47. default: true,
  48. },
  49. tabs: {
  50. type: Array,
  51. default: () => [],
  52. },
  53. mode: {
  54. type: String,
  55. default: 'picker', // 原生 picker 模式 或自定义弹窗模式 custom
  56. },
  57. // 是否多选
  58. multiple: {
  59. type: Boolean,
  60. default: false, // 只有自定义弹窗模式下生效
  61. },
  62. });
  63. const options = computed(() => {
  64. return props.tabs.map((item: any) => {
  65. return {
  66. name: item.label,
  67. value: item.value,
  68. span: item.elTagClass || 10,
  69. };
  70. });
  71. });
  72. const showModel = ref(false);
  73. const emit = defineEmits(['close', 'confirm', 'open', 'update:show', 'update:modelValue', 'change']);
  74. const checkeds = ref<any>({});
  75. const close = () => {
  76. showModel.value = false;
  77. // 如果有初始值,恢复初始值
  78. checkeds.value = { ...initialCheckeds.value };
  79. emit('update:show', false);
  80. emit('close');
  81. };
  82. const clickCol = (item: any) => {
  83. // 判断是单选还是多选
  84. if (props.multiple) {
  85. // 多选
  86. if (checkeds.value[item.value]) {
  87. // 取消选择
  88. delete checkeds.value[item.value];
  89. } else {
  90. // 选择
  91. checkeds.value[item.value] = true;
  92. }
  93. } else {
  94. // 单选
  95. checkeds.value = {
  96. [item.value]: true,
  97. };
  98. emit('update:modelValue', item.value);
  99. emit('change', item.value);
  100. close();
  101. }
  102. };
  103. // 未选择之前的
  104. const initialCheckeds = ref({});
  105. const selectChange = (item: any) => {
  106. const selectedValues = options.value[item.detail.value].value;
  107. emit('update:modelValue', selectedValues);
  108. emit('change', selectedValues);
  109. close();
  110. };
  111. watch(
  112. () => props.modelValue,
  113. (newVal: any) => {
  114. // 初始化已选择项
  115. let selected: any = {};
  116. if (props.multiple && Array.isArray(newVal)) {
  117. newVal.forEach((val: any) => {
  118. selected[val] = true;
  119. });
  120. } else if (!props.multiple && newVal != null) {
  121. selected = {
  122. [newVal as string]: true,
  123. };
  124. }
  125. checkeds.value = selected;
  126. },
  127. { immediate: true },
  128. );
  129. onMounted(() => {
  130. // 初始化已选择项
  131. console.log(props.tabs);
  132. });
  133. </script>
  134. <style lang="scss" scoped>
  135. .ut-custom-item-sheet {
  136. padding: 18rpx 6rpx;
  137. border: 1rpx solid #f7f7f7;
  138. background-color: #f7f7f7;
  139. border-radius: 10rpx;
  140. text-align: center;
  141. font-size: 30rpx;
  142. color: #333;
  143. &.active {
  144. border-color: #37a954;
  145. background-color: #e6f4f0;
  146. color: #37a954;
  147. }
  148. }
  149. .checked-icon {
  150. position: absolute;
  151. right: 0;
  152. bottom: 0;
  153. }
  154. </style>