From d6749f95c526c0e71ec946bd3bb777bc42b2c34a Mon Sep 17 00:00:00 2001 From: Ben Lin <maobin001@msn.com> Date: 星期日, 20 十月 2024 17:59:31 +0800 Subject: [PATCH] 工艺绑定优化 --- src/components/Form/src/components/ApiSelect.vue | 251 ++++++++++++++++++++++++++------------------------ 1 files changed, 131 insertions(+), 120 deletions(-) diff --git a/src/components/Form/src/components/ApiSelect.vue b/src/components/Form/src/components/ApiSelect.vue index 8239915..df59336 100644 --- a/src/components/Form/src/components/ApiSelect.vue +++ b/src/components/Form/src/components/ApiSelect.vue @@ -20,132 +20,143 @@ </template> </Select> </template> -<script lang="ts"> - import { defineComponent, PropType, ref, watchEffect, computed, unref, watch } from 'vue'; +<script lang="ts" setup> + import { PropType, ref, computed, unref, watch } from 'vue'; import { Select } from 'ant-design-vue'; - import { isFunction } from '/@/utils/is'; - import { useRuleFormItem } from '/@/hooks/component/useFormItem'; - import { useAttrs } from '@vben/hooks'; - import { get, omit } from 'lodash-es'; + import type { SelectValue } from 'ant-design-vue/es/select'; + import { isFunction } from '@/utils/is'; + import { useRuleFormItem } from '@/hooks/component/useFormItem'; + import { get, omit, isEqual } from 'lodash-es'; import { LoadingOutlined } from '@ant-design/icons-vue'; - import { useI18n } from '/@/hooks/web/useI18n'; - import { propTypes } from '/@/utils/propTypes'; + import { useI18n } from '@/hooks/web/useI18n'; + import { propTypes } from '@/utils/propTypes'; - type OptionsItem = { label: string; value: string; disabled?: boolean }; + type OptionsItem = { label?: string; value?: string; disabled?: boolean; [name: string]: any }; - export default defineComponent({ - name: 'ApiSelect', - components: { - Select, - LoadingOutlined, + defineOptions({ name: 'ApiSelect', inheritAttrs: false }); + + const props = defineProps({ + value: { type: [Array, Object, String, Number] as PropType<SelectValue> }, + numberToString: propTypes.bool, + api: { + type: Function as PropType<(arg?: any) => Promise<OptionsItem[] | Recordable<any>>>, + default: null, }, - inheritAttrs: false, - props: { - value: [Array, Object, String, Number], - numberToString: propTypes.bool, - api: { - type: Function as PropType<(arg?: any) => Promise<OptionsItem[]>>, - default: null, - }, - // api params - params: propTypes.any.def({}), - // support xxx.xxx.xx - resultField: propTypes.string.def(''), - labelField: propTypes.string.def('label'), - valueField: propTypes.string.def('value'), - immediate: propTypes.bool.def(true), - alwaysLoad: propTypes.bool.def(false), + // api params + params: propTypes.any.def({}), + // support xxx.xxx.xx + resultField: propTypes.string.def(''), + labelField: propTypes.string.def('label'), + valueField: propTypes.string.def('value'), + immediate: propTypes.bool.def(true), + alwaysLoad: propTypes.bool.def(false), + options: { + type: Array<OptionsItem>, + default: [], }, - emits: ['options-change', 'change', 'update:value'], - setup(props, { emit }) { - const options = ref<OptionsItem[]>([]); - const loading = ref(false); - const isFirstLoad = ref(true); - const emitData = ref<any[]>([]); - const attrs = useAttrs(); - const { t } = useI18n(); - - // Embedded in the form, just use the hook binding to perform form verification - const [state] = useRuleFormItem(props, 'value', 'change', emitData); - - const getOptions = computed(() => { - const { labelField, valueField, numberToString } = props; - - return unref(options).reduce((prev, next: any) => { - if (next) { - const value = get(next, valueField); - prev.push({ - ...omit(next, [labelField, valueField]), - label: get(next, labelField), - value: numberToString ? `${value}` : value, - }); - } - return prev; - }, [] as OptionsItem[]); - }); - - watchEffect(() => { - props.immediate && !props.alwaysLoad && fetch(); - }); - - watch( - () => state.value, - (v) => { - emit('update:value', v); - }, - ); - - watch( - () => props.params, - () => { - !unref(isFirstLoad) && fetch(); - }, - { deep: true }, - ); - - async function fetch() { - const api = props.api; - if (!api || !isFunction(api)) return; - options.value = []; - try { - loading.value = true; - const res = await api(props.params); - if (Array.isArray(res)) { - options.value = res; - emitChange(); - return; - } - if (props.resultField) { - options.value = get(res, props.resultField) || []; - } - emitChange(); - } catch (error) { - console.warn(error); - } finally { - loading.value = false; - } - } - - async function handleFetch(visible) { - if (visible) { - if (props.alwaysLoad) { - await fetch(); - } else if (!props.immediate && unref(isFirstLoad)) { - await fetch(); - isFirstLoad.value = false; - } - } - } - - function emitChange() { - emit('options-change', unref(getOptions)); - } - - function handleChange(_, ...args) { - emitData.value = args; - } - - return { state, attrs, getOptions, loading, t, handleFetch, handleChange }; + beforeFetch: { + type: Function as PropType<Fn>, + default: null, + }, + afterFetch: { + type: Function as PropType<Fn>, + default: null, }, }); + + const emit = defineEmits(['options-change', 'change', 'update:value']); + + const optionsRef = ref<OptionsItem[]>([]); + + const loading = ref(false); + // 棣栨鏄惁鍔犺浇杩囦簡 + const isFirstLoaded = ref(false); + const emitData = ref<OptionsItem[]>([]); + const { t } = useI18n(); + + // Embedded in the form, just use the hook binding to perform form verification + const [state] = useRuleFormItem(props, 'value', 'change', emitData); + + const getOptions = computed(() => { + const { labelField, valueField, numberToString } = props; + + let data = unref(optionsRef).reduce((prev, next: any) => { + if (next) { + const value = get(next, valueField); + prev.push({ + ...omit(next, [labelField, valueField]), + label: get(next, labelField), + value: numberToString ? `${value}` : value, + }); + } + return prev; + }, [] as OptionsItem[]); + return data.length > 0 ? data : props.options; + }); + + watch( + () => state.value, + (v) => { + emit('update:value', v); + }, + ); + + watch( + () => props.params, + (value, oldValue) => { + if (isEqual(value, oldValue)) return; + fetch(); + }, + { deep: true, immediate: props.immediate }, + ); + + async function fetch() { + let { api, beforeFetch, afterFetch, params, resultField } = props; + if (!api || !isFunction(api) || loading.value) return; + optionsRef.value = []; + try { + loading.value = true; + if (beforeFetch && isFunction(beforeFetch)) { + params = (await beforeFetch(params)) || params; + } + let res = await api(params); + if (afterFetch && isFunction(afterFetch)) { + res = (await afterFetch(res)) || res; + } + isFirstLoaded.value = true; + if (Array.isArray(res)) { + optionsRef.value = res; + emitChange(); + return; + } + if (resultField) { + optionsRef.value = get(res, resultField) || []; + } + emitChange(); + } catch (error) { + console.warn(error); + // reset status + isFirstLoaded.value = false; + } finally { + loading.value = false; + } + } + + async function handleFetch(visible: boolean) { + if (visible) { + if (props.alwaysLoad) { + await fetch(); + } else if (!props.immediate && !unref(isFirstLoaded)) { + await fetch(); + } + } + } + + function emitChange() { + emit('options-change', unref(getOptions)); + } + + function handleChange(_, ...args) { + emitData.value = args; + } </script> -- Gitblit v1.9.3