// 需要传入构造项-formItems对象数组来生成表单
// 对象可配置属性name(必须),label(必须),type(默认text),default,required(默认true),disabled(默认false),onBlur,onFocus
// type可设为number(数字)
// select(选择器),需要配套options对象(同antd),拥有onDropdown事件(展开项)
// switch(开关),默认值false
// mul(多行多项),值为一个数组
// obj(对象),值为一个对象,本质是不可新增行的mul
// kvObj(键值对对象),值为一个对象
// 通过调用setValue()方法赋值给表单,调用getValue()方法获取表单数据,getValueByName()方法可以获得单个值...
<template>
<a-form-model ref="ruleForm" :model="form">
<div v-for="formItem in formItems" :key="formItem.name">
<template v-if="!isMulType(formItem)">
<a-form-model-item
:label="formItem.label"
:prop="formItem.name"
:wrapper-col="{ span: wrapperWidth }"
:label-col="{ span: labelWidth }"
:rules="formItem.required !== false ? { required: true, message: `请输入${formItem.label}` } : undefined"
>
<a-input
v-if="!formItem.type"
v-model="form[formItem.name]"
:disabled="formItem.disabled"
@blur="formItem.onBlur && formItem.onBlur()"
@focus="formItem.onFocus && formItem.onFocus()"
/>
<a-input-number
style="width: 100%"
v-if="formItem.type === 'number'"
v-model="form[formItem.name]"
:min="formItem.min || undefined"
:max="formItem.max || undefined"
:disabled="formItem.disabled"
@blur="formItem.onBlur && formItem.onBlur()"
@focus="formItem.onFocus && formItem.onFocus()"
/>
<a-select
v-if="formItem.type === 'select'"
v-model="form[formItem.name]"
:options="formItem.options"
:disabled="formItem.disabled"
allow-clear
:get-popup-container="triggerNode => (triggerNode.parentNode || document.body)"
:show-search="true"
@blur="formItem.onBlur && formItem.onBlur()"
@focus="formItem.onFocus && formItem.onFocus()"
@dropdownVisibleChange="formItem.onDropdown ? formItem.onDropdown() : {}"
/>
<a-auto-complete
v-if="formItem.type === 'auto'"
v-model="form[formItem.name]"
:data-source="formItem.options"
:disabled="formItem.disabled"
:filter-option="true"
:get-popup-container="triggerNode => (triggerNode.parentNode || document.body)"
@blur="formItem.onBlur && formItem.onBlur()"
@focus="formItem.onFocus && formItem.onFocus()"
/>
</a-form-model-item>
</template>
<template v-else>
<div v-for="(childValue, index) in form[formItem.name]" :key="formItem.name + index">
<div
v-for="(child, num) in formItem.children"
:key="child.name"
>
<a-form-model-item
style="margin:0"
:wrapper-col="{ span: wrapperWidth, offset: num === 0 ? 0 : labelWidth }"
:label-col="{ span: labelWidth }"
:label="num === 0 ? formItem.label : false"
:prop="`${formItem.name}.${index}.${child.name}`"
:rules="child.required !== false ? { required: true, message: `请输入${child.label}` } : undefined"
>
<a-input
:placeholder="child.name"
v-model="childValue[child.name]"
v-if="!child.type"
:disabled="formItem.disabled"
@blur="formItem.onBlur && formItem.onBlur()"
@focus="formItem.onFocus && formItem.onFocus()"
/>
<a-input-number
:placeholder="child.name"
v-model="childValue[child.name]"
v-if="child.type === 'number'"
:disabled="formItem.disabled"
@blur="formItem.onBlur && formItem.onBlur()"
@focus="formItem.onFocus && formItem.onFocus()"
/>
<a-select
:placeholder="child.name"
v-model="childValue[child.name]"
:mode="child.mode || 'default'"
v-if="child.type === 'select'"
:options="child.options"
:disabled="formItem.disabled"
allow-clear
@blur="formItem.onBlur && formItem.onBlur()"
@focus="formItem.onFocus && formItem.onFocus()"
/>
<div v-if="child.type === 'switch'">
<span style="margin-right: 10px">{{ child.label }}:</span>
<a-switch
v-model="childValue[child.name]"
:disabled="formItem.disabled"
@change="formItem.onChange && formItem.onChange()"
/>
</div>
<div v-if="child.type === 'json'">
<span style="margin-right: 10px">{{ child.label }}:</span>
<json-editor v-model="childValue[child.name]" />
</div>
</a-form-model-item>
</div>
<a-row>
<a-col :span="wrapperWidth" :offset="labelWidth" v-if="formItem.type !== 'obj'">
<a-form-model-item>
<a-popconfirm
title="确定删除该项吗?"
v-if="form[formItem.name].length > 1"
@confirm="deleteVal(formItem.name, index)"
>
<a-button type="danger" size="small" style="margin-right:10px;">
删除
</a-button>
</a-popconfirm>
<a-button
size="small"
v-if="index === form[formItem.name].length - 1"
@click="addVal(formItem.name)"
>
添加
</a-button>
</a-form-model-item>
</a-col>
</a-row>
</div>
</template>
</div>
</a-form-model>
</template>
<script>
export default {
data() {
return {
form: {}
};
},
props: {
formItems: {
required: true,
type: Array,
default: () => []
},
labelWidth: {
required: false,
type: Number,
default: 6
},
wrapperWidth: {
required: false,
type: Number,
default: 22 - 6
}
},
methods: {
isMulType(obj) {
if (obj.type === undefined) {
return false;
} else if (['mul', 'obj', 'kvObj'].includes(obj.type)) {
return true;
} else {
return false;
}
},
deleteVal(name, index) {
this.form[name].splice(index, 1);
},
addVal(name) {
const names = this.formItemObj[name].children.map(item => item.name);
const tempObj = {};
names.forEach(item => {
tempObj[item] = undefined;
});
this.formItemObj[name].children.forEach(item => {
tempObj[item.name] = item.default || undefined;
});
this.form[name].push(tempObj);
},
reset() {
this.form = {};
this.$refs.ruleForm.resetFields();
for (let formItem of this.formItems) {
if (this.isMulType(formItem)) {
this.$set(this.form, formItem.name, []);
this.addVal(formItem.name);
} else {
this.$set(this.form, formItem.name, formItem.default);
}
}
},
setValue(formData) {
this.reset();
Object.entries(formData).forEach(([key, value]) => {
if (typeof value === 'object') {
value = JSON.parse(JSON.stringify(value));
}
if (this.formItemObj[key] === undefined) {
return;
}
if (value === null || value === undefined) {
if (this.isMulType(this.formItemObj[key]) && this.form[key].length === 0) {
this.addVal(this.formItemObj[key].name);
}
} else if (this.formItemObj[key].type === 'obj') {
this.$set(this.form, key, [value]);
} else if (this.formItemObj[key].type === 'kvObj') {
const result = Object.keys(value).map(item => ({ key: item, value: value[item] }));
this.$set(this.form, key, result);
} else {
this.$set(this.form, key, value);
}
});
},
getValue() {
let tempForm = {};
this.$refs.ruleForm.validate(valid => {
if (!valid) {
tempForm = false;
return;
}
Object.entries(this.form).forEach(([key, value]) => {
if (this.formItemObj[key].type === 'mul') {
const result = [];
value.forEach(item => {
if (Object.keys(item).length === 0) {
return;
}
if (Object.values(item).every(o => o === undefined)) {
return;
}
result.push(item);
});
tempForm[key] = result;
} else if (this.formItemObj[key].type === 'obj') {
tempForm[key] = value[0];
} else if (this.formItemObj[key].type === 'kvObj') {
const result = {};
value.forEach(item => {
if (item.key !== undefined && item.key.trim() !== '') {
result[item.key] = item.value;
}
});
tempForm[key] = result;
} else {
tempForm[key] = value;
}
});
});
return tempForm;
},
getValueByName(name) {
const value = this.form[name];
if (this.formItemObj[name].type === 'obj') {
return value[0];
} else if (this.formItemObj[name].type === 'kvObj') {
const result = {};
value.forEach(item => {
if (item.key !== undefined && item.key.trim() !== '') {
result[item.key] = item.value;
}
});
return result;
} else {
return value;
}
},
setValueByName(name, data) {
if (typeof data === 'object') {
data = JSON.parse(JSON.stringify(data));
}
if (this.formItemObj[name].type === 'obj') {
this.$set(this.form, name, [data]);
} else if (this.formItemObj[name].type === 'kvObj') {
const result = Object.keys(data).map(item => ({ key: item, value: data[item] }));
this.$set(this.form, name, result);
} else {
this.$set(this.form, name, data);
}
}
},
mounted() {
this.reset();
},
computed: {
formItemObj() {
const temp = {};
this.formItems.forEach(formItem => {
temp[formItem.name] = formItem;
});
return temp;
}
}
};
</script>