Commit dffd175ccf4e7782a13e12b56cfaf096f14fc763
1 parent
430f1369
初始化 form 动态表单的详情,暂未接入数据
Showing
17 changed files
with
1032 additions
and
26 deletions
yudao-admin-ui/src/utils/generator/README.md
0 → 100644
yudao-admin-ui/src/utils/index.js
| @@ -5,12 +5,12 @@ import { parseTime } from './ruoyi' | @@ -5,12 +5,12 @@ import { parseTime } from './ruoyi' | ||
| 5 | */ | 5 | */ |
| 6 | export function formatDate(cellValue) { | 6 | export function formatDate(cellValue) { |
| 7 | if (cellValue == null || cellValue == "") return ""; | 7 | if (cellValue == null || cellValue == "") return ""; |
| 8 | - var date = new Date(cellValue) | 8 | + var date = new Date(cellValue) |
| 9 | var year = date.getFullYear() | 9 | var year = date.getFullYear() |
| 10 | var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 | 10 | var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 |
| 11 | - var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() | ||
| 12 | - var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() | ||
| 13 | - var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() | 11 | + var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() |
| 12 | + var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() | ||
| 13 | + var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() | ||
| 14 | var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() | 14 | var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() |
| 15 | return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds | 15 | return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds |
| 16 | } | 16 | } |
| @@ -250,26 +250,65 @@ export function debounce(func, wait, immediate) { | @@ -250,26 +250,65 @@ export function debounce(func, wait, immediate) { | ||
| 250 | } | 250 | } |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | -/** | ||
| 254 | - * This is just a simple version of deep copy | ||
| 255 | - * Has a lot of edge cases bug | ||
| 256 | - * If you want to use a perfect deep copy, use lodash's _.cloneDeep | ||
| 257 | - * @param {Object} source | ||
| 258 | - * @returns {Object} | ||
| 259 | - */ | ||
| 260 | -export function deepClone(source) { | ||
| 261 | - if (!source && typeof source !== 'object') { | ||
| 262 | - throw new Error('error arguments', 'deepClone') | 253 | +// /** |
| 254 | +// * This is just a simple version of deep copy | ||
| 255 | +// * Has a lot of edge cases bug | ||
| 256 | +// * If you want to use a perfect deep copy, use lodash's _.cloneDeep | ||
| 257 | +// * @param {Object} source | ||
| 258 | +// * @returns {Object} | ||
| 259 | +// */ | ||
| 260 | +// export function deepClone(source) { | ||
| 261 | +// if (!source && typeof source !== 'object') { | ||
| 262 | +// throw new Error('error arguments', 'deepClone') | ||
| 263 | +// } | ||
| 264 | +// const targetObj = source.constructor === Array ? [] : {} | ||
| 265 | +// Object.keys(source).forEach(keys => { | ||
| 266 | +// if (source[keys] && typeof source[keys] === 'object') { | ||
| 267 | +// targetObj[keys] = deepClone(source[keys]) | ||
| 268 | +// } else { | ||
| 269 | +// targetObj[keys] = source[keys] | ||
| 270 | +// } | ||
| 271 | +// }) | ||
| 272 | +// return targetObj | ||
| 273 | +// } | ||
| 274 | + | ||
| 275 | +// 深拷贝对象 | ||
| 276 | +// 【add by 芋道源码】https://github.com/JakHuang/form-generator/blob/dev/src/utils/index.js#L107 | ||
| 277 | +export function deepClone(obj) { | ||
| 278 | + const _toString = Object.prototype.toString | ||
| 279 | + | ||
| 280 | + // null, undefined, non-object, function | ||
| 281 | + if (!obj || typeof obj !== 'object') { | ||
| 282 | + return obj | ||
| 263 | } | 283 | } |
| 264 | - const targetObj = source.constructor === Array ? [] : {} | ||
| 265 | - Object.keys(source).forEach(keys => { | ||
| 266 | - if (source[keys] && typeof source[keys] === 'object') { | ||
| 267 | - targetObj[keys] = deepClone(source[keys]) | ||
| 268 | - } else { | ||
| 269 | - targetObj[keys] = source[keys] | ||
| 270 | - } | ||
| 271 | - }) | ||
| 272 | - return targetObj | 284 | + |
| 285 | + // DOM Node | ||
| 286 | + if (obj.nodeType && 'cloneNode' in obj) { | ||
| 287 | + return obj.cloneNode(true) | ||
| 288 | + } | ||
| 289 | + | ||
| 290 | + // Date | ||
| 291 | + if (_toString.call(obj) === '[object Date]') { | ||
| 292 | + return new Date(obj.getTime()) | ||
| 293 | + } | ||
| 294 | + | ||
| 295 | + // RegExp | ||
| 296 | + if (_toString.call(obj) === '[object RegExp]') { | ||
| 297 | + const flags = [] | ||
| 298 | + if (obj.global) { flags.push('g') } | ||
| 299 | + if (obj.multiline) { flags.push('m') } | ||
| 300 | + if (obj.ignoreCase) { flags.push('i') } | ||
| 301 | + | ||
| 302 | + return new RegExp(obj.source, flags.join('')) | ||
| 303 | + } | ||
| 304 | + | ||
| 305 | + const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {} | ||
| 306 | + | ||
| 307 | + for (const key in obj) { | ||
| 308 | + result[key] = deepClone(obj[key]) | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + return result | ||
| 273 | } | 312 | } |
| 274 | 313 | ||
| 275 | /** | 314 | /** |
| @@ -330,7 +369,7 @@ export function makeMap(str, expectsLowerCase) { | @@ -330,7 +369,7 @@ export function makeMap(str, expectsLowerCase) { | ||
| 330 | ? val => map[val.toLowerCase()] | 369 | ? val => map[val.toLowerCase()] |
| 331 | : val => map[val] | 370 | : val => map[val] |
| 332 | } | 371 | } |
| 333 | - | 372 | + |
| 334 | export const exportDefault = 'export default ' | 373 | export const exportDefault = 'export default ' |
| 335 | 374 | ||
| 336 | export const beautifierConf = { | 375 | export const beautifierConf = { |
| @@ -387,4 +426,4 @@ export function camelCase(str) { | @@ -387,4 +426,4 @@ export function camelCase(str) { | ||
| 387 | export function isNumberStr(str) { | 426 | export function isNumberStr(str) { |
| 388 | return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str) | 427 | return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str) |
| 389 | } | 428 | } |
| 390 | - | 429 | + |
yudao-admin-ui/src/utils/parser/Parser.vue
0 → 100644
| 1 | +<script> | ||
| 2 | +import { deepClone } from '@/utils/index' | ||
| 3 | +// import render from '@/components/render/render.js' | ||
| 4 | +import render from '../render/render.js' // edit by 芋道源码 | ||
| 5 | + | ||
| 6 | +const ruleTrigger = { | ||
| 7 | + 'el-input': 'blur', | ||
| 8 | + 'el-input-number': 'blur', | ||
| 9 | + 'el-select': 'change', | ||
| 10 | + 'el-radio-group': 'change', | ||
| 11 | + 'el-checkbox-group': 'change', | ||
| 12 | + 'el-cascader': 'change', | ||
| 13 | + 'el-time-picker': 'change', | ||
| 14 | + 'el-date-picker': 'change', | ||
| 15 | + 'el-rate': 'change' | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +const layouts = { | ||
| 19 | + colFormItem(h, scheme) { | ||
| 20 | + const config = scheme.__config__ | ||
| 21 | + const listeners = buildListeners.call(this, scheme) | ||
| 22 | + | ||
| 23 | + let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null | ||
| 24 | + if (config.showLabel === false) labelWidth = '0' | ||
| 25 | + return ( | ||
| 26 | + <el-col span={config.span}> | ||
| 27 | + <el-form-item label-width={labelWidth} prop={scheme.__vModel__} | ||
| 28 | + label={config.showLabel ? config.label : ''}> | ||
| 29 | + <render conf={scheme} on={listeners} /> | ||
| 30 | + </el-form-item> | ||
| 31 | + </el-col> | ||
| 32 | + ) | ||
| 33 | + }, | ||
| 34 | + rowFormItem(h, scheme) { | ||
| 35 | + let child = renderChildren.apply(this, arguments) | ||
| 36 | + if (scheme.type === 'flex') { | ||
| 37 | + child = <el-row type={scheme.type} justify={scheme.justify} align={scheme.align}> | ||
| 38 | + {child} | ||
| 39 | + </el-row> | ||
| 40 | + } | ||
| 41 | + return ( | ||
| 42 | + <el-col span={scheme.span}> | ||
| 43 | + <el-row gutter={scheme.gutter}> | ||
| 44 | + {child} | ||
| 45 | + </el-row> | ||
| 46 | + </el-col> | ||
| 47 | + ) | ||
| 48 | + } | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +function renderFrom(h) { | ||
| 52 | + const { formConfCopy } = this | ||
| 53 | + | ||
| 54 | + return ( | ||
| 55 | + <el-row gutter={formConfCopy.gutter}> | ||
| 56 | + <el-form | ||
| 57 | + size={formConfCopy.size} | ||
| 58 | + label-position={formConfCopy.labelPosition} | ||
| 59 | + disabled={formConfCopy.disabled} | ||
| 60 | + label-width={`${formConfCopy.labelWidth}px`} | ||
| 61 | + ref={formConfCopy.formRef} | ||
| 62 | + // model不能直接赋值 https://github.com/vuejs/jsx/issues/49#issuecomment-472013664 | ||
| 63 | + props={{ model: this[formConfCopy.formModel] }} | ||
| 64 | + rules={this[formConfCopy.formRules]} | ||
| 65 | + > | ||
| 66 | + {renderFormItem.call(this, h, formConfCopy.fields)} | ||
| 67 | + {formConfCopy.formBtns && formBtns.call(this, h)} | ||
| 68 | + </el-form> | ||
| 69 | + </el-row> | ||
| 70 | + ) | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +function formBtns(h) { | ||
| 74 | + return <el-col> | ||
| 75 | + <el-form-item size="large"> | ||
| 76 | + <el-button type="primary" onClick={this.submitForm}>提交</el-button> | ||
| 77 | + <el-button onClick={this.resetForm}>重置</el-button> | ||
| 78 | + </el-form-item> | ||
| 79 | + </el-col> | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +function renderFormItem(h, elementList) { | ||
| 83 | + return elementList.map(scheme => { | ||
| 84 | + const config = scheme.__config__ | ||
| 85 | + const layout = layouts[config.layout] | ||
| 86 | + | ||
| 87 | + if (layout) { | ||
| 88 | + return layout.call(this, h, scheme) | ||
| 89 | + } | ||
| 90 | + throw new Error(`没有与${config.layout}匹配的layout`) | ||
| 91 | + }) | ||
| 92 | +} | ||
| 93 | + | ||
| 94 | +function renderChildren(h, scheme) { | ||
| 95 | + const config = scheme.__config__ | ||
| 96 | + if (!Array.isArray(config.children)) return null | ||
| 97 | + return renderFormItem.call(this, h, config.children) | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +function setValue(event, config, scheme) { | ||
| 101 | + this.$set(config, 'defaultValue', event) | ||
| 102 | + this.$set(this[this.formConf.formModel], scheme.__vModel__, event) | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +function buildListeners(scheme) { | ||
| 106 | + const config = scheme.__config__ | ||
| 107 | + const methods = this.formConf.__methods__ || {} | ||
| 108 | + const listeners = {} | ||
| 109 | + | ||
| 110 | + // 给__methods__中的方法绑定this和event | ||
| 111 | + Object.keys(methods).forEach(key => { | ||
| 112 | + listeners[key] = event => methods[key].call(this, event) | ||
| 113 | + }) | ||
| 114 | + // 响应 render.js 中的 vModel $emit('input', val) | ||
| 115 | + listeners.input = event => setValue.call(this, event, config, scheme) | ||
| 116 | + | ||
| 117 | + return listeners | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +export default { | ||
| 121 | + components: { | ||
| 122 | + render | ||
| 123 | + }, | ||
| 124 | + props: { | ||
| 125 | + formConf: { | ||
| 126 | + type: Object, | ||
| 127 | + required: true | ||
| 128 | + } | ||
| 129 | + }, | ||
| 130 | + data() { | ||
| 131 | + const data = { | ||
| 132 | + formConfCopy: deepClone(this.formConf), | ||
| 133 | + [this.formConf.formModel]: {}, | ||
| 134 | + [this.formConf.formRules]: {} | ||
| 135 | + } | ||
| 136 | + this.initFormData(data.formConfCopy.fields, data[this.formConf.formModel]) | ||
| 137 | + this.buildRules(data.formConfCopy.fields, data[this.formConf.formRules]) | ||
| 138 | + return data | ||
| 139 | + }, | ||
| 140 | + methods: { | ||
| 141 | + initFormData(componentList, formData) { | ||
| 142 | + componentList.forEach(cur => { | ||
| 143 | + const config = cur.__config__ | ||
| 144 | + if (cur.__vModel__) formData[cur.__vModel__] = config.defaultValue | ||
| 145 | + // debugger | ||
| 146 | + if (config.children) this.initFormData(config.children, formData) | ||
| 147 | + }) | ||
| 148 | + }, | ||
| 149 | + buildRules(componentList, rules) { | ||
| 150 | + componentList.forEach(cur => { | ||
| 151 | + const config = cur.__config__ | ||
| 152 | + if (Array.isArray(config.regList)) { | ||
| 153 | + if (config.required) { | ||
| 154 | + const required = { required: config.required, message: cur.placeholder } | ||
| 155 | + if (Array.isArray(config.defaultValue)) { | ||
| 156 | + required.type = 'array' | ||
| 157 | + required.message = `请至少选择一个${config.label}` | ||
| 158 | + } | ||
| 159 | + required.message === undefined && (required.message = `${config.label}不能为空`) | ||
| 160 | + config.regList.push(required) | ||
| 161 | + } | ||
| 162 | + rules[cur.__vModel__] = config.regList.map(item => { | ||
| 163 | + item.pattern && (item.pattern = eval(item.pattern)) | ||
| 164 | + item.trigger = ruleTrigger && ruleTrigger[config.tag] | ||
| 165 | + return item | ||
| 166 | + }) | ||
| 167 | + } | ||
| 168 | + if (config.children) this.buildRules(config.children, rules) | ||
| 169 | + }) | ||
| 170 | + }, | ||
| 171 | + resetForm() { | ||
| 172 | + this.formConfCopy = deepClone(this.formConf) | ||
| 173 | + this.$refs[this.formConf.formRef].resetFields() | ||
| 174 | + }, | ||
| 175 | + submitForm() { | ||
| 176 | + this.$refs[this.formConf.formRef].validate(valid => { | ||
| 177 | + if (!valid) return false | ||
| 178 | + // 触发sumit事件 | ||
| 179 | + this.$emit('submit', this[this.formConf.formModel]) | ||
| 180 | + return true | ||
| 181 | + }) | ||
| 182 | + } | ||
| 183 | + }, | ||
| 184 | + render(h) { | ||
| 185 | + return renderFrom.call(this, h) | ||
| 186 | + } | ||
| 187 | +} | ||
| 188 | +</script> |
yudao-admin-ui/src/utils/parser/README.md
0 → 100644
| 1 | +## form-generator JSON 解析器 | ||
| 2 | +>用于将form-generator导出的JSON解析成一个表单。 | ||
| 3 | + | ||
| 4 | +### 安装组件 | ||
| 5 | +``` | ||
| 6 | +npm i form-gen-parser | ||
| 7 | +``` | ||
| 8 | +或者 | ||
| 9 | +``` | ||
| 10 | +yarn add form-gen-parser | ||
| 11 | +``` | ||
| 12 | + | ||
| 13 | +### 使用示例 | ||
| 14 | +> [查看在线示例](https://mrhj.gitee.io/form-generator/#/parser) | ||
| 15 | + | ||
| 16 | +示例代码: | ||
| 17 | +> [src\components\parser\example\Index.vue](https://github.com/JakHuang/form-generator/blob/dev/src/components/parser/example/Index.vue) | ||
| 18 | + | ||
| 19 | +【add by 芋道源码】https://github.com/JakHuang/form-generator/blob/dev/src/components/parser/ | ||
| 0 | \ No newline at end of file | 20 | \ No newline at end of file |
yudao-admin-ui/src/utils/parser/example/Index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="test-form"> | ||
| 3 | + <parser :form-conf="formConf" @submit="sumbitForm1" /> | ||
| 4 | + <parser :key="key2" :form-conf="formConf" @submit="sumbitForm2" /> | ||
| 5 | + <el-button @click="change"> | ||
| 6 | + change | ||
| 7 | + </el-button> | ||
| 8 | + </div> | ||
| 9 | +</template> | ||
| 10 | + | ||
| 11 | +<script> | ||
| 12 | +import Parser from '../Parser' | ||
| 13 | + | ||
| 14 | +// 若parser是通过安装npm方式集成到项目中的,使用此行引入 | ||
| 15 | +// import Parser from 'form-gen-parser' | ||
| 16 | + | ||
| 17 | +export default { | ||
| 18 | + components: { | ||
| 19 | + Parser | ||
| 20 | + }, | ||
| 21 | + props: {}, | ||
| 22 | + data() { | ||
| 23 | + return { | ||
| 24 | + key2: +new Date(), | ||
| 25 | + formConf: { | ||
| 26 | + fields: [ | ||
| 27 | + { | ||
| 28 | + __config__: { | ||
| 29 | + label: '单行文本', | ||
| 30 | + labelWidth: null, | ||
| 31 | + showLabel: true, | ||
| 32 | + changeTag: true, | ||
| 33 | + tag: 'el-input', | ||
| 34 | + tagIcon: 'input', | ||
| 35 | + required: true, | ||
| 36 | + layout: 'colFormItem', | ||
| 37 | + span: 24, | ||
| 38 | + document: 'https://element.eleme.cn/#/zh-CN/component/input', | ||
| 39 | + regList: [ | ||
| 40 | + { | ||
| 41 | + pattern: '/^1(3|4|5|7|8|9)\\d{9}$/', | ||
| 42 | + message: '手机号格式错误' | ||
| 43 | + } | ||
| 44 | + ] | ||
| 45 | + }, | ||
| 46 | + __slot__: { | ||
| 47 | + prepend: '', | ||
| 48 | + append: '' | ||
| 49 | + }, | ||
| 50 | + __vModel__: 'mobile', | ||
| 51 | + placeholder: '请输入手机号', | ||
| 52 | + style: { | ||
| 53 | + width: '100%' | ||
| 54 | + }, | ||
| 55 | + clearable: true, | ||
| 56 | + 'prefix-icon': 'el-icon-mobile', | ||
| 57 | + 'suffix-icon': '', | ||
| 58 | + maxlength: 11, | ||
| 59 | + 'show-word-limit': true, | ||
| 60 | + readonly: false, | ||
| 61 | + disabled: false | ||
| 62 | + }, | ||
| 63 | + { | ||
| 64 | + __config__: { | ||
| 65 | + label: '日期范围', | ||
| 66 | + tag: 'el-date-picker', | ||
| 67 | + tagIcon: 'date-range', | ||
| 68 | + defaultValue: null, | ||
| 69 | + span: 24, | ||
| 70 | + showLabel: true, | ||
| 71 | + labelWidth: null, | ||
| 72 | + required: true, | ||
| 73 | + layout: 'colFormItem', | ||
| 74 | + regList: [], | ||
| 75 | + changeTag: true, | ||
| 76 | + document: | ||
| 77 | + 'https://element.eleme.cn/#/zh-CN/component/date-picker', | ||
| 78 | + formId: 101, | ||
| 79 | + renderKey: 1585980082729 | ||
| 80 | + }, | ||
| 81 | + style: { | ||
| 82 | + width: '100%' | ||
| 83 | + }, | ||
| 84 | + type: 'daterange', | ||
| 85 | + 'range-separator': '至', | ||
| 86 | + 'start-placeholder': '开始日期', | ||
| 87 | + 'end-placeholder': '结束日期', | ||
| 88 | + disabled: false, | ||
| 89 | + clearable: true, | ||
| 90 | + format: 'yyyy-MM-dd', | ||
| 91 | + 'value-format': 'yyyy-MM-dd', | ||
| 92 | + readonly: false, | ||
| 93 | + __vModel__: 'field101' | ||
| 94 | + }, | ||
| 95 | + { | ||
| 96 | + __config__: { | ||
| 97 | + layout: 'rowFormItem', | ||
| 98 | + tagIcon: 'row', | ||
| 99 | + label: '行容器', | ||
| 100 | + layoutTree: true, | ||
| 101 | + children: [ | ||
| 102 | + { | ||
| 103 | + __config__: { | ||
| 104 | + label: '评分', | ||
| 105 | + tag: 'el-rate', | ||
| 106 | + tagIcon: 'rate', | ||
| 107 | + defaultValue: 0, | ||
| 108 | + span: 24, | ||
| 109 | + showLabel: true, | ||
| 110 | + labelWidth: null, | ||
| 111 | + layout: 'colFormItem', | ||
| 112 | + required: true, | ||
| 113 | + regList: [], | ||
| 114 | + changeTag: true, | ||
| 115 | + document: 'https://element.eleme.cn/#/zh-CN/component/rate', | ||
| 116 | + formId: 102, | ||
| 117 | + renderKey: 1586839671259 | ||
| 118 | + }, | ||
| 119 | + style: {}, | ||
| 120 | + max: 5, | ||
| 121 | + 'allow-half': false, | ||
| 122 | + 'show-text': false, | ||
| 123 | + 'show-score': false, | ||
| 124 | + disabled: false, | ||
| 125 | + __vModel__: 'field102' | ||
| 126 | + } | ||
| 127 | + ], | ||
| 128 | + document: 'https://element.eleme.cn/#/zh-CN/component/layout', | ||
| 129 | + formId: 101, | ||
| 130 | + span: 24, | ||
| 131 | + renderKey: 1586839668999, | ||
| 132 | + componentName: 'row101', | ||
| 133 | + gutter: 15 | ||
| 134 | + }, | ||
| 135 | + type: 'default', | ||
| 136 | + justify: 'start', | ||
| 137 | + align: 'top' | ||
| 138 | + }, | ||
| 139 | + { | ||
| 140 | + __config__: { | ||
| 141 | + label: '按钮', | ||
| 142 | + showLabel: true, | ||
| 143 | + changeTag: true, | ||
| 144 | + labelWidth: null, | ||
| 145 | + tag: 'el-button', | ||
| 146 | + tagIcon: 'button', | ||
| 147 | + span: 24, | ||
| 148 | + layout: 'colFormItem', | ||
| 149 | + document: 'https://element.eleme.cn/#/zh-CN/component/button', | ||
| 150 | + renderKey: 1594288459289 | ||
| 151 | + }, | ||
| 152 | + __slot__: { | ||
| 153 | + default: '测试按钮1' | ||
| 154 | + }, | ||
| 155 | + type: 'primary', | ||
| 156 | + icon: 'el-icon-search', | ||
| 157 | + round: false, | ||
| 158 | + size: 'medium', | ||
| 159 | + plain: false, | ||
| 160 | + circle: false, | ||
| 161 | + disabled: false, | ||
| 162 | + on: { | ||
| 163 | + click: 'clickTestButton1' | ||
| 164 | + } | ||
| 165 | + } | ||
| 166 | + ], | ||
| 167 | + __methods__: { | ||
| 168 | + clickTestButton1() { | ||
| 169 | + console.log( | ||
| 170 | + `%c【测试按钮1】点击事件里可以访问当前表单: | ||
| 171 | + 1) formModel='formData', 所以this.formData可以拿到当前表单的model | ||
| 172 | + 2) formRef='elForm', 所以this.$refs.elForm可以拿到当前表单的ref(vue组件) | ||
| 173 | + `, | ||
| 174 | + 'color:#409EFF;font-size: 15px' | ||
| 175 | + ) | ||
| 176 | + console.log('表单的Model:', this.formData) | ||
| 177 | + console.log('表单的ref:', this.$refs.elForm) | ||
| 178 | + } | ||
| 179 | + }, | ||
| 180 | + formRef: 'elForm', | ||
| 181 | + formModel: 'formData', | ||
| 182 | + size: 'small', | ||
| 183 | + labelPosition: 'right', | ||
| 184 | + labelWidth: 100, | ||
| 185 | + formRules: 'rules', | ||
| 186 | + gutter: 15, | ||
| 187 | + disabled: false, | ||
| 188 | + span: 24, | ||
| 189 | + formBtns: true, | ||
| 190 | + unFocusedComponentBorder: false | ||
| 191 | + }, | ||
| 192 | + formConf2: { | ||
| 193 | + fields: [ | ||
| 194 | + { | ||
| 195 | + __config__: { | ||
| 196 | + label: '单行文本', | ||
| 197 | + labelWidth: null, | ||
| 198 | + showLabel: true, | ||
| 199 | + changeTag: true, | ||
| 200 | + tag: 'el-input', | ||
| 201 | + tagIcon: 'input', | ||
| 202 | + required: true, | ||
| 203 | + layout: 'colFormItem', | ||
| 204 | + span: 24, | ||
| 205 | + document: 'https://element.eleme.cn/#/zh-CN/component/input', | ||
| 206 | + regList: [ | ||
| 207 | + { | ||
| 208 | + pattern: '/^1(3|4|5|7|8|9)\\d{9}$/', | ||
| 209 | + message: '手机号格式错误' | ||
| 210 | + } | ||
| 211 | + ] | ||
| 212 | + }, | ||
| 213 | + __slot__: { | ||
| 214 | + prepend: '', | ||
| 215 | + append: '' | ||
| 216 | + }, | ||
| 217 | + __vModel__: 'mobile', | ||
| 218 | + placeholder: '请输入手机号', | ||
| 219 | + style: { | ||
| 220 | + width: '100%' | ||
| 221 | + }, | ||
| 222 | + clearable: true, | ||
| 223 | + 'prefix-icon': 'el-icon-mobile', | ||
| 224 | + 'suffix-icon': '', | ||
| 225 | + maxlength: 11, | ||
| 226 | + 'show-word-limit': true, | ||
| 227 | + readonly: false, | ||
| 228 | + disabled: false | ||
| 229 | + }, | ||
| 230 | + { | ||
| 231 | + __config__: { | ||
| 232 | + label: '日期范围', | ||
| 233 | + tag: 'el-date-picker', | ||
| 234 | + tagIcon: 'date-range', | ||
| 235 | + defaultValue: null, | ||
| 236 | + span: 24, | ||
| 237 | + showLabel: true, | ||
| 238 | + labelWidth: null, | ||
| 239 | + required: true, | ||
| 240 | + layout: 'colFormItem', | ||
| 241 | + regList: [], | ||
| 242 | + changeTag: true, | ||
| 243 | + document: | ||
| 244 | + 'https://element.eleme.cn/#/zh-CN/component/date-picker', | ||
| 245 | + formId: 101, | ||
| 246 | + renderKey: 1585980082729 | ||
| 247 | + }, | ||
| 248 | + style: { | ||
| 249 | + width: '100%' | ||
| 250 | + }, | ||
| 251 | + type: 'daterange', | ||
| 252 | + 'range-separator': '至', | ||
| 253 | + 'start-placeholder': '开始日期', | ||
| 254 | + 'end-placeholder': '结束日期', | ||
| 255 | + disabled: false, | ||
| 256 | + clearable: true, | ||
| 257 | + format: 'yyyy-MM-dd', | ||
| 258 | + 'value-format': 'yyyy-MM-dd', | ||
| 259 | + readonly: false, | ||
| 260 | + __vModel__: 'field101' | ||
| 261 | + } | ||
| 262 | + ], | ||
| 263 | + formRef: 'elForm', | ||
| 264 | + formModel: 'formData', | ||
| 265 | + size: 'small', | ||
| 266 | + labelPosition: 'right', | ||
| 267 | + labelWidth: 100, | ||
| 268 | + formRules: 'rules', | ||
| 269 | + gutter: 15, | ||
| 270 | + disabled: false, | ||
| 271 | + span: 24, | ||
| 272 | + formBtns: true, | ||
| 273 | + unFocusedComponentBorder: false | ||
| 274 | + } | ||
| 275 | + } | ||
| 276 | + }, | ||
| 277 | + computed: {}, | ||
| 278 | + watch: {}, | ||
| 279 | + created() {}, | ||
| 280 | + mounted() { | ||
| 281 | + // 表单数据回填,模拟异步请求场景 | ||
| 282 | + setTimeout(() => { | ||
| 283 | + // 请求回来的表单数据 | ||
| 284 | + const data = { | ||
| 285 | + mobile: '18836662555' | ||
| 286 | + } | ||
| 287 | + // 回填数据 | ||
| 288 | + this.fillFormData(this.formConf, data) | ||
| 289 | + // 更新表单 | ||
| 290 | + this.key2 = +new Date() | ||
| 291 | + }, 2000) | ||
| 292 | + }, | ||
| 293 | + methods: { | ||
| 294 | + fillFormData(form, data) { | ||
| 295 | + form.fields.forEach(item => { | ||
| 296 | + const val = data[item.__vModel__] | ||
| 297 | + if (val) { | ||
| 298 | + item.__config__.defaultValue = val | ||
| 299 | + } | ||
| 300 | + }) | ||
| 301 | + }, | ||
| 302 | + change() { | ||
| 303 | + this.key2 = +new Date() | ||
| 304 | + const t = this.formConf | ||
| 305 | + this.formConf = this.formConf2 | ||
| 306 | + this.formConf2 = t | ||
| 307 | + }, | ||
| 308 | + sumbitForm1(data) { | ||
| 309 | + console.log('sumbitForm1提交数据:', data) | ||
| 310 | + }, | ||
| 311 | + sumbitForm2(data) { | ||
| 312 | + console.log('sumbitForm2提交数据:', data) | ||
| 313 | + } | ||
| 314 | + } | ||
| 315 | +} | ||
| 316 | +</script> | ||
| 317 | + | ||
| 318 | +<style lang="scss" scoped> | ||
| 319 | +.test-form { | ||
| 320 | + margin: 15px auto; | ||
| 321 | + width: 800px; | ||
| 322 | + padding: 15px; | ||
| 323 | +} | ||
| 324 | +</style> |
yudao-admin-ui/src/utils/parser/index.js
0 → 100644
yudao-admin-ui/src/utils/parser/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name": "form-gen-parser", | ||
| 3 | + "version": "1.0.3", | ||
| 4 | + "description": "表单json解析器", | ||
| 5 | + "main": "lib/form-gen-parser.umd.js", | ||
| 6 | + "directories": { | ||
| 7 | + "example": "example" | ||
| 8 | + }, | ||
| 9 | + "scripts": { | ||
| 10 | + "test": "echo \"Error: no test specified\" && exit 1" | ||
| 11 | + }, | ||
| 12 | + "repository": { | ||
| 13 | + "type": "git", | ||
| 14 | + "url": "git+https://github.com/JakHuang/form-generator.git" | ||
| 15 | + }, | ||
| 16 | + "dependencies": { | ||
| 17 | + "form-gen-render": "^1.0.0" | ||
| 18 | + }, | ||
| 19 | + "author": "jakHuang", | ||
| 20 | + "license": "MIT", | ||
| 21 | + "bugs": { | ||
| 22 | + "url": "https://github.com/JakHuang/form-generator/issues" | ||
| 23 | + }, | ||
| 24 | + "homepage": "https://github.com/JakHuang/form-generator/blob/dev/src/components/parser" | ||
| 25 | +} |
yudao-admin-ui/src/utils/render/README.md
0 → 100644
yudao-admin-ui/src/utils/render/package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name": "form-gen-render", | ||
| 3 | + "version": "1.0.4", | ||
| 4 | + "description": "表单核心render", | ||
| 5 | + "main": "lib/form-gen-render.umd.js", | ||
| 6 | + "scripts": { | ||
| 7 | + "test": "echo \"Error: no test specified\" && exit 1" | ||
| 8 | + }, | ||
| 9 | + "repository": { | ||
| 10 | + "type": "git", | ||
| 11 | + "url": "git+https://github.com/JakHuang/form-generator.git" | ||
| 12 | + }, | ||
| 13 | + "author": "jakhuang", | ||
| 14 | + "license": "MIT", | ||
| 15 | + "bugs": { | ||
| 16 | + "url": "https://github.com/JakHuang/form-generator/issues" | ||
| 17 | + }, | ||
| 18 | + "homepage": "https://github.com/JakHuang/form-generator#readme" | ||
| 19 | +} |
yudao-admin-ui/src/utils/render/render.js
0 → 100644
| 1 | +import { deepClone } from '@/utils/index' | ||
| 2 | + | ||
| 3 | +const componentChild = {} | ||
| 4 | +/** | ||
| 5 | + * 将./slots中的文件挂载到对象componentChild上 | ||
| 6 | + * 文件名为key,对应JSON配置中的__config__.tag | ||
| 7 | + * 文件内容为value,解析JSON配置中的__slot__ | ||
| 8 | + */ | ||
| 9 | +const slotsFiles = require.context('./slots', false, /\.js$/) | ||
| 10 | +const keys = slotsFiles.keys() || [] | ||
| 11 | +keys.forEach(key => { | ||
| 12 | + const tag = key.replace(/^\.\/(.*)\.\w+$/, '$1') | ||
| 13 | + const value = slotsFiles(key).default | ||
| 14 | + componentChild[tag] = value | ||
| 15 | +}) | ||
| 16 | + | ||
| 17 | +function vModel(dataObject, defaultValue) { | ||
| 18 | + dataObject.props.value = defaultValue | ||
| 19 | + | ||
| 20 | + dataObject.on.input = val => { | ||
| 21 | + this.$emit('input', val) | ||
| 22 | + } | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +function mountSlotFiles(h, confClone, children) { | ||
| 26 | + const childObjs = componentChild[confClone.__config__.tag] | ||
| 27 | + if (childObjs) { | ||
| 28 | + Object.keys(childObjs).forEach(key => { | ||
| 29 | + const childFunc = childObjs[key] | ||
| 30 | + if (confClone.__slot__ && confClone.__slot__[key]) { | ||
| 31 | + children.push(childFunc(h, confClone, key)) | ||
| 32 | + } | ||
| 33 | + }) | ||
| 34 | + } | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +function emitEvents(confClone) { | ||
| 38 | + ['on', 'nativeOn'].forEach(attr => { | ||
| 39 | + const eventKeyList = Object.keys(confClone[attr] || {}) | ||
| 40 | + eventKeyList.forEach(key => { | ||
| 41 | + const val = confClone[attr][key] | ||
| 42 | + if (typeof val === 'string') { | ||
| 43 | + confClone[attr][key] = event => this.$emit(val, event) | ||
| 44 | + } | ||
| 45 | + }) | ||
| 46 | + }) | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +function buildDataObject(confClone, dataObject) { | ||
| 50 | + Object.keys(confClone).forEach(key => { | ||
| 51 | + const val = confClone[key] | ||
| 52 | + if (key === '__vModel__') { | ||
| 53 | + vModel.call(this, dataObject, confClone.__config__.defaultValue) | ||
| 54 | + } else if (dataObject[key] !== undefined) { | ||
| 55 | + if (dataObject[key] === null | ||
| 56 | + || dataObject[key] instanceof RegExp | ||
| 57 | + || ['boolean', 'string', 'number', 'function'].includes(typeof dataObject[key])) { | ||
| 58 | + dataObject[key] = val | ||
| 59 | + } else if (Array.isArray(dataObject[key])) { | ||
| 60 | + dataObject[key] = [...dataObject[key], ...val] | ||
| 61 | + } else { | ||
| 62 | + dataObject[key] = { ...dataObject[key], ...val } | ||
| 63 | + } | ||
| 64 | + } else { | ||
| 65 | + dataObject.attrs[key] = val | ||
| 66 | + } | ||
| 67 | + }) | ||
| 68 | + | ||
| 69 | + // 清理属性 | ||
| 70 | + clearAttrs(dataObject) | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +function clearAttrs(dataObject) { | ||
| 74 | + delete dataObject.attrs.__config__ | ||
| 75 | + delete dataObject.attrs.__slot__ | ||
| 76 | + delete dataObject.attrs.__methods__ | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +function makeDataObject() { | ||
| 80 | + // 深入数据对象: | ||
| 81 | + // https://cn.vuejs.org/v2/guide/render-function.html#%E6%B7%B1%E5%85%A5%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1 | ||
| 82 | + return { | ||
| 83 | + class: {}, | ||
| 84 | + attrs: {}, | ||
| 85 | + props: {}, | ||
| 86 | + domProps: {}, | ||
| 87 | + nativeOn: {}, | ||
| 88 | + on: {}, | ||
| 89 | + style: {}, | ||
| 90 | + directives: [], | ||
| 91 | + scopedSlots: {}, | ||
| 92 | + slot: null, | ||
| 93 | + key: null, | ||
| 94 | + ref: null, | ||
| 95 | + refInFor: true | ||
| 96 | + } | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +export default { | ||
| 100 | + props: { | ||
| 101 | + conf: { | ||
| 102 | + type: Object, | ||
| 103 | + required: true | ||
| 104 | + } | ||
| 105 | + }, | ||
| 106 | + render(h) { | ||
| 107 | + const dataObject = makeDataObject() | ||
| 108 | + const confClone = deepClone(this.conf) | ||
| 109 | + const children = this.$slots.default || [] | ||
| 110 | + | ||
| 111 | + // 如果slots文件夹存在与当前tag同名的文件,则执行文件中的代码 | ||
| 112 | + mountSlotFiles.call(this, h, confClone, children) | ||
| 113 | + | ||
| 114 | + // 将字符串类型的事件,发送为消息 | ||
| 115 | + emitEvents.call(this, confClone) | ||
| 116 | + | ||
| 117 | + // 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)” | ||
| 118 | + buildDataObject.call(this, confClone, dataObject) | ||
| 119 | + | ||
| 120 | + return h(this.conf.__config__.tag, dataObject, children) | ||
| 121 | + } | ||
| 122 | +} |
yudao-admin-ui/src/utils/render/slots/el-button.js
0 → 100644
yudao-admin-ui/src/utils/render/slots/el-checkbox-group.js
0 → 100644
| 1 | +export default { | ||
| 2 | + options(h, conf, key) { | ||
| 3 | + const list = [] | ||
| 4 | + conf.__slot__.options.forEach(item => { | ||
| 5 | + if (conf.__config__.optionType === 'button') { | ||
| 6 | + list.push(<el-checkbox-button label={item.value}>{item.label}</el-checkbox-button>) | ||
| 7 | + } else { | ||
| 8 | + list.push(<el-checkbox label={item.value} border={conf.border}>{item.label}</el-checkbox>) | ||
| 9 | + } | ||
| 10 | + }) | ||
| 11 | + return list | ||
| 12 | + } | ||
| 13 | +} |
yudao-admin-ui/src/utils/render/slots/el-input.js
0 → 100644
yudao-admin-ui/src/utils/render/slots/el-radio-group.js
0 → 100644
| 1 | +export default { | ||
| 2 | + options(h, conf, key) { | ||
| 3 | + const list = [] | ||
| 4 | + conf.__slot__.options.forEach(item => { | ||
| 5 | + if (conf.__config__.optionType === 'button') { | ||
| 6 | + list.push(<el-radio-button label={item.value}>{item.label}</el-radio-button>) | ||
| 7 | + } else { | ||
| 8 | + list.push(<el-radio label={item.value} border={conf.border}>{item.label}</el-radio>) | ||
| 9 | + } | ||
| 10 | + }) | ||
| 11 | + return list | ||
| 12 | + } | ||
| 13 | +} |
yudao-admin-ui/src/utils/render/slots/el-select.js
0 → 100644
yudao-admin-ui/src/utils/render/slots/el-upload.js
0 → 100644
| 1 | +export default { | ||
| 2 | + 'list-type': (h, conf, key) => { | ||
| 3 | + const list = [] | ||
| 4 | + const config = conf.__config__ | ||
| 5 | + if (conf['list-type'] === 'picture-card') { | ||
| 6 | + list.push(<i class="el-icon-plus"></i>) | ||
| 7 | + } else { | ||
| 8 | + list.push(<el-button size="small" type="primary" icon="el-icon-upload">{config.buttonText}</el-button>) | ||
| 9 | + } | ||
| 10 | + if (config.showTip) { | ||
| 11 | + list.push( | ||
| 12 | + <div slot="tip" class="el-upload__tip">只能上传不超过 {config.fileSize}{config.sizeUnit} 的{conf.accept}文件</div> | ||
| 13 | + ) | ||
| 14 | + } | ||
| 15 | + return list | ||
| 16 | + } | ||
| 17 | +} |
yudao-admin-ui/src/views/bpm/form/index.vue
| @@ -38,6 +38,8 @@ | @@ -38,6 +38,8 @@ | ||
| 38 | </el-table-column> | 38 | </el-table-column> |
| 39 | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | 39 | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| 40 | <template slot-scope="scope"> | 40 | <template slot-scope="scope"> |
| 41 | + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleDetail(scope.row)" | ||
| 42 | + v-hasPermi="['bpm:form:query']">详情</el-button> | ||
| 41 | <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" | 43 | <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" |
| 42 | v-hasPermi="['bpm:form:update']">修改</el-button> | 44 | v-hasPermi="['bpm:form:update']">修改</el-button> |
| 43 | <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" | 45 | <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" |
| @@ -48,15 +50,24 @@ | @@ -48,15 +50,24 @@ | ||
| 48 | <!-- 分页组件 --> | 50 | <!-- 分页组件 --> |
| 49 | <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | 51 | <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" |
| 50 | @pagination="getList"/> | 52 | @pagination="getList"/> |
| 53 | + | ||
| 54 | + <!--表单配置详情--> | ||
| 55 | + <el-dialog title="表单详情" :visible.sync="detailOpen" width="50%" append-to-body> | ||
| 56 | + <div class="test-form"> | ||
| 57 | + <parser :key="new Date().getTime()" :form-conf="detailForm" /> | ||
| 58 | + </div> | ||
| 59 | + </el-dialog> | ||
| 51 | </div> | 60 | </div> |
| 52 | </template> | 61 | </template> |
| 53 | 62 | ||
| 54 | <script> | 63 | <script> |
| 55 | -import { deleteForm, getFormPage} from "@/api/bpm/form"; | 64 | +import {deleteForm, getForm, getFormPage} from "@/api/bpm/form"; |
| 65 | +import Parser from '@/utils/parser/Parser' | ||
| 56 | 66 | ||
| 57 | export default { | 67 | export default { |
| 58 | name: "Form", | 68 | name: "Form", |
| 59 | components: { | 69 | components: { |
| 70 | + Parser | ||
| 60 | }, | 71 | }, |
| 61 | data() { | 72 | data() { |
| 62 | return { | 73 | return { |
| @@ -74,6 +85,9 @@ export default { | @@ -74,6 +85,9 @@ export default { | ||
| 74 | pageSize: 10, | 85 | pageSize: 10, |
| 75 | name: null, | 86 | name: null, |
| 76 | }, | 87 | }, |
| 88 | + // 表单详情 | ||
| 89 | + detailOpen: false, | ||
| 90 | + detailForm: {} | ||
| 77 | }; | 91 | }; |
| 78 | }, | 92 | }, |
| 79 | created() { | 93 | created() { |
| @@ -102,6 +116,192 @@ export default { | @@ -102,6 +116,192 @@ export default { | ||
| 102 | this.resetForm("queryForm"); | 116 | this.resetForm("queryForm"); |
| 103 | this.handleQuery(); | 117 | this.handleQuery(); |
| 104 | }, | 118 | }, |
| 119 | + /** 详情按钮操作 */ | ||
| 120 | + handleDetail(row) { | ||
| 121 | + this.detailOpen = true | ||
| 122 | + getForm(row.id).then(response => { | ||
| 123 | + const data = response.data | ||
| 124 | + // this.detailForm = { | ||
| 125 | + // ...JSON.parse(data.conf), | ||
| 126 | + // fields: this.decodeFields(data.fields) | ||
| 127 | + // } | ||
| 128 | + this.detailForm = { | ||
| 129 | + fields: [ | ||
| 130 | + { | ||
| 131 | + __config__: { | ||
| 132 | + label: '单行文本', | ||
| 133 | + labelWidth: null, | ||
| 134 | + showLabel: true, | ||
| 135 | + changeTag: true, | ||
| 136 | + tag: 'el-input', | ||
| 137 | + tagIcon: 'input', | ||
| 138 | + required: true, | ||
| 139 | + layout: 'colFormItem', | ||
| 140 | + span: 24, | ||
| 141 | + document: 'https://element.eleme.cn/#/zh-CN/component/input', | ||
| 142 | + regList: [ | ||
| 143 | + { | ||
| 144 | + pattern: '/^1(3|4|5|7|8|9)\\d{9}$/', | ||
| 145 | + message: '手机号格式错误' | ||
| 146 | + } | ||
| 147 | + ] | ||
| 148 | + }, | ||
| 149 | + __slot__: { | ||
| 150 | + prepend: '', | ||
| 151 | + append: '' | ||
| 152 | + }, | ||
| 153 | + __vModel__: 'mobile', | ||
| 154 | + placeholder: '请输入手机号', | ||
| 155 | + style: { | ||
| 156 | + width: '100%' | ||
| 157 | + }, | ||
| 158 | + clearable: true, | ||
| 159 | + 'prefix-icon': 'el-icon-mobile', | ||
| 160 | + 'suffix-icon': '', | ||
| 161 | + maxlength: 11, | ||
| 162 | + 'show-word-limit': true, | ||
| 163 | + readonly: false, | ||
| 164 | + disabled: false | ||
| 165 | + }, | ||
| 166 | + { | ||
| 167 | + __config__: { | ||
| 168 | + label: '日期范围', | ||
| 169 | + tag: 'el-date-picker', | ||
| 170 | + tagIcon: 'date-range', | ||
| 171 | + defaultValue: null, | ||
| 172 | + span: 24, | ||
| 173 | + showLabel: true, | ||
| 174 | + labelWidth: null, | ||
| 175 | + required: true, | ||
| 176 | + layout: 'colFormItem', | ||
| 177 | + regList: [], | ||
| 178 | + changeTag: true, | ||
| 179 | + document: | ||
| 180 | + 'https://element.eleme.cn/#/zh-CN/component/date-picker', | ||
| 181 | + formId: 101, | ||
| 182 | + renderKey: 1585980082729 | ||
| 183 | + }, | ||
| 184 | + style: { | ||
| 185 | + width: '100%' | ||
| 186 | + }, | ||
| 187 | + type: 'daterange', | ||
| 188 | + 'range-separator': '至', | ||
| 189 | + 'start-placeholder': '开始日期', | ||
| 190 | + 'end-placeholder': '结束日期', | ||
| 191 | + disabled: false, | ||
| 192 | + clearable: true, | ||
| 193 | + format: 'yyyy-MM-dd', | ||
| 194 | + 'value-format': 'yyyy-MM-dd', | ||
| 195 | + readonly: false, | ||
| 196 | + __vModel__: 'field101' | ||
| 197 | + }, | ||
| 198 | + { | ||
| 199 | + __config__: { | ||
| 200 | + layout: 'rowFormItem', | ||
| 201 | + tagIcon: 'row', | ||
| 202 | + label: '行容器', | ||
| 203 | + layoutTree: true, | ||
| 204 | + children: [ | ||
| 205 | + { | ||
| 206 | + __config__: { | ||
| 207 | + label: '评分', | ||
| 208 | + tag: 'el-rate', | ||
| 209 | + tagIcon: 'rate', | ||
| 210 | + defaultValue: 0, | ||
| 211 | + span: 24, | ||
| 212 | + showLabel: true, | ||
| 213 | + labelWidth: null, | ||
| 214 | + layout: 'colFormItem', | ||
| 215 | + required: true, | ||
| 216 | + regList: [], | ||
| 217 | + changeTag: true, | ||
| 218 | + document: 'https://element.eleme.cn/#/zh-CN/component/rate', | ||
| 219 | + formId: 102, | ||
| 220 | + renderKey: 1586839671259 | ||
| 221 | + }, | ||
| 222 | + style: {}, | ||
| 223 | + max: 5, | ||
| 224 | + 'allow-half': false, | ||
| 225 | + 'show-text': false, | ||
| 226 | + 'show-score': false, | ||
| 227 | + disabled: false, | ||
| 228 | + __vModel__: 'field102' | ||
| 229 | + } | ||
| 230 | + ], | ||
| 231 | + document: 'https://element.eleme.cn/#/zh-CN/component/layout', | ||
| 232 | + formId: 101, | ||
| 233 | + span: 24, | ||
| 234 | + renderKey: 1586839668999, | ||
| 235 | + componentName: 'row101', | ||
| 236 | + gutter: 15 | ||
| 237 | + }, | ||
| 238 | + type: 'default', | ||
| 239 | + justify: 'start', | ||
| 240 | + align: 'top' | ||
| 241 | + }, | ||
| 242 | + { | ||
| 243 | + __config__: { | ||
| 244 | + label: '按钮', | ||
| 245 | + showLabel: true, | ||
| 246 | + changeTag: true, | ||
| 247 | + labelWidth: null, | ||
| 248 | + tag: 'el-button', | ||
| 249 | + tagIcon: 'button', | ||
| 250 | + span: 24, | ||
| 251 | + layout: 'colFormItem', | ||
| 252 | + document: 'https://element.eleme.cn/#/zh-CN/component/button', | ||
| 253 | + renderKey: 1594288459289 | ||
| 254 | + }, | ||
| 255 | + __slot__: { | ||
| 256 | + default: '测试按钮1' | ||
| 257 | + }, | ||
| 258 | + type: 'primary', | ||
| 259 | + icon: 'el-icon-search', | ||
| 260 | + round: false, | ||
| 261 | + size: 'medium', | ||
| 262 | + plain: false, | ||
| 263 | + circle: false, | ||
| 264 | + disabled: false, | ||
| 265 | + on: { | ||
| 266 | + click: 'clickTestButton1' | ||
| 267 | + } | ||
| 268 | + } | ||
| 269 | + ], | ||
| 270 | + __methods__: { | ||
| 271 | + clickTestButton1() { | ||
| 272 | + console.log( | ||
| 273 | + `%c【测试按钮1】点击事件里可以访问当前表单: | ||
| 274 | + 1) formModel='formData', 所以this.formData可以拿到当前表单的model | ||
| 275 | + 2) formRef='elForm', 所以this.$refs.elForm可以拿到当前表单的ref(vue组件) | ||
| 276 | + `, | ||
| 277 | + 'color:#409EFF;font-size: 15px' | ||
| 278 | + ) | ||
| 279 | + console.log('表单的Model:', this.formData) | ||
| 280 | + console.log('表单的ref:', this.$refs.elForm) | ||
| 281 | + } | ||
| 282 | + }, | ||
| 283 | + formRef: 'elForm', | ||
| 284 | + formModel: 'formData', | ||
| 285 | + size: 'small', | ||
| 286 | + labelPosition: 'right', | ||
| 287 | + labelWidth: 100, | ||
| 288 | + formRules: 'rules', | ||
| 289 | + gutter: 15, | ||
| 290 | + disabled: false, | ||
| 291 | + span: 24, | ||
| 292 | + formBtns: true, | ||
| 293 | + unFocusedComponentBorder: false | ||
| 294 | + } | ||
| 295 | + console.log(this.detailForm) | ||
| 296 | + }); | ||
| 297 | + }, | ||
| 298 | + decodeFields(fields) { | ||
| 299 | + const drawingList = [] | ||
| 300 | + fields.forEach(item => { | ||
| 301 | + drawingList.push(JSON.parse(item)) | ||
| 302 | + }) | ||
| 303 | + return drawingList | ||
| 304 | + }, | ||
| 105 | /** 新增按钮操作 */ | 305 | /** 新增按钮操作 */ |
| 106 | handleAdd() { | 306 | handleAdd() { |
| 107 | this.$router.push({ | 307 | this.$router.push({ |