2 changed files with 128 additions and 0 deletions
@ -0,0 +1,126 @@ |
|||||||
|
<script lang="ts" setup> |
||||||
|
import type { PropType } from 'vue' |
||||||
|
import { computed, ref, unref, watch, watchEffect } from 'vue' |
||||||
|
import { Checkbox } from 'ant-design-vue' |
||||||
|
import { get, omit } from 'lodash-es' |
||||||
|
import type { CheckboxChangeEvent } from 'ant-design-vue/lib/checkbox/interface' |
||||||
|
import { isFunction } from '@/utils/is' |
||||||
|
import { useRuleFormItem } from '@/hooks/component/useFormItem' |
||||||
|
import { useAttrs } from '@/hooks/core/useAttrs' |
||||||
|
import { propTypes } from '@/utils/propTypes' |
||||||
|
|
||||||
|
interface OptionsItem { |
||||||
|
label?: string |
||||||
|
value?: string | number |
||||||
|
disabled?: boolean |
||||||
|
indeterminate?: boolean |
||||||
|
onChange?: (e: CheckboxChangeEvent) => void |
||||||
|
[key: string]: any |
||||||
|
} |
||||||
|
|
||||||
|
defineOptions({ name: 'ApiCheckboxGroup' }) |
||||||
|
|
||||||
|
const props = defineProps({ |
||||||
|
api: { |
||||||
|
type: Function as PropType<(arg?: any) => Promise<OptionsItem[]>>, |
||||||
|
default: null, |
||||||
|
}, |
||||||
|
params: { |
||||||
|
type: [Object, String] as PropType<any | string>, |
||||||
|
default: () => ({}), |
||||||
|
}, |
||||||
|
value: { |
||||||
|
type: Array as PropType<(string | number | boolean)[]>, |
||||||
|
}, |
||||||
|
numberToString: propTypes.bool, |
||||||
|
resultField: propTypes.string.def(''), |
||||||
|
labelField: propTypes.string.def('label'), |
||||||
|
valueField: propTypes.string.def('value'), |
||||||
|
immediate: propTypes.bool.def(true), |
||||||
|
}) |
||||||
|
const emit = defineEmits(['options-change', 'change']) |
||||||
|
|
||||||
|
const options = ref<OptionsItem[]>([]) |
||||||
|
const loading = ref(false) |
||||||
|
const isFirstLoad = ref(true) |
||||||
|
const emitData = ref<any[]>([]) |
||||||
|
const attrs = useAttrs() |
||||||
|
// Embedded in the form, just use the hook binding to perform form verification |
||||||
|
const [state] = useRuleFormItem(props, 'value', 'change', emitData) |
||||||
|
|
||||||
|
// Processing options value |
||||||
|
const getOptions = computed(() => { |
||||||
|
const { labelField, valueField, numberToString } = props |
||||||
|
|
||||||
|
return unref(options).reduce((prev, next: any) => { |
||||||
|
if (next) { |
||||||
|
const value = next[valueField] |
||||||
|
prev.push({ |
||||||
|
label: next[labelField], |
||||||
|
value: numberToString ? `${value}` : value, |
||||||
|
...omit(next, [labelField, valueField]), |
||||||
|
}) |
||||||
|
} |
||||||
|
return prev |
||||||
|
}, [] as (OptionsItem & { value: OptionsItem['label '] })[]) |
||||||
|
}) |
||||||
|
|
||||||
|
watchEffect(() => { |
||||||
|
props.immediate && fetch() |
||||||
|
}) |
||||||
|
|
||||||
|
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 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function emitChange() { |
||||||
|
emit('options-change', unref(getOptions)) |
||||||
|
} |
||||||
|
|
||||||
|
function handleClick(...args) { |
||||||
|
emitData.value = args |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<Checkbox.Group v-bind="attrs" v-model:value="state"> |
||||||
|
<template v-for="item in getOptions" :key="`${item.value}`"> |
||||||
|
<Checkbox |
||||||
|
v-bind="item" |
||||||
|
@click="handleClick(item)" |
||||||
|
> |
||||||
|
{{ item.label }} |
||||||
|
</Checkbox> |
||||||
|
</template> |
||||||
|
</Checkbox.Group> |
||||||
|
</template> |
Reference in new issue