<template> <ElForm :style="getStyle()" :label-width="labelWidth" class="FormConfig" size="mini"> <ElFormItem class="formItem" :rules="getRules(item)" v-for="(item, index) in formList" :key="item.key" :label="item.label" :style="gridStyle(item, index)"> <slot :name="item.key" :data="item" :formData="formData"> <component :is="getComponent(item.type)" v-bind="getBindData(item)" v-model="formData[item.key]" /> </slot> </ElFormItem> </ElForm> </template> <script> import { resolveName } from "./utils/index" import { reduceDefaultValue } from "./utils/defaultValue" const files = require.context('./components', true, /^.\/[^/]+\/index\.vue$|^.\/[^/]+.vue$/); const components = files.keys().reduce((prev, key) => { prev[key.match(/[^./]+/g)[0]] = files(key).default; return prev; }, { Empty: 'div' }) export default { name: 'FormConfig', components: { // FormInput, // FormTimePicker }, provide() { return { getComponent: this.getComponent, getBindData: this.getBindData } }, props: { /** * { * label: String; * key: String; * type: 'input' | 'timePicker', * gridArea?: "", * gridColumn?: "", * gridRow?: "", * options?: {} * }[] */ formList: { type: Array, default: () => [] }, labelWidth: { type: String, default: "auto" }, rules: { type: Object, default: null }, column: { type: [String, Number], default: "3" } }, data() { return { formData: {} } }, created() { this.reset(); }, computed: { gridStyle() { return (item, index) => ({ gridRow: `span ${item.gridRow || 1}`, gridColumn: `span ${item.gridColumn || item.isAlone && this.column || 1}`, }) } }, methods: { reset() { return this.formData = reduceDefaultValue(this.formList); }, getStyle() { return { gridTemplateColumns: `repeat(${this.column}, 1fr)`, } }, getBindData(item) { return { placeholder: "请输入", ...item.options } }, getComponent(type) { if (!type) type = 'input'; const componentKey = resolveName(type); const ElComponentKey = `El${componentKey}`; return components[componentKey] || components[ElComponentKey] || ElComponentKey; }, getRules(item) { if (this.rules?.[item.key]) return this.rules[item.key]; if (item.rules) return item.rules; if (item.required) return [ { required: true, message: `${item.options?.placeholder || `${item.label}不能为空`}`, trigger: "blur", }, ] } } } </script> <style lang='scss' scoped> .FormConfig { display: grid; align-content: start; width: 100%; gap: 15px 15px; overflow-x: hidden; .formItem { display: flex; align-items: center; } ::v-deep { .el-form-item { align-items: center; margin: 0; height: 100%; &:first-child { .el-form-item__label-wrap { // padding-top: 9px; } } .el-form-item__label-wrap { width: fit-content; } .el-form-item__label { height: 22px; font-size: 15px; // font-family: PingFang SC, PingFang SC; font-weight: 400; color: #3DE8FF; line-height: 19px; // -webkit-background-clip: text; // -webkit-text-fill-color: transparent; } .el-form-item__content { margin: 0 !important; flex: 1; height: 100%; .el-input__prefix { color: #fff; } } } } } </style>