diff --git a/.eslintignore b/.eslintignore index f563a2c..fe76fd2 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,4 +6,4 @@ vue.config.js src/utils/sign.js src/views/form/ src/utils/ -src/components/parser +src/components/ diff --git a/.stylelintignore b/.stylelintignore index 21cc331..89a3ac0 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -5,4 +5,4 @@ src/theme/ src/utils/sign.js src/views/form/ src/utils/ -src/components/parser +src/components/ diff --git a/docs/mobile-support.md b/docs/mobile-support.md index 37adccf..7ac3e44 100644 --- a/docs/mobile-support.md +++ b/docs/mobile-support.md @@ -36,4 +36,4 @@ module.exports = { } ``` -最后在开发中就可以直接使用 px 了,最终输出就是 vw 。 \ No newline at end of file +最后在开发中就可以直接使用 px 了,最终输出就是 vw 。 diff --git a/package.json b/package.json index 0cb4f8b..48ec428 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ }, "dependencies": { "axios": "^0.21.0", - "clipboard": "^2.0.6", "core-js": "^3.6.4", "dayjs": "^1.9.4", "element-ui": "^2.14.0", diff --git a/public/index.html b/public/index.html index f26e756..2a63094 100644 --- a/public/index.html +++ b/public/index.html @@ -3,7 +3,7 @@ - + <%= htmlWebpackPlugin.options.title %> <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %> diff --git a/src/assets/styles/home.scss b/src/assets/styles/home.scss index 399dce2..f0226e0 100644 --- a/src/assets/styles/home.scss +++ b/src/assets/styles/home.scss @@ -1,5 +1,5 @@ -$selectedColor: #f6f7ff; -$lighterBlue: #409eff; +$selectedColor: #f5f8ff; +$lighterBlue: #4aa0fa; .container { position: relative; width: 100%; @@ -41,10 +41,10 @@ $lighterBlue: #409eff; font-size: 15px; } &:hover { - border: 1px dashed #787be8; - color: #787be8; + border: 1px dashed #4144f8; + color: #4480f5; .svg-icon { - color: #787be8; + color: #4144f8; } } } @@ -54,14 +54,13 @@ $lighterBlue: #409eff; left: 0; top: 20px; height: 100vh; - background-color: rgba(255, 255, 255, 100); + //background-color: rgba(255, 255, 255, 100); } .el-menu.el-menu--horizontal { border-bottom: none; } .left-scrollbar { - //height: calc(100vh - 42px); - height: calc(100vh - 142px); + height: calc(100vh - 290px); overflow: hidden; margin: 5px; border-radius: 7px; @@ -70,22 +69,19 @@ $lighterBlue: #409eff; border: 1px solid rgba(255, 255, 255, 100); } .center-scrollbar { - height: calc(100vh - 42px); + height: calc(100vh - 230px); overflow: hidden; width: 80%; - //border-left: 1px solid #f1e8e8; - //border-right: 1px solid #f1e8e8; margin: 20px auto 0; - //margin-top: 20px; box-sizing: border-box; background-color: rgba(255, 255, 255, 100); border: 2px solid rgba(255, 255, 255, 100); overflow-y: hidden; } .center-board { - height: 100vh; + height: calc(100vh - 220px); width: auto; - margin: 0 350px 0 260px; + margin: 0 350px 80px 260px; box-sizing: border-box; } .empty-info { @@ -95,7 +91,7 @@ $lighterBlue: #409eff; right: 0; text-align: center; font-size: 18px; - color: #ccb1ea; + color: #0067f3; letter-spacing: 4px; } .action-bar { diff --git a/src/components/generator/config.js b/src/components/generator/config.js index ee6fcb1..33d4900 100644 --- a/src/components/generator/config.js +++ b/src/components/generator/config.js @@ -185,7 +185,7 @@ export const selectComponents = [ tagIcon: 'cascader', layout: 'colFormItem', defaultValue: [], - dataType: 'dynamic', + dataType: 'static', span: 24, required: true, regList: [], diff --git a/src/components/generator/css.js b/src/components/generator/css.js deleted file mode 100644 index 7cb86e6..0000000 --- a/src/components/generator/css.js +++ /dev/null @@ -1,18 +0,0 @@ -const styles = { - 'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}', - 'el-upload': '.el-upload__tip{line-height: 1.2;}' -} - -function addCss(cssList, el) { - const css = styles[el.__config__.tag] - css && cssList.indexOf(css) === -1 && cssList.push(css) - if (el.__config__.children) { - el.__config__.children.forEach(el2 => addCss(cssList, el2)) - } -} - -export function makeUpCss(conf) { - const cssList = [] - conf.fields.forEach(el => addCss(cssList, el)) - return cssList.join('\n') -} diff --git a/src/components/generator/html.js b/src/components/generator/html.js deleted file mode 100644 index 6e9a32e..0000000 --- a/src/components/generator/html.js +++ /dev/null @@ -1,399 +0,0 @@ -/* eslint-disable max-len */ -import ruleTrigger from './ruleTrigger' - -let confGlobal -let someSpanIsNot24 - -export function dialogWrapper(str) { - return ` - ${str} -
- 取消 - 确定 -
-
` -} - -export function vueTemplate(str) { - return `` -} - -export function vueScript(str) { - return `` -} - -export function cssStyle(cssStr) { - return `` -} - -function buildFormTemplate(scheme, child, type) { - let labelPosition = '' - if (scheme.labelPosition !== 'right') { - labelPosition = `label-position="${scheme.labelPosition}"` - } - const disabled = scheme.disabled ? `:disabled="${scheme.disabled}"` : '' - let str = ` - ${child} - ${buildFromBtns(scheme, type)} - ` - if (someSpanIsNot24) { - str = ` - ${str} - ` - } - return str -} - -function buildFromBtns(scheme, type) { - let str = '' - if (scheme.formBtns && type === 'file') { - str = ` - 提交 - 重置 - ` - if (someSpanIsNot24) { - str = ` - ${str} - ` - } - } - return str -} - -// span不为24的用el-col包裹 -function colWrapper(scheme, str) { - if (someSpanIsNot24 || scheme.__config__.span !== 24) { - return ` - ${str} - ` - } - return str -} - -const layouts = { - colFormItem(scheme) { - const config = scheme.__config__ - let labelWidth = '' - let label = `label="${config.label}"` - if (config.labelWidth && config.labelWidth !== confGlobal.labelWidth) { - labelWidth = `label-width="${config.labelWidth}px"` - } - if (config.showLabel === false) { - labelWidth = 'label-width="0"' - label = '' - } - const required = !ruleTrigger[config.tag] && config.required ? 'required' : '' - const tagDom = tags[config.tag] ? tags[config.tag](scheme) : null - let str = ` - ${tagDom} - ` - str = colWrapper(scheme, str) - return str - }, - rowFormItem(scheme) { - const config = scheme.__config__ - const type = scheme.type === 'default' ? '' : `type="${scheme.type}"` - const justify = scheme.type === 'default' ? '' : `justify="${scheme.justify}"` - const align = scheme.type === 'default' ? '' : `align="${scheme.align}"` - const gutter = scheme.gutter ? `:gutter="${scheme.gutter}"` : '' - const children = config.children.map(el => layouts[el.__config__.layout](el)) - let str = ` - ${children.join('\n')} - ` - str = 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 round = el.round ? 'round' : '' - const size = el.size ? `size="${el.size}"` : '' - const plain = el.plain ? 'plain' : '' - const circle = el.circle ? 'circle' : '' - let child = buildElButtonChild(el) - - if (child) child = `\n${child}\n` // 换行 - return `<${tag} ${type} ${icon} ${round} ${size} ${plain} ${disabled} ${circle}>${child}` - }, - 'el-input': el => { - const { - tag, 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 `<${tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}` - }, - 'el-input-number': el => { - const { - tag, 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 `<${tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}>` - }, - 'el-select': el => { - const { - tag, 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 `<${tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}` - }, - 'el-radio-group': el => { - const { tag, disabled, vModel } = attrBuilder(el) - const size = `size="${el.size}"` - let child = buildElRadioGroupChild(el) - - if (child) child = `\n${child}\n` // 换行 - return `<${tag} ${vModel} ${size} ${disabled}>${child}` - }, - 'el-checkbox-group': el => { - const { tag, 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 `<${tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}` - }, - 'el-switch': el => { - const { tag, 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 `<${tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}>` - }, - 'el-cascader': el => { - const { - tag, 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 `<${tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}>` - }, - 'el-slider': el => { - const { tag, 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 `<${tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}>` - }, - 'el-time-picker': el => { - const { - tag, 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 `<${tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}>` - }, - 'el-date-picker': el => { - const { - tag, 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 `<${tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}>` - }, - 'el-rate': el => { - const { tag, 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 `<${tag} ${vModel} ${max} ${allowHalf} ${showText} ${showScore} ${disabled}>` - }, - 'el-color-picker': el => { - const { tag, 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 `<${tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}>` - }, - 'el-upload': el => { - const { tag } = el.__config__ - 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 `<${tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}` - }, - tinymce: el => { - const { tag, vModel, placeholder } = attrBuilder(el) - const height = el.height ? `:height="${el.height}"` : '' - const branding = el.branding ? `:branding="${el.branding}"` : '' - return `<${tag} ${vModel} ${placeholder} ${height} ${branding}>` - } -} - -function attrBuilder(el) { - return { - tag: el.__config__.tag, - 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\'' : '' - } -} - -// el-buttin 子级 -function buildElButtonChild(scheme) { - const children = [] - const slot = scheme.__slot__ || {} - if (slot.default) { - children.push(slot.default) - } - return children.join('\n') -} - -// el-input 子级 -function buildElInputChild(scheme) { - const children = [] - const slot = scheme.__slot__ - if (slot && slot.prepend) { - children.push(``) - } - if (slot && slot.append) { - children.push(``) - } - return children.join('\n') -} - -// el-select 子级 -function buildElSelectChild(scheme) { - const children = [] - const slot = scheme.__slot__ - if (slot && slot.options && slot.options.length) { - children.push(``) - } - return children.join('\n') -} - -// el-radio-group 子级 -function buildElRadioGroupChild(scheme) { - const children = [] - const slot = scheme.__slot__ - const config = scheme.__config__ - if (slot && slot.options && slot.options.length) { - const tag = config.optionType === 'button' ? 'el-radio-button' : 'el-radio' - const border = config.border ? 'border' : '' - children.push(`<${tag} v-for="(item, index) in ${scheme.__vModel__}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}`) - } - return children.join('\n') -} - -// el-checkbox-group 子级 -function buildElCheckboxGroupChild(scheme) { - const children = [] - const slot = scheme.__slot__ - const config = scheme.__config__ - if (slot && slot.options && slot.options.length) { - const tag = config.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox' - const border = config.border ? 'border' : '' - children.push(`<${tag} v-for="(item, index) in ${scheme.__vModel__}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}`) - } - return children.join('\n') -} - -// el-upload 子级 -function buildElUploadChild(scheme) { - const list = [] - const config = scheme.__config__ - if (scheme['list-type'] === 'picture-card') list.push('') - else list.push(`${config.buttonText}`) - if (config.showTip) list.push(`
只能上传不超过 ${config.fileSize}${config.sizeUnit} 的${scheme.accept}文件
`) - return list.join('\n') -} - -/** - * 组装html代码。【入口函数】 - * @param {Object} formConfig 整个表单配置 - * @param {String} type 生成类型,文件或弹窗等 - */ -export function makeUpHtml(formConfig, type) { - const htmlList = [] - confGlobal = formConfig - // 判断布局是否都沾满了24个栅格,以备后续简化代码结构 - someSpanIsNot24 = formConfig.fields.some(item => item.__config__.span !== 24) - // 遍历渲染每个组件成html - formConfig.fields.forEach(el => { - htmlList.push(layouts[el.__config__.layout](el)) - }) - const htmlStr = htmlList.join('\n') - // 将组件代码放进form标签 - let temp = buildFormTemplate(formConfig, htmlStr, type) - // dialog标签包裹代码 - if (type === 'dialog') { - temp = dialogWrapper(temp) - } - confGlobal = null - return temp -} diff --git a/src/components/generator/js.js b/src/components/generator/js.js deleted file mode 100644 index c4b2a57..0000000 --- a/src/components/generator/js.js +++ /dev/null @@ -1,271 +0,0 @@ -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 = [] - - formConfig.fields.forEach(el => { - buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList, created) - }) - - 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') - ) - confGlobal = null - return script -} - -// 构建组件属性 -function buildAttributes(scheme, dataList, ruleList, optionsList, methodList, propsList, uploadVarList, created) { - const config = scheme.__config__ - const slot = scheme.__slot__ - buildData(scheme, dataList) - buildRules(scheme, ruleList) - - // 特殊处理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) - } - } - - // 处理props - if (scheme.props && scheme.props.props) { - buildProps(scheme, propsList) - } - - // 处理el-upload的action - if (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 = []; const - minxins = { - 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) return - this.close() - }) - },` - } - } - - const methods = minxins[type] - if (methods) { - Object.keys(methods).forEach(key => { - list.push(methods[key]) - }) - } - - return list -} - -// 构建data -function buildData(scheme, dataList) { - const config = scheme.__config__ - if (scheme.__vModel__ === undefined) return - const defaultValue = JSON.stringify(config.defaultValue) - dataList.push(`${scheme.__vModel__}: ${defaultValue},`) -} - -// 构建校验规则 -function buildRules(scheme, ruleList) { - const config = scheme.__config__ - if (scheme.__vModel__ === undefined) return - const rules = [] - if (ruleTrigger[config.tag]) { - if (config.required) { - const type = isArray(config.defaultValue) ? 'type: \'array\',' : '' - let message = isArray(config.defaultValue) ? `请至少选择一个${config.label}` : scheme.placeholder - if (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 } = scheme - if (!options) options = scheme.__slot__.options - if (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 = ''; const - returnList = [] - 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 } = resp - this.${model} = data.${config.dataKey} - }) - },` - methodList.push(str) -} - -// js整体拼接 -function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods, created) { - const str = `${exportDefault}{ - ${inheritAttrs[type]} - components: {}, - props: [], - data () { - return { - ${conf.formModel}: { - ${data} - }, - ${conf.formRules}: { - ${rules} - }, - ${uploadVar} - ${selectOptions} - ${props} - } - }, - computed: {}, - watch: {}, - created () { - ${created} - }, - mounted () {}, - methods: { - ${methods} - } -}` - return str -} diff --git a/src/components/parser/Parser.vue b/src/components/parser/Parser.vue index e1106fc..8e275a3 100644 --- a/src/components/parser/Parser.vue +++ b/src/components/parser/Parser.vue @@ -3,185 +3,194 @@ import { deepClone } from '@/utils/index' import render from '@/components/render/render.js' const ruleTrigger = { - 'el-input': 'blur', - 'el-input-number': 'blur', - 'el-select': 'change', - 'el-radio-group': 'change', - 'el-checkbox-group': 'change', - 'el-cascader': 'change', - 'el-time-picker': 'change', - 'el-date-picker': 'change', - 'el-rate': 'change' + 'el-input': 'blur', + 'el-input-number': 'blur', + 'el-select': 'change', + 'el-radio-group': 'change', + 'el-checkbox-group': 'change', + 'el-cascader': 'change', + 'el-time-picker': 'change', + 'el-date-picker': 'change', + 'el-rate': 'change' } const layouts = { - colFormItem(h, scheme) { - const config = scheme.__config__ - const listeners = buildListeners.call(this, scheme) + colFormItem(h, scheme) { + const config = scheme.__config__ + const listeners = buildListeners.call(this, scheme) - let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null - if (config.showLabel === false) labelWidth = '0' - return ( - - - 处理过程 - - - - ) - }, - rowFormItem(h, scheme) { - let child = renderChildren.apply(this, arguments) - if (scheme.type === 'flex') { - child = - {child} + let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null + if (config.showLabel === false) labelWidth = '0' + return ( + + + + + + ) + }, + rowFormItem(h, scheme) { + let child = renderChildren.apply(this, arguments) + if (scheme.type === 'flex') { + child = + {child} + } + return ( + + + {child} + + + ) } - return ( - - - {child} - - - ) - } } function renderFrom(h) { - const { formConfCopy } = this + const { formConfCopy } = this - return ( - - - {renderFormItem.call(this, h, formConfCopy.fields)} - {formConfCopy.formBtns && formBtns.call(this, h)} - - - ) + return ( + + + {renderFormItem.call(this, h, formConfCopy.fields)} + {formConfCopy.formBtns && formBtns.call(this, h)} + + + ) } function formBtns(h) { - return - - 提交 - 重置 - - + return + + 提交 + 重置 + + } function renderFormItem(h, elementList) { - return elementList.map(scheme => { - const config = scheme.__config__ - const layout = layouts[config.layout] + return elementList.map(scheme => { + const config = scheme.__config__ + const layout = layouts[config.layout] - if (layout) { - return layout.call(this, h, scheme) - } - throw new Error(`没有与${config.layout}匹配的layout`) - }) + if (layout) { + return layout.call(this, h, scheme) + } + throw new Error(`没有与${config.layout}匹配的layout`) + }) } function renderChildren(h, scheme) { - const config = scheme.__config__ - if (!Array.isArray(config.children)) return null - return renderFormItem.call(this, h, config.children) + const config = scheme.__config__ + if (!Array.isArray(config.children)) return null + return renderFormItem.call(this, h, config.children) } function setValue(event, config, scheme) { - this.$set(config, 'defaultValue', event) - this.$set(this[this.formConf.formModel], scheme.__vModel__, event) + this.$set(config, 'defaultValue', event) + this.$set(this[this.formConf.formModel], scheme.__vModel__, event) } function buildListeners(scheme) { - const config = scheme.__config__ - const methods = this.formConf.__methods__ || {} - const listeners = {} + const config = scheme.__config__ + const methods = this.formConf.__methods__ || {} + const listeners = {} - // 给__methods__中的方法绑定this和event - Object.keys(methods).forEach(key => { - listeners[key] = event => methods[key].call(this, event) - }) - // 响应 render.js 中的 vModel $emit('input', val) - listeners.input = event => setValue.call(this, event, config, scheme) + // 给__methods__中的方法绑定this和event + Object.keys(methods).forEach(key => { + listeners[key] = event => methods[key].call(this, event) + }) + // 响应 render.js 中的 vModel $emit('input', val) + listeners.input = event => setValue.call(this, event, config, scheme) - return listeners + return listeners } export default { - components: { - render - }, - props: { - formConf: { - type: Object, - required: true - } - }, - data() { - const data = { - formConfCopy: deepClone(this.formConf), - [this.formConf.formModel]: {}, - [this.formConf.formRules]: {} - } - this.initFormData(data.formConfCopy.fields, data[this.formConf.formModel]) - this.buildRules(data.formConfCopy.fields, data[this.formConf.formRules]) - return data - }, - methods: { - initFormData(componentList, formData) { - componentList.forEach(cur => { - const config = cur.__config__ - if (cur.__vModel__) formData[cur.__vModel__] = config.defaultValue - if (config.children) this.initFormData(config.children, formData) - }) + components: { + render + }, + props: { + formConf: { + type: Object, + required: true + } }, - buildRules(componentList, rules) { - componentList.forEach(cur => { - const config = cur.__config__ - if (Array.isArray(config.regList)) { - if (config.required) { - const required = { required: config.required, message: cur.placeholder } - if (Array.isArray(config.defaultValue)) { - required.type = 'array' - required.message = `请至少选择一个${config.label}` - } - required.message === undefined && (required.message = `${config.label}不能为空`) - config.regList.push(required) - } - rules[cur.__vModel__] = config.regList.map(item => { - item.pattern && (item.pattern = eval(item.pattern)) - item.trigger = ruleTrigger && ruleTrigger[config.tag] - return item - }) + watch: { + formConf: { + handler(val) { + this.formConfCopy = val + this.initFormData(data.formConfCopy.fields, data[this.formConf.formModel]) + this.buildRules(data.formConfCopy.fields, data[this.formConf.formRules]) + }, + deep: true } - if (config.children) this.buildRules(config.children, rules) - }) }, - resetForm() { - this.formConfCopy = deepClone(this.formConf) - this.$refs[this.formConf.formRef].resetFields() + data() { + const data = { + formConfCopy: deepClone(this.formConf), + [this.formConf.formModel]: {}, + [this.formConf.formRules]: {} + } + this.initFormData(data.formConfCopy.fields, data[this.formConf.formModel]) + this.buildRules(data.formConfCopy.fields, data[this.formConf.formRules]) + return data + }, + methods: { + initFormData(componentList, formData) { + componentList.forEach(cur => { + const config = cur.__config__ + if (cur.__vModel__) formData[cur.__vModel__] = config.defaultValue + if (config.children) this.initFormData(config.children, formData) + }) + }, + buildRules(componentList, rules) { + componentList.forEach(cur => { + const config = cur.__config__ + if (Array.isArray(config.regList)) { + if (config.required) { + const required = { required: config.required, message: cur.placeholder } + if (Array.isArray(config.defaultValue)) { + required.type = 'array' + required.message = `请至少选择一个${config.label}` + } + required.message === undefined && (required.message = `${config.label}不能为空`) + config.regList.push(required) + } + rules[cur.__vModel__] = config.regList.map(item => { + item.pattern && (item.pattern = eval(item.pattern)) + item.trigger = ruleTrigger && ruleTrigger[config.tag] + return item + }) + } + if (config.children) this.buildRules(config.children, rules) + }) + }, + resetForm() { + this.formConfCopy = deepClone(this.formConf) + this.$refs[this.formConf.formRef].resetFields() + }, + submitForm() { + this.$refs[this.formConf.formRef].validate(valid => { + if (!valid) return false + // 触发sumit事件 + this.$emit('submit', this[this.formConf.formModel]) + return true + }) + } }, - submitForm() { - this.$refs[this.formConf.formRef].validate(valid => { - if (!valid) return false - // 触发sumit事件 - this.$emit('submit', this[this.formConf.formModel]) - return true - }) + render(h) { + return renderFrom.call(this, h) } - }, - render(h) { - return renderFrom.call(this, h) - } } diff --git a/src/router/modules/root.js b/src/router/modules/root.js index c9f4ad1..0b7d699 100644 --- a/src/router/modules/root.js +++ b/src/router/modules/root.js @@ -58,15 +58,8 @@ export default [ } ] }, { - path: '/form', - meta: {requireLogin: true}, - component: () => import(/* webpackChunkName: 'root' */ '@/views/home/index.vue'), - children: [ - { - path: 'create', - meta: {requireLogin: true}, - component: () => import(/* webpackChunkName: 'root' */ '@/views/project/create.vue') - } - ] + path: '/project/preview', + meta: {requireLogin: false}, + component: () => import(/* webpackChunkName: 'root' */ '@/views/form/PreView.vue') } ] diff --git a/src/utils/formDataConvert.js b/src/utils/convert.js similarity index 57% rename from src/utils/formDataConvert.js rename to src/utils/convert.js index f12690a..efa9666 100644 --- a/src/utils/formDataConvert.js +++ b/src/utils/convert.js @@ -1,15 +1,18 @@ import _ from 'lodash' +import {inputComponents, selectComponents} from '@/components/generator/config' +import {jsonClone} from '@/utils/index' /** * 表单json转换为后台需要的对象 * @param item */ export function formItemConvertData(item, projectKey) { + console.log(item) let data = { 'type': item.typeId, 'formItemId': item.__config__.formId, 'label': item.__config__.label, - 'defaultValue': item.defaultValue, + 'defaultValue': item.__config__.defaultValue, 'required': item.__config__.required, 'placeholder': item.placeholder, 'regList': item.__config__.regList, @@ -27,6 +30,47 @@ export function formItemConvertData(item, projectKey) { return data } +//类型关系map +let typeMap = new Map() + +/** + * 后台存储的数据转换为elementui表单需要的Json + * @param data + */ +export function dbDataConvertForItemJson(data) { + if (!typeMap.size > 0) { + //根据类型获取默认数据 + _.concat(inputComponents, selectComponents).forEach(item => { + typeMap.set(item.typeId, item) + }) + } + const defaultJsonItem = typeMap.get(data.type) + let jsonItem = _.cloneDeep(defaultJsonItem) + let param = dataParams[data.type] + if (param) { + Object.keys(param).forEach(key => { + let value = _.get(data.expand, key) + _.set(jsonItem, param[key], value) + }) + } + jsonItem.typeId = data.type + jsonItem.__config__.formId = data.formItemId + jsonItem.__config__.label = data.label + jsonItem.__config__.required = data.required + jsonItem.__config__.regList = data.regList + if (data.defaultValue) { + if (data.defaultValue.json) { + jsonItem.__config__.defaultValue = JSON.parse(data.defaultValue.value) + } else { + jsonItem.__config__.defaultValue = data.defaultValue.value + } + } + jsonItem.regList = data.regList + jsonItem.placeholder = data.placeholder + jsonItem.__vModel__ = 'field' + data.formItemId + return jsonItem +} + /** * 不同属性的存在json的位置不用 使用变量记录key 通过lodash表达式获取 1 2 3 4 为typeId * @type {{'1': {maxlength: string, prepend: string, append: string}}} @@ -48,7 +92,7 @@ let dataParams = { //计数器 4: { 'min': 'min', - 'max': 'min', + 'max': 'max', 'maxlength': 'maxlength', 'step': 'step', 'step-strictly': 'step-strictly', @@ -79,18 +123,14 @@ let dataParams = { 'max': 'max', 'min': 'min' }, //开关 - 9: { - - }, + 9: {}, //滑块 - 10:{ + 10: { 'min': 'min', 'max': 'max', - 'step': 'step', + 'step': 'step' },//时间选择 - 11:{ - - } + 11: {} } diff --git a/src/utils/loadBeautifier.js b/src/utils/loadBeautifier.js deleted file mode 100644 index a3bef88..0000000 --- a/src/utils/loadBeautifier.js +++ /dev/null @@ -1,26 +0,0 @@ -import loadScript from './loadScript' -import ELEMENT from 'element-ui' - -let beautifierObj - -export default function loadBeautifier(cb) { - if (beautifierObj) { - cb(beautifierObj) - return - } - - const loading = ELEMENT.Loading.service({ - fullscreen: true, - lock: true, - text: '格式化资源加载中...', - spinner: 'el-icon-loading', - background: 'rgba(255, 255, 255, 0.5)' - }) - - loadScript('https://lib.baomitu.com/js-beautify/1.10.2/beautifier.min.js', () => { - loading.close() - // eslint-disable-next-line no-undef - beautifierObj = beautifier - cb(beautifierObj) - }) -} diff --git a/src/utils/loadMonaco.js b/src/utils/loadMonaco.js deleted file mode 100644 index 14fc1d0..0000000 --- a/src/utils/loadMonaco.js +++ /dev/null @@ -1,42 +0,0 @@ -import { loadScriptQueue } from './loadScript' -import ELEMENT from 'element-ui' - -// monaco-editor单例 -let monacoEidtor - -/** - * 动态加载monaco-editor cdn资源 - * @param {Function} cb 回调,必填 - */ -export default function loadMonaco(cb) { - if (monacoEidtor) { - cb(monacoEidtor) - return - } - - const vs = 'https://lib.baomitu.com/monaco-editor/0.19.3/min/vs' - - // 使用element ui实现加载提示 - const loading = ELEMENT.Loading.service({ - fullscreen: true, - lock: true, - text: '编辑器资源初始化中...', - spinner: 'el-icon-loading', - background: 'rgba(255, 255, 255, 0.5)' - }) - - !window.require && (window.require = {}) - !window.require.paths && (window.require.paths = {}) - window.require.paths.vs = vs - - loadScriptQueue([ - `${vs}/loader.js`, - `${vs}/editor/editor.main.nls.js`, - `${vs}/editor/editor.main.js` - ], () => { - loading.close() - // eslint-disable-next-line no-undef - monacoEidtor = monaco - cb(monacoEidtor) - }) -} diff --git a/src/views/404.vue b/src/views/404.vue index 07c480e..fcd993e 100644 --- a/src/views/404.vue +++ b/src/views/404.vue @@ -3,3 +3,19 @@ 我真的尽力了,但还是找不到页面 + diff --git a/src/views/form/CodeTypeDialog.vue b/src/views/form/CodeTypeDialog.vue deleted file mode 100644 index 6f0c0d1..0000000 --- a/src/views/form/CodeTypeDialog.vue +++ /dev/null @@ -1,110 +0,0 @@ - - - - diff --git a/src/views/form/FormDrawer.vue b/src/views/form/FormDrawer.vue deleted file mode 100644 index 65748d5..0000000 --- a/src/views/form/FormDrawer.vue +++ /dev/null @@ -1,332 +0,0 @@ -