234 lines
5.5 KiB
Vue
234 lines
5.5 KiB
Vue
<template>
|
|
<el-form
|
|
ref="form"
|
|
:label-width="labelWidth"
|
|
label-position="right"
|
|
size="medium"
|
|
:model="formData"
|
|
inline
|
|
:rules="rules"
|
|
:inline-message="false"
|
|
>
|
|
<el-form-item
|
|
v-for="(item, i) in formItems"
|
|
:key="i"
|
|
:style="{ width: item.width }"
|
|
:label="item.label"
|
|
:prop="item.key"
|
|
>
|
|
<div :style="{ width: item.contentWidth || contentWidth }">
|
|
<el-date-picker
|
|
v-if="item.type === 'date'"
|
|
v-model="formData[item.key]"
|
|
type="date"
|
|
size="normal"
|
|
placeholder="请选择日期"
|
|
></el-date-picker>
|
|
<el-input-number
|
|
v-else-if="item.type === 'number'"
|
|
:style="{ width: item.width || '192px' }"
|
|
v-model="formData[item.key]"
|
|
size="small"
|
|
:min="0"
|
|
:placeholder="placeholderWidthFormItem(item)"
|
|
></el-input-number>
|
|
<el-switch
|
|
v-else-if="item.type === 'switch'"
|
|
v-model="formData[item.key]"
|
|
:disabled="item.disabled"
|
|
></el-switch>
|
|
<el-select
|
|
v-else-if="item.type === 'select'"
|
|
v-model="formData[item.key]"
|
|
:disabled="item.disabled"
|
|
:placeholder="placeholderWidthFormItem(item)"
|
|
size="small"
|
|
clearable
|
|
>
|
|
<el-option
|
|
v-for="(option, index) in item.options"
|
|
:key="index"
|
|
:label="option.label"
|
|
:value="option.value"
|
|
>
|
|
</el-option>
|
|
</el-select>
|
|
<base-upload
|
|
v-else-if="item.type === 'image'"
|
|
v-model="formData[item.key]"
|
|
:cover="formData[item.key]"
|
|
:hide="true"
|
|
width="100px"
|
|
height="100px"
|
|
@successCallback="(res) => {formData[item.key] = res.data.coverImg}"
|
|
></base-upload>
|
|
<imgs-upload
|
|
ref="imgsUpload"
|
|
v-else-if="item.type === 'images'"
|
|
v-model="formData[item.key]"
|
|
:hide="true"
|
|
width="100px"
|
|
height="100px"
|
|
></imgs-upload>
|
|
<el-input
|
|
v-else
|
|
:type="item.type"
|
|
v-model="formData[item.key]"
|
|
:placeholder="item.placeholder || placeholderWidthFormItem(item)"
|
|
clearable
|
|
size="small"
|
|
></el-input>
|
|
</div>
|
|
</el-form-item>
|
|
<slot></slot>
|
|
</el-form>
|
|
</template>
|
|
|
|
<script>
|
|
import baseUpload from "../baseUpload.vue";
|
|
import ImgsUpload from "../imgsUpload.vue";
|
|
|
|
export default {
|
|
name: "ConfigForms",
|
|
components: { baseUpload, ImgsUpload },
|
|
props: {
|
|
labelWidth: {
|
|
type: String,
|
|
default: "80px"
|
|
},
|
|
contentWidth: {
|
|
type: String,
|
|
default: "200px"
|
|
},
|
|
data: {
|
|
type: Object,
|
|
default() {
|
|
return {};
|
|
}
|
|
},
|
|
/**
|
|
* Array<FormItem>
|
|
* FormItem:
|
|
* - label: string
|
|
* - key: string | number
|
|
* - required: bool
|
|
* - type?: 'select' | 'date' | 'text' | 'textarea' | 'number' | 'tags'
|
|
* - options?: FormOption[]
|
|
*
|
|
*
|
|
* FormOption:
|
|
* - label: string
|
|
* - value: string | number
|
|
*/
|
|
formItems: {
|
|
type: Array,
|
|
default() {
|
|
return [];
|
|
}
|
|
}
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
formData: {},
|
|
tagList: []
|
|
};
|
|
},
|
|
computed: {
|
|
rules() {
|
|
const rs = {};
|
|
this.formItems.forEach((item) => {
|
|
rs[item.key] = [
|
|
{
|
|
required: !!item.required,
|
|
message: this.placeholderWidthFormItem(item)
|
|
}
|
|
];
|
|
});
|
|
return rs;
|
|
},
|
|
containTags() {
|
|
return this.formItems.findIndex((v) => v.type === "tags") >= 0;
|
|
}
|
|
},
|
|
watch: {
|
|
formItems: {
|
|
handler() {
|
|
this.setFormDataDefault();
|
|
},
|
|
immediate: true
|
|
},
|
|
data: {
|
|
handler(val, oldVal) {
|
|
let isSame = false;
|
|
if (val && oldVal) {
|
|
isSame = val.id === oldVal.id;
|
|
}
|
|
if (this.$refs.imgsUpload && !isSame) {
|
|
this.$refs.imgsUpload.forEach((el) => el.clearImg());
|
|
}
|
|
if (val && Object.keys(val).length) {
|
|
this.assign(this.formData, val, "entry");
|
|
} else {
|
|
Object.keys(this.formData).forEach(
|
|
(key) => (this.formData[key] = null)
|
|
);
|
|
}
|
|
},
|
|
immediate: true
|
|
},
|
|
formData: {
|
|
handler(val) {
|
|
this.$emit("change", val);
|
|
},
|
|
deep: true
|
|
}
|
|
},
|
|
|
|
mounted() {},
|
|
|
|
methods: {
|
|
async validate() {
|
|
await this.$refs.form.validate();
|
|
const data = {};
|
|
this.assign(data, this.formData, "output");
|
|
return data;
|
|
},
|
|
assign(target, source, type) {
|
|
Object.keys(source).forEach((key) => {
|
|
const itemVal = source[key];
|
|
const config = this.formItems.find((v) => v.key === key);
|
|
if (config) {
|
|
const func = config[type];
|
|
target[key] = func ? func(itemVal) : itemVal;
|
|
} else {
|
|
target[key] = itemVal;
|
|
}
|
|
});
|
|
},
|
|
placeholderWidthFormItem(item) {
|
|
const prefix = {
|
|
select: "请选择",
|
|
date: "请选择",
|
|
text: "请输入",
|
|
number: "请输入",
|
|
tags: "请选择",
|
|
switch: "请选择",
|
|
image: "请上传",
|
|
images: "请上传"
|
|
};
|
|
const cur = prefix[item.type] || "请输入";
|
|
return cur + item.label;
|
|
},
|
|
|
|
setFormDataDefault() {
|
|
this.formItems.forEach((v) => {
|
|
this.$set(this.formData, v.key, null);
|
|
});
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped></style>
|