| | |
| | | * @version: 1.0 |
| | | * @Author: sakuya |
| | | * @Date: 2021年9月22日09:26:25 |
| | | * @LastEditors: |
| | | * @LastEditTime: |
| | | * @LastEditors: Sneed |
| | | * @LastEditTime: 2024-06-02 15:06:45 |
| | | --> |
| | | |
| | | <template> |
| | | <el-skeleton v-if="renderLoading || Object.keys(form).length==0" animated /> |
| | | <el-skeleton v-if="renderLoading || Object.keys(form).length == 0" animated /> |
| | | |
| | | <el-form v-else ref="form" :model="form" :label-width="config.labelWidth" :label-position="config.labelPosition" v-loading="loading" element-loading-text="Loading..."> |
| | | <el-form v-else ref="form" :model="form" :label-width="config.labelWidth" :label-position="config.labelPosition" |
| | | v-loading="loading" element-loading-text="Loading..."> |
| | | <el-row :gutter="15"> |
| | | <template v-for="(item, index) in config.formItems" :key="index"> |
| | | <el-col :span="item.span || 24" v-if="!hideHandle(item)"> |
| | | <sc-title v-if="item.component=='title'" :title="item.label"></sc-title> |
| | | <sc-title v-if="item.component == 'title'" :title="item.label"></sc-title> |
| | | <el-form-item v-else :prop="item.name" :rules="rulesHandle(item)"> |
| | | <template #label> |
| | | {{item.label}} |
| | | {{ item.label }} |
| | | <el-tooltip v-if="item.tips" :content="item.tips"> |
| | | <el-icon><el-icon-question-filled /></el-icon> |
| | | </el-tooltip> |
| | | </template> |
| | | <!-- input --> |
| | | <template v-if="item.component=='input'" > |
| | | <el-input v-model="form[item.name]" :placeholder="item.options.placeholder" clearable :maxlength="item.options.maxlength" show-word-limit></el-input> |
| | | <template v-if="item.component == 'input'"> |
| | | <el-input v-model="form[item.name]" :placeholder="item.options.placeholder" clearable |
| | | :maxlength="item.options.maxlength" show-word-limit></el-input> |
| | | </template> |
| | | <!-- checkbox --> |
| | | <template v-else-if="item.component=='checkbox'" > |
| | | <template v-if="item.name" > |
| | | <el-checkbox v-model="form[item.name][_item.name]" :label="_item.label" v-for="(_item, _index) in item.options.items" :key="_index"></el-checkbox> |
| | | <template v-else-if="item.component == 'checkbox'"> |
| | | <template v-if="item.name"> |
| | | <el-checkbox v-model="form[item.name][_item.name]" :label="_item.label" |
| | | v-for="(_item, _index) in item.options.items" :key="_index"></el-checkbox> |
| | | </template> |
| | | <template v-else > |
| | | <el-checkbox v-model="form[_item.name]" :label="_item.label" v-for="(_item, _index) in item.options.items" :key="_index"></el-checkbox> |
| | | <template v-else> |
| | | <el-checkbox v-model="form[_item.name]" :label="_item.label" |
| | | v-for="(_item, _index) in item.options.items" :key="_index"></el-checkbox> |
| | | </template> |
| | | </template> |
| | | <!-- checkboxGroup --> |
| | | <template v-else-if="item.component=='checkboxGroup'" > |
| | | <template v-else-if="item.component == 'checkboxGroup'"> |
| | | <el-checkbox-group v-model="form[item.name]"> |
| | | <el-checkbox v-for="_item in item.options.items" :key="_item.value" :label="_item.value">{{_item.label}}</el-checkbox> |
| | | <el-checkbox v-for="_item in item.options.items" :key="_item.value" |
| | | :label="_item.value">{{ _item.label }}</el-checkbox> |
| | | </el-checkbox-group> |
| | | </template> |
| | | <!-- upload --> |
| | | <template v-else-if="item.component=='upload'" > |
| | | <template v-else-if="item.component == 'upload'"> |
| | | <el-col v-for="(_item, _index) in item.options.items" :key="_index"> |
| | | <el-form-item :prop="_item.name"> |
| | | <sc-upload v-model="form[_item.name]" :title="_item.label"></sc-upload> |
| | |
| | | </el-col> |
| | | </template> |
| | | <!-- switch --> |
| | | <template v-else-if="item.component=='switch'" > |
| | | <template v-else-if="item.component == 'switch'"> |
| | | <el-switch v-model="form[item.name]" /> |
| | | </template> |
| | | <!-- select --> |
| | | <template v-else-if="item.component=='select'" > |
| | | <el-select v-model="form[item.name]" :multiple="item.options.multiple" :placeholder="item.options.placeholder" clearable filterable style="width: 100%;"> |
| | | <el-option v-for="option in item.options.items" :key="option.value" :label="option.label" :value="option.value"></el-option> |
| | | <template v-else-if="item.component == 'select'"> |
| | | <el-select v-model="form[item.name]" :multiple="item.options.multiple" |
| | | :placeholder="item.options.placeholder" clearable filterable style="width: 100%;"> |
| | | <el-option v-for="option in item.options.items" :key="option.value" |
| | | :label="option.label" :value="option.value"></el-option> |
| | | </el-select> |
| | | </template> |
| | | <!-- cascader --> |
| | | <template v-else-if="item.component=='cascader'" > |
| | | <el-cascader v-model="form[item.name]" :options="item.options.items" clearable></el-cascader> |
| | | <template v-else-if="item.component == 'cascader'"> |
| | | <el-cascader v-model="form[item.name]" :options="item.options.items" |
| | | clearable></el-cascader> |
| | | </template> |
| | | <!-- date --> |
| | | <template v-else-if="item.component=='date'" > |
| | | <el-date-picker v-model="form[item.name]" :type="item.options.type" :shortcuts="item.options.shortcuts" :default-time="item.options.defaultTime" :value-format="item.options.valueFormat" :placeholder="item.options.placeholder || '请选择'"></el-date-picker> |
| | | <template v-else-if="item.component == 'date'"> |
| | | <el-date-picker v-model="form[item.name]" :type="item.options.type" |
| | | :shortcuts="item.options.shortcuts" :default-time="item.options.defaultTime" |
| | | :value-format="item.options.valueFormat" |
| | | :placeholder="item.options.placeholder || '请选择'"></el-date-picker> |
| | | </template> |
| | | <!-- number --> |
| | | <template v-else-if="item.component=='number'" > |
| | | <template v-else-if="item.component == 'number'"> |
| | | <el-input-number v-model="form[item.name]" controls-position="right"></el-input-number> |
| | | </template> |
| | | <!-- radio --> |
| | | <template v-else-if="item.component=='radio'" > |
| | | <template v-else-if="item.component == 'radio'"> |
| | | <el-radio-group v-model="form[item.name]"> |
| | | <el-radio v-for="_item in item.options.items" :key="_item.value" :label="_item.value">{{_item.label}}</el-radio> |
| | | <el-radio v-for="_item in item.options.items" :key="_item.value" |
| | | :label="_item.value">{{ _item.label }}</el-radio> |
| | | </el-radio-group> |
| | | </template> |
| | | <!-- color --> |
| | | <template v-else-if="item.component=='color'" > |
| | | <template v-else-if="item.component == 'color'"> |
| | | <el-color-picker v-model="form[item.name]" /> |
| | | </template> |
| | | <!-- rate --> |
| | | <template v-else-if="item.component=='rate'" > |
| | | <template v-else-if="item.component == 'rate'"> |
| | | <el-rate style="margin-top: 6px;" v-model="form[item.name]"></el-rate> |
| | | </template> |
| | | <!-- slider --> |
| | | <template v-else-if="item.component=='slider'" > |
| | | <template v-else-if="item.component == 'slider'"> |
| | | <el-slider v-model="form[item.name]" :marks="item.options.marks"></el-slider> |
| | | </template> |
| | | <!-- tableselect --> |
| | | <template v-else-if="item.component=='tableselect'" > |
| | | <template v-else-if="item.component == 'tableselect'"> |
| | | <tableselect-render v-model="form[item.name]" :item="item"></tableselect-render> |
| | | </template> |
| | | <!-- editor --> |
| | | <template v-else-if="item.component=='editor'" > |
| | | <template v-else-if="item.component == 'editor'"> |
| | | <sc-editor v-model="form[item.name]" placeholder="请输入" :height="400"></sc-editor> |
| | | </template> |
| | | <!-- noComponent --> |
| | | <template v-else> |
| | | <el-tag type="danger">[{{item.component}}] Component not found</el-tag> |
| | | <el-tag type="danger">[{{ item.component }}] Component not found</el-tag> |
| | | </template> |
| | | <div v-if="item.message" class="el-form-item-msg">{{item.message}}</div> |
| | | <div v-if="item.message" class="el-form-item-msg">{{ item.message }}</div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import http from "@/utils/request" |
| | | import http from "@/utils/request" |
| | | |
| | | import { defineAsyncComponent } from 'vue' |
| | | const tableselectRender = defineAsyncComponent(() => import('./items/tableselect')) |
| | | const scEditor = defineAsyncComponent(() => import('@/components/scEditor')) |
| | | import { defineAsyncComponent } from 'vue' |
| | | const tableselectRender = defineAsyncComponent(() => import('./items/tableselect')) |
| | | const scEditor = defineAsyncComponent(() => import('@/components/scEditor')) |
| | | |
| | | export default { |
| | | props: { |
| | | modelValue: { type: Object, default: () => {} }, |
| | | config: { type: Object, default: () => {} }, |
| | | loading: { type: Boolean, default: false }, |
| | | }, |
| | | components: { |
| | | tableselectRender, |
| | | scEditor |
| | | }, |
| | | data() { |
| | | return { |
| | | form: {}, |
| | | renderLoading: false |
| | | export default { |
| | | props: { |
| | | modelValue: { type: Object, default: () => { } }, |
| | | config: { type: Object, default: () => { } }, |
| | | loading: { type: Boolean, default: false }, |
| | | }, |
| | | components: { |
| | | tableselectRender, |
| | | scEditor |
| | | }, |
| | | data() { |
| | | return { |
| | | form: {}, |
| | | renderLoading: false |
| | | } |
| | | }, |
| | | watch: { |
| | | modelValue() { |
| | | if (this.hasConfig) { |
| | | this.deepMerge(this.form, this.modelValue) |
| | | } |
| | | }, |
| | | watch:{ |
| | | modelValue(){ |
| | | if(this.hasConfig){ |
| | | this.deepMerge(this.form, this.modelValue) |
| | | } |
| | | }, |
| | | config(){ |
| | | this.render() |
| | | }, |
| | | form:{ |
| | | handler(val){ |
| | | this.$emit("update:modelValue", val) |
| | | }, |
| | | deep: true |
| | | } |
| | | config() { |
| | | this.render() |
| | | }, |
| | | computed: { |
| | | hasConfig(){ |
| | | return Object.keys(this.config).length>0 |
| | | form: { |
| | | handler(val) { |
| | | this.$emit("update:modelValue", val) |
| | | }, |
| | | hasValue(){ |
| | | return Object.keys(this.modelValue).length>0 |
| | | } |
| | | deep: true |
| | | } |
| | | }, |
| | | computed: { |
| | | hasConfig() { |
| | | return Object.keys(this.config).length > 0 |
| | | }, |
| | | created() { |
| | | hasValue() { |
| | | return Object.keys(this.modelValue).length > 0 |
| | | } |
| | | }, |
| | | created() { |
| | | |
| | | }, |
| | | mounted() { |
| | | if(this.hasConfig){ |
| | | this.render() |
| | | } |
| | | }, |
| | | methods: { |
| | | //构建form对象 |
| | | render() { |
| | | this.config.formItems.forEach((item) => { |
| | | if(item.component == 'checkbox'){ |
| | | if(item.name){ |
| | | const value = {} |
| | | item.options.items.forEach((option) => { |
| | | value[option.name] = option.value |
| | | }) |
| | | this.form[item.name] = value |
| | | }else{ |
| | | item.options.items.forEach((option) => { |
| | | this.form[option.name] = option.value |
| | | }) |
| | | } |
| | | }else if(item.component == 'upload'){ |
| | | if(item.name){ |
| | | const value = {} |
| | | item.options.items.forEach((option) => { |
| | | value[option.name] = option.value |
| | | }) |
| | | this.form[item.name] = value |
| | | }else{ |
| | | item.options.items.forEach((option) => { |
| | | this.form[option.name] = option.value |
| | | }) |
| | | } |
| | | }else{ |
| | | this.form[item.name] = item.value |
| | | } |
| | | }) |
| | | if(this.hasValue){ |
| | | this.form = this.deepMerge(this.form, this.modelValue) |
| | | } |
| | | this.getData() |
| | | }, |
| | | //处理远程选项数据 |
| | | getData() { |
| | | this.renderLoading = true |
| | | var remoteData = [] |
| | | this.config.formItems.forEach((item) => { |
| | | if(item.options && item.options.remote){ |
| | | var req = http.get(item.options.remote.api, item.options.remote.data).then(res=>{ |
| | | item.options.items = res.data |
| | | }, |
| | | mounted() { |
| | | if (this.hasConfig) { |
| | | this.render() |
| | | } |
| | | }, |
| | | methods: { |
| | | //构建form对象 |
| | | render() { |
| | | this.config.formItems.forEach((item) => { |
| | | if (item.component == 'checkbox') { |
| | | if (item.name) { |
| | | const value = {} |
| | | item.options.items.forEach((option) => { |
| | | value[option.name] = option.value |
| | | }) |
| | | remoteData.push(req) |
| | | this.form[item.name] = value |
| | | } else { |
| | | item.options.items.forEach((option) => { |
| | | this.form[option.name] = option.value |
| | | }) |
| | | } |
| | | }) |
| | | Promise.all(remoteData).then(()=>{ |
| | | this.renderLoading = false |
| | | }) |
| | | }, |
| | | //合并深结构对象 |
| | | deepMerge(obj1, obj2) { |
| | | let key; |
| | | for (key in obj2) { |
| | | obj1[key] = obj1[key] && obj1[key].toString() === "[object Object]" && (obj2[key] && obj2[key].toString() === "[object Object]") ? this.deepMerge(obj1[key], obj2[key]) : (obj1[key] = obj2[key]) |
| | | } else if (item.component == 'upload') { |
| | | if (item.name) { |
| | | const value = {} |
| | | item.options.items.forEach((option) => { |
| | | value[option.name] = option.value |
| | | }) |
| | | this.form[item.name] = value |
| | | } else { |
| | | item.options.items.forEach((option) => { |
| | | this.form[option.name] = option.value |
| | | }) |
| | | } |
| | | } else { |
| | | this.form[item.name] = item.value |
| | | } |
| | | return obj1 |
| | | //return JSON.parse(JSON.stringify(obj1)) |
| | | }, |
| | | //处理动态隐藏 |
| | | hideHandle(item){ |
| | | if(item.hideHandle){ |
| | | const exp = eval(item.hideHandle.replace(/\$/g,"this.form")) |
| | | return exp |
| | | } |
| | | return false |
| | | }, |
| | | //处理动态必填 |
| | | rulesHandle(item){ |
| | | if(item.requiredHandle){ |
| | | const exp = eval(item.requiredHandle.replace(/\$/g,"this.form")) |
| | | var requiredRule = item.rules.find(t => 'required' in t) |
| | | requiredRule.required = exp |
| | | } |
| | | return item.rules |
| | | }, |
| | | //数据验证 |
| | | validate(valid, obj){ |
| | | return this.$refs.form.validate(valid, obj) |
| | | }, |
| | | scrollToField(prop){ |
| | | return this.$refs.form.scrollToField(prop) |
| | | }, |
| | | resetFields(){ |
| | | return this.$refs.form.resetFields() |
| | | }, |
| | | //提交 |
| | | submit(){ |
| | | this.$emit("submit", this.form) |
| | | }) |
| | | if (this.hasValue) { |
| | | this.form = this.deepMerge(this.form, this.modelValue) |
| | | } |
| | | this.getData() |
| | | }, |
| | | //处理远程选项数据 |
| | | getData() { |
| | | this.renderLoading = true |
| | | var remoteData = [] |
| | | this.config.formItems.forEach((item) => { |
| | | if (item.options && item.options.remote) { |
| | | var req = http.get(item.options.remote.api, item.options.remote.data).then(res => { |
| | | item.options.items = res.data |
| | | }) |
| | | remoteData.push(req) |
| | | } |
| | | }) |
| | | Promise.all(remoteData).then(() => { |
| | | this.renderLoading = false |
| | | }) |
| | | }, |
| | | //合并深结构对象 |
| | | deepMerge(obj1, obj2) { |
| | | let key; |
| | | for (key in obj2) { |
| | | obj1[key] = obj1[key] && obj1[key].toString() === "[object Object]" && (obj2[key] && obj2[key].toString() === "[object Object]") ? this.deepMerge(obj1[key], obj2[key]) : (obj1[key] = obj2[key]) |
| | | } |
| | | return obj1 |
| | | //return JSON.parse(JSON.stringify(obj1)) |
| | | }, |
| | | //处理动态隐藏 |
| | | hideHandle(item) { |
| | | if (item.hideHandle) { |
| | | const exp = eval(item.hideHandle.replace(/\$/g, "this.form")) |
| | | return exp |
| | | } |
| | | return false |
| | | }, |
| | | //处理动态必填 |
| | | rulesHandle(item) { |
| | | if (item.requiredHandle) { |
| | | const exp = eval(item.requiredHandle.replace(/\$/g, "this.form")) |
| | | var requiredRule = item.rules.find(t => 'required' in t) |
| | | requiredRule.required = exp |
| | | } |
| | | return item.rules |
| | | }, |
| | | //数据验证 |
| | | validate(valid, obj) { |
| | | return this.$refs.form.validate(valid, obj) |
| | | }, |
| | | scrollToField(prop) { |
| | | return this.$refs.form.scrollToField(prop) |
| | | }, |
| | | resetFields() { |
| | | return this.$refs.form.resetFields() |
| | | }, |
| | | //提交 |
| | | submit() { |
| | | this.$emit("submit", this.form) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | </style> |
| | | <style></style> |