<!--
Template Name: 公用表單
Create author: xingyuelognchen
Create Time : 2020-03-31
-->
<template>
<el-form
ref="form"
:model="fieldsData"
:size="options.size"
:inline="options.inline||false"
@validate="validated"
>
<template v-for="(v,i) in mapFields">
<el-row :key="i">
<template v-for="(item,index) in v">
<el-col :key="index" :span="item.span||24" :xs="item.xs||24">
<el-form-item
:label-width="item.labelWidth?item.labelWidth+'px' :'120px'"
:label="item.label"
:prop="item.prop"
:rules="item.rule"
:required="item.required"
>
<template v-if="['text','textarea','number','email'].indexOf(item.type)!==-1">
<el-input
class="input"
v-model="fieldsData[item.prop]"
inline-message
:placeholder="item.placeholder"
:readonly="item.readonly"
:type="item.type"
@change="change(item,index,'change')"
>
<span v-if="item.prepend" slot="prepend" @click.stop="click(item,index)">
<template v-if="/^(el-icon|my-icon).*/.test(item.prepend)">
<i :class="item.prepend"></i>
</template>
<template v-else>{{item.prepend}}</template>
</span>
<span v-if="item.append" slot="append" @click.stop="click(item,index)">
<template v-if="/^(el-icon|my-icon).*/.test(item.append)">
<i :class="item.append"></i>
</template>
<template v-else>{{item.append}}</template>
</span>
</el-input>
</template>
<template v-if="item.type == 'select'">
<el-select
v-if="!item.readonly"
v-model="fieldsData[item.prop]"
:disabled="item.disabled"
:multiple="item.multiple"
:collapse-tags="item.multiple"
@change="change(item,index,'change')"
>
<el-option
v-for="(k,i) in item.options"
:key="i"
:disabled="k.disabled"
:value-id="k.id"
:label="k.label || k[item.config.label]"
:value="k.value || k[item.config.value] || k"
/>
</el-select>
<el-input
v-else
v-model="fieldsData[item.prop]"
:disabled="item.disabled"
:readonly="item.readonly"
></el-input>
</template>
<template v-if="item.type == 'switch'">
<el-switch v-model="fieldsData[item.prop]" :disabled="item.disabled" />
</template>
<template v-if="item.type == 'slider'">
<el-slider
v-model="fieldsData[item.prop]"
:format-tooltip="item.formatTooltip"
:disabled="item.disabled"
/>
</template>
<template v-if="item.type == 'checkbox'">
<template v-if="item.options && item.options.length">
<el-checkbox
v-model="fieldsData[item.prop]"
v-for="(k,i) in item.options"
:key="i"
:label="k.value ||k[item.config.value] || k.id || k.label"
:disabled="k.disabled"
:checked="k.checked"
>{{k.label || k[item.config.label] }}</el-checkbox>
</template>
<el-checkbox
v-else
v-model="fieldsData[item.prop]"
:label="item.options.value"
:disabled="item.disabled"
:checked="item.checked"
>{{item.options.label}}</el-checkbox>
</template>
<template v-if="item.type == 'cascader'">
<el-cascader
v-if="!item.readonly"
v-model="fieldsData[item.prop]"
:disabled="item.disabled"
:readonly="item.readonly"
:checkStrictly="true"
:emitPath="false"
:options="item.options"
:props="item.config || {label:'name',value:'id'}"
@change="change(item,index,'change')"
></el-cascader>
<el-input
v-else
v-model="fieldsData[item.prop]"
:disabled="item.disabled"
:readonly="item.readonly"
></el-input>
</template>
<template v-if="item.type == 'checkboxgroup'">
<el-checkbox-group v-model="fieldsData[item.prop]" :disabled="item.disabled">
<el-checkbox
v-for="(k,i) in item.options"
:label="k.value||k.id||k.label"
:key="i"
:disabled="k.disabled"
:checked="k.checked"
>{{k.label || k[item.config.label] }}</el-checkbox>
</el-checkbox-group>
</template>
<template v-if="item.type == 'radio'">
<template v-if="item.options && item.options.length">
<el-radio
v-model="fieldsData[item.prop]"
v-for="(k,i) in item.options"
:key="i"
:label="k.value"
:disabled="k.disabled"
>{{k.label}}</el-radio>
</template>
<el-radio
v-else
v-model="fieldsData[item.prop]"
:label="item.options.value"
:disabled="item.disabled"
>{{item.options.label}}</el-radio>
</template>
<template v-if="item.type == 'radiogroup'">
<el-radio-group v-model="fieldsData[item.prop]" :disabled="item.disabled">
<el-radio
v-for="(k,i) in item.options"
:label="k.value"
:key="i"
:disabled="k.disabled"
>{{k.label}}</el-radio>
</el-radio-group>
</template>
<template v-if="item.type == 'button'">
<div v-if="item.options && item.options.length">
<el-button
v-for="(k,i) in item.options"
:key="i"
:type="k.style"
@click.stop="click(k,i,item)"
>{{k.label}}</el-button>
</div>
<div v-else>
<el-button
:key="index"
:type="item.options.style"
@click.stop="click(item.options,index,item)"
>{{item.options.label}}</el-button>
</div>
</template>
<template v-if="['date','datetime'].indexOf(item.type)>=0">
<el-date-picker
:type="item.type"
value-format="yyyy-MM-dd"
v-model="fieldsData[item.prop]"
:placeholder="item.label"
:disabled="item.disabled"
:readonly="item.readonly"
></el-date-picker>
</template>
<template v-if="item.type == 'image'">
<div :key="key" class="image">
<el-input
v-model="files[item.prop]"
type="text"
@paste.native.capture.prevent="onPaste($event,item,index)"
placeholder="粘貼截圖上傳"
>
<el-button slot="append" @click.native.stop="$refs.upload[0].click()">本地上傳</el-button>
</el-input>
<input
ref="upload"
type="file"
accept="image/png, image/jpg, image/jpeg, image/gif, image/svg"
@input="upload($event,item)"
v-show="false"
/>
<div
v-if="fieldsData[item.prop] && fieldsData[item.prop].length"
class="image-box"
>
<template v-for="(v,i) in fieldsData[item.prop]">
<div class="image-item" :key="i">
<el-image :src="v" :preview-src-list="fieldsData[item.prop]" fit="cover" />
<i class="el-icon-delete" @click="onDelImage(item,i)"></i>
</div>
</template>
</div>
</div>
</template>
<template v-if="item.type == 'upload'">
<el-button
@click="$refs.upload[0].click()"
:type="item.style || 'primary'"
:icon="item.icon || 'el-icon-upload2'"
>點(diǎn)擊上傳</el-button>
<input
type="file"
ref="upload"
@change="onUpload($event,item)"
multiple
v-show="false"
/>
<div v-if="fileList && fileList.length">
<span class="file-list" v-for="(k,i) in fileList" :key="i">{{k.name}}</span>
</div>
</template>
<template v-if="item.type == 'plan'">
<el-progress
:percentage="fieldsData[item.prop]"
text-inside
type="line"
:stroke-width="25"
></el-progress>
</template>
</el-form-item>
</el-col>
</template>
</el-row>
</template>
</el-form>
</template>
<script>
export default {
name: "mixForm",
model: {
prop: "fieldsData"
},
props: {
fields: {
type: Array,
default: () => [
{
label: "菜單名稱",
prop: "title",
type: "text",
rule: null,
append: "arrow-right",
click: (item, index) => {
console.log(item);
}
},
{
label: "菜單名稱",
prop: "title",
type: "text",
rule: null,
append: "el-icon-arrow-right"
},
{
label: "菜單名稱",
prop: "title",
type: "text",
rule: null,
prepend: "el-icon-arrow-left"
},
{ label: "菜單名稱", prop: "switch", type: "switch", rule: null },
{ label: "單選框", prop: "radio", type: "radio", rule: null },
{
label: "單選框組",
prop: "radiogroup",
type: "radio",
options: [
{ label: "a", value: "a" },
{ label: "b", value: "b" }
],
rule: null
},
{ label: "復(fù)選框", prop: "checkbox", type: "checkbox", rule: null },
{
label: "復(fù)選框",
prop: "checkboxgroup",
type: "checkbox",
options: [
{ label: "a", value: "a" },
{ label: "b", value: "b" }
],
rule: null
}
]
},
fieldsData: {
type: Object,
default: () => {
return {
title: "false",
switch: true,
checkbox: false,
checkboxgroup: [],
radio: true,
radiogroup: []
};
}
},
options: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return { key: "key", mapFields: [], files: [], fileList: [] };
},
watch: {
fields() {
this.onMapFields();
},
fieldsData() {
this.key = Math.random();
}
},
created() {
this.onMapFields();
},
methods: {
async onUpload(event, item) {
this.fileList = event.target.files || [];
let formData = new FormData();
this.fileList.forEach(e => {
formData.append("files", e);
});
// 這里需要修改文件上傳接口地址
let { data } = await this.axios("/admin/Publics/UploadFiles", {
data: formData
});
if (data.code) {
this.fieldsData[item.prop] = data.data;
}
},
previewFile(file, files) {
console.log(file, files);
},
removeFile(file, files) {
console.log(file, files);
},
// 上傳圖片
list(item) {
if (item && item.length) {
return item.map(e => {
return e.blob || e;
});
}
return [];
},
// 刪除選擇的圖片
onDelImage(item, i) {
this.fieldsData[item.prop].splice(i, 1);
this.key = Math.random();
},
// 點(diǎn)擊按鈕上傳
upload(event, item) {
this.update(event.target.files[0], event.target.files[0].type, item);
},
// 粘貼剪切板截圖
onPaste(event, item, index) {
if (!(event.clipboardData && event.clipboardData.items)) {
this.$message.error("當(dāng)前環(huán)境不支持粘貼上傳站欺,\n請(qǐng)手動(dòng)點(diǎn)擊上傳圖片");
return;
}
if (event.clipboardData.items[0].type.indexOf("image") >= 0) {
let file = event.clipboardData.items[0].getAsFile();
let mime = event.clipboardData.items[0].type;
this.update(file, mime, item);
}
},
// 更新表單數(shù)據(jù)源字段內(nèi)容
async update(file, mime, item) {
let obj = new FormData();
obj.append("files", file);
// 這里需要修改文件上傳接口地址
let { data } = await this.axios("/admin/Publics/uploadsImage", {
data: obj
});
if (data.code) {
let blob = window.URL.createObjectURL(file);
if (this.fieldsData[item.prop] && this.fieldsData[item.prop].length) {
this.fieldsData[item.prop].push(data.data);
} else {
this.fieldsData[item.prop] = [data.data];
}
this.key = Math.random();
}
},
onMapFields() {
this.mapFields = [];
let arr = [];
this.fields.forEach(e => {
if (e.wrap) {
this.mapFields.push(arr);
arr = [];
}
arr.push(e);
});
this.mapFields.push(arr);
},
change(item, index, type) {
let click = item[type];
if (!click) return;
this.onClick(click, item, index, type);
},
click(item, index, option) {
let click = item["click"];
if (!click) return;
this.onClick(click, item, index, option);
},
onClick(click, item, index, option) {
if (typeof click == "function") {
click(item, index, option);
return;
}
if (typeof this.$parent[click] == "function") {
this.$parent[click](item, index, option);
return;
}
},
// 輸入觸發(fā)驗(yàn)證
validated(prop) {
// 驗(yàn)證
console.log("表單驗(yàn)證字段:", prop);
},
// 表單驗(yàn)證
async validate(prop) {
try {
return await this.$refs["form"].validate();
} catch (error) {
return error;
}
},
resetFields() {
this.$refs["form"].resetFields();
},
clearValidate() {
this.$refs["form"].clearValidate();
},
resetForm() {
this.$refs["form"].resetFields();
}
}
};
</script>
<style lang='less' scoped>
.el-form {
border: 1px solid #ccc;
margin-bottom: 20px;
padding-top: 20px;
}
.file-list {
display: block;
padding: 3px 15px;
border: 1px solid #eee;
margin-top: 10px;
cursor: pointer;
&:not(:last-child) {
border-bottom: none;
}
&:not(:first-child) {
border-top: none;
}
}
.el-col {
min-width: 280px;
}
.input /deep/ input[readonly="readonly"] {
border: none;
background: none;
}
.el-select,
.el-cascader,
.el-date-editor {
width: 100%;
}
.image-box {
display: flex;
flex-wrap: wrap-reverse;
align-content: center;
align-items: center;
.image-item {
// width: 50px;
// height: 50px;
max-width: 150px;
min-width: 150px;
border: 1px solid #ccc;
margin: 5px;
position: relative;
overflow: hidden;
i {
display: none;
cursor: pointer;
}
&:hover {
i {
position: absolute;
top: 0;
right: 0;
margin: auto;
display: block;
background: #fff;
}
}
}
}
</style>