123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- <template>
- <el-form @submit.prevent :model="formModel" v-bind="_options" ref="formRef">
- <el-row :gutter="5">
- <template v-for="(item, index) in fieldList" :key="index">
- <el-col :span="item.span || 24">
- <el-form-item :rules="item.rules" :title="item.label" :prop="[item.field]">
- <template #label>
- <el-space :size="1">
- <span>{{ `${item.label}` }}</span>
- <el-tooltip v-if="item?.tooltip" effect="dark" :content="item.tooltip" placement="top">
- <i :class="'iconfont icon-yiwen'"></i>
- </el-tooltip>
- </el-space>
- </template>
- <template #default>
- <!-- 单选框 -->
- <el-radio-group v-if="item.type === 'radio'" v-model="formModel[item.field]" :disabled="item.disabled">
- <el-radio
- :label="val[item.options?.valueKey || 'value']"
- v-for="val in item.options?.data"
- :key="val[item.options?.valueKey || 'value']"
- >
- {{ val[item.options?.labelKey || 'label'] }}
- </el-radio>
- </el-radio-group>
- <!-- 复选框 -->
- <el-checkbox-group v-else-if="item.type === 'checkbox'" v-model="formModel[item.field]" :disabled="item.disabled">
- <el-checkbox
- v-for="val in item.options?.data"
- :key="val[item.options?.valueKey || 'value']"
- :label="val[item.options?.valueKey || 'value']"
- >{{ val[item.options?.labelKey || 'label'] }}
- </el-checkbox>
- </el-checkbox-group>
- <!-- 下拉框 -->
- <el-select
- v-else-if="item.type === 'select'"
- v-model="formModel[item.field]"
- :placeholder="item.options?.placeholder || '请选择'"
- :clearable="item.clearable"
- :multiple="item.options?.multiple"
- :filterable="item.options?.filterable"
- :allow-create="item.options?.allowCreate"
- :disabled="item.disabled"
- >
- <el-option
- v-for="val in item.options?.data"
- :key="val[item.options?.valueKey || 'value']"
- :label="val[item.options?.labelKey || 'label']"
- :value="val[item.options?.valueKey || 'value']"
- />
- </el-select>
- <el-tree-select
- v-else-if="item.type === 'select-tree'"
- v-model="formModel[item.field]"
- :data="item.options?.data"
- :props="{
- label: `${item.options?.labelKey || 'label'}`,
- children: `${item.options?.children || 'children'}`
- }"
- :node-key="`${item.options?.valueKey || 'id'}`"
- placeholder="请选择归属部门"
- clearable
- check-strictly
- />
- <!-- 时间 -->
- <el-date-picker
- v-else-if="item.type === 'date-picker'"
- v-model="formModel[item.field]"
- :readonly="item.readonly"
- :type="item.options?.type ?? 'data'"
- :placeholder="item.placeholder || item.label"
- :disabled="item.disabled"
- :value-format="item.options?.valueFormat ?? 'YYYY-MM-DD HH:mm:ss'"
- :clearable="item.clearable"
- />
- <el-input-number
- v-else-if="item.type === 'input-number'"
- v-model="formModel[item.field]"
- :min="item.options?.min"
- :max="item.options?.max"
- controls-position="right"
- />
- <SelectIcon v-else-if="item.type === 'select-icon'" v-model:icon-value="formModel[item.field]" />
- <!-- 默认输入框 -->
- <el-input
- v-else
- v-model="formModel[item.field]"
- :readonly="item.readonly"
- :type="item.type ?? 'text'"
- :placeholder="item.placeholder || item.label"
- :disabled="item.disabled"
- :show-password="item.showPassword"
- :clearable="item.clearable"
- @keyup.enter="handleKeyUp(item.enterable)"
- />
- </template>
- </el-form-item>
- </el-col>
- </template>
- </el-row>
- <el-form-item v-if="_options.hasFooter">
- <slot name="buttons" :model="formModel" :form-ref="formRef">
- <el-button type="primary" @click="onSubmit(formRef)">{{ _options.submitButtonText }}</el-button>
- <el-button v-if="_options.showResetButton" type="info" @click="resetForm(formRef)">
- {{ _options.resetButtonText }}
- </el-button>
- <el-button v-if="_options.showCancelButton" @click="emit('cancel')">
- {{ _options.cancelButtonText }}
- </el-button>
- </slot>
- </el-form-item>
- </el-form>
- </template>
- <script setup lang="ts" name="ProFormOld">
- import type { FormInstance } from 'element-plus'
- import { ComputedRef, ref, computed, watch, unref } from 'vue'
- import SelectIcon from '@/components/SelectIcon/index.vue'
- // 父组件传递的值
- export interface ProFormProps {
- fieldList: Form.FieldItem[]
- model?: Record<Form.FieldItem['field'], Form.FieldItem['value']>
- options?: Form.Options
- }
- // 表单的数据
- const formModel = ref<Record<string, any>>({})
- const formRef = ref<FormInstance>()
- const props = defineProps<ProFormProps>()
- // 设置option默认值,如果传入自定义的配置则合并option配置项
- const _options: ComputedRef<Form.Options> = computed(() => {
- const option = {
- labelPosition: 'right',
- disabled: false,
- hasFooter: true,
- submitButtonText: '提交',
- resetButtonText: '重置',
- cancelButtonText: '取消'
- }
- return Object.assign(option, props?.options)
- })
- interface EmitEvent {
- (e: 'submit', params: any): void
- (e: 'reset'): void
- (e: 'cancel'): void
- }
- const enumMap = ref(new Map<string, { [key: string]: any }[]>())
- const setEnumMap = async ({ field, enum: enumValue }: Form.FieldItem) => {
- if (!enumValue) return
- // 如果当前 enumMap 存在相同的值 return
- if (enumMap.value.has(field!) && (typeof enumValue === 'function' || enumMap.value.get(field!) === enumValue)) return
- // 当前 enum 为静态数据,则直接存储到 enumMap
- if (typeof enumValue !== 'function') return enumMap.value.set(field!, unref(enumValue!))
- // 为了防止接口执行慢,而存储慢,导致重复请求,所以预先存储为[],接口返回后再二次存储
- enumMap.value.set(field!, [])
- // 当前 enum 为后台数据需要请求数据,则调用该请求接口,并存储到 enumMap
- let { data } = await enumValue()
- enumMap.value.set(field!, data)
- }
- // 处理枚举
- const handelEnum = (item: Form.FieldItem) => {
- let enumData = enumMap.value.get(item.field)
- if (!enumData) return []
- // 返回对象类型
- if (item.type === 'select-tree' && item.options?.labelKey && item.options?.valueKey) {
- enumData = enumData.map((el: { [key: string]: any }) => {
- return {
- ...el,
- label: el[item.options?.labelKey || 'label'],
- children: el[item.options?.children || 'children'] || []
- }
- })
- }
- return enumData
- }
- // 处理表单项需要的参数
- props.fieldList.forEach(async item => {
- await setEnumMap(item)
- if (item.options) item.options.data = handelEnum(item)
- })
- const emit = defineEmits<EmitEvent>()
- // 根据fieldList初始化model, 如果formModel有传值就用传递的model数据模型,否则就给上面声明的formModel设置相应的(key,value) [item.field], item.value是表单的默认值(选填)
- watch(
- () => props.model,
- () => {
- props.fieldList.map((item: Form.FieldItem) => {
- // 如果类型为checkbox,默认值需要设置一个空数组
- const value = item.type === 'checkbox' ? [] : ''
- props.model ? (formModel.value = props.model) : (formModel.value[item.field] = item.value || value)
- })
- },
- { immediate: true }
- )
- // 提交按钮
- const onSubmit = (formEl: FormInstance | undefined) => {
- if (!formEl) return
- formEl.validate(valid => {
- if (valid) {
- emit('submit', formModel.value)
- } else {
- return false
- }
- })
- }
- // 输入框回车事件
- const handleKeyUp = (enterable: boolean | undefined) => {
- if (!enterable) return
- onSubmit(formRef.value)
- }
- // 重置
- const resetForm = (formEl: FormInstance | undefined) => {
- if (!formEl) return
- formEl.resetFields()
- }
- defineExpose({
- formRef,
- resetForm,
- onSubmit
- })
- </script>
|