<template>
<div class="myform">
<el-form
v-bind="$attrs"
v-on="$listeners"
:model="formmodel"
:inline="inline"
ref="myform"
:rules="rules"
:label-width="$attrs['label-width']||calclabelwidth"
>
<div style="width:100%">
<slot name="btns" :data="Object.assign({},formmodel)"></slot>
</div>
<el-form-item
:label="item.label+':'"
:prop="item.prop"
v-for="(item, index) in formconfig"
:style="{width: item.width +'%','margin-right':0}"
:key="index"
>
<!--自定义render-->
<template v-if="item.render">
<component
:is="'renderComponent'"
:value="formmodel[item.prop]"
:input="e => formmodel[item.prop] = e"
v-bind="{ ...item }"
></component>
</template>
<!--自定义插槽-->
<template v-else-if="item.type==='custom'">
<slot :name="item.slot" :row="{ ...item, formmodel, index }" />
</template>
<!--下拉框-->
<template v-else-if="item.type === 'select'">
<el-select v-bind="item.attrs" v-model="formmodel[item.prop]" v-on="getlisteners(item)">
<el-option
v-for="(sitem, index) in getOptions(item)"
:key="index"
:label="sitem[item.optionlabel||'text']"
:value="sitem[item.optionvalue||'value']"
></el-option>
</el-select>
</template>
<!--component-->
<template v-else-if="item.type">
<myitem v-bind="getattrs(item)" v-on="getlisteners(item)" v-model="formmodel[item.prop]"></myitem>
</template>
</el-form-item>
<div style="width:100%">
<slot name="bottom" :data="Object.assign({},formmodel)"></slot>
</div>
</el-form>
</div>
</template>
<script>
// 邮箱的正则校验
const validateEmail = (rule, value, callback) => {
if (value) {
var email =
/^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
if (!email.test(value)) {
callback(new Error("邮箱地址格式不正确"));
} else {
callback();
}
} else {
//可以为空
callback();
}
};
// url地址的正则校验
const validateUrl = (rule, value, callback) => {
if (value != "") {
var Url =
/^((ht|f)tps?):\/\/([\w-]+(\.[\w-]+)*\/?)+(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?$/;
if (!Url.test(value)) {
callback(new Error("URL地址格式不正确"));
} else {
callback();
}
}
};
// 电话号码的正则校验
const validateTel = (rule, value, callback) => {
if (value != "") {
var tel = /^1[3456789]\d{9}$/;
if (!tel.test(value)) {
callback(new Error("电话号码格式不正确"));
} else {
callback();
}
}
};
// 身份证号码的校验规则
const validateIdCard = (rule, value, callback) => {
if (value != "") {
var IdCard =
/(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{7}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/;
if (!IdCard.test(value)) {
callback(new Error("身份证号码格式不正确"));
} else {
callback();
}
}
};
// 日期校验规则
const validateDate = (rule, value, callback) => {
if (value != "") {
var Date =
/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/;
if (!Date.test(value)) {
callback(new Error("日期格式不正确"));
} else {
callback();
}
}
};
// 数字校验
const validateNum = (rule, value, callback) => {
if (!value || isNaN(value)) {
callback(new Error("数字格式不正确"));
} else {
callback();
}
};
// 时间校验规则
const validateTime = (rule, value, callback) => {
if (value != null && value != "") {
var flag = /^([0-1][0-9]|2[0-3]):([0-5][0-9])$/;
if (!flag.test(value)) {
callback(new Error("时间格式不正确,格式为 HH:MM"));
} else {
callback();
}
}
};
// 自定义校验规则
const validateCustom = (val) => {
return (rule, value, callback) => {
if (value != null && value != "") {
var flag = new RegExp(val.patternStr);
if (!flag.test(value)) {
callback(new Error(String(val.errorMessage)));
} else {
callback();
}
}
};
};
// 长度校验
const min = (val) => {
return (rule, value, callback) => {
if (value != null && value != "") {
if (val.min && val.min > value.length) {
callback(new Error(`长度下限为 ${val.min} 个字符`));
} else {
callback();
}
} else {
callback(new Error(`长度下限为 ${val.min} 个字符`));
}
};
};
const max = (val) => {
return (rule, value, callback) => {
if (value != null && value != "") {
if (val.max && val.max < value.length) {
callback(new Error(`长度上限为 ${val.max} 个字符`));
} else {
callback();
}
} else {
callback(new Error(`长度上限为 ${val.max} 个字符`));
}
};
};
const regExpFn = {
email: validateEmail,
url: validateUrl,
phone: validateTel,
identity: validateIdCard,
date: validateDate,
number: validateNum,
timeEmptyAble: validateTime,
validateCustom: validateCustom,
min: min,
max: max,
};
const renderComponent = {
functional: true,
props: ["value"],
render(h, ctx) {
const { render, attrs, input: handleInput } = ctx.data.attrs;
return render(h, {
attrs: {
...attrs,
value: ctx.props.value,
},
on: {
input(e) {
// handleInput(e);
},
},
});
},
};
export default {
inheritAttrs: false,
name: "myform",
components: { renderComponent },
props: {
selectUpdate: {
type: Object,
default: () => ({}),
},
inline: {
type: Boolean,
default: true,
},
formmodel: {
type: Object,
default: () => ({}),
},
formconfig: {
type: Array,
default: () => [],
},
},
data() {
return {
rules: {},
};
},
watch: {
formconfig: {
handler(val) {
this.generateRules();
},
},
},
computed: {
calclabelwidth() {
let width = 100;
let len = 2;
if (Array.isArray(this.formconfig) && this.formconfig.length) {
let lenlist = this.formconfig.map((item) => {
if (typeof item.label === "string") {
return item.label.length;
} else {
return 2;
}
});
len = Math.max.apply(null, lenlist);
}
width =
parseFloat(len * 16 + 30) > parseFloat(width) ? len * 16 + 30 : width;
return width + "px";
},
},
methods: {
getOptions(item){
if(item.optkey){
return this.selectUpdate[item.optkey]
}else{
return this.selectUpdate[item.prop]||item.options||[]
}
},
//设置下拉
setOptions() {
Object.keys(this.selectUpdate).forEach((v) => {
const index = this.formconfig.findIndex((k) => k.prop === v);
if (index !== -1) {
this.$set(this.formconfig[index], "options", this.selectUpdate[v]);
}
const index2 = this.formconfig.findIndex((k) => k.optkey === v);
if (index2 !== -1) {
this.$set(this.formconfig[index2], "options", this.selectUpdate[v]);
}
});
},
// 查询系统集成的自定规则
ergExtFunc(val) {
if (regExpFn[val]) {
return {
trigger: "blur",
validator: regExpFn[val],
};
}
},
// 根据传进来的正则规则生成符合el-form的校验规则
regExpCustom(val) {
// console.log(val);
// if (val.patternStr && val.errorMessage) return;
if (val.type == "select" || val.type == "tree") {
return {
trigger: "change",
validator: regExpFn.validateCustom(val),
};
}
// console.log(regExpFn.validateCustom(val));
return {
trigger: "blur",
validator: regExpFn.validateCustom(val),
};
},
generateRules() {
// 生成校验规则
this.rules = {};
this.formconfig.forEach((v) => {
const model = [];
const item = {};
const origin = {};
// 必填校验
if (v.required) {
if (v.type == "select" || v.type == "tree") {
item.required = true;
item.message = v.message || `${v.label}必填`;
item.trigger = "change";
model.push(item);
} else if (v.type == "selectInput") {
model.push({
required: true,
message: `${v.label}必填`,
trigger: "change",
});
} else {
item.required = true;
item.message = v.message || `${v.label}必填`;
item.trigger = "blur";
model.push(item);
}
}
// 长度校验
if (v.min || v.max) {
if (v.min) {
item.min = v.min;
item.message = `长度下限 ${item.min} 个字符`;
}
if (v.max) {
item.max = v.max;
item.message = `长度上限 ${item.max} 个字符`;
}
if (v.min && v.max) {
item.message = `长度在 ${item.min} 到 ${item.max} 个字符`;
}
item.trigger = "blur";
model.push(item);
}
if (typeof v.validate == "string") {
const validateList = v.validate.split("|");
// console.log(validateList);
validateList.forEach((validate) => {
// 以下皆为系统自定义集成的规则
if (validate == "date") {
model.push(this.ergExtFunc("date"));
}
if (validate == "email") {
model.push(this.ergExtFunc("email"));
}
if (validate == "url") {
model.push(this.ergExtFunc("url"));
}
if (validate == "phone") {
model.push(this.ergExtFunc("phone"));
}
if (validate == "identity") {
model.push(this.ergExtFunc("identity"));
}
if (validate == "number") {
model.push(this.ergExtFunc("number"));
}
if (validate == "timeEmptyAble") {
model.push(this.ergExtFunc("timeEmptyAble"));
}
// 以下为用户添加的自定义校验规则
if (validate == "pattern") {
model.push(this.regExpCustom(v));
}
});
}
// 自定义校验规则
if (v.validate && typeof v.validate != "string") {
if (v.type == "select" || v.type == "tree") {
origin.trigger = "change";
origin.validator = v.validate;
model.push(origin);
} else {
origin.trigger = "blur";
origin.validator = v.validate;
model.push(origin);
}
}
if (model.length > 0) {
this.$set(this.rules, v.prop, model);
}
if (v.type === "selectDate") {
v.children.forEach((j) => {
if (j.required) {
item.required = true;
item.message = `${v.label}必填`;
item.trigger = "change";
model.unshift(item);
this.$set(this.rules, j.prop, model);
}
});
}
});
this.$nextTick(() => {
this.$refs.myform.clearValidate();
});
},
//继承el-form 方法
extendMethod() {
const refMethod = Object.entries(this.$refs["myform"]);
for (const [key, value] of refMethod) {
if (!(key.includes("$") || key.includes("_"))) {
this[key] = value;
}
}
},
getattrs(item) {
let obj = item.attrs || {};
if (!obj.placeholder) {
let prevtext = "请输入";
if (item.type === "select") {
prevtext = "请选择";
}
obj.placeholder = prevtext + item.label;
}
if (typeof item.disabled === "boolean") {
obj.disabled = item.disabled;
}
let component = "";
switch (item.type) {
case "input":
case "search":
case "text":
component = "el-input";
break;
case "textarea":
component = "el-input";
obj.type = "textarea";
obj.rows = parseInt(obj.rows) || 3;
obj.resize = "none";
break;
case "switch":
component = "el-switch";
obj.activeColor = obj.activeColor || "rgb(64,158,255)";
obj.inactiveColor = obj.inactiveColor || "#ff4949";
break;
case "date":
component = "el-date-picker";
obj.type = "date";
obj.format = "yyyy-MM-dd";
obj.valueFormat = "yyyy-MM-dd";
break;
case "year":
component = "el-date-picker";
obj.type = "year";
obj.format = "yyyy";
obj.valueFormat = "yyyy";
break;
case "yearmonth":
component = "el-date-picker";
obj.type = "month";
obj.format = "yyyy-MM";
obj.valueFormat = "yyyy-MM";
break;
case "datetimerange":
component = "el-date-picker";
obj.type = "datetimerange";
obj.rangeSeparator = "至";
obj.format = "yyyy-MM-dd";
obj.valueFormat = "yyyy-MM-dd";
break;
default:
component;
break;
}
if (!obj.component) {
obj.component = component;
}
return obj;
},
getlisteners(item) {
return item.event || {};
},
},
mounted() {
this.extendMethod();
// this.setOptions();
},
created() {
this.generateRules();
// this.$emit('update:model', this.model);
},
};
</script>
<style lang="scss" scoped>
.myform {
}
</style>
<myform :selectUpdate="selectUpdate" :formconfig="formconfig" :formmodel="formmodel" @search='search'></myform>
search(val,type){
console.log(val,type);
}
formmodel: {
// date: "",
// name: "",
// address: "",
// number: "",
// scholl: "",
},
formconfig: [
{
type: "text",
prop: "date",
label: "日期",
width: 50,
event: {
change: (a, b, c, d) => {
console.log(a, b, c, d);
},
},
},
{
type: "text",
prop: "date",
label: "日期",
width: 50,
event: {
change: (a, b, c, d) => {
console.log(a, b, c, d);
},
},
},
{
type: "text",
prop: "date",
label: "日期",
width: 50,
event: {
change: (a, b, c, d) => {
console.log(a, b, c, d);
},
},
},
{
type: "text",
prop: "date",
label: "日期",
width: 50,
event: {
change: (a, b, c, d) => {
console.log(a, b, c, d);
},
},
},
{
type: "text",
prop: "name",
label: "名称",
width: 50,
attrs: {
placeholder: "请填写名称",
},
},
{
type: "select",
prop: "address",
label: "地址",
width: 50,
attrs: {
placeholder: "请选择地址",
style: {
width: "100%",
},
},
optionlabel: "11",
optionvalue: "777",
// options: {
// // data: this.tableData,
// // extraProps: {
// // value: "address",
// // label: "address",
// // },
// },
},
{
type: "text",
slot: "number",
width: 50,
label: "编号",
attrs: {
placeholder: "请输入编号",
},
},
{
type: "text",
prop: "scholl",
width: 50,
label: "毕业学校",
attrs: {
placeholder: "请输入毕业学校",
},
// render: (h, props) =>
// h("el-input", {
// ...props,
// }),
},
],