mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-09-25 06:57:12 +08:00
refactor: 优化 GiForm 组件代码(同步 GiDemo 更新)
This commit is contained in:
@@ -1,196 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-form ref="formRef" v-bind="options.form" :model="modelValue" :auto-label-width="true">
|
<a-form ref="formRef" :auto-label-width="true" v-bind="options.form" :model="modelValue">
|
||||||
<a-row :gutter="14" v-bind="options.row" class="w-full">
|
<a-row :gutter="14" v-bind="options.row" class="w-full">
|
||||||
<template v-for="(item, index) in columns" :key="item.field">
|
<template v-for="(item, index) in columns" :key="item.field">
|
||||||
<a-col
|
<a-col v-if="!isHide(item.hide)" v-show="colVShow(index)" :span="item.span || 12"
|
||||||
v-if="!isHide(item.hide)"
|
v-bind="item.col || item.span ? item.col : options.col">
|
||||||
v-show="index <= (options.fold?.index || 0) || (index >= (options.fold?.index || 0) && !collapsed)"
|
<a-form-item v-bind="item.item" :label="item.label" :field="item.field" :rules="item.rules"
|
||||||
:span="item.span || 12"
|
:disabled="isDisabled(item.disabled)">
|
||||||
v-bind="item.col || item.span ? item.col : options.col"
|
<slot v-if="!['group-title'].includes(item.type || '')" :name="item.field"
|
||||||
>
|
v-bind="{ disabled: isDisabled(item.disabled) }">
|
||||||
<a-form-item
|
|
||||||
v-bind="item.item"
|
|
||||||
:label="item.label"
|
|
||||||
:field="item.field"
|
|
||||||
:rules="item.rules"
|
|
||||||
:disabled="isDisabled(item.disabled)"
|
|
||||||
>
|
|
||||||
<slot :name="item.field" v-bind="{ disabled: isDisabled(item.disabled) }">
|
|
||||||
<template v-if="item.type === 'input'">
|
|
||||||
<a-input
|
|
||||||
:placeholder="`请输入${item.label}`"
|
|
||||||
v-bind="(item.props as A.InputInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
></a-input>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'input-password'">
|
|
||||||
<a-input-password
|
|
||||||
:placeholder="`请输入${item.label}`"
|
|
||||||
v-bind="(item.props as A.InputInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
></a-input-password>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'input-number'">
|
|
||||||
<a-input-number
|
|
||||||
:placeholder="`请输入${item.label}`"
|
|
||||||
v-bind="(item.props as A.InputNumberInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
></a-input-number>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'textarea'">
|
|
||||||
<a-textarea
|
|
||||||
:placeholder="`请输入${item.label}`"
|
|
||||||
:show-word-limit="true"
|
|
||||||
v-bind="(item.props as A.TextareaInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
></a-textarea>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'select'">
|
|
||||||
<a-select
|
|
||||||
:placeholder="`请选择${item.label}`"
|
|
||||||
v-bind="(item.props as A.SelectInstance['$props'])"
|
|
||||||
:options="dicData[item.field] || (item.options as A.SelectInstance['$props']['options'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
></a-select>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'cascader'">
|
|
||||||
<a-cascader
|
|
||||||
:placeholder="`请选择${item.label}`"
|
|
||||||
v-bind="(item.props as A.CascaderInstance['$props'])"
|
|
||||||
:options="dicData[item.field] || (item.options as A.CascaderInstance['$props']['options'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'tree-select'">
|
|
||||||
<a-tree-select
|
|
||||||
:placeholder="`请选择${item.label}`"
|
|
||||||
v-bind="(item.props as A.TreeSelectInstance['$props'])"
|
|
||||||
:data="dicData[item.field] || (item.data as A.TreeSelectInstance['$props']['data'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
>
|
|
||||||
</a-tree-select>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'radio-group'">
|
|
||||||
<a-radio-group
|
|
||||||
v-bind="(item.props as A.RadioGroupInstance['$props'])"
|
|
||||||
:options="dicData[item.field] || (item.options as A.RadioGroupInstance['$props']['options'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
></a-radio-group>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'checkbox-group'">
|
|
||||||
<a-checkbox-group
|
|
||||||
v-bind="(item.props as A.CheckboxGroupInstance['$props'])"
|
|
||||||
:options="dicData[item.field] || (item.options as A.CheckboxGroupInstance['$props']['options'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
></a-checkbox-group>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'date-picker'">
|
|
||||||
<a-date-picker
|
|
||||||
placeholder="请选择日期"
|
|
||||||
v-bind="(item.props as A.DatePickerInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
></a-date-picker>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'time-picker'">
|
|
||||||
<a-time-picker
|
|
||||||
placeholder="请选择时间"
|
|
||||||
v-bind="(item.props as A.TimePickerInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
>
|
|
||||||
</a-time-picker>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'year-picker'">
|
|
||||||
<a-year-picker
|
|
||||||
v-bind="(item.props as A.YearPickerInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"></a-year-picker>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'month-picker'">
|
|
||||||
<a-month-picker
|
|
||||||
v-bind="(item.props as A.MonthPickerInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"></a-month-picker>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'quarter-picker'">
|
|
||||||
<a-quarter-picker
|
|
||||||
v-bind="(item.props as A.QuarterPickerInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"></a-quarter-picker>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'week-picker'">
|
|
||||||
<a-week-picker
|
|
||||||
v-bind="(item.props as A.WeekPickerInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"></a-week-picker>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'range-picker'">
|
<template v-if="item.type === 'range-picker'">
|
||||||
<DateRangePicker v-bind="(item.props as A.RangePickerInstance['$props'])"
|
<DateRangePicker v-bind="(item.props as A.RangePickerInstance['$props'])"
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
||||||
@update:model-value="valueChange($event, item.field)" />
|
@update:model-value="valueChange($event, item.field)" />
|
||||||
</template>
|
</template>
|
||||||
|
<component v-else :is="`a-${item.type}`" v-bind="getComponentBindProps(item)"
|
||||||
<template v-if="item.type === 'color-picker'">
|
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
||||||
<a-color-picker
|
@update:model-value="valueChange($event, item.field)"></component>
|
||||||
v-bind="(item.props as A.ColorPickerInstance['$props'])"
|
</slot>
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
<slot v-else name="group-title">
|
||||||
@update:model-value="valueChange($event, item.field)"></a-color-picker>
|
<a-alert v-bind="item.props">{{ item.label }}</a-alert>
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'rate'">
|
|
||||||
<a-rate
|
|
||||||
v-bind="(item.props as A.RateInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'switch'">
|
|
||||||
<a-switch
|
|
||||||
v-bind="(item.props as A.SwitchInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="item.type === 'slider'">
|
|
||||||
<a-slider
|
|
||||||
v-bind="(item.props as A.SliderInstance['$props'])"
|
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
|
||||||
@update:model-value="valueChange($event, item.field)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</slot>
|
</slot>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</template>
|
</template>
|
||||||
<a-col v-if="!options.btns?.hide" :span="options.btns?.span || 12" v-bind="options.btns?.col">
|
<a-col v-if="!options.btns?.hide" :span="options.btns?.span || 12" v-bind="options.btns?.col">
|
||||||
<a-space wrap :size="[8, 16]" style="flex-wrap: nowrap">
|
<a-space wrap>
|
||||||
<slot name="suffix">
|
<slot name="suffix">
|
||||||
<a-button type="primary" @click="emit('search')">
|
<a-button type="primary" @click="emit('search')">
|
||||||
<template #icon><icon-search /></template>
|
<template #icon><icon-search /></template>
|
||||||
@@ -215,7 +49,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type * as A from '@arco-design/web-vue'
|
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
import type { Columns, ColumnsItem, ColumnsItemDisabled, ColumnsItemHide, Options } from './type'
|
import type { Columns, ColumnsItem, ColumnsItemDisabled, ColumnsItemHide, Options } from './type'
|
||||||
import DateRangePicker from '@/components/DateRangePicker/index.vue'
|
import DateRangePicker from '@/components/DateRangePicker/index.vue'
|
||||||
@@ -234,14 +67,63 @@ const emit = defineEmits<{
|
|||||||
(e: 'reset'): void
|
(e: 'reset'): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const formRef = ref('formRef')
|
||||||
|
const collapsed = ref(props.options.fold?.defaultCollapsed ?? false)
|
||||||
|
const dicData: Record<string, any> = reactive({})
|
||||||
|
|
||||||
|
// col组件的显示隐藏
|
||||||
|
const colVShow = (index: number) => {
|
||||||
|
return index <= (props.options.fold?.index || 0) || (index >= (props.options.fold?.index || 0) && !collapsed.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件的默认props配置
|
||||||
|
const getComponentBindProps = (item: ColumnsItem) => {
|
||||||
|
const obj: Partial<ColumnsItem['props'] & { placeholder: string }> = {}
|
||||||
|
if (item.type === 'input') {
|
||||||
|
obj.placeholder = `请输入${item.label}`
|
||||||
|
}
|
||||||
|
if (item.type === 'input-password') {
|
||||||
|
obj.placeholder = `请输入${item.label}`
|
||||||
|
}
|
||||||
|
if (item.type === 'input-number') {
|
||||||
|
obj.placeholder = `请输入${item.label}`
|
||||||
|
}
|
||||||
|
if (item.type === 'textarea') {
|
||||||
|
obj.placeholder = `请输入${item.label}`
|
||||||
|
obj.maxLength = 200
|
||||||
|
}
|
||||||
|
if (item.type === 'select') {
|
||||||
|
obj.placeholder = `请选择${item.label}`
|
||||||
|
obj.options = dicData[item.field] || item.options
|
||||||
|
}
|
||||||
|
if (item.type === 'cascader') {
|
||||||
|
obj.placeholder = `请选择${item.label}`
|
||||||
|
obj.options = dicData[item.field] || item.options
|
||||||
|
}
|
||||||
|
if (item.type === 'tree-select') {
|
||||||
|
obj.placeholder = `请选择${item.label}`
|
||||||
|
obj.data = dicData[item.field] || item.data
|
||||||
|
}
|
||||||
|
if (item.type === 'radio-group') {
|
||||||
|
obj.options = dicData[item.field] || item.options
|
||||||
|
}
|
||||||
|
if (item.type === 'checkbox-group') {
|
||||||
|
obj.options = dicData[item.field] || item.options
|
||||||
|
}
|
||||||
|
if (item.type === 'date-picker') {
|
||||||
|
obj.placeholder = '请选择日期'
|
||||||
|
}
|
||||||
|
if (item.type === 'time-picker') {
|
||||||
|
obj.allowClear = true
|
||||||
|
obj.placeholder = `请选择时间`
|
||||||
|
}
|
||||||
|
return { ...obj, ...item.props }
|
||||||
|
}
|
||||||
|
|
||||||
const valueChange = (value: any, field: string) => {
|
const valueChange = (value: any, field: string) => {
|
||||||
emit('update:modelValue', Object.assign(props.modelValue, { [field]: value }))
|
emit('update:modelValue', Object.assign(props.modelValue, { [field]: value }))
|
||||||
}
|
}
|
||||||
|
|
||||||
const collapsed = ref(props.options.fold?.defaultCollapsed ?? false)
|
|
||||||
const formRef = ref<A.FormInstance>()
|
|
||||||
defineExpose({ formRef })
|
|
||||||
|
|
||||||
const isHide = (hide?: ColumnsItemHide<boolean | object>) => {
|
const isHide = (hide?: ColumnsItemHide<boolean | object>) => {
|
||||||
if (hide === undefined) return false
|
if (hide === undefined) return false
|
||||||
if (typeof hide === 'boolean') return hide
|
if (typeof hide === 'boolean') return hide
|
||||||
@@ -258,7 +140,8 @@ const isDisabled = (disabled?: ColumnsItemDisabled<boolean | object>) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dicData: Record<string, any> = reactive({})
|
defineExpose({ formRef })
|
||||||
|
|
||||||
props.columns.forEach((item) => {
|
props.columns.forEach((item) => {
|
||||||
if (item.request && typeof item.request === 'function' && item?.init) {
|
if (item.request && typeof item.request === 'function' && item?.init) {
|
||||||
item.request(props.modelValue).then((res) => {
|
item.request(props.modelValue).then((res) => {
|
||||||
@@ -305,7 +188,7 @@ watch(cloneForm as any, (newVal, oldVal) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
:deep(.arco-form-item-layout-inline) {
|
:deep(.arco-form-item-layout-inline) {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -2,28 +2,32 @@ import type * as A from '@arco-design/web-vue'
|
|||||||
|
|
||||||
export type FormType =
|
export type FormType =
|
||||||
| 'input'
|
| 'input'
|
||||||
|
| 'input-password'
|
||||||
|
| 'input-number'
|
||||||
| 'select'
|
| 'select'
|
||||||
| 'radio-group'
|
| 'radio-group'
|
||||||
| 'checkbox-group'
|
| 'checkbox-group'
|
||||||
| 'textarea'
|
| 'textarea'
|
||||||
| 'date-picker'
|
| 'date-picker'
|
||||||
| 'time-picker'
|
|
||||||
| 'year-picker'
|
| 'year-picker'
|
||||||
| 'quarter-picker'
|
| 'quarter-picker'
|
||||||
| 'week-picker'
|
| 'week-picker'
|
||||||
| 'range-picker'
|
| 'range-picker'
|
||||||
| 'month-picker'
|
| 'month-picker'
|
||||||
|
| 'time-picker'
|
||||||
| 'color-picker'
|
| 'color-picker'
|
||||||
| 'input-number'
|
|
||||||
| 'rate'
|
| 'rate'
|
||||||
| 'switch'
|
| 'switch'
|
||||||
| 'slider'
|
| 'slider'
|
||||||
| 'cascader'
|
| 'cascader'
|
||||||
| 'tree-select'
|
| 'tree-select'
|
||||||
| 'input-password'
|
| 'upload'
|
||||||
|
| 'group-title'
|
||||||
|
|
||||||
export type ColumnsItemPropsKey =
|
export type ColumnsItemPropsKey =
|
||||||
| keyof A.InputInstance['$props']
|
| keyof A.InputInstance['$props']
|
||||||
|
| keyof A.InputPasswordInstance['$props']
|
||||||
|
| keyof A.InputNumberInstance['$props']
|
||||||
| keyof A.SelectInstance['$props']
|
| keyof A.SelectInstance['$props']
|
||||||
| keyof A.TextareaInstance['$props']
|
| keyof A.TextareaInstance['$props']
|
||||||
| keyof A.DatePickerInstance['$props']
|
| keyof A.DatePickerInstance['$props']
|
||||||
@@ -35,13 +39,14 @@ export type ColumnsItemPropsKey =
|
|||||||
| keyof A.RangePickerInstance['$props']
|
| keyof A.RangePickerInstance['$props']
|
||||||
| keyof A.RadioGroupInstance['$props']
|
| keyof A.RadioGroupInstance['$props']
|
||||||
| keyof A.CheckboxGroupInstance['$props']
|
| keyof A.CheckboxGroupInstance['$props']
|
||||||
| keyof A.InputNumberInstance['$props']
|
|
||||||
| keyof A.ColorPickerInstance['$props']
|
| keyof A.ColorPickerInstance['$props']
|
||||||
| keyof A.RateInstance['$props']
|
| keyof A.RateInstance['$props']
|
||||||
| keyof A.SwitchInstance['$props']
|
| keyof A.SwitchInstance['$props']
|
||||||
| keyof A.SliderInstance['$props']
|
| keyof A.SliderInstance['$props']
|
||||||
| keyof A.CascaderInstance['$props']
|
| keyof A.CascaderInstance['$props']
|
||||||
| keyof A.TreeSelectInstance['$props']
|
| keyof A.TreeSelectInstance['$props']
|
||||||
|
| keyof A.UploadInstance['$props']
|
||||||
|
| keyof A.AlertInstance['$props']
|
||||||
|
|
||||||
export type ColumnsItemHide<F> = boolean | ((form: F) => boolean)
|
export type ColumnsItemHide<F> = boolean | ((form: F) => boolean)
|
||||||
export type ColumnsItemDisabled<F> = boolean | ((form: F) => boolean)
|
export type ColumnsItemDisabled<F> = boolean | ((form: F) => boolean)
|
||||||
@@ -71,18 +76,21 @@ export interface ColumnsItem<F = any> {
|
|||||||
item?: Omit<A.FormItemInstance['$props'], 'label' | 'field'> // a-form-item的props
|
item?: Omit<A.FormItemInstance['$props'], 'label' | 'field'> // a-form-item的props
|
||||||
props?:
|
props?:
|
||||||
& A.InputInstance['$props']
|
& A.InputInstance['$props']
|
||||||
|
& A.InputPasswordInstance['$props']
|
||||||
|
& A.InputNumberInstance['$props']
|
||||||
& A.SelectInstance['$props']
|
& A.SelectInstance['$props']
|
||||||
& A.TextareaInstance['$props']
|
& A.TextareaInstance['$props']
|
||||||
& A.DatePickerInstance['$props']
|
& A.DatePickerInstance['$props']
|
||||||
& A.TimePickerInstance['$props']
|
& A.TimePickerInstance['$props']
|
||||||
& A.RadioGroupInstance['$props']
|
& A.RadioGroupInstance['$props']
|
||||||
& A.CheckboxGroupInstance['$props']
|
& A.CheckboxGroupInstance['$props']
|
||||||
& A.InputNumberInstance['$props']
|
|
||||||
& A.RateInstance['$props']
|
& A.RateInstance['$props']
|
||||||
& A.SwitchInstance['$props']
|
& A.SwitchInstance['$props']
|
||||||
& A.SliderInstance['$props']
|
& A.SliderInstance['$props']
|
||||||
& A.CascaderInstance['$props']
|
& A.CascaderInstance['$props']
|
||||||
& A.TreeSelectInstance['$props']
|
& A.TreeSelectInstance['$props']
|
||||||
|
& A.UploadInstance['$props']
|
||||||
|
& A.AlertInstance['$props']
|
||||||
rules?: A.FormItemInstance['$props']['rules'] // 表单校验规则
|
rules?: A.FormItemInstance['$props']['rules'] // 表单校验规则
|
||||||
// 下拉列表|复选框组|单选框组|级联选择组件的options
|
// 下拉列表|复选框组|单选框组|级联选择组件的options
|
||||||
options?:
|
options?:
|
||||||
|
Reference in New Issue
Block a user