mx-condition-dropdown-popup.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <template>
  2. <uv-popup ref="popup" mode="top" :safe-area-inset-bottom="false" :offset-top="relTop" @change="handleChange">
  3. <scroll-view scroll-y style="max-height: 35vh;">
  4. <view class="w-screen px-30 py-10 box-border" @touchmove.stop>
  5. <component :is="comp" v-model="model[config.key]" placement="column" icon-placement="right">
  6. <component :is="itemComp" v-for="i in list" :name="getValue(i)" :label="getLabel(i)"/>
  7. </component>
  8. </view>
  9. </scroll-view>
  10. <mx-bottom-buttons left-type="primary" left="重置" :right="right" class="p-30"
  11. @left="handleReset" @right="handleConfirm"/>
  12. </uv-popup>
  13. </template>
  14. <script setup>
  15. import {ref, computed} from 'vue';
  16. import {useElementBounding} from "@vueuse/core";
  17. import {useInjectConditionDropdownPopup} from "@/components/mx-condition-dropdown/useConditionDropdownPopupInjection";
  18. import {deepClone, sleep} from "@/uni_modules/uv-ui-tools/libs/function";
  19. import {useInjectSearchModel} from "@/components/mx-condition/useSearchModelInjection";
  20. import UvCheckboxGroup from "@/uni_modules/uv-checkbox/components/uv-checkbox-group/uv-checkbox-group.vue";
  21. import UvRadioGroup from "@/uni_modules/uv-radio/components/uv-radio-group/uv-radio-group.vue";
  22. import UvCheckbox from "@/uni_modules/uv-checkbox/components/uv-checkbox/uv-checkbox.vue";
  23. import UvRadio from "@/uni_modules/uv-radio/components/uv-radio/uv-radio.vue";
  24. import {func} from "@/uni_modules/uv-ui-tools/libs/function/test";
  25. const popup = ref(null)
  26. const {bottom, container} = useInjectConditionDropdownPopup()
  27. const {queryParams} = useInjectSearchModel()
  28. const model = ref({}) // 存放queryParams副本
  29. const show = ref(false)
  30. const condition = ref(null)
  31. const list = computed(() => condition.value?.list || [])
  32. const config = computed(() => condition.value?.config || {})
  33. const multiple = computed(() => config.value?.multiple)
  34. const comp = computed(() => multiple.value ? UvCheckboxGroup : UvRadioGroup)
  35. const itemComp = computed(() => multiple.value ? UvCheckbox : UvRadio)
  36. const right = computed(() => {
  37. if (!multiple.value) return '确定'
  38. const cur = model.value[config.value.key]
  39. if (cur.length < 1) return '确定'
  40. return `确定(${cur.length})`
  41. })
  42. // TODO: 相对位置不精准
  43. // baseTop 理论上应该找当前容器的值,但目前筛选器是紧贴swiper容器的,所以取的是筛选器的顶部
  44. // 如果以后有定位不对的情况,请修正该值
  45. const {top: baseTop} = useElementBounding(container)
  46. const {bottom: baseBottom} = useElementBounding(bottom)
  47. const relTop = computed(() => baseBottom.value - baseTop.value - 1)
  48. const handleReset = () => {
  49. // 重置本地model状态
  50. if (multiple.value) model.value[config.value.key] = []
  51. else model.value[config.value.key] = ''
  52. if (config.value.defaultValue) {
  53. let val = config.value.defaultValue
  54. if (func(val)) val = val(condition.value)
  55. model.value[config.value.key] = val
  56. }
  57. }
  58. const handleConfirm = () => {
  59. // 将本地model状态赋值回queryParams
  60. const key = config.value.key
  61. queryParams.value[key] = model.value[key]
  62. close()
  63. }
  64. const open = function (cond) {
  65. // console.log('open begin', new Date().getTime())
  66. if (cond == condition.value && show.value) {
  67. popup.value.close()
  68. // console.log('open end', new Date().getTime())
  69. } else {
  70. condition.value = cond
  71. // 每次打开都创建一个副本,用户确认后才将结果反向从model赋回queryParams
  72. model.value = deepClone(queryParams.value)
  73. popup.value.open()
  74. // console.log('open end', new Date().getTime())
  75. }
  76. }
  77. const close = function () {
  78. // console.log('close begin', new Date().getTime())
  79. popup.value.close()
  80. // console.log('close end', new Date().getTime())
  81. }
  82. const handleChange = async function (e) {
  83. // console.log('change begin', new Date().getTime())
  84. show.value = e.show
  85. await sleep()
  86. if (!show.value) {
  87. // always clean current condition&model while hidden.
  88. condition.value = null
  89. model.value = {}
  90. }
  91. // console.log('change end', new Date().getTime())
  92. }
  93. const getLabel = (item) => config.value.keyName ? item[config.value.keyName] : item
  94. const getValue = (item) => config.value.keyValue ? item[config.value.keyValue] : item
  95. defineExpose({open, close, show, condition})
  96. </script>
  97. <style scoped lang="scss">
  98. ::v-deep(.uv-checkbox-group),
  99. ::v-deep(.uv-radio-group) {
  100. .uv-checkbox-label--right,
  101. .uv-radio-label--right {
  102. padding-top: 20rpx;
  103. padding-bottom: 20rpx;
  104. border-bottom: 0.5px solid var(--border-color);
  105. }
  106. }
  107. </style>