207 lines
7.2 KiB
Vue
207 lines
7.2 KiB
Vue
<template>
|
|
<a-form
|
|
ref="formProMaxRef"
|
|
v-bind="props"
|
|
:model="modelValue"
|
|
>
|
|
<a-row :gutter="props.gutter">
|
|
<a-col
|
|
v-for="(item,field) in props.formItemOptions as FormProMaxItemOptions<T>"
|
|
:key="field"
|
|
v-bind="getResponsive(item)"
|
|
>
|
|
<a-form-item
|
|
:name="field"
|
|
v-bind="item"
|
|
:label="undefined"
|
|
>
|
|
<template v-slot:label>
|
|
{{ item.label }}
|
|
<template v-if="item.remarkRender">
|
|
<a-popover :title="item.label" :content="item.remarkRender()">
|
|
<QuestionCircleOutlined class="margin-left-xs" style="color: red"/>
|
|
</a-popover>
|
|
</template>
|
|
</template>
|
|
<!-- 自定义组件 -->
|
|
<!-- ant design vue 组件 -->
|
|
<a-input
|
|
v-if="item.type==='input'"
|
|
v-model:value="modelValue[field]"
|
|
style="width: 100%"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="getPlaceholder(item)"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
/>
|
|
<a-input-password
|
|
v-else-if="item.type==='inputPassword'"
|
|
v-model:value="modelValue[field]"
|
|
style="width: 100%"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="getPlaceholder(item)"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
/>
|
|
<a-input-number
|
|
v-else-if="item.type==='inputNumber'"
|
|
v-model:value="modelValue[field]"
|
|
style="width: 100%"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="getPlaceholder(item)"
|
|
/>
|
|
<a-textarea
|
|
v-else-if="item.type==='inputTextArea'"
|
|
v-model:value="modelValue[field]"
|
|
style="width: 100%"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="getPlaceholder(item)"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
/>
|
|
<a-radio-group
|
|
v-else-if="item.type==='radioGroup'"
|
|
v-model:value="modelValue[field]"
|
|
style="width: 100%"
|
|
v-bind="item.componentsProps"
|
|
:options="item.options"
|
|
/>
|
|
<a-checkbox-group
|
|
v-else-if="item.type==='checkboxGroup'"
|
|
v-model:value="modelValue[field]"
|
|
style="width: 100%"
|
|
v-bind="item.componentsProps"
|
|
:options="item.options"
|
|
/>
|
|
<a-select
|
|
v-else-if="item.type==='select'"
|
|
v-model:value="modelValue[field]"
|
|
style="width: 100%"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="getPlaceholder(item)"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
:options="item.options"
|
|
/>
|
|
<a-tree-select
|
|
v-else-if="item.type==='treeSelect'"
|
|
style="width: 100%"
|
|
v-model:value="modelValue[field]"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="getPlaceholder(item)"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
:tree-data="item.options"
|
|
/>
|
|
<a-cascader
|
|
v-else-if="item.type ==='cascader'"
|
|
style="width: 100%"
|
|
v-model:value="modelValue[field]"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="getPlaceholder(item)"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
:options="item.options"
|
|
/>
|
|
<a-range-picker
|
|
v-else-if="item.type ==='rangePicker'"
|
|
style="width: 100%"
|
|
v-model:value="modelValue[field]"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="item.componentsProps?.placeholder ?? ['开始日期', '结束日期']"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
/>
|
|
<a-date-picker
|
|
v-else-if="item.type ==='datePicker'"
|
|
style="width: 100%"
|
|
v-model:value="modelValue[field]"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="item.componentsProps?.placeholder ?? '请选择日期'"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
/>
|
|
<a-time-range-picker
|
|
v-else-if="item.type ==='timeRangePicker'"
|
|
style="width: 100%"
|
|
v-model:value="modelValue[field]"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="item.componentsProps?.placeholder ?? ['开始时间', '结束时间']"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
/>
|
|
<a-time-picker
|
|
v-else-if="item.type ==='timePicker'"
|
|
style="width: 100%"
|
|
v-model:value="modelValue[field]"
|
|
v-bind="item.componentsProps"
|
|
:placeholder="getPlaceholder(item)"
|
|
:allowClear="item.componentsProps?.allowClear ?? true"
|
|
/>
|
|
<template v-else-if="item.type==='custom'">
|
|
<component :is="item.customRender"/>
|
|
</template>
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
<slot name="formOperation"></slot>
|
|
</a-form>
|
|
</template>
|
|
|
|
<script setup lang="ts" generic="T extends Record<string,any>">
|
|
import {FormInstance} from "ant-design-vue";
|
|
import {ref} from "vue";
|
|
import {FormExpose} from "ant-design-vue/es/form/Form";
|
|
import {QuestionCircleOutlined} from '@ant-design/icons-vue'
|
|
import {FormProMaxItemOptions, FormProMaxItemProps, FormProMaxProps} from "@/types/components/form/index.ts";
|
|
|
|
|
|
const modelValue = defineModel<T>('value', {
|
|
default: {}
|
|
})
|
|
|
|
const props = withDefaults(defineProps<FormProMaxProps<T>>(), {
|
|
grid: () => {
|
|
return {
|
|
span: 24
|
|
}
|
|
},
|
|
gutter: 10,
|
|
labelCol: () => {
|
|
return {
|
|
style: {
|
|
width: '120px'
|
|
}
|
|
}
|
|
},
|
|
wrapperCol: () => {
|
|
return {
|
|
span: 18
|
|
}
|
|
},
|
|
labelAlign: "left",
|
|
colon: undefined,
|
|
disabled: undefined,
|
|
hideRequiredMark: undefined,
|
|
labelWrap: undefined,
|
|
scrollToFirstError: undefined,
|
|
validateOnRuleChange: undefined
|
|
})
|
|
|
|
const formProMaxRef = ref<FormInstance>(null!)
|
|
|
|
const getResponsive = (item: FormProMaxItemProps): Grid => {
|
|
//span优先级高于响应式设置
|
|
if (item.grid) return item.grid.span ? {span: item.grid.span} : {...item.grid};
|
|
return {...props.grid}
|
|
}
|
|
|
|
//优先级: 组件本身=》formItem=》label
|
|
const getPlaceholder = (item: FormProMaxItemProps) => item.componentsProps?.placeholder ?? item.placeholder ?? (item.type.includes('input') ? `请输入${item.label}` : `请选择${item.label}`)
|
|
|
|
defineExpose<FormExpose>({
|
|
validate: (nameList, options) => formProMaxRef.value?.validate(nameList, options),
|
|
resetFields: (name) => formProMaxRef.value?.resetFields(name),
|
|
clearValidate: () => formProMaxRef.value?.clearValidate(),
|
|
getFieldsValue: (nameList) => formProMaxRef.value?.getFieldsValue(nameList),
|
|
scrollToField: (name, options) => formProMaxRef.value?.scrollToField(name, options),
|
|
validateFields: (nameList, options) => formProMaxRef.value?.validateFields(nameList, options)
|
|
})
|
|
|
|
</script>
|
|
|
|
<style scoped>
|
|
|
|
</style>
|