123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- <template>
- <view class="flex-1 fx-row fx-end-cen gap-10" @click="handleClick">
- <view v-if="valueMode" class="text-sm">{{ display }}</view>
- <view v-else class="text-sm text-light">{{ placeholder }}</view>
- <uv-icon name="arrow-down"/>
- <uv-picker ref="picker" :columns="columns" :default-index="defaultIndex" :title="title" :key-name="labelProp"
- @confirm="handleConfirm" @change="handleChange"/>
- </view>
- </template>
- <script setup>
- import {computed, getCurrentInstance, ref} from 'vue'
- import {empty} from "@/uni_modules/uv-ui-tools/libs/function/test";
- import _ from "lodash";
- import {createPropDefine} from "@/utils";
- import {findTreePath} from "@/utils/tree-helper";
- import {autoFormValidate} from "@/utils/uni-helper";
- const picker = ref(null)
- const props = defineProps({
- title: createPropDefine(''),
- placeholder: createPropDefine(''),
- data: createPropDefine([], Array),
- modelValue: createPropDefine(null, [String, Number, Object]),
- labelProp: createPropDefine(''),
- valueProp: createPropDefine(''),
- emptyDisplay: createPropDefine(''),
- treeProp: createPropDefine('')
- })
- const emits = defineEmits(['change', 'update:modelValue'])
- const instance = getCurrentInstance()
- const valueMode = computed(() => !empty(props.modelValue) || !!props.emptyDisplay)
- const display = computed(() => {
- if (empty(props.modelValue) && !!props.emptyDisplay) return props.emptyDisplay
- return getLabel(current.value) || props.emptyDisplay
- })
- const currentPath = computed(() => findTreePath(props.data, item => getValue(item) == props.modelValue, props.treeProp))
- const current = computed(() => _.last(currentPath.value))
- const columns = ref([])
- const defaultIndex = ref([])
- const handleClick = function () {
- setDefaultColumnsAndIndexs()
- picker.value.open()
- }
- // columnIndex 正在改变的列 > index 改变后的序号 > indexs 当前选中的全部序号
- // > value 当前选中的全部元素 > values 当前columns
- const handleConfirm = function ({value}) {
- const selected = _.last(value)
- const selectedValue = getValue(selected)
- emits('update:modelValue', selectedValue)
- emits('change', selected)
- // try trigger uv-form validate
- autoFormValidate(instance, 'change')
- }
- const handleChange = function ({columnIndex, value}) {
- if (!props.treeProp) return // 不是树形结构
- if (columnIndex == value.length - 1) return // 操作的是最后一列
- const changToValue = getValue(value[columnIndex])
- const {cols, idxes} = calculateColumnsAndIndexs(changToValue)
- console.log('calculateColumnsAndIndexs', cols, idxes)
- columns.value = cols
- picker.value.setIndexs(idxes, true)
- }
- const setDefaultColumnsAndIndexs = function () {
- const {cols, idxes} = calculateColumnsAndIndexs(props.modelValue)
- columns.value = cols
- defaultIndex.value = idxes
- }
- /*
- * @description 根据给定的值计算picker所需要的columns和indexs
- * */
- const calculateColumnsAndIndexs = function (value, autoEnd = true) {
- const {data, treeProp} = props
- const cols = []
- const idxes = []
- const path = findTreePath(data, n => getValue(n) == value, treeProp)
- // auto end // 指定的条件,可能查出来的是中间某列的值,此时自动帮它选中至最后一列
- if (autoEnd && treeProp && path?.length) {
- let final = _.last(path)
- while (final[treeProp]?.length) {
- final = final[treeProp][0]
- path.push(final)
- }
- }
- // modelValue logic
- let prevNode = data
- _.forEach(path, item => {
- const idx = prevNode.findIndex(n => getValue(n) == getValue(item))
- if (idx < 0) {
- // 无效值,停止迭代
- cols.length = 0
- idxes.length = 0
- return false // lodash.forEach接收到false返回会终止迭代
- }
- cols.push(prevNode)
- idxes.push(idx)
- prevNode = _.get(prevNode, idx + '.' + treeProp)
- })
- // default logic
- if (!cols.length && data.length) {
- prevNode = data
- do {
- cols.push(prevNode)
- idxes.push(0)
- prevNode = _.get(prevNode, '0.' + props.treeProp)
- } while (prevNode)
- }
- return {cols, idxes}
- }
- const getValue = item => _.get(item, props.valueProp, item)
- const getLabel = item => _.get(item, props.labelProp, item)
- defineExpose({current, currentPath})
- </script>
- <style scoped>
- </style>
|