Commit 0c57c6d7f244b5b4e4ee8fef3aad9a7fa327fb0f
1 parent
2161ab68
feat:新增Form 里的远程下拉radio,精简版没有,完整版有
Showing
4 changed files
with
135 additions
and
0 deletions
| ... | ... | @@ -9,5 +9,7 @@ export { useForm } from './src/hooks/useForm'; |
| 9 | 9 | export { default as ApiSelect } from './src/components/ApiSelect.vue'; |
| 10 | 10 | export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue'; |
| 11 | 11 | export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue'; |
| 12 | +export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue'; | |
| 13 | + | |
| 12 | 14 | |
| 13 | 15 | export { BasicForm }; | ... | ... |
| ... | ... | @@ -27,6 +27,7 @@ import { BasicUpload } from '/@/components/Upload'; |
| 27 | 27 | import { StrengthMeter } from '/@/components/StrengthMeter'; |
| 28 | 28 | import { IconPicker } from '/@/components/Icon'; |
| 29 | 29 | import { CountdownInput } from '/@/components/CountDown'; |
| 30 | +import ApiRadioGroup from './components/ApiRadioGroup.vue'; | |
| 30 | 31 | //自定义组件 |
| 31 | 32 | import JAddInput from './jeecg/components/JAddInput.vue'; |
| 32 | 33 | |
| ... | ... | @@ -39,6 +40,7 @@ componentMap.set('InputSearch', Input.Search); |
| 39 | 40 | componentMap.set('InputTextArea', Input.TextArea); |
| 40 | 41 | componentMap.set('InputNumber', InputNumber); |
| 41 | 42 | componentMap.set('AutoComplete', AutoComplete); |
| 43 | +componentMap.set('ApiRadioGroup', ApiRadioGroup); | |
| 42 | 44 | |
| 43 | 45 | componentMap.set('Select', Select); |
| 44 | 46 | componentMap.set('ApiSelect', ApiSelect); | ... | ... |
| 1 | +<!-- | |
| 2 | + * @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component | |
| 3 | +--> | |
| 4 | +<template> | |
| 5 | + <RadioGroup v-bind="attrs" v-model:value="state" button-style="solid" @change="handleChange"> | |
| 6 | + <template v-for="item in getOptions" :key="`${item.value}`"> | |
| 7 | + <RadioButton v-if="props.isBtn" :value="item.value" :disabled="item.disabled"> | |
| 8 | + {{ item.label }} | |
| 9 | + </RadioButton> | |
| 10 | + <Radio v-else :value="item.value" :disabled="item.disabled"> | |
| 11 | + {{ item.label }} | |
| 12 | + </Radio> | |
| 13 | + </template> | |
| 14 | + </RadioGroup> | |
| 15 | +</template> | |
| 16 | +<script lang="ts"> | |
| 17 | + import { defineComponent, PropType, ref, watchEffect, computed, unref, watch } from 'vue'; | |
| 18 | + import { Radio } from 'ant-design-vue'; | |
| 19 | + import { isFunction } from '/@/utils/is'; | |
| 20 | + import { useRuleFormItem } from '/@/hooks/component/useFormItem'; | |
| 21 | + import { useAttrs } from '/@/hooks/core/useAttrs'; | |
| 22 | + import { propTypes } from '/@/utils/propTypes'; | |
| 23 | + import { get, omit } from 'lodash-es'; | |
| 24 | + import { useI18n } from '/@/hooks/web/useI18n'; | |
| 25 | + type OptionsItem = { label: string; value: string | number | boolean; disabled?: boolean }; | |
| 26 | + | |
| 27 | + export default defineComponent({ | |
| 28 | + name: 'ApiRadioGroup', | |
| 29 | + components: { | |
| 30 | + RadioGroup: Radio.Group, | |
| 31 | + RadioButton: Radio.Button, | |
| 32 | + Radio, | |
| 33 | + }, | |
| 34 | + props: { | |
| 35 | + api: { | |
| 36 | + type: Function as PropType<(arg?: Recordable | string) => Promise<OptionsItem[]>>, | |
| 37 | + default: null, | |
| 38 | + }, | |
| 39 | + params: { | |
| 40 | + type: [Object, String] as PropType<Recordable | string>, | |
| 41 | + default: () => ({}), | |
| 42 | + }, | |
| 43 | + value: { | |
| 44 | + type: [String, Number, Boolean] as PropType<string | number | boolean>, | |
| 45 | + }, | |
| 46 | + isBtn: { | |
| 47 | + type: [Boolean] as PropType<boolean>, | |
| 48 | + default: false, | |
| 49 | + }, | |
| 50 | + numberToString: propTypes.bool, | |
| 51 | + resultField: propTypes.string.def(''), | |
| 52 | + labelField: propTypes.string.def('label'), | |
| 53 | + valueField: propTypes.string.def('value'), | |
| 54 | + immediate: propTypes.bool.def(true), | |
| 55 | + }, | |
| 56 | + emits: ['options-change', 'change'], | |
| 57 | + setup(props, { emit }) { | |
| 58 | + const options = ref<OptionsItem[]>([]); | |
| 59 | + const loading = ref(false); | |
| 60 | + const isFirstLoad = ref(true); | |
| 61 | + const emitData = ref<any[]>([]); | |
| 62 | + const attrs = useAttrs(); | |
| 63 | + const { t } = useI18n(); | |
| 64 | + // Embedded in the form, just use the hook binding to perform form verification | |
| 65 | + const [state] = useRuleFormItem(props); | |
| 66 | + | |
| 67 | + // Processing options value | |
| 68 | + const getOptions = computed(() => { | |
| 69 | + const { labelField, valueField, numberToString } = props; | |
| 70 | + | |
| 71 | + return unref(options).reduce((prev, next: Recordable) => { | |
| 72 | + if (next) { | |
| 73 | + const value = next[valueField]; | |
| 74 | + prev.push({ | |
| 75 | + label: next[labelField], | |
| 76 | + value: numberToString ? `${value}` : value, | |
| 77 | + ...omit(next, [labelField, valueField]), | |
| 78 | + }); | |
| 79 | + } | |
| 80 | + return prev; | |
| 81 | + }, [] as OptionsItem[]); | |
| 82 | + }); | |
| 83 | + | |
| 84 | + watchEffect(() => { | |
| 85 | + props.immediate && fetch(); | |
| 86 | + }); | |
| 87 | + | |
| 88 | + watch( | |
| 89 | + () => props.params, | |
| 90 | + () => { | |
| 91 | + !unref(isFirstLoad) && fetch(); | |
| 92 | + }, | |
| 93 | + { deep: true }, | |
| 94 | + ); | |
| 95 | + | |
| 96 | + async function fetch() { | |
| 97 | + const api = props.api; | |
| 98 | + if (!api || !isFunction(api)) return; | |
| 99 | + options.value = []; | |
| 100 | + try { | |
| 101 | + loading.value = true; | |
| 102 | + const res = await api(props.params); | |
| 103 | + if (Array.isArray(res)) { | |
| 104 | + options.value = res; | |
| 105 | + emitChange(); | |
| 106 | + return; | |
| 107 | + } | |
| 108 | + if (props.resultField) { | |
| 109 | + options.value = get(res, props.resultField) || []; | |
| 110 | + } | |
| 111 | + emitChange(); | |
| 112 | + } catch (error) { | |
| 113 | + console.warn(error); | |
| 114 | + } finally { | |
| 115 | + loading.value = false; | |
| 116 | + } | |
| 117 | + } | |
| 118 | + | |
| 119 | + function emitChange() { | |
| 120 | + emit('options-change', unref(getOptions)); | |
| 121 | + } | |
| 122 | + | |
| 123 | + function handleChange(_, ...args) { | |
| 124 | + emitData.value = args; | |
| 125 | + } | |
| 126 | + | |
| 127 | + return { state, getOptions, attrs, loading, t, handleChange, props }; | |
| 128 | + }, | |
| 129 | + }); | |
| 130 | +</script> | ... | ... |