123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- <template>
- <div id="custom-form">
- <el-form ref="formRef" :model="form" :rules="rules" :label-width="labelWidth" class="form" @submit.prevent :disabled="disabled">
- <el-col :span="span" v-for="(item, index) in fields" :key="index">
- <el-form-item v-if="display(item)" :key="`form-field-${item.model}`" :label="getField('label', item)" :prop="item.model" :required="item.required">
- <template v-if="item.custom">
- <slot :name="item.model" v-bind="{ item }"></slot>
- </template>
- <template v-else>
- <template v-if="item.type === 'textarea'">
- <el-input
- clearable
- v-model="form[item.model]"
- :type="item.type"
- :placeholder="getField('placeholder', item)"
- v-bind="item.options"
- @change="dataChange(item.model)"
- show-word-limit
- ></el-input>
- </template>
- <template v-else-if="item.type === 'numbers'">
- <el-input-number v-model="form[item.model]" :placeholder="getField('placeholder', item)" @change="dataChange(item.model)" style="width: 100%" />
- </template>
- <template v-else-if="item.type === 'radio'">
- <el-radio-group v-model="form[item.model]" :type="item.type" v-bind="item.options" @change="dataChange(item.model)">
- <slot :name="item.model" v-bind="{ item }"></slot>
- </el-radio-group>
- </template>
- <template v-else-if="item.type === 'checkbox'">
- <el-checkbox-group v-model="form[item.model]" :type="item.type" v-bind="item.options">
- <slot :name="item.model" v-bind="{ item }"></slot>
- </el-checkbox-group>
- </template>
- <template v-else-if="item.type === 'select'">
- <el-select
- clearable
- filterable
- allow-create
- default-first-option
- v-model="form[item.model]"
- :type="item.type"
- :placeholder="getField('selectplaceholder', item)"
- v-bind="item.options"
- @change="dataChange(item.model)"
- style="width: 100%"
- >
- <slot :name="item.model" v-bind="{ item }"></slot>
- </el-select>
- </template>
- <template v-else-if="item.type === 'selectMany'">
- <el-select
- filterable
- clearable
- multiple
- collapse-tags
- v-model="form[item.model]"
- :type="item.type"
- :placeholder="getField('selectplaceholder', item)"
- v-bind="item.options"
- @change="dataChange(item.model)"
- style="width: 100%"
- >
- <slot :name="item.model" v-bind="{ item }"></slot>
- </el-select>
- </template>
- <template v-else-if="item.type === `year` || item.type == 'month' || item.type == 'date' || item.type == 'daterange' || item.type == 'datetime' || item.type == 'datetimerange'">
- <el-date-picker
- v-model="form[item.model]"
- :type="item.type"
- :placeholder="getField('selectplaceholder', item)"
- :format="getDateFormat(item.type)"
- :value-format="getDateFormat(item.type)"
- v-bind="item.options"
- @change="dataChange(item.model)"
- range-separator="至"
- style="width: 100%"
- >
- </el-date-picker>
- </template>
- <template v-else-if="item.type === `time`">
- <el-time-picker
- v-model="form[item.model]"
- :placeholder="getField('selectplaceholder', item)"
- :format="getDateFormat(item.type)"
- :value-format="getDateFormat(item.type)"
- v-bind="item.options"
- @change="dataChange(item.model)"
- style="width: 100%"
- >
- </el-time-picker>
- </template>
- <template v-else-if="item.type === `inputnumber`">
- <el-input-number v-model="form[item.model]" :placeholder="getField('placeholder', item)" v-bind="item.options" @change="dataChange(item.model)" style="width: 100%"></el-input-number>
- </template>
- <template v-else>
- <el-input
- clearable
- v-model="form[item.model]"
- :type="getField('type', item)"
- :placeholder="getField('placeholder', item)"
- :show-password="getField('type', item) === 'password'"
- v-bind="item.options"
- @change="dataChange(item.model)"
- ></el-input>
- </template>
- </template>
- </el-form-item>
- </el-col>
- <el-col :span="24" label="" class="btn" v-if="useSave">
- <slot name="submit">
- <el-button type="primary" @click="save(formRef)">{{ submitText || submitTextDefault }}</el-button>
- </slot>
- </el-col>
- </el-form>
- </div>
- </template>
- <script setup>
- import { get, isFunction } from 'lodash-es'
- const { t } = useI18n()
- const submitTextDefault = t('common.save')
- const props = defineProps({
- modelValue: { type: Object },
- rules: { type: Array, default: () => {} },
- labelWidth: { type: String, default: 'auto' },
- disabled: { type: Boolean, default: false },
- fields: { type: Array, default: () => [] },
- submitText: { type: String },
- useSave: { type: Boolean, default: true },
- span: { type: Number, default: 24 } // 限制两侧的距离,24就是整行全用
- })
- const emits = defineEmits(['update:modelValue', 'dataChange', 'save'])
- const formRef = ref()
- const form = computed({
- get() {
- return props.modelValue
- },
- set(value) {
- console.log(value)
- emits('update:modelValue', value)
- }
- })
- const save = async (formEl) => {
- if (!formEl) return
- await formEl.validate((valid, fields) => {
- if (valid) {
- emits('save', form.value)
- } else {
- console.log('error submit!', fields)
- }
- })
- }
- const getField = (item, data) => {
- let res = get(data, item, null)
- if (item === 'type') res = res === null ? `text` : res
- if (item === 'placeholder') res = res === null ? `请输入${data.label}` : res
- if (item === `selectplaceholder`) res = res === null ? `请选择${data.label}` : res
- if (item === 'required') res = res === null ? false : res
- if (item === `error`) res = res === null ? `${data.label}错误` : res
- return res
- }
- const dataChange = (model) => {
- const value = form.value[model]
- emits('dataChange', { model, value })
- }
- const display = (field) => {
- let dis = get(field, `display`)
- if (!isFunction(dis)) return true
- else {
- return dis(field, form)
- }
- }
- const getDateFormat = (e) => {
- if (e === 'year') return 'YYYY'
- if (e === 'month') return 'MM'
- if (e === 'date') return 'YYYY-MM-DD'
- if (e === 'daterange') return 'YYYY-MM-DD'
- if (e === 'datetime') return 'YYYY-MM-DD HH:mm:ss'
- if (e === 'datetimerange') return 'YYYY-MM-DD HH:mm:ss'
- if (e === 'time') return 'HH:mm:ss'
- }
- </script>
- <style scoped>
- .btn {
- text-align: center;
- }
- .form {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- }
- </style>
|