From cb0a4b78ee30e49c695c565ad47b9470bfc8d321 Mon Sep 17 00:00:00 2001 From: RuoYi Date: Mon, 24 Feb 2020 09:28:16 +0800 Subject: [PATCH] =?UTF-8?q?=E8=8B=A5=E4=BE=9D=202.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/package.json | 11 +- ruoyi-ui/src/assets/icons/svg/cascader.svg | 1 + ruoyi-ui/src/assets/icons/svg/checkbox.svg | 1 + ruoyi-ui/src/assets/icons/svg/color.svg | 1 + ruoyi-ui/src/assets/icons/svg/component.svg | 2 +- ruoyi-ui/src/assets/icons/svg/date-range.svg | 1 + ruoyi-ui/src/assets/icons/svg/date.svg | 2 +- ruoyi-ui/src/assets/icons/svg/github.svg | 1 + ruoyi-ui/src/assets/icons/svg/input.svg | 1 + ruoyi-ui/src/assets/icons/svg/number.svg | 1 + ruoyi-ui/src/assets/icons/svg/password.svg | 2 +- ruoyi-ui/src/assets/icons/svg/question.svg | 1 + ruoyi-ui/src/assets/icons/svg/radio.svg | 1 + ruoyi-ui/src/assets/icons/svg/rate.svg | 1 + ruoyi-ui/src/assets/icons/svg/row.svg | 1 + ruoyi-ui/src/assets/icons/svg/select.svg | 1 + ruoyi-ui/src/assets/icons/svg/slider.svg | 1 + ruoyi-ui/src/assets/icons/svg/switch.svg | 1 + ruoyi-ui/src/assets/icons/svg/textarea.svg | 1 + ruoyi-ui/src/assets/icons/svg/time-range.svg | 1 + ruoyi-ui/src/assets/icons/svg/time.svg | 1 + ruoyi-ui/src/assets/icons/svg/upload.svg | 1 + ruoyi-ui/src/components/RuoYi/Doc/index.vue | 21 + .../src/components/RuoYi/{ => Git}/index.vue | 6 +- ruoyi-ui/src/layout/components/Navbar.vue | 14 +- ruoyi-ui/src/main.js | 3 +- ruoyi-ui/src/utils/generator/config.js | 423 ++++++++ ruoyi-ui/src/utils/generator/css.js | 18 + .../src/utils/generator/drawingDefalut.js | 29 + ruoyi-ui/src/utils/generator/html.js | 338 +++++++ ruoyi-ui/src/utils/generator/icon.json | 1 + ruoyi-ui/src/utils/generator/js.js | 236 +++++ ruoyi-ui/src/utils/generator/render.js | 121 +++ ruoyi-ui/src/utils/index.js | 69 ++ ruoyi-ui/src/utils/permission.js | 39 +- ruoyi-ui/src/utils/ruoyi.js | 31 +- ruoyi-ui/src/views/system/dept/index.vue | 21 +- ruoyi-ui/src/views/system/menu/index.vue | 22 +- .../src/views/tool/build/CodeTypeDialog.vue | 106 ++ .../src/views/tool/build/DraggableItem.vue | 100 ++ ruoyi-ui/src/views/tool/build/IconsDialog.vue | 123 +++ ruoyi-ui/src/views/tool/build/RightPanel.vue | 944 ++++++++++++++++++ .../src/views/tool/build/TreeNodeDialog.vue | 149 +++ ruoyi-ui/src/views/tool/build/index.vue | 790 ++++++++++++++- ruoyi-ui/src/views/tool/gen/genInfoForm.vue | 2 +- ruoyi/pom.xml | 10 +- .../ruoyi/common/constant/GenConstants.java | 2 +- .../ruoyi/common/utils/html/EscapeUtil.java | 2 +- .../framework/web/domain/TreeEntity.java | 79 ++ .../system/controller/SysDeptController.java | 2 +- .../system/controller/SysMenuController.java | 2 +- .../tool/gen/controller/GenController.java | 1 - .../project/tool/gen/domain/GenTable.java | 4 +- .../project/tool/gen/util/VelocityUtils.java | 17 +- ruoyi/src/main/resources/application.yml | 2 +- .../mybatis/monitor/SysLogininforMapper.xml | 1 + .../mybatis/monitor/SysOperLogMapper.xml | 2 +- .../main/resources/vm/java/controller.java.vm | 11 + .../src/main/resources/vm/java/domain.java.vm | 12 +- .../main/resources/vm/vue/index-tree.vue.vm | 410 ++++++++ ruoyi/src/main/resources/vm/vue/index.vue.vm | 6 +- 61 files changed, 4144 insertions(+), 60 deletions(-) create mode 100644 ruoyi-ui/src/assets/icons/svg/cascader.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/checkbox.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/color.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/date-range.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/github.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/input.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/number.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/question.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/radio.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/rate.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/row.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/select.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/slider.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/switch.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/textarea.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/time-range.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/time.svg create mode 100644 ruoyi-ui/src/assets/icons/svg/upload.svg create mode 100644 ruoyi-ui/src/components/RuoYi/Doc/index.vue rename ruoyi-ui/src/components/RuoYi/{ => Git}/index.vue (63%) create mode 100644 ruoyi-ui/src/utils/generator/config.js create mode 100644 ruoyi-ui/src/utils/generator/css.js create mode 100644 ruoyi-ui/src/utils/generator/drawingDefalut.js create mode 100644 ruoyi-ui/src/utils/generator/html.js create mode 100644 ruoyi-ui/src/utils/generator/icon.json create mode 100644 ruoyi-ui/src/utils/generator/js.js create mode 100644 ruoyi-ui/src/utils/generator/render.js create mode 100644 ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue create mode 100644 ruoyi-ui/src/views/tool/build/DraggableItem.vue create mode 100644 ruoyi-ui/src/views/tool/build/IconsDialog.vue create mode 100644 ruoyi-ui/src/views/tool/build/RightPanel.vue create mode 100644 ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue create mode 100644 ruoyi/src/main/java/com/ruoyi/framework/web/domain/TreeEntity.java create mode 100644 ruoyi/src/main/resources/vm/vue/index-tree.vue.vm diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json index ceb331e29..69920443c 100644 --- a/ruoyi-ui/package.json +++ b/ruoyi-ui/package.json @@ -1,6 +1,6 @@ { "name": "ruoyi", - "version": "2.0.0", + "version": "2.1.0", "description": "若依管理系统", "author": "若依", "license": "MIT", @@ -41,11 +41,12 @@ }, "dependencies": { "@riophae/vue-treeselect": "0.4.0", - "vue-quill-editor": "3.0.6", - "vue-cropper": "0.4.9", "axios": "0.18.1", + "clipboard": "2.0.4", "echarts": "4.2.1", "element-ui": "2.11.1", + "file-saver": "2.0.1", + "js-beautify": "^1.10.2", "fuse.js": "3.4.4", "js-cookie": "2.2.0", "jsencrypt": "3.0.0-rc.1", @@ -55,13 +56,17 @@ "screenfull": "4.2.0", "vue": "2.6.10", "vue-count-to": "1.0.13", + "vue-quill-editor": "3.0.6", + "vue-cropper": "0.4.9", "vue-router": "3.0.2", "vue-splitpane": "1.0.4", + "vuedraggable": "2.20.0", "vuex": "3.1.0" }, "devDependencies": { "@babel/core": "7.0.0", "@babel/register": "7.0.0", + "@babel/parser": "^7.7.4", "@vue/cli-plugin-babel": "3.5.3", "@vue/cli-plugin-eslint": "^3.9.1", "@vue/cli-plugin-unit-jest": "3.5.3", diff --git a/ruoyi-ui/src/assets/icons/svg/cascader.svg b/ruoyi-ui/src/assets/icons/svg/cascader.svg new file mode 100644 index 000000000..e256024f9 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/cascader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/checkbox.svg b/ruoyi-ui/src/assets/icons/svg/checkbox.svg new file mode 100644 index 000000000..013fd3a27 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/checkbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/color.svg b/ruoyi-ui/src/assets/icons/svg/color.svg new file mode 100644 index 000000000..44a81aab1 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/component.svg b/ruoyi-ui/src/assets/icons/svg/component.svg index 207ada34f..29c345809 100644 --- a/ruoyi-ui/src/assets/icons/svg/component.svg +++ b/ruoyi-ui/src/assets/icons/svg/component.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/date-range.svg b/ruoyi-ui/src/assets/icons/svg/date-range.svg new file mode 100644 index 000000000..fda571e70 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/date-range.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/date.svg b/ruoyi-ui/src/assets/icons/svg/date.svg index 2a28112eb..52dc73eec 100644 --- a/ruoyi-ui/src/assets/icons/svg/date.svg +++ b/ruoyi-ui/src/assets/icons/svg/date.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/github.svg b/ruoyi-ui/src/assets/icons/svg/github.svg new file mode 100644 index 000000000..db0a0d430 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/input.svg b/ruoyi-ui/src/assets/icons/svg/input.svg new file mode 100644 index 000000000..ab91381e6 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/input.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/number.svg b/ruoyi-ui/src/assets/icons/svg/number.svg new file mode 100644 index 000000000..ad5ce9af2 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/number.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/password.svg b/ruoyi-ui/src/assets/icons/svg/password.svg index e291d85df..6c64defe3 100644 --- a/ruoyi-ui/src/assets/icons/svg/password.svg +++ b/ruoyi-ui/src/assets/icons/svg/password.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/question.svg b/ruoyi-ui/src/assets/icons/svg/question.svg new file mode 100644 index 000000000..cf75bd4be --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/question.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/radio.svg b/ruoyi-ui/src/assets/icons/svg/radio.svg new file mode 100644 index 000000000..0cde34521 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/radio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/rate.svg b/ruoyi-ui/src/assets/icons/svg/rate.svg new file mode 100644 index 000000000..aa3b14d7d --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/rate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/row.svg b/ruoyi-ui/src/assets/icons/svg/row.svg new file mode 100644 index 000000000..078099222 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/row.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/select.svg b/ruoyi-ui/src/assets/icons/svg/select.svg new file mode 100644 index 000000000..d6283828b --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/select.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/slider.svg b/ruoyi-ui/src/assets/icons/svg/slider.svg new file mode 100644 index 000000000..fbe4f39f0 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/slider.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/switch.svg b/ruoyi-ui/src/assets/icons/svg/switch.svg new file mode 100644 index 000000000..0ba61e38d --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/switch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/textarea.svg b/ruoyi-ui/src/assets/icons/svg/textarea.svg new file mode 100644 index 000000000..2709f292e --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/textarea.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/time-range.svg b/ruoyi-ui/src/assets/icons/svg/time-range.svg new file mode 100644 index 000000000..13c1202bd --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/time-range.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/time.svg b/ruoyi-ui/src/assets/icons/svg/time.svg new file mode 100644 index 000000000..b376e32a6 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/assets/icons/svg/upload.svg b/ruoyi-ui/src/assets/icons/svg/upload.svg new file mode 100644 index 000000000..bae49c0a5 --- /dev/null +++ b/ruoyi-ui/src/assets/icons/svg/upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-ui/src/components/RuoYi/Doc/index.vue b/ruoyi-ui/src/components/RuoYi/Doc/index.vue new file mode 100644 index 000000000..3915c2965 --- /dev/null +++ b/ruoyi-ui/src/components/RuoYi/Doc/index.vue @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/ruoyi-ui/src/components/RuoYi/index.vue b/ruoyi-ui/src/components/RuoYi/Git/index.vue similarity index 63% rename from ruoyi-ui/src/components/RuoYi/index.vue rename to ruoyi-ui/src/components/RuoYi/Git/index.vue index 530d57f72..2aab63c15 100644 --- a/ruoyi-ui/src/components/RuoYi/index.vue +++ b/ruoyi-ui/src/components/RuoYi/Git/index.vue @@ -1,19 +1,19 @@ ` +} + +export function cssStyle(cssStr) { + return `` +} + +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 = ` + ${child} + ${buildFromBtns(conf, type)} + ` + if (someSpanIsNot24) { + str = ` + ${str} + ` + } + return str +} + +function buildFromBtns(conf, type) { + let str = '' + if (conf.formBtns && type === 'file') { + str = ` + 提交 + 重置 + ` + if (someSpanIsNot24) { + str = ` + ${str} + ` + } + } + return str +} + +// span不为24的用el-col包裹 +function colWrapper(element, str) { + if (someSpanIsNot24 || element.span !== 24) { + return ` + ${str} + ` + } + 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) : null + let str = ` + ${tagDom} + ` + 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 = ` + ${children.join('\n')} + ` + str = colWrapper(element, str) + return str + } +} + +const tags = { + '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-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-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-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-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-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-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-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-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-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-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-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-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}` + } +} + +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\'' : '' + } +} + +// el-input innerHTML +function buildElInputChild(conf) { + const children = [] + if (conf.prepend) { + children.push(``) + } + if (conf.append) { + children.push(``) + } + return children.join('\n') +} + +function buildElSelectChild(conf) { + const children = [] + if (conf.options && conf.options.length) { + children.push(``) + } + 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}}`) + } + 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}}`) + } + return children.join('\n') +} + +function buildElUploadChild(conf) { + const list = [] + if (conf['list-type'] === 'picture-card') list.push('') + else list.push(`${conf.buttonText}`) + if (conf.showTip) list.push(`
只能上传不超过 ${conf.fileSize}${conf.sizeUnit} 的${conf.accept}文件
`) + return list.join('\n') +} + +export function makeUpHtml(conf, type) { + const htmlList = [] + confGlobal = conf + someSpanIsNot24 = 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 = null + return temp +} diff --git a/ruoyi-ui/src/utils/generator/icon.json b/ruoyi-ui/src/utils/generator/icon.json new file mode 100644 index 000000000..2d9999a31 --- /dev/null +++ b/ruoyi-ui/src/utils/generator/icon.json @@ -0,0 +1 @@ +["platform-eleme","eleme","delete-solid","delete","s-tools","setting","user-solid","user","phone","phone-outline","more","more-outline","star-on","star-off","s-goods","goods","warning","warning-outline","question","info","remove","circle-plus","success","error","zoom-in","zoom-out","remove-outline","circle-plus-outline","circle-check","circle-close","s-help","help","minus","plus","check","close","picture","picture-outline","picture-outline-round","upload","upload2","download","camera-solid","camera","video-camera-solid","video-camera","message-solid","bell","s-cooperation","s-order","s-platform","s-fold","s-unfold","s-operation","s-promotion","s-home","s-release","s-ticket","s-management","s-open","s-shop","s-marketing","s-flag","s-comment","s-finance","s-claim","s-custom","s-opportunity","s-data","s-check","s-grid","menu","share","d-caret","caret-left","caret-right","caret-bottom","caret-top","bottom-left","bottom-right","back","right","bottom","top","top-left","top-right","arrow-left","arrow-right","arrow-down","arrow-up","d-arrow-left","d-arrow-right","video-pause","video-play","refresh","refresh-right","refresh-left","finished","sort","sort-up","sort-down","rank","loading","view","c-scale-to-original","date","edit","edit-outline","folder","folder-opened","folder-add","folder-remove","folder-delete","folder-checked","tickets","document-remove","document-delete","document-copy","document-checked","document","document-add","printer","paperclip","takeaway-box","search","monitor","attract","mobile","scissors","umbrella","headset","brush","mouse","coordinate","magic-stick","reading","data-line","data-board","pie-chart","data-analysis","collection-tag","film","suitcase","suitcase-1","receiving","collection","files","notebook-1","notebook-2","toilet-paper","office-building","school","table-lamp","house","no-smoking","smoking","shopping-cart-full","shopping-cart-1","shopping-cart-2","shopping-bag-1","shopping-bag-2","sold-out","sell","present","box","bank-card","money","coin","wallet","discount","price-tag","news","guide","male","female","thumb","cpu","link","connection","open","turn-off","set-up","chat-round","chat-line-round","chat-square","chat-dot-round","chat-dot-square","chat-line-square","message","postcard","position","turn-off-microphone","microphone","close-notification","bangzhu","time","odometer","crop","aim","switch-button","full-screen","copy-document","mic","stopwatch","medal-1","medal","trophy","trophy-1","first-aid-kit","discover","place","location","location-outline","location-information","add-location","delete-location","map-location","alarm-clock","timer","watch-1","watch","lock","unlock","key","service","mobile-phone","bicycle","truck","ship","basketball","football","soccer","baseball","wind-power","light-rain","lightning","heavy-rain","sunrise","sunrise-1","sunset","sunny","cloudy","partly-cloudy","cloudy-and-sunny","moon","moon-night","dish","dish-1","food","chicken","fork-spoon","knife-fork","burger","tableware","sugar","dessert","ice-cream","hot-water","water-cup","coffee-cup","cold-drink","goblet","goblet-full","goblet-square","goblet-square-full","refrigerator","grape","watermelon","cherry","apple","pear","orange","coffee","ice-tea","ice-drink","milk-tea","potato-strips","lollipop","ice-cream-square","ice-cream-round"] \ No newline at end of file diff --git a/ruoyi-ui/src/utils/generator/js.js b/ruoyi-ui/src/utils/generator/js.js new file mode 100644 index 000000000..81afc7004 --- /dev/null +++ b/ruoyi-ui/src/utils/generator/js.js @@ -0,0 +1,236 @@ +import { isArray } from 'util' +import { exportDefault, titleCase } from '@/utils/index' +import { trigger } from './config' + +const units = { + KB: '1024', + MB: '1024 / 1024', + GB: '1024 / 1024 / 1024' +} +let confGlobal +const inheritAttrs = { + file: '', + dialog: 'inheritAttrs: false,' +} + + +export function makeUpJs(conf, type) { + confGlobal = conf = JSON.parse(JSON.stringify(conf)) + const dataList = [] + const ruleList = [] + const optionsList = [] + const propsList = [] + const methodList = mixinMethod(type) + const uploadVarList = [] + + conf.fields.forEach(el => { + buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) + }) + + const script = buildexport( + conf, + type, + dataList.join('\n'), + ruleList.join('\n'), + optionsList.join('\n'), + uploadVarList.join('\n'), + propsList.join('\n'), + methodList.join('\n') + ) + confGlobal = null + return script +} + +function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) { + buildData(el, dataList) + buildRules(el, ruleList) + + if (el.options && el.options.length) { + buildOptions(el, optionsList) + if (el.dataType === 'dynamic') { + const model = `${el.vModel}Options` + const options = titleCase(model) + buildOptionMethod(`get${options}`, model, methodList) + } + } + + if (el.props && el.props.props) { + buildProps(el, propsList) + } + + if (el.action && el.tag === 'el-upload') { + uploadVarList.push( + `${el.vModel}Action: '${el.action}', + ${el.vModel}fileList: [],` + ) + methodList.push(buildBeforeUpload(el)) + if (!el['auto-upload']) { + methodList.push(buildSubmitUpload(el)) + } + } + + if (el.children) { + el.children.forEach(el2 => { + buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) + }) + } +} + +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 +} + +function buildData(conf, dataList) { + if (conf.vModel === undefined) return + let defaultValue + if (typeof (conf.defaultValue) === 'string' && !conf.multiple) { + defaultValue = `'${conf.defaultValue}'` + } else { + defaultValue = `${JSON.stringify(conf.defaultValue)}` + } + dataList.push(`${conf.vModel}: ${defaultValue},`) +} + +function buildRules(conf, ruleList) { + if (conf.vModel === undefined) return + const rules = [] + if (trigger[conf.tag]) { + if (conf.required) { + const type = isArray(conf.defaultValue) ? 'type: \'array\',' : '' + let message = isArray(conf.defaultValue) ? `请至少选择一个${conf.vModel}` : conf.placeholder + if (message === undefined) message = `${conf.label}不能为空` + rules.push(`{ required: true, ${type} message: '${message}', trigger: '${trigger[conf.tag]}' }`) + } + if (conf.regList && isArray(conf.regList)) { + conf.regList.forEach(item => { + if (item.pattern) { + rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`) + } + }) + } + ruleList.push(`${conf.vModel}: [${rules.join(',')}],`) + } +} + +function buildOptions(conf, optionsList) { + if (conf.vModel === undefined) return + if (conf.dataType === 'dynamic') { conf.options = [] } + const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},` + optionsList.push(str) +} + +function buildProps(conf, propsList) { + if (conf.dataType === 'dynamic') { + conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey) + conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey) + conf.childrenKey !== 'children' && (conf.props.props.children = conf.childrenKey) + } + const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},` + propsList.push(str) +} + +function buildBeforeUpload(conf) { + const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const + returnList = [] + if (conf.fileSize) { + rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize} + if(!isRightSize){ + this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}') + }` + returnList.push('isRightSize') + } + if (conf.accept) { + acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type) + if(!isAccept){ + this.$message.error('应该选择${conf.accept}类型的文件') + }` + returnList.push('isAccept') + } + const str = `${conf.vModel}BeforeUpload(file) { + ${rightSizeCode} + ${acceptCode} + return ${returnList.join('&&')} + },` + return returnList.length ? str : '' +} + +function buildSubmitUpload(conf) { + const str = `submitUpload() { + this.$refs['${conf.vModel}'].submit() + },` + return str +} + +function buildOptionMethod(methodName, model, methodList) { + const str = `${methodName}() { + // TODO 发起请求获取数据 + this.${model} + },` + methodList.push(str) +} + +function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) { + const str = `${exportDefault}{ + ${inheritAttrs[type]} + components: {}, + props: [], + data () { + return { + ${conf.formModel}: { + ${data} + }, + ${conf.formRules}: { + ${rules} + }, + ${uploadVar} + ${selectOptions} + ${props} + } + }, + computed: {}, + watch: {}, + created () {}, + mounted () {}, + methods: { + ${methods} + } +}` + return str +} diff --git a/ruoyi-ui/src/utils/generator/render.js b/ruoyi-ui/src/utils/generator/render.js new file mode 100644 index 000000000..42cd6646d --- /dev/null +++ b/ruoyi-ui/src/utils/generator/render.js @@ -0,0 +1,121 @@ +import { makeMap } from '@/utils/index' + +// 参考https://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js +const isAttr = makeMap( + 'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,' + + 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,' + + 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,' + + 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,' + + 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,' + + 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,' + + 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,' + + 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,' + + 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,' + + 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,' + + 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,' + + 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,' + + 'target,title,type,usemap,value,width,wrap' +) + +function vModel(self, dataObject, defaultValue) { + dataObject.props.value = defaultValue + + dataObject.on.input = val => { + self.$emit('input', val) + } +} + +const componentChild = { + 'el-input': { + prepend(h, conf, key) { + return + }, + append(h, conf, key) { + return + } + }, + 'el-select': { + options(h, conf, key) { + const list = [] + conf.options.forEach(item => { + list.push() + }) + return list + } + }, + 'el-radio-group': { + options(h, conf, key) { + const list = [] + conf.options.forEach(item => { + if (conf.optionType === 'button') list.push({item.label}) + else list.push({item.label}) + }) + return list + } + }, + 'el-checkbox-group': { + options(h, conf, key) { + const list = [] + conf.options.forEach(item => { + if (conf.optionType === 'button') { + list.push({item.label}) + } else { + list.push({item.label}) + } + }) + return list + } + }, + 'el-upload': { + 'list-type': (h, conf, key) => { + const list = [] + if (conf['list-type'] === 'picture-card') { + list.push() + } else { + list.push({conf.buttonText}) + } + if (conf.showTip) { + list.push(
只能上传不超过 {conf.fileSize}{conf.sizeUnit} 的{conf.accept}文件
) + } + return list + } + } +} + +export default { + render(h) { + const dataObject = { + attrs: {}, + props: {}, + on: {}, + style: {} + } + const confClone = JSON.parse(JSON.stringify(this.conf)) + const children = [] + + const childObjs = componentChild[confClone.tag] + if (childObjs) { + Object.keys(childObjs).forEach(key => { + const childFunc = childObjs[key] + if (confClone[key]) { + children.push(childFunc(h, confClone, key)) + } + }) + } + + Object.keys(confClone).forEach(key => { + const val = confClone[key] + if (key === 'vModel') { + vModel(this, dataObject, confClone.defaultValue) + } else if (dataObject[key]) { + dataObject[key] = val + } else if (!isAttr(key)) { + dataObject.props[key] = val + } else { + dataObject.attrs[key] = val + } + }) + return h(this.conf.tag, dataObject, children) + }, + props: ['conf'] +} diff --git a/ruoyi-ui/src/utils/index.js b/ruoyi-ui/src/utils/index.js index 9e171eb55..6c3017c76 100644 --- a/ruoyi-ui/src/utils/index.js +++ b/ruoyi-ui/src/utils/index.js @@ -315,3 +315,72 @@ export function removeClass(ele, cls) { ele.className = ele.className.replace(reg, ' ') } } + +export function makeMap(str, expectsLowerCase) { + const map = Object.create(null) + const list = str.split(',') + for (let i = 0; i < list.length; i++) { + map[list[i]] = true + } + return expectsLowerCase + ? val => map[val.toLowerCase()] + : val => map[val] +} + +export const exportDefault = 'export default ' + +export const beautifierConf = { + html: { + indent_size: '2', + indent_char: ' ', + max_preserve_newlines: '-1', + preserve_newlines: false, + keep_array_indentation: false, + break_chained_methods: false, + indent_scripts: 'separate', + brace_style: 'end-expand', + space_before_conditional: true, + unescape_strings: false, + jslint_happy: false, + end_with_newline: true, + wrap_line_length: '110', + indent_inner_html: true, + comma_first: false, + e4x: true, + indent_empty_lines: true + }, + js: { + indent_size: '2', + indent_char: ' ', + max_preserve_newlines: '-1', + preserve_newlines: false, + keep_array_indentation: false, + break_chained_methods: false, + indent_scripts: 'normal', + brace_style: 'end-expand', + space_before_conditional: true, + unescape_strings: false, + jslint_happy: true, + end_with_newline: true, + wrap_line_length: '110', + indent_inner_html: true, + comma_first: false, + e4x: true, + indent_empty_lines: true + } +} + +// 首字母大小 +export function titleCase(str) { + return str.replace(/( |^)[a-z]/g, L => L.toUpperCase()) +} + +// 下划转驼峰 +export function camelCase(str) { + return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase()) +} + +export function isNumberStr(str) { + return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str) +} + \ No newline at end of file diff --git a/ruoyi-ui/src/utils/permission.js b/ruoyi-ui/src/utils/permission.js index efb4cc88f..784e379de 100644 --- a/ruoyi-ui/src/utils/permission.js +++ b/ruoyi-ui/src/utils/permission.js @@ -1,16 +1,17 @@ import store from '@/store' /** - * @param {Array} value + * 字符权限校验 + * @param {Array} value 校验值 * @returns {Boolean} */ -export default function checkPermission(value) { +export function checkPermi(value) { if (value && value instanceof Array && value.length > 0) { - const roles = store.getters && store.getters.roles - const permissionRoles = value + const permissions = store.getters && store.getters.permissions + const permissionDatas = value - const hasPermission = roles.some(role => { - return permissionRoles.includes(role) + const hasPermission = permissions.some(permission => { + return permissionDatas.includes(permission) }) if (!hasPermission) { @@ -18,7 +19,31 @@ export default function checkPermission(value) { } return true } else { - console.error(`need roles! Like v-permission="['admin','editor']"`) + console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`) return false } } + +/** + * 角色权限校验 + * @param {Array} value 校验值 + * @returns {Boolean} + */ +export function checkRole(value) { + if (value && value instanceof Array && value.length > 0) { + const roles = store.getters && store.getters.roles + const permissionRoles = value + + const hasRole = roles.some(role => { + return permissionRoles.includes(role) + }) + + if (!hasRole) { + return false + } + return true + } else { + console.error(`need roles! Like checkRole="['admin','editor']"`) + return false + } +} \ No newline at end of file diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js index 069a1aec2..380e3ce82 100644 --- a/ruoyi-ui/src/utils/ruoyi.js +++ b/ruoyi-ui/src/utils/ruoyi.js @@ -100,4 +100,33 @@ export function praseStrEmpty(str) { return ""; } return str; -} \ No newline at end of file +} + +/** + * 构造树型结构数据 + * @param {*} data 数据源 + * @param {*} id id字段 默认 'id' + * @param {*} parentId 父节点字段 默认 'parentId' + * @param {*} children 孩子节点字段 默认 'children' + * @param {*} rootId 根Id 默认 0 + */ +export function handleTree(data, id, parentId, children, rootId) { + id = id || 'id' + parentId = parentId || 'parentId' + children = children || 'children' + rootId = rootId || 0 + //对源数据深度克隆 + const cloneData = JSON.parse(JSON.stringify(data)) + //循环所有项 + const treeData = cloneData.filter(father => { + let branchArr = cloneData.filter(child => { + //返回每一项的子级数组 + return father[id] === child[parentId] + }); + branchArr.length > 0 ? father.children = branchArr : ''; + //返回第一层 + return father[parentId] === rootId; + }); + return treeData != '' ? treeData : data; + } + \ No newline at end of file diff --git a/ruoyi-ui/src/views/system/dept/index.vue b/ruoyi-ui/src/views/system/dept/index.vue index c3574b123..cca08b28c 100644 --- a/ruoyi-ui/src/views/system/dept/index.vue +++ b/ruoyi-ui/src/views/system/dept/index.vue @@ -88,7 +88,7 @@ - + @@ -138,7 +138,7 @@ diff --git a/ruoyi-ui/src/views/tool/build/DraggableItem.vue b/ruoyi-ui/src/views/tool/build/DraggableItem.vue new file mode 100644 index 000000000..f669ac0e6 --- /dev/null +++ b/ruoyi-ui/src/views/tool/build/DraggableItem.vue @@ -0,0 +1,100 @@ + diff --git a/ruoyi-ui/src/views/tool/build/IconsDialog.vue b/ruoyi-ui/src/views/tool/build/IconsDialog.vue new file mode 100644 index 000000000..0d1277835 --- /dev/null +++ b/ruoyi-ui/src/views/tool/build/IconsDialog.vue @@ -0,0 +1,123 @@ + + + diff --git a/ruoyi-ui/src/views/tool/build/RightPanel.vue b/ruoyi-ui/src/views/tool/build/RightPanel.vue new file mode 100644 index 000000000..1acdc5794 --- /dev/null +++ b/ruoyi-ui/src/views/tool/build/RightPanel.vue @@ -0,0 +1,944 @@ + + + + + diff --git a/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue b/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue new file mode 100644 index 000000000..477c010b9 --- /dev/null +++ b/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue @@ -0,0 +1,149 @@ + + diff --git a/ruoyi-ui/src/views/tool/build/index.vue b/ruoyi-ui/src/views/tool/build/index.vue index 9d4496ea3..0d8adef7c 100644 --- a/ruoyi-ui/src/views/tool/build/index.vue +++ b/ruoyi-ui/src/views/tool/build/index.vue @@ -1,5 +1,789 @@ \ No newline at end of file + + + + + diff --git a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue index 7b9a32a69..41ad4e58d 100644 --- a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue +++ b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue @@ -6,7 +6,7 @@ 生成模板 - + diff --git a/ruoyi/pom.xml b/ruoyi/pom.xml index d44b49f34..e32da8aeb 100644 --- a/ruoyi/pom.xml +++ b/ruoyi/pom.xml @@ -5,7 +5,7 @@ com.ruoyi ruoyi - 2.0.0 + 2.1.0 jar ruoyi @@ -43,14 +43,6 @@ org.springframework.boot spring-boot-starter - diff --git a/ruoyi/src/main/java/com/ruoyi/common/constant/GenConstants.java b/ruoyi/src/main/java/com/ruoyi/common/constant/GenConstants.java index 068969be7..0001785c5 100644 --- a/ruoyi/src/main/java/com/ruoyi/common/constant/GenConstants.java +++ b/ruoyi/src/main/java/com/ruoyi/common/constant/GenConstants.java @@ -48,7 +48,7 @@ public class GenConstants public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" }; /** Tree基类字段 */ - public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors" }; + public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" }; /** 文本框 */ public static final String HTML_INPUT = "input"; diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java b/ruoyi/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java index 0f455275d..8989ca1e1 100644 --- a/ruoyi/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java +++ b/ruoyi/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java @@ -144,7 +144,7 @@ public class EscapeUtil public static void main(String[] args) { - String html = ""; + String html = "alert('11111');"; System.out.println(EscapeUtil.clean(html)); System.out.println(EscapeUtil.escape(html)); System.out.println(EscapeUtil.unescape(html)); diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/TreeEntity.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/TreeEntity.java new file mode 100644 index 000000000..af8643736 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/TreeEntity.java @@ -0,0 +1,79 @@ +package com.ruoyi.framework.web.domain; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tree基类 + * + * @author ruoyi + */ +public class TreeEntity extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 父菜单名称 */ + private String parentName; + + /** 父菜单ID */ + private Long parentId; + + /** 显示顺序 */ + private Integer orderNum; + + /** 祖级列表 */ + private String ancestors; + + /** 子部门 */ + private List children = new ArrayList<>(); + + public String getParentName() + { + return parentName; + } + + public void setParentName(String parentName) + { + this.parentName = parentName; + } + + public Long getParentId() + { + return parentId; + } + + public void setParentId(Long parentId) + { + this.parentId = parentId; + } + + public Integer getOrderNum() + { + return orderNum; + } + + public void setOrderNum(Integer orderNum) + { + this.orderNum = orderNum; + } + + public String getAncestors() + { + return ancestors; + } + + public void setAncestors(String ancestors) + { + this.ancestors = ancestors; + } + + public List getChildren() + { + return children; + } + + public void setChildren(List children) + { + this.children = children; + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java index 314af5d96..686748a50 100644 --- a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java +++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java @@ -41,7 +41,7 @@ public class SysDeptController extends BaseController public AjaxResult list(SysDept dept) { List depts = deptService.selectDeptList(dept); - return AjaxResult.success(deptService.buildDeptTree(depts)); + return AjaxResult.success(depts); } /** diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java index 0cb277edd..35ca406ef 100644 --- a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java +++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java @@ -49,7 +49,7 @@ public class SysMenuController extends BaseController LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); Long userId = loginUser.getUser().getUserId(); List menus = menuService.selectMenuList(menu, userId); - return AjaxResult.success(menuService.buildMenuTree(menus)); + return AjaxResult.success(menus); } /** diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java index 515842b58..986f777d6 100644 --- a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java @@ -37,7 +37,6 @@ import com.ruoyi.project.tool.gen.service.IGenTableService; @RequestMapping("/tool/gen") public class GenController extends BaseController { - @Autowired private IGenTableService genTableService; diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTable.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTable.java index d608c82db..039af5eb2 100644 --- a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTable.java +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTable.java @@ -3,6 +3,7 @@ package com.ruoyi.project.tool.gen.domain; import java.util.List; import javax.validation.Valid; import javax.validation.constraints.NotBlank; +import org.apache.commons.lang3.ArrayUtils; import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.web.domain.BaseEntity; @@ -262,7 +263,8 @@ public class GenTable extends BaseEntity { if (isTree(tplCategory)) { - StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.TREE_ENTITY); + return StringUtils.equalsAnyIgnoreCase(javaField, + ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY)); } return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); } diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityUtils.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityUtils.java index 52d209b88..3b5b02c9c 100644 --- a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityUtils.java +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityUtils.java @@ -95,7 +95,14 @@ public class VelocityUtils templates.add("vm/xml/mapper.xml.vm"); templates.add("vm/sql/sql.vm"); templates.add("vm/js/api.js.vm"); - templates.add("vm/vue/index.vue.vm"); + if (GenConstants.TPL_CRUD.equals(tplCategory)) + { + templates.add("vm/vue/index.vue.vm"); + } + else if (GenConstants.TPL_TREE.equals(tplCategory)) + { + templates.add("vm/vue/index-tree.vue.vm"); + } return templates; } @@ -147,11 +154,15 @@ public class VelocityUtils { fileName = businessName + "Menu.sql"; } - else if (template.contains("js.vm")) + else if (template.contains("api.js.vm")) { fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName); } - else if (template.contains("vue.vm")) + else if (template.contains("index.vue.vm")) + { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } + else if (template.contains("index-tree.vue.vm")) { fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); } diff --git a/ruoyi/src/main/resources/application.yml b/ruoyi/src/main/resources/application.yml index 0537e7593..6725ccf70 100644 --- a/ruoyi/src/main/resources/application.yml +++ b/ruoyi/src/main/resources/application.yml @@ -3,7 +3,7 @@ ruoyi: # 名称 name: RuoYi # 版本 - version: 2.0.0 + version: 2.1.0 # 版权年份 copyrightYear: 2019 # 实例演示开关 diff --git a/ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml b/ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml index d62a0c4e9..ba3194dc6 100644 --- a/ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml +++ b/ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml @@ -40,6 +40,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and date_format(login_time,'%y%m%d') <= date_format(#{endTime},'%y%m%d') + order by info_id desc diff --git a/ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml b/ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml index 96b74b378..50e18b489 100644 --- a/ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml +++ b/ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml @@ -25,7 +25,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time - from sys_oper_log + from sys_oper_log order by oper_id desc diff --git a/ruoyi/src/main/resources/vm/java/controller.java.vm b/ruoyi/src/main/resources/vm/java/controller.java.vm index cd6f9beec..c45ba6699 100644 --- a/ruoyi/src/main/resources/vm/java/controller.java.vm +++ b/ruoyi/src/main/resources/vm/java/controller.java.vm @@ -18,7 +18,10 @@ import ${packageName}.service.I${ClassName}Service; import com.ruoyi.framework.web.controller.BaseController; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.common.utils.poi.ExcelUtil; +#if($table.crud) import com.ruoyi.framework.web.page.TableDataInfo; +#elseif($table.tree) +#end /** * ${functionName}Controller @@ -38,12 +41,20 @@ public class ${ClassName}Controller extends BaseController */ @PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')") @GetMapping("/list") +#if($table.crud) public TableDataInfo list(${ClassName} ${className}) { startPage(); List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); return getDataTable(list); } +#elseif($table.tree) + public AjaxResult list(${ClassName} ${className}) + { + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + return AjaxResult.success(list); + } +#end /** * 导出${functionName}列表 diff --git a/ruoyi/src/main/resources/vm/java/domain.java.vm b/ruoyi/src/main/resources/vm/java/domain.java.vm index 137727816..e99ef2cf2 100644 --- a/ruoyi/src/main/resources/vm/java/domain.java.vm +++ b/ruoyi/src/main/resources/vm/java/domain.java.vm @@ -3,7 +3,11 @@ package ${packageName}.domain; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.framework.aspectj.lang.annotation.Excel; +#if($table.crud) import com.ruoyi.framework.web.domain.BaseEntity; +#elseif($table.tree) +import com.ruoyi.framework.web.domain.TreeEntity; +#end #foreach ($import in $importList) import ${import}; #end @@ -14,7 +18,11 @@ import ${import}; * @author ${author} * @date ${datetime} */ +#if($table.crud) #set($Entity="BaseEntity") +#elseif($table.tree) +#set($Entity="TreeEntity") +#end public class ${ClassName} extends ${Entity} { private static final long serialVersionUID = 1L; @@ -43,7 +51,7 @@ public class ${ClassName} extends ${Entity} #end #foreach ($column in $columns) #if(!$table.isSuperColumn($column.javaField)) -#if($column.javaField > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) #set($AttrName=$column.javaField) #else #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) @@ -64,7 +72,7 @@ public class ${ClassName} extends ${Entity} public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) #foreach ($column in $columns) -#if($column.javaField > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) #set($AttrName=$column.javaField) #else #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) diff --git a/ruoyi/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi/src/main/resources/vm/vue/index-tree.vue.vm new file mode 100644 index 000000000..280417a32 --- /dev/null +++ b/ruoyi/src/main/resources/vm/vue/index-tree.vue.vm @@ -0,0 +1,410 @@ + + + \ No newline at end of file diff --git a/ruoyi/src/main/resources/vm/vue/index.vue.vm b/ruoyi/src/main/resources/vm/vue/index.vue.vm index 212d20a43..3110a169a 100644 --- a/ruoyi/src/main/resources/vm/vue/index.vue.vm +++ b/ruoyi/src/main/resources/vm/vue/index.vue.vm @@ -22,7 +22,7 @@ /> #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) - + #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) - + @@ -230,6 +230,7 @@ import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}"; export default { + name: "${BusinessName}", data() { return { // 遮罩层 @@ -288,6 +289,7 @@ export default { $column.javaField: [ { required: true, message: "$comment不能为空", trigger: "blur" } ]#if($velocityCount != $columns.size()),#end + #end #end }