效果图:
在若依框架自带的流程表单配置基础上添加这两个组件
config.js
// 表单属性【右面板】
export const formConf = {formRef: 'elForm',formModel: 'formData',other: 'other',size: 'medium',labelPosition: 'right',labelWidth: 100,formRules: 'rules',gutter: 15,disabled: false,span: 24,formBtns: true,tableName: '',//关联表名flowName: '',//关联流程flowId: '',//关联流程id
}// 输入型组件 【左面板】
export const inputComponents = [{__config__: {label: '文本',width: '200px',prop: '',align: '',labelWidth: null,labelHeight: null,showLabel: false,changeTag: true,tag: 'ts-text',tagIcon: 'edit',defaultValue: undefined,style: {fonWeight: 'bold'},required: false,layout: 'colFormItem',span: 24,document: 'https://element.eleme.cn/#/zh-CN/component/input',// 正则校验规则regList: []},// 组件的插槽属性__slot__: {span: '文本'},// 其余的为可直接写在组件标签上的属性style: { width: '100%' },clearable: true,'prefix-icon': '','suffix-icon': '',maxlength: null,'show-word-limit': false,readonly: false,disabled: false},{__config__: {label: '操作人',showLabel: true,width: '200px',prop: '',align: '',labelWidth: null,labelHeight: null,changeTag: true,tag: 'ts-signature',tagIcon: 'icon-account',defaultValue: undefined,style: {fonWeight: 'bold'},required: false,layout: 'colFormItem',span: 24,document: 'https://element.eleme.cn/#/zh-CN/component/input',// 正则校验规则regList: []},// 组件的插槽属性__slot__: {span: '文本'},// 其余的为可直接写在组件标签上的属性style: { width: '100%' },clearable: true,'prefix-icon': '','suffix-icon': '',maxlength: null,'show-word-limit': false,readonly: false,disabled: false},{// 组件的自定义配置__config__: {label: '单行文本',labelWidth: null,showLabel: true,changeTag: true,tag: 'el-input',tagIcon: 'input',defaultValue: undefined,required: true,layout: 'colFormItem',span: 24,document: 'https://element.eleme.cn/#/zh-CN/component/input',// 正则校验规则regList: []},// 组件的插槽属性__slot__: {prepend: '',append: ''},// 其余的为可直接写在组件标签上的属性placeholder: '请输入',style: {width: '100%'},clearable: true,'prefix-icon': '','suffix-icon': '',maxlength: null,'show-word-limit': false,readonly: false,disabled: false},{__config__: {label: '多行文本',labelWidth: null,showLabel: true,tag: 'el-input',tagIcon: 'textarea',defaultValue: undefined,required: true,layout: 'colFormItem',span: 24,regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/input'},type: 'textarea',placeholder: '请输入',autosize: {minRows: 4,maxRows: 4},style: {width: '100%'},maxlength: null,'show-word-limit': false,readonly: false,disabled: false},{__config__: {label: '密码',showLabel: true,labelWidth: null,changeTag: true,tag: 'el-input',tagIcon: 'password',defaultValue: undefined,layout: 'colFormItem',span: 24,required: true,regList: [],document: 'https://element.eleme.cn/#/zh-CN/component/input'},__slot__: {prepend: '',append: ''},placeholder: '请输入','show-password': true,style: {width: '100%'},clearable: true,'prefix-icon': '','suffix-icon': '',maxlength: null,'show-word-limit': false,readonly: false,disabled: false},{__config__: {label: '计数器',showLabel: true,changeTag: true,labelWidth: null,tag: 'el-input-number',tagIcon: 'number',defaultValue: undefined,span: 24,layout: 'colFormItem',required: true,regList: [],document: 'https://element.eleme.cn/#/zh-CN/component/input-number'},placeholder: '',min: undefined,max: undefined,step: 1,'step-strictly': false,precision: undefined,'controls-position': '',disabled: false},{__config__: {label: '编辑器',showLabel: true,changeTag: true,labelWidth: null,tag: 'tinymce',tagIcon: 'keyInput',defaultValue: null,span: 24,layout: 'colFormItem',required: true,regList: [],document: 'http://tinymce.ax-z.cn'},placeholder: '请输入',height: 300, // 编辑器高度branding: false // 隐藏右下角品牌烙印},{__config__: {layout: 'tsSubform', // 拖拽处理方法tagIcon: 'row',tag: 'ts-sub-form', // 组件名称label: '子表单',showLabel: false,defaultValue: [], // v-modelchildren: [] // 子节点},addButton: true, // 默认可添加deleteButton: true, // 默认可删除displayShow: 'transverse',canEdit: true // 默认可编辑,为false时添加和删除都不可用,并且表单为disabled状态}
]// 选择型组件 【左面板】
export const selectComponents = [{__config__: {label: '下拉选择',showLabel: true,labelWidth: null,tag: 'el-select',tagIcon: 'select',layout: 'colFormItem',span: 24,required: true,regList: [],dataType: 'dynamic',dataTypeDetail: 'dynamic',dictType: '',changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/select'},__slot__: {options: [{label: '选项一',value: 1}, {label: '选项二',value: 2}]},placeholder: '请选择',style: {width: '100%'},clearable: true,disabled: false,filterable: false,multiple: false},{__config__: {label: '部门选择',showLabel: true,labelWidth: null,tag: 'ts-select-tree',tagIcon: 'select',layout: 'colFormItem',span: 24,required: true,regList: [],dataType: 'dynamic',dataTypeDetail: 'dynamic',dictType: '',changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/select'},__slot__: {options: [{"id": 100,"label": "A集团","children": [{"id": 367,"label": "AB发电公司","children": [{"id": 368,"label": "A电厂"},{"id": 369,"label": "B电厂"}]},{"id": 370,"label": "ABC发电公司","children": [{"id": 371,"label": "A发电厂"}]}]}]},placeholder: '请选择',style: {width: '100%'},clearable: true,disabled: false,filterable: false,multiple: false},{__config__: {label: '级联选择',url: 'https://www.fastmock.site/mock/f8d7a54fb1e60561e2f720d5a810009d/fg/cascaderList',method: 'get',dataPath: 'list',dataConsumer: 'options',showLabel: true,labelWidth: null,tag: 'el-cascader',tagIcon: 'cascader',layout: 'colFormItem',defaultValue: [],dataType: 'dynamic',span: 24,required: true,regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/cascader'},options: [{id: 1,value: 1,label: '选项1',children: [{id: 2,value: 2,label: '选项1-1'}]}],placeholder: '请选择',style: {width: '100%'},props: {props: {multiple: false,label: 'label',value: 'value',children: 'children'}},'show-all-levels': true,disabled: false,clearable: true,filterable: false,separator: '/'},{__config__: {label: '单选框组',labelWidth: null,showLabel: true,tag: 'el-radio-group',tagIcon: 'radio',changeTag: true,defaultValue: undefined,layout: 'colFormItem',span: 24,optionType: 'default',regList: [],required: true,border: false,document: 'https://element.eleme.cn/#/zh-CN/component/radio'},__slot__: {options: [{label: '选项一',value: 1}, {label: '选项二',value: 2}]},style: {},size: 'medium',disabled: false},{__config__: {label: '多选框组',tag: 'el-checkbox-group',tagIcon: 'checkbox',defaultValue: [],span: 24,showLabel: true,labelWidth: null,layout: 'colFormItem',optionType: 'default',required: true,regList: [],changeTag: true,border: false,document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'},__slot__: {options: [{label: '选项一',value: 1}, {label: '选项二',value: 2}]},style: {},size: 'medium',min: null,max: null,disabled: false},{__config__: {label: '开关',tag: 'el-switch',tagIcon: 'switch',defaultValue: false,span: 24,showLabel: true,labelWidth: null,layout: 'colFormItem',required: true,regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/switch'},style: {},disabled: false,'active-text': '','inactive-text': '','active-color': null,'inactive-color': null,'active-value': true,'inactive-value': false},{__config__: {label: '滑块',tag: 'el-slider',tagIcon: 'slider',defaultValue: null,span: 24,showLabel: true,layout: 'colFormItem',labelWidth: null,required: true,regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/slider'},disabled: false,min: 0,max: 100,step: 1,'show-stops': false,range: false},{__config__: {label: '时间选择',tag: 'el-time-picker',tagIcon: 'time',defaultValue: null,span: 24,showLabel: true,layout: 'colFormItem',labelWidth: null,required: true,regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'},placeholder: '请选择',style: {width: '100%'},disabled: false,clearable: true,'picker-options': {selectableRange: '00:00:00-23:59:59'},format: 'HH:mm:ss','value-format': 'HH:mm:ss'},{__config__: {label: '时间范围',tag: 'el-time-picker',tagIcon: 'time-range',span: 24,showLabel: true,labelWidth: null,layout: 'colFormItem',defaultValue: null,required: true,regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'},style: {width: '100%'},disabled: false,clearable: true,'is-range': true,'range-separator': '至','start-placeholder': '开始时间','end-placeholder': '结束时间',format: 'HH:mm:ss','value-format': 'HH:mm:ss'},{__config__: {label: '日期选择',tag: 'el-date-picker',tagIcon: 'date',defaultValue: null,showLabel: true,labelWidth: null,span: 24,layout: 'colFormItem',required: true,regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'},placeholder: '请选择',type: 'date',style: {width: '100%'},disabled: false,clearable: true,format: 'yyyy-MM-dd','value-format': 'yyyy-MM-dd',readonly: false},{__config__: {label: '日期范围',tag: 'el-date-picker',tagIcon: 'date-range',defaultValue: null,span: 24,showLabel: true,labelWidth: null,required: true,layout: 'colFormItem',regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'},style: {width: '100%'},type: 'daterange','range-separator': '至','start-placeholder': '开始日期','end-placeholder': '结束日期',disabled: false,clearable: true,format: 'yyyy-MM-dd','value-format': 'yyyy-MM-dd',readonly: false},{__config__: {label: '评分',tag: 'el-rate',tagIcon: 'rate',defaultValue: 0,span: 24,showLabel: true,labelWidth: null,layout: 'colFormItem',required: true,regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/rate'},style: {},max: 5,'allow-half': false,'show-text': false,'show-score': false,disabled: false},{__config__: {label: '颜色选择',tag: 'el-color-picker',tagIcon: 'color',span: 24,defaultValue: null,showLabel: true,labelWidth: null,layout: 'colFormItem',required: true,regList: [],changeTag: true,document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'},'show-alpha': false,'color-format': '',disabled: false,size: 'medium'},{__config__: {label: '上传',tag: 'el-upload',tagIcon: 'upload',layout: 'colFormItem',defaultValue: null,showLabel: true,labelWidth: null,required: true,span: 24,showTip: false,buttonText: '点击上传',regList: [],changeTag: true,fileSize: 2,sizeUnit: 'MB',document: 'https://element.eleme.cn/#/zh-CN/component/upload'},__slot__: {'list-type': true},action: 'https://jsonplaceholder.typicode.com/posts/',disabled: false,accept: '',name: 'file','auto-upload': true,'list-type': 'text',multiple: false}
]// 布局型组件 【左面板】
export const layoutComponents = [{__config__: {layout: 'rowFormItem',tagIcon: 'row',label: '行容器',layoutTree: true,document: 'https://element.eleme.cn/#/zh-CN/component/layout#row-attributes'},type: 'default',justify: 'start',align: 'top'},{__config__: {label: '按钮',showLabel: true,changeTag: true,labelWidth: null,tag: 'el-button',tagIcon: 'button',span: 24,layout: 'colFormItem',document: 'https://element.eleme.cn/#/zh-CN/component/button'},__slot__: {default: '主要按钮'},type: 'primary',icon: 'el-icon-search',round: false,size: 'medium',plain: false,circle: false,disabled: false},// {// __config__: {// layout: 'colFormItem',// tagIcon: 'table',// tag: 'el-table',// document: 'https://element.eleme.cn/#/zh-CN/component/table',// span: 24,// formId: 101,// renderKey: 1595761764203,// componentName: 'row101',// showLabel: true,// changeTag: true,// labelWidth: null,// label: '表格[开发中]',// dataType: 'dynamic',// method: 'get',// dataPath: 'list',// dataConsumer: 'data',// url: 'https://www.fastmock.site/mock/f8d7a54fb1e60561e2f720d5a810009d/fg/tableData',// children: [{// __config__: {// layout: 'raw',// tag: 'el-table-column',// renderKey: 15957617660153// },// prop: 'date',// label: '日期'// }, {// __config__: {// layout: 'raw',// tag: 'el-table-column',// renderKey: 15957617660152// },// prop: 'address',// label: '地址'// }, {// __config__: {// layout: 'raw',// tag: 'el-table-column',// renderKey: 15957617660151// },// prop: 'name',// label: '名称'// }, {// __config__: {// layout: 'raw',// tag: 'el-table-column',// renderKey: 1595774496335,// children: [// {// __config__: {// label: '按钮',// tag: 'el-button',// tagIcon: 'button',// layout: 'raw',// renderKey: 1595779809901// },// __slot__: {// default: '主要按钮'// },// type: 'primary',// icon: 'el-icon-search',// round: false,// size: 'medium'// }// ]// },// label: '操作'// }]// },// data: [],// directives: [{// name: 'loading',// value: true// }],// border: true,// type: 'default',// justify: 'start',// align: 'top'// }{__config__: {layout: 'colFormItem',tagIcon: 'table',tag: 'ts-designer-table',span: 24,formId: 101,componentName: 'row101',showLabel: false,changeTag: true,labelWidth: null,data: [],label: '表格布局',class: 'ts-designer-table',children: [{__config__: {layout: 'raw',tag: 'ts-designer-tr',opDomain: '',children: [{__config__: {layout: 'raw',tag: 'ts-designer-td',children: [{__config__: {layout: 'rowFormItem',type: 'TsDesignerTable',children: []},align: 'middle',justify: 'default',type: 'default'}]},style: {border: '1px solid #000',width: '',background: ''},colspan: 1,rowspan: 1}]}}]},border: true,type: 'default',justify: 'start',align: 'top'},{__config__: {formId: 102,label: '标签页', // 在home.vue页面左侧呈现的组件名称tagIcon: 'table', // 在home.vue页面左侧呈现的组件图标showLabel: false, // 是否在中间可视化区域默认显示labelchangeTag: false, // 是否在右侧操作面板可进行组件类型切换labelWidth: null, // 组件默认宽度defaultValue: 'first',componentName: 'row89757',tag: 'el-tabs', // 组件的名称span: 24, // 默认栅格布局数值layout: 'tsElTabs' // 在DraggableItem.vue中默认处理的方法},children: [{label: '用户管理',children: [], // 主要用于存储拖拽进来的子组件name: 'first'},{children: [],label: '配置管理',name: 'second'}],// 从这里开始就是el-tabs标签的属性 主要是在home.vue页面的右侧操作面板进行操作更改type: 'card', // 风格类型closable: false, // 标签是否可关闭addable: false, // 标签是否可增加editable: false, // 标签是否同时可增加和关闭'tab-position': 'top', // 选项卡所在位置stretch: false // 标签的宽度是否自撑开}
]
html.js
/* eslint-disable max-len */
import { trigger } from './config'let confGlobal
let someSpanIsNot24export function dialogWrapper(str) {return `<el-dialog v-bind="$attrs" v-on="$listeners" @open="onOpen" @close="onClose" title="Dialog Title">${str}<div slot="footer"><el-button @click="close">取消</el-button><el-button type="primary" @click="handleConfirm">确定</el-button></div></el-dialog>`
}export function vueTemplate(str) {return `<template><div>${str}</div></template>`
}export function vueScript(str) {return `<script>${str}</script>`
}export function cssStyle(cssStr) {return `<style>${cssStr}</style>`
}function buildFormTemplate(conf, child, type) {let labelPosition = ''if (conf.labelPosition !== 'right') {labelPosition = `label-position="${conf.labelPosition}"`}const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : ''let str = `<el-form ref="${conf.formRef}" :model="${conf.formModel}" :rules="${conf.formRules}" size="${conf.size}" ${disabled} label-width="${conf.labelWidth}px" ${labelPosition}>${child}${buildFromBtns(conf, type)}</el-form>`if (someSpanIsNot24) {str = `<el-row :gutter="${conf.gutter}">${str}</el-row>`}return str
}function buildFromBtns(conf, type) {let str = ''if (conf.formBtns && type === 'file') {str = `<el-form-item size="large"><el-button type="primary" @click="submitForm">提交</el-button><el-button @click="resetForm">重置</el-button></el-form-item>`if (someSpanIsNot24) {str = `<el-col :span="24">${str}</el-col>`}}return str
}// span不为24的用el-col包裹
function colWrapper(element, str) {if (someSpanIsNot24 || element.span !== 24) {return `<el-col :span="${element.span}">${str}</el-col>`}return str
}const layouts = {colFormItem(element) {let labelWidth = ''if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) {labelWidth = `label-width="${element.labelWidth}px"`}const required = !trigger[element.tag] && element.required ? 'required' : ''const tagDom = tags[element.tag] ? tags[element.tag](element) : nulllet str = `<el-form-item ${labelWidth} label="${element.label}" prop="${element.vModel}" ${required}>${tagDom}</el-form-item>`str = colWrapper(element, str)return str},rowFormItem(element) {const type = element.type === 'default' ? '' : `type="${element.type}"`const justify = element.type === 'default' ? '' : `justify="${element.justify}"`const align = element.type === 'default' ? '' : `align="${element.align}"`const gutter = element.gutter ? `gutter="${element.gutter}"` : ''const children = element.children.map(el => layouts[el.layout](el))let str = `<el-row ${type} ${justify} ${align} ${gutter}>${children.join('\n')}</el-row>`str = colWrapper(element, str)return str},tsSubform(scheme) {const dataName = `:table-data="other.subForm${scheme.__config__.formId}"`const value = `v-model="other.subForm${scheme.__config__.formId}Data"`const addButton = `:addButton="other.addButton${scheme.__config__.formId}"`const deleteButton = `:deleteButton="other.deleteButton${scheme.__config__.formId}"`const displayShow = `:displayShow="other.displayShow${scheme.__config__.formId}"`const canEdit = `:canEdit="other.canEdit${scheme.__config__.formId}"`return `<ts-sub-form ${dataName} ${value} ${addButton} ${deleteButton} ${displayShow} ${canEdit}></ts-sub-form>`},raw(scheme) {let str = ''if (scheme.style && scheme.style.display) {return str}if (scheme.__config__.tag === 'ts-designer-tr' || scheme.__config__.tag === 'ts-designer-td') {const config = scheme.__config__const tagDom = tags[config.tag] ? tags[config.tag](scheme) : nullstr = `${tagDom}`}return str},tsElTabs(scheme) {const config = scheme.__config__const tagDom = tags[config.tag] ? tags[config.tag](scheme) : nulllet str = tagDomstr = colWrapper(scheme, str)return str}}const tags = {'el-button': el => {const {tag, disabled} = attrBuilder(el)const type = el.type ? `type="${el.type}"` : ''const icon = el.icon ? `icon="${el.icon}"` : ''const size = el.size ? `size="${el.size}"` : ''let child = buildElButtonChild(el)if (child) child = `\n${child}\n` // 换行return `<${el.tag} ${type} ${icon} ${size} ${disabled}>${child}</${el.tag}>`},'el-input': el => {const {disabled, vModel, clearable, placeholder, width} = attrBuilder(el)const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''const readonly = el.readonly ? 'readonly' : ''const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : ''const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : ''const showPassword = el['show-password'] ? 'show-password' : ''const type = el.type ? `type="${el.type}"` : ''const autosize = el.autosize && el.autosize.minRows? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"`: ''let child = buildElInputChild(el)if (child) child = `\n${child}\n` // 换行return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}</${el.tag}>`},'el-input-number': el => {const { disabled, vModel, placeholder } = attrBuilder(el)const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : ''const min = el.min ? `:min='${el.min}'` : ''const max = el.max ? `:max='${el.max}'` : ''const step = el.step ? `:step='${el.step}'` : ''const stepStrictly = el['step-strictly'] ? 'step-strictly' : ''const precision = el.precision ? `:precision='${el.precision}'` : ''return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}></${el.tag}>`},'el-select': el => {const {disabled, vModel, clearable, placeholder, width} = attrBuilder(el)const filterable = el.filterable ? 'filterable' : ''const multiple = el.multiple ? 'multiple' : ''let child = buildElSelectChild(el)if (child) child = `\n${child}\n` // 换行return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}</${el.tag}>`},'el-radio-group': el => {const { disabled, vModel } = attrBuilder(el)const size = `size="${el.size}"`let child = buildElRadioGroupChild(el)if (child) child = `\n${child}\n` // 换行return `<${el.tag} ${vModel} ${size} ${disabled}>${child}</${el.tag}>`},'el-checkbox-group': el => {const { disabled, vModel } = attrBuilder(el)const size = `size="${el.size}"`const min = el.min ? `:min="${el.min}"` : ''const max = el.max ? `:max="${el.max}"` : ''let child = buildElCheckboxGroupChild(el)if (child) child = `\n${child}\n` // 换行return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}</${el.tag}>`},'el-switch': el => {const { disabled, vModel } = attrBuilder(el)const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : ''const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : ''const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : ''const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : ''const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : ''const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : ''return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}></${el.tag}>`},'el-cascader': el => {const {disabled, vModel, clearable, placeholder, width} = attrBuilder(el)const options = el.options ? `:options="${el.vModel}Options"` : ''const props = el.props ? `:props="${el.vModel}Props"` : ''const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"'const filterable = el.filterable ? 'filterable' : ''const separator = el.separator === '/' ? '' : `separator="${el.separator}"`return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}></${el.tag}>`},'el-slider': el => {const { disabled, vModel } = attrBuilder(el)const min = el.min ? `:min='${el.min}'` : ''const max = el.max ? `:max='${el.max}'` : ''const step = el.step ? `:step='${el.step}'` : ''const range = el.range ? 'range' : ''const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : ''return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}></${el.tag}>`},'el-time-picker': el => {const {disabled, vModel, clearable, placeholder, width} = attrBuilder(el)const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''const isRange = el['is-range'] ? 'is-range' : ''const format = el.format ? `format="${el.format}"` : ''const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : ''return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}></${el.tag}>`},'el-date-picker': el => {const {disabled, vModel, clearable, placeholder, width} = attrBuilder(el)const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''const format = el.format ? `format="${el.format}"` : ''const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''const type = el.type === 'date' ? '' : `type="${el.type}"`const readonly = el.readonly ? 'readonly' : ''return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}></${el.tag}>`},'el-rate': el => {const { disabled, vModel } = attrBuilder(el)const max = el.max ? `:max='${el.max}'` : ''const allowHalf = el['allow-half'] ? 'allow-half' : ''const showText = el['show-text'] ? 'show-text' : ''const showScore = el['show-score'] ? 'show-score' : ''return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}></${el.tag}>`},'el-color-picker': el => {const { disabled, vModel } = attrBuilder(el)const size = `size="${el.size}"`const showAlpha = el['show-alpha'] ? 'show-alpha' : ''const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : ''return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}></${el.tag}>`},'el-upload': el => {const disabled = el.disabled ? ':disabled=\'true\'' : ''const action = el.action ? `:action="${el.vModel}Action"` : ''const multiple = el.multiple ? 'multiple' : ''const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : ''const accept = el.accept ? `accept="${el.accept}"` : ''const name = el.name !== 'file' ? `name="${el.name}"` : ''const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : ''const beforeUpload = `:before-upload="${el.vModel}BeforeUpload"`const fileList = `:file-list="${el.vModel}fileList"`const ref = `ref="${el.vModel}"`let child = buildElUploadChild(el)if (child) child = `\n${child}\n` // 换行return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}</${el.tag}>`},'ts-sub-form': el => {const dataName = `:table-data="other.subForm${el.__config__.formId}"`const value = `v-model="other.subForm${el.__config__.formId}Data"`const addButton = `:addButton="other.addButton${el.__config__.formId}"`const deleteButton = `:deleteButton="other.deleteButton${el.__config__.formId}"`const displayShow = `:displayShow="other.displayShow${el.__config__.formId}"`const canEdit = `:canEdit="other.canEdit${el.__config__.formId}"`return `<ts-sub-form ${dataName} ${value} ${addButton} ${deleteButton} ${displayShow} ${canEdit}></ts-sub-form>`},'ts-text': el => {const {clearable, placeholder, width} = attrBuilder(el)const text = el.__slot__.spanconst { style } = ellet styles = ''// eslint-disable-next-line guard-for-in,no-restricted-syntaxfor (const key in style) {styles += `${key}:${style[key]};`}return `<div ${clearable} style="${styles}" ${placeholder}><span>${text}</span></div>`},'ts-designer-table': el => {const child = tsDesignerAttrBuilder(el)return `<table class="ts-designer-table">${child}</table>`},'ts-designer-tr': el => {const child = tsDesignerAttrBuilder(el)return `<tr >${child}</tr>`},'ts-designer-td': el => {const child = tsDesignerTdAttrBuilder(el)const { style } = ellet syles = ''// eslint-disable-next-line guard-for-in,no-restricted-syntaxfor (const key in style) {syles += `${key}:${style[key]};`}syles = `"${syles}"`return `<td class="ts-designer-td" style=${syles} colspan=${el.colspan} rowspan=${el.rowspan}>${child}</td>`},'el-tabs': el => {const { tag, vModel } = attrBuilder(el)const type = el.type ? `type="${el.type}"` : ''const closable = el.closable ? `type="${el.closable}"` : ''const tabPosition = el['tab-position'] ? `tab-position="${el['tab-position']}"` : ''const child = exportTabsChild(el)return `<${tag} ${type} ${vModel} ${closable} ${tabPosition}>${child}</${tag}>`}
}
function exportTabsChild(scheme) {debuggerconst childrenList = []const { children } = schemefor (let i = 0; i < children.length; i++) {let childHtml = []for (let j = 0; j < children[i].children.length; j++) {if (children[i].children[j]) {const oneChildHtml = layouts[children[i].children[j].__config__.layout](children[i].children[j])childHtml.push(oneChildHtml)}}childHtml = childHtml.join('\n')childrenList.push(`<el-tab-pane label='${children[i].label}'>${childHtml}</el-tab-pane>`)}return childrenList.join('\n')
}
function attrBuilder(el) {return {vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`,clearable: el.clearable ? 'clearable' : '',placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '',width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '',disabled: el.disabled ? ':disabled=\'true\'' : ''}
}
function tsDesignerAttrBuilder(el) {const children = []for (let i = 0; i < el.__config__.children.length; i++) {if (el.__config__.children[i]) {const trHtml = layouts[el.__config__.children[i].__config__.layout](el.__config__.children[i])children.push(`${trHtml}`)}}return children.join('\n')
}function tsDesignerTdAttrBuilder(el) {const children = []const trHtml = layouts[el.__config__.children[0].__config__.layout](el.__config__.children[0])children.push(`${trHtml}`)return children.join('\n')
}
// el-buttin 子级
function buildElButtonChild(conf) {const children = []if (conf.default) {children.push(conf.default)}return children.join('\n')
}// el-input innerHTML
function buildElInputChild(conf) {const children = []if (conf.prepend) {children.push(`<template slot="prepend">${conf.prepend}</template>`)}if (conf.append) {children.push(`<template slot="append">${conf.append}</template>`)}return children.join('\n')
}function buildElSelectChild(conf) {const children = []if (conf.options && conf.options.length) {children.push(`<el-option v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option>`)}return children.join('\n')
}function buildElRadioGroupChild(conf) {const children = []if (conf.options && conf.options.length) {const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio'const border = conf.border ? 'border' : ''children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)}return children.join('\n')
}function buildElCheckboxGroupChild(conf) {const children = []if (conf.options && conf.options.length) {const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox'const border = conf.border ? 'border' : ''children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)}return children.join('\n')
}function buildElUploadChild(conf) {const list = []if (conf['list-type'] === 'picture-card') list.push('<i class="el-icon-plus"></i>')else list.push(`<el-button size="small" type="primary" icon="el-icon-upload">${conf.buttonText}</el-button>`)if (conf.showTip) list.push(`<div slot="tip" class="el-upload__tip">只能上传不超过 ${conf.fileSize}${conf.sizeUnit} 的${conf.accept}文件</div>`)return list.join('\n')
}export function makeUpHtml(conf, type) {const htmlList = []confGlobal = confsomeSpanIsNot24 = conf.fields.some(item => item.span !== 24)conf.fields.forEach(el => {htmlList.push(layouts[el.layout](el))})const htmlStr = htmlList.join('\n')let temp = buildFormTemplate(conf, htmlStr, type)if (type === 'dialog') {temp = dialogWrapper(temp)}confGlobal = nullreturn temp
}
js.js
import { isArray } from 'util'
import { exportDefault, titleCase, deepClone } from '@/utils/index'
import ruleTrigger from './ruleTrigger'const units = {KB: '1024',MB: '1024 / 1024',GB: '1024 / 1024 / 1024'
}
let confGlobal
const inheritAttrs = {file: '',dialog: 'inheritAttrs: false,'
}/*** 组装js 【入口函数】* @param {Object} formConfig 整个表单配置* @param {String} type 生成类型,文件或弹窗等*/
export function makeUpJs(formConfig, type) {confGlobal = formConfig = deepClone(formConfig)const dataList = []const ruleList = []const optionsList = []const propsList = []const methodList = mixinMethod(type)const uploadVarList = []const created = []const other = []formConfig.fields.forEach(el => {buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList, created, other)})const script = buildexport(formConfig,type,dataList.join('\n'),ruleList.join('\n'),optionsList.join('\n'),uploadVarList.join('\n'),propsList.join('\n'),methodList.join('\n'),created.join('\n'),other.join('\n'))confGlobal = nullreturn script
}// 构建组件属性
// eslint-disable-next-line max-len
function buildAttributes(scheme, dataList, ruleList, optionsList, methodList, propsList, uploadVarList, created, other) {const config = scheme.__config__const slot = scheme.__slot__buildData(scheme, dataList, other)buildRules(scheme, ruleList)// 主要就是这一段代码的新增,其他地方都没有更改if (config.tag === 'el-tabs') {scheme.children.forEach(item => {item.children.forEach(el => {buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList, created)})})}// 特殊处理options属性if (scheme.options || (slot && slot.options && slot.options.length)) {buildOptions(scheme, optionsList)if (config.dataType === 'dynamic') {const model = `${scheme.__vModel__}Options`const options = titleCase(model)const methodName = `get${options}`buildOptionMethod(methodName, model, methodList, scheme)callInCreated(methodName, created)}}// 处理propsif (scheme.props && scheme.props.props) {buildProps(scheme, propsList)}// 处理el-upload的actionif (scheme.action && config.tag === 'el-upload') {uploadVarList.push(`${scheme.__vModel__}Action: '${scheme.action}',${scheme.__vModel__}fileList: [],`)methodList.push(buildBeforeUpload(scheme))// 非自动上传时,生成手动上传的函数if (!scheme['auto-upload']) {methodList.push(buildSubmitUpload(scheme))}}// 构建子级组件属性if (config.children) {config.children.forEach(item => {buildAttributes(item, dataList, ruleList, optionsList, methodList, propsList, uploadVarList, created)})}
}// 在Created调用函数
function callInCreated(methodName, created) {created.push(`this.${methodName}()`)
}// 混入处理函数
function mixinMethod(type) {const list = []; constminxins = {file: confGlobal.formBtns ? {submitForm: `submitForm() {this.$refs['${confGlobal.formRef}'].validate(valid => {if(!valid) return// TODO 提交表单})},`,resetForm: `resetForm() {this.$refs['${confGlobal.formRef}'].resetFields()},`} : null,dialog: {onOpen: 'onOpen() {},',onClose: `onClose() {this.$refs['${confGlobal.formRef}'].resetFields()},`,close: `close() {this.$emit('update:visible', false)},`,handelConfirm: `handelConfirm() {this.$refs['${confGlobal.formRef}'].validate(valid => {if(!valid) returnthis.close()})},`}}const methods = minxins[type]if (methods) {Object.keys(methods).forEach(key => {list.push(methods[key])})}return list
}// 构建data
function buildData(scheme, dataList, other) {const config = scheme.__config__if (config.tag === 'ts-sub-form') {const subformData = []if (scheme.__config__.children.length > 0) {scheme.__config__.children.forEach(item => {const basicsData = JSON.parse(JSON.stringify(item))basicsData.__config__.prop = item.__vModel__basicsData.disabled = item.disabledbasicsData.readonly = item.readonlysubformData.push(basicsData)})}other.push(`subForm${config.formId}: ${JSON.stringify(subformData)},`)other.push(`subForm${config.formId}Data: ${JSON.stringify(config.defaultValue)},`)other.push(`addButton${config.formId}: ${JSON.stringify(scheme.addButton)},`)other.push(`canEdit${config.formId}: ${JSON.stringify(scheme.canEdit)},`)other.push(`deleteButton${config.formId}: ${JSON.stringify(scheme.deleteButton)},`)other.push(`displayShow${config.formId}: ${JSON.stringify(scheme.displayShow)},`)return} if (scheme.__vModel__ === undefined) returnconst defaultValue = JSON.stringify(config.defaultValue)dataList.push(`${scheme.__vModel__}: ${defaultValue},`)
}// 构建校验规则
function buildRules(scheme, ruleList) {const config = scheme.__config__if (scheme.__vModel__ === undefined) returnconst rules = []if (ruleTrigger[config.tag]) {if (config.required) {const type = isArray(config.defaultValue) ? 'type: \'array\',' : ''let message = isArray(config.defaultValue) ? `请至少选择一个${config.label}` : scheme.placeholderif (message === undefined) message = `${config.label}不能为空`rules.push(`{ required: true, ${type} message: '${message}', trigger: '${ruleTrigger[config.tag]}' }`)}if (config.regList && isArray(config.regList)) {config.regList.forEach(item => {if (item.pattern) {rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${ruleTrigger[config.tag]}' }`)}})}ruleList.push(`${scheme.__vModel__}: [${rules.join(',')}],`)}
}// 构建options
function buildOptions(scheme, optionsList) {if (scheme.__vModel__ === undefined) return// el-cascader直接有options属性,其他组件都是定义在slot中,所以有两处判断let { options } = schemeif (!options) options = scheme.__slot__.optionsif (scheme.__config__.dataType === 'dynamic') { options = [] }const str = `${scheme.__vModel__}Options: ${JSON.stringify(options)},`optionsList.push(str)
}function buildProps(scheme, propsList) {const str = `${scheme.__vModel__}Props: ${JSON.stringify(scheme.props.props)},`propsList.push(str)
}// el-upload的BeforeUpload
function buildBeforeUpload(scheme) {const config = scheme.__config__const unitNum = units[config.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; constreturnList = []if (config.fileSize) {rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${config.fileSize}if(!isRightSize){this.$message.error('文件大小超过 ${config.fileSize}${config.sizeUnit}')}`returnList.push('isRightSize')}if (scheme.accept) {acceptCode = `let isAccept = new RegExp('${scheme.accept}').test(file.type)if(!isAccept){this.$message.error('应该选择${scheme.accept}类型的文件')}`returnList.push('isAccept')}const str = `${scheme.__vModel__}BeforeUpload(file) {${rightSizeCode}${acceptCode}return ${returnList.join('&&')}},`return returnList.length ? str : ''
}// el-upload的submit
function buildSubmitUpload(scheme) {const str = `submitUpload() {this.$refs['${scheme.__vModel__}'].submit()},`return str
}function buildOptionMethod(methodName, model, methodList, scheme) {const config = scheme.__config__const str = `${methodName}() {// 注意:this.$axios是通过Vue.prototype.$axios = axios挂载产生的this.$axios({method: '${config.method}',url: '${config.url}'}).then(resp => {var { data } = respthis.${model} = data.${config.dataPath}})},`methodList.push(str)
}// js整体拼接
function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods, created, other) {const str = `${exportDefault}{${inheritAttrs[type]}components: {},props: [],data () {return {${conf.other}: {${other}},${conf.formModel}: {${data}},${conf.formRules}: {${rules}},${uploadVar}${selectOptions}${props}}},computed: {},watch: {},created () {${created}},mounted () {},methods: {${methods}}
}`return str
}
表格组件源码要的私聊我!