From dc05b8f734de9df8aa51004a57cf766da2ff1d1e Mon Sep 17 00:00:00 2001
From: yigehui <351591801@qq.com>
Date: Sun, 17 May 2020 20:47:06 +0800
Subject: [PATCH] =?UTF-8?q?1.=E6=96=B0=E5=A2=9E=E6=95=B0=E6=8D=AE=E6=A8=A1?=
=?UTF-8?q?=E5=9E=8B=E6=A8=A1=E5=9D=97=202.=E6=9B=B4=E6=96=B0form-design?=
=?UTF-8?q?=E6=8F=92=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ruoyi-ui/package.json | 223 ++++---
ruoyi-ui/public/preview.html | 38 ++
ruoyi-ui/src/api/system/form.js | 53 ++
ruoyi-ui/src/assets/icons/svg/button.svg | 1 +
ruoyi-ui/src/assets/icons/svg/rich-text.svg | 1 +
ruoyi-ui/src/assets/styles/index.scss | 127 ++++
ruoyi-ui/src/assets/styles/mixin.scss | 34 +
ruoyi-ui/src/assets/styles/ruoyi.scss | 10 +-
ruoyi-ui/src/main.js | 1 -
ruoyi-ui/src/permission.js | 69 +-
ruoyi-ui/src/store/index.js | 2 +-
ruoyi-ui/src/utils/generator/config.js | 630 +++++++++++-------
ruoyi-ui/src/utils/generator/css.js | 6 +-
ruoyi-ui/src/utils/generator/db.js | 64 ++
.../src/utils/generator/drawingDefalut.js | 42 +-
ruoyi-ui/src/utils/generator/html.js | 241 ++++---
ruoyi-ui/src/utils/generator/index.js | 102 +++
ruoyi-ui/src/utils/generator/js.js | 153 +++--
.../src/utils/generator/loadBeautifier.js | 26 +
ruoyi-ui/src/utils/generator/loadMonaco.js | 42 ++
ruoyi-ui/src/utils/generator/loadScript.js | 60 ++
ruoyi-ui/src/utils/generator/loadTinymce.js | 26 +
.../src/utils/generator/parser/Parser.vue | 166 +++++
ruoyi-ui/src/utils/generator/parser/README.md | 17 +
.../utils/generator/parser/example/Index.vue | 264 ++++++++
ruoyi-ui/src/utils/generator/parser/index.js | 3 +
.../src/utils/generator/parser/package.json | 25 +
ruoyi-ui/src/utils/generator/render.js | 2 +-
.../src/utils/generator/render/package.json | 19 +
ruoyi-ui/src/utils/generator/render/render.js | 59 ++
.../utils/generator/render/slots/el-button.js | 5 +
.../render/slots/el-checkbox-group.js | 13 +
.../utils/generator/render/slots/el-input.js | 8 +
.../generator/render/slots/el-radio-group.js | 13 +
.../utils/generator/render/slots/el-select.js | 9 +
.../utils/generator/render/slots/el-upload.js | 17 +
ruoyi-ui/src/utils/generator/ruleTrigger.js | 17 +
.../src/utils/generator/tinymce/config.js | 8 +
.../src/utils/generator/tinymce/index.vue | 93 +++
ruoyi-ui/src/utils/generator/tinymce/zh_CN.js | 420 ++++++++++++
ruoyi-ui/src/views/system/form/index.vue | 325 +++++++++
.../src/views/tool/build/CodeTypeDialog.vue | 4 +
.../src/views/tool/build/DraggableItem.vue | 46 +-
ruoyi-ui/src/views/tool/build/FormDrawer.vue | 341 ++++++++++
ruoyi-ui/src/views/tool/build/JsonDrawer.vue | 147 ++++
.../src/views/tool/build/ResourceDialog.vue | 114 ++++
ruoyi-ui/src/views/tool/build/RightPanel.vue | 263 +++++---
.../src/views/tool/build/TreeNodeDialog.vue | 13 +-
ruoyi-ui/src/views/tool/build/index.vue | 445 ++++++-------
ruoyi-ui/src/views/tool/build/preview/main.js | 64 ++
ruoyi-ui/vue.config.js | 40 +-
.../controller/PCommFormController.java | 103 +++
.../project/system/domain/PCommForm.java | 112 ++++
.../system/mapper/PCommFormMapper.java | 61 ++
.../system/service/IPCommFormService.java | 61 ++
.../service/impl/PCommFormServiceImpl.java | 96 +++
.../src/main/resources/application-druid.yml | 6 +-
ruoyi/src/main/resources/application.yml | 10 +-
.../mybatis/system/PCommFormMapper.xml | 93 +++
59 files changed, 4498 insertions(+), 955 deletions(-)
create mode 100644 ruoyi-ui/public/preview.html
create mode 100644 ruoyi-ui/src/api/system/form.js
create mode 100644 ruoyi-ui/src/assets/icons/svg/button.svg
create mode 100644 ruoyi-ui/src/assets/icons/svg/rich-text.svg
create mode 100644 ruoyi-ui/src/utils/generator/db.js
create mode 100644 ruoyi-ui/src/utils/generator/index.js
create mode 100644 ruoyi-ui/src/utils/generator/loadBeautifier.js
create mode 100644 ruoyi-ui/src/utils/generator/loadMonaco.js
create mode 100644 ruoyi-ui/src/utils/generator/loadScript.js
create mode 100644 ruoyi-ui/src/utils/generator/loadTinymce.js
create mode 100644 ruoyi-ui/src/utils/generator/parser/Parser.vue
create mode 100644 ruoyi-ui/src/utils/generator/parser/README.md
create mode 100644 ruoyi-ui/src/utils/generator/parser/example/Index.vue
create mode 100644 ruoyi-ui/src/utils/generator/parser/index.js
create mode 100644 ruoyi-ui/src/utils/generator/parser/package.json
create mode 100644 ruoyi-ui/src/utils/generator/render/package.json
create mode 100644 ruoyi-ui/src/utils/generator/render/render.js
create mode 100644 ruoyi-ui/src/utils/generator/render/slots/el-button.js
create mode 100644 ruoyi-ui/src/utils/generator/render/slots/el-checkbox-group.js
create mode 100644 ruoyi-ui/src/utils/generator/render/slots/el-input.js
create mode 100644 ruoyi-ui/src/utils/generator/render/slots/el-radio-group.js
create mode 100644 ruoyi-ui/src/utils/generator/render/slots/el-select.js
create mode 100644 ruoyi-ui/src/utils/generator/render/slots/el-upload.js
create mode 100644 ruoyi-ui/src/utils/generator/ruleTrigger.js
create mode 100644 ruoyi-ui/src/utils/generator/tinymce/config.js
create mode 100644 ruoyi-ui/src/utils/generator/tinymce/index.vue
create mode 100644 ruoyi-ui/src/utils/generator/tinymce/zh_CN.js
create mode 100644 ruoyi-ui/src/views/system/form/index.vue
create mode 100644 ruoyi-ui/src/views/tool/build/FormDrawer.vue
create mode 100644 ruoyi-ui/src/views/tool/build/JsonDrawer.vue
create mode 100644 ruoyi-ui/src/views/tool/build/ResourceDialog.vue
create mode 100644 ruoyi-ui/src/views/tool/build/preview/main.js
create mode 100644 ruoyi/src/main/java/com/ruoyi/project/system/controller/PCommFormController.java
create mode 100644 ruoyi/src/main/java/com/ruoyi/project/system/domain/PCommForm.java
create mode 100644 ruoyi/src/main/java/com/ruoyi/project/system/mapper/PCommFormMapper.java
create mode 100644 ruoyi/src/main/java/com/ruoyi/project/system/service/IPCommFormService.java
create mode 100644 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/PCommFormServiceImpl.java
create mode 100644 ruoyi/src/main/resources/mybatis/system/PCommFormMapper.xml
diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 62c2bddb1..60d9c7193 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -1,109 +1,114 @@
-{
- "name": "ruoyi",
- "version": "2.2.0",
- "description": "若依管理系统",
- "author": "若依",
- "license": "MIT",
- "scripts": {
- "dev": "vue-cli-service serve",
- "build:prod": "vue-cli-service build",
- "build:stage": "vue-cli-service build --mode staging",
- "preview": "node build/index.js --preview",
- "lint": "eslint --ext .js,.vue src",
- "test:unit": "jest --clearCache && vue-cli-service test:unit",
- "test:ci": "npm run lint && npm run test:unit",
- "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
- "new": "plop"
- },
- "husky": {
- "hooks": {
- "pre-commit": "lint-staged"
- }
- },
- "lint-staged": {
- "src/**/*.{js,vue}": [
- "eslint --fix",
- "git add"
- ]
- },
- "keywords": [
- "vue",
- "admin",
- "dashboard",
- "element-ui",
- "boilerplate",
- "admin-template",
- "management-system"
- ],
- "repository": {
- "type": "git",
- "url": "https://gitee.com/y_project/RuoYi-Vue.git"
- },
- "dependencies": {
- "@riophae/vue-treeselect": "0.4.0",
- "axios": "0.18.1",
- "clipboard": "2.0.4",
- "echarts": "4.2.1",
- "element-ui": "2.13.0",
- "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",
- "normalize.css": "7.0.0",
- "nprogress": "0.2.0",
- "path-to-regexp": "2.4.0",
- "screenfull": "4.2.0",
- "sortablejs": "1.8.4",
- "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",
- "@vue/cli-service": "3.5.3",
- "@vue/test-utils": "1.0.0-beta.29",
- "autoprefixer": "^9.5.1",
- "babel-core": "7.0.0-bridge.0",
- "babel-eslint": "10.0.1",
- "babel-jest": "23.6.0",
- "chalk": "2.4.2",
- "chokidar": "2.1.5",
- "connect": "3.6.6",
- "eslint": "5.15.3",
- "eslint-plugin-vue": "5.2.2",
- "html-webpack-plugin": "3.2.0",
- "http-proxy-middleware": "^0.19.1",
- "husky": "1.3.1",
- "lint-staged": "8.1.5",
- "mockjs": "1.0.1-beta3",
- "node-sass": "^4.9.0",
- "plop": "2.3.0",
- "runjs": "^4.3.2",
- "sass-loader": "^7.1.0",
- "script-ext-html-webpack-plugin": "2.1.3",
- "script-loader": "0.7.2",
- "serve-static": "^1.13.2",
- "svg-sprite-loader": "4.1.3",
- "svgo": "1.2.0",
- "vue-template-compiler": "2.6.10"
- },
- "engines": {
- "node": ">=8.9",
- "npm": ">= 3.0.0"
- },
- "browserslist": [
- "> 1%",
- "last 2 versions"
- ]
-}
+{
+ "name": "ruoyi",
+ "version": "2.2.0",
+ "description": "若依管理系统",
+ "author": "若依",
+ "license": "MIT",
+ "scripts": {
+ "dev": "vue-cli-service serve",
+ "build:prod": "vue-cli-service build",
+ "build:stage": "vue-cli-service build --mode staging",
+ "preview": "node build/index.js --preview",
+ "lint": "eslint --ext .js,.vue src",
+ "test:unit": "jest --clearCache && vue-cli-service test:unit",
+ "test:ci": "npm run lint && npm run test:unit",
+ "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
+ "new": "plop"
+ },
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "lint-staged": {
+ "src/**/*.{js,vue}": [
+ "eslint --fix",
+ "git add"
+ ]
+ },
+ "keywords": [
+ "vue",
+ "admin",
+ "dashboard",
+ "element-ui",
+ "boilerplate",
+ "admin-template",
+ "management-system"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://gitee.com/y_project/RuoYi-Vue.git"
+ },
+ "dependencies": {
+ "@riophae/vue-treeselect": "0.4.0",
+ "axios": "0.18.1",
+ "clipboard": "2.0.4",
+ "echarts": "4.2.1",
+ "element-ui": "2.12.0",
+ "file-saver": "2.0.1",
+ "fuse.js": "3.4.4",
+ "js-beautify": "^1.10.2",
+ "js-cookie": "2.2.0",
+ "jsencrypt": "3.0.0-rc.1",
+ "monaco-editor": "^0.20.0",
+ "monaco-editor-webpack-plugin": "^1.9.0",
+ "normalize.css": "7.0.0",
+ "nprogress": "0.2.0",
+ "path-to-regexp": "2.4.0",
+ "screenfull": "4.2.0",
+ "sortablejs": "1.8.4",
+ "vue": "2.6.10",
+ "vue-count-to": "1.0.13",
+ "vue-cropper": "0.4.9",
+ "vue-quill-editor": "3.0.6",
+ "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/parser": "^7.7.4",
+ "@babel/register": "7.0.0",
+ "@vue/cli-plugin-babel": "3.5.3",
+ "@vue/cli-plugin-eslint": "^3.9.1",
+ "@vue/cli-plugin-unit-jest": "3.5.3",
+ "@vue/cli-service": "3.5.3",
+ "@vue/test-utils": "1.0.0-beta.29",
+ "autoprefixer": "^9.5.1",
+ "babel-core": "7.0.0-bridge.0",
+ "babel-eslint": "10.0.1",
+ "babel-jest": "23.6.0",
+ "chalk": "2.4.2",
+ "chokidar": "2.1.5",
+ "connect": "3.6.6",
+ "eslint": "5.15.3",
+ "eslint-config-airbnb-base": "^14.0.0",
+ "eslint-plugin-import": "^2.20.0",
+ "eslint-plugin-vue": "5.2.2",
+ "html-webpack-plugin": "3.2.0",
+ "http-proxy-middleware": "^0.19.1",
+ "husky": "1.3.1",
+ "lint-staged": "8.1.5",
+ "mockjs": "1.0.1-beta3",
+ "monaco-editor-webpack-plugin": "^1.9.0",
+ "node-sass": "^4.9.0",
+ "plop": "2.3.0",
+ "runjs": "^4.3.2",
+ "sass-loader": "^7.1.0",
+ "script-ext-html-webpack-plugin": "2.1.3",
+ "script-loader": "0.7.2",
+ "serve-static": "^1.13.2",
+ "svg-sprite-loader": "4.1.3",
+ "svgo": "1.2.0",
+ "vue-template-compiler": "2.6.10"
+ },
+ "engines": {
+ "node": ">=8.9",
+ "npm": ">= 3.0.0"
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions"
+ ]
+}
diff --git a/ruoyi-ui/public/preview.html b/ruoyi-ui/public/preview.html
new file mode 100644
index 000000000..409ae7425
--- /dev/null
+++ b/ruoyi-ui/public/preview.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+ form-generator-preview
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/form.js b/ruoyi-ui/src/api/system/form.js
new file mode 100644
index 000000000..ed1048e2d
--- /dev/null
+++ b/ruoyi-ui/src/api/system/form.js
@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询数据模型列表
+export function listForm(query) {
+ return request({
+ url: '/system/form/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询数据模型详细
+export function getForm(formId) {
+ return request({
+ url: '/system/form/' + formId,
+ method: 'get'
+ })
+}
+
+// 新增数据模型
+export function addForm(data) {
+ return request({
+ url: '/system/form',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改数据模型
+export function updateForm(data) {
+ return request({
+ url: '/system/form',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除数据模型
+export function delForm(formId) {
+ return request({
+ url: '/system/form/' + formId,
+ method: 'delete'
+ })
+}
+
+// 导出数据模型
+export function exportForm(query) {
+ return request({
+ url: '/system/form/export',
+ method: 'get',
+ params: query
+ })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/button.svg b/ruoyi-ui/src/assets/icons/svg/button.svg
new file mode 100644
index 000000000..904fddc85
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/button.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/rich-text.svg b/ruoyi-ui/src/assets/icons/svg/rich-text.svg
new file mode 100644
index 000000000..76c45bfe3
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/rich-text.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/styles/index.scss b/ruoyi-ui/src/assets/styles/index.scss
index 9f536ae80..8c819125c 100644
--- a/ruoyi-ui/src/assets/styles/index.scss
+++ b/ruoyi-ui/src/assets/styles/index.scss
@@ -189,3 +189,130 @@ aside {
.multiselect--active {
z-index: 1000 !important;
}
+
+
+
+//form desigen 全局样式
+$editorTabsborderColor: #121315;
+.editor-tabs{
+ background: $editorTabsborderColor;
+ .el-tabs__header{
+ margin: 0;
+ border-bottom-color: $editorTabsborderColor;
+ .el-tabs__nav{
+ border-color: $editorTabsborderColor;
+ }
+ }
+ .el-tabs__item{
+ height: 32px;
+ line-height: 32px;
+ color: #888a8e;
+ border-left: 1px solid $editorTabsborderColor!important;
+ background: #363636;
+ margin-right: 5px;
+ user-select: none;
+ }
+ .el-tabs__item.is-active{
+ background: #1e1e1e;
+ border-bottom-color: #1e1e1e!important;
+ color: #fff;
+ }
+ .el-icon-edit{
+ color: #f1fa8c;
+ }
+ .el-icon-document{
+ color: #a95812;
+ }
+}
+
+// home
+.right-scrollbar {
+ .el-scrollbar__view {
+ padding: 12px 18px 15px 15px;
+ }
+}
+.el-scrollbar__wrap {
+ box-sizing: border-box;
+ overflow-x: hidden !important;
+ margin-bottom: 0 !important;
+}
+.center-tabs{
+ .el-tabs__header{
+ margin-bottom: 0!important;
+ }
+ .el-tabs__item{
+ width: 50%;
+ text-align: center;
+ }
+ .el-tabs__nav{
+ width: 100%;
+ }
+}
+.reg-item{
+ padding: 12px 6px;
+ background: #f8f8f8;
+ position: relative;
+ border-radius: 4px;
+ .close-btn{
+ position: absolute;
+ right: -6px;
+ top: -6px;
+ display: block;
+ width: 16px;
+ height: 16px;
+ line-height: 16px;
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 50%;
+ color: #fff;
+ text-align: center;
+ z-index: 1;
+ cursor: pointer;
+ font-size: 12px;
+ &:hover{
+ background: rgba(210, 23, 23, 0.5)
+ }
+ }
+ & + .reg-item{
+ margin-top: 18px;
+ }
+}
+.action-bar{
+ & .el-button+.el-button {
+ margin-left: 15px;
+ }
+ & i {
+ font-size: 20px;
+ vertical-align: middle;
+ position: relative;
+ top: -1px;
+ }
+}
+
+.custom-tree-node{
+ width: 100%;
+ font-size: 14px;
+ .node-operation{
+ float: right;
+ }
+ i[class*="el-icon"] + i[class*="el-icon"]{
+ margin-left: 6px;
+ }
+ .el-icon-plus{
+ color: #409EFF;
+ }
+ .el-icon-delete{
+ color: #157a0c;
+ }
+}
+
+.el-scrollbar__view{
+ overflow-x: hidden;
+}
+
+.el-rate{
+ display: inline-block;
+ vertical-align: text-top;
+}
+.el-upload__tip{
+ line-height: 1.2;
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/styles/mixin.scss b/ruoyi-ui/src/assets/styles/mixin.scss
index 64d9cf6fe..b0a00e202 100644
--- a/ruoyi-ui/src/assets/styles/mixin.scss
+++ b/ruoyi-ui/src/assets/styles/mixin.scss
@@ -64,3 +64,37 @@
border-bottom: $transparent-border-style;
}
}
+
+@mixin action-bar {
+ .action-bar {
+ height: 33px;
+ background: #f2fafb;
+ padding: 0 15px;
+ box-sizing: border-box;
+
+ .bar-btn {
+ display: inline-block;
+ padding: 0 6px;
+ line-height: 32px;
+ color: #8285f5;
+ cursor: pointer;
+ font-size: 14px;
+ user-select: none;
+ & i {
+ font-size: 20px;
+ }
+ &:hover {
+ color: #4348d4;
+ }
+ }
+ .bar-btn + .bar-btn {
+ margin-left: 8px;
+ }
+ .delete-btn {
+ color: #f56c6c;
+ &:hover {
+ color: #ea0b30;
+ }
+ }
+ }
+}
diff --git a/ruoyi-ui/src/assets/styles/ruoyi.scss b/ruoyi-ui/src/assets/styles/ruoyi.scss
index b6c40ac9f..fa076517d 100644
--- a/ruoyi-ui/src/assets/styles/ruoyi.scss
+++ b/ruoyi-ui/src/assets/styles/ruoyi.scss
@@ -190,8 +190,8 @@
}
/* 拖拽列样式 */
-.sortable-ghost{
- opacity: .8;
- color: #fff!important;
- background: #42b983!important;
-}
\ No newline at end of file
+// .sortable-ghost{
+// opacity: .8;
+// color: #fff!important;
+// background: #42b983!important;
+// }
\ No newline at end of file
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
index c2834bf76..0ba87a3ca 100644
--- a/ruoyi-ui/src/main.js
+++ b/ruoyi-ui/src/main.js
@@ -47,7 +47,6 @@ Vue.prototype.msgInfo = function (msg) {
Vue.component('Pagination', Pagination)
Vue.use(permission)
-
/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
diff --git a/ruoyi-ui/src/permission.js b/ruoyi-ui/src/permission.js
index 1813f429f..3961b2a8c 100644
--- a/ruoyi-ui/src/permission.js
+++ b/ruoyi-ui/src/permission.js
@@ -7,45 +7,52 @@ import { getToken } from '@/utils/auth'
NProgress.configure({ showSpinner: false })
-const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
+const whiteList = ['/login', '/auth-redirect', '/bind', '/register','/preview.html']
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken()) {
/* has token*/
- if (to.path === '/login') {
- next({ path: '/' })
- NProgress.done()
- } else {
- if (store.getters.roles.length === 0) {
- // 判断当前用户是否已拉取完user_info信息
- store.dispatch('GetInfo').then(res => {
- // 拉取user_info
- const roles = res.roles
- store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => {
- // 测试 默认静态页面
- // store.dispatch('permission/generateRoutes', { roles }).then(accessRoutes => {
- // 根据roles权限生成可访问的路由表
- router.addRoutes(accessRoutes) // 动态添加可访问路由表
- next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
- })
- })
- .catch(err => {
- store.dispatch('FedLogOut').then(() => {
- Message.error(err)
- next({ path: '/' })
+ if (whiteList.indexOf(to.path) !== -1) {
+ // 在免登录白名单,直接进入
+ next()
+ }else{
+
+ if (to.path === '/login') {
+ next({ path: '/' })
+ NProgress.done()
+ } else {
+ if (store.getters.roles.length === 0) {
+ // 判断当前用户是否已拉取完user_info信息
+ store.dispatch('GetInfo').then(res => {
+ // 拉取user_info
+ const roles = res.roles
+ store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => {
+ // 测试 默认静态页面
+ // store.dispatch('permission/generateRoutes', { roles }).then(accessRoutes => {
+ // 根据roles权限生成可访问的路由表
+ router.addRoutes(accessRoutes) // 动态添加可访问路由表
+ next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
})
})
- } else {
- next()
- // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
- // if (hasPermission(store.getters.roles, to.meta.roles)) {
- // next()
- // } else {
- // next({ path: '/401', replace: true, query: { noGoBack: true }})
- // }
- // 可删 ↑
+ .catch(err => {
+ store.dispatch('FedLogOut').then(() => {
+ Message.error(err)
+ next({ path: '/' })
+ })
+ })
+ } else {
+ next()
+ // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
+ // if (hasPermission(store.getters.roles, to.meta.roles)) {
+ // next()
+ // } else {
+ // next({ path: '/401', replace: true, query: { noGoBack: true }})
+ // }
+ // 可删 ↑
+ }
}
+
}
} else {
// 没有token
diff --git a/ruoyi-ui/src/store/index.js b/ruoyi-ui/src/store/index.js
index eceb2cd2b..e534b4429 100644
--- a/ruoyi-ui/src/store/index.js
+++ b/ruoyi-ui/src/store/index.js
@@ -8,7 +8,7 @@ import settings from './modules/settings'
import getters from './getters'
Vue.use(Vuex)
-
+Vue.config.devtools = process.env.NODE_ENV === 'development'
const store = new Vuex.Store({
modules: {
app,
diff --git a/ruoyi-ui/src/utils/generator/config.js b/ruoyi-ui/src/utils/generator/config.js
index 471f83879..238e4104b 100644
--- a/ruoyi-ui/src/utils/generator/config.js
+++ b/ruoyi-ui/src/utils/generator/config.js
@@ -1,3 +1,4 @@
+// 表单属性【右面板】
export const formConf = {
formRef: 'elForm',
formModel: 'formData',
@@ -11,39 +12,58 @@ export const formConf = {
formBtns: true
}
+// 输入型组件 【左面板】
export const inputComponents = [
{
- label: '单行文本',
- tag: 'el-input',
- tagIcon: 'input',
+ // 组件的自定义配置
+ __config__: {
+ label: '单行文本',
+ labelWidth: null,
+ showLabel: true,
+ changeTag: true,
+ tag: 'el-input',
+ tagIcon: 'input',
+ defaultValue: undefined,
+ required: true,
+ layout: 'colFormItem',
+ span: 24,
+ document: 'https://element.eleme.cn/#/zh-CN/component/input',
+ // 正则校验规则
+ regList: []
+ },
+ // 组件的插槽属性
+ __slot__: {
+ prepend: '',
+ append: ''
+ },
+ // 其余的为可直接写在组件标签上的属性
placeholder: '请输入',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
style: { width: '100%' },
clearable: true,
- prepend: '',
- append: '',
'prefix-icon': '',
'suffix-icon': '',
maxlength: null,
'show-word-limit': false,
readonly: false,
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ disabled: false
},
{
- label: '多行文本',
- tag: 'el-input',
- tagIcon: 'textarea',
+ __config__: {
+ label: '多行文本',
+ labelWidth: null,
+ showLabel: true,
+ tag: 'el-input',
+ tagIcon: 'textarea',
+ defaultValue: undefined,
+ required: true,
+ layout: 'colFormItem',
+ span: 24,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ },
type: 'textarea',
placeholder: '请输入',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
autosize: {
minRows: 4,
maxRows: 4
@@ -52,103 +72,131 @@ export const inputComponents = [
maxlength: null,
'show-word-limit': false,
readonly: false,
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ disabled: false
},
{
- label: '密码',
- tag: 'el-input',
- tagIcon: 'password',
+ __config__: {
+ label: '密码',
+ showLabel: true,
+ labelWidth: null,
+ changeTag: true,
+ tag: 'el-input',
+ tagIcon: 'password',
+ defaultValue: undefined,
+ layout: 'colFormItem',
+ span: 24,
+ required: true,
+ regList: [],
+ document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ },
+ __slot__: {
+ prepend: '',
+ append: ''
+ },
placeholder: '请输入',
- defaultValue: undefined,
- span: 24,
'show-password': true,
- labelWidth: null,
style: { width: '100%' },
clearable: true,
- prepend: '',
- append: '',
'prefix-icon': '',
'suffix-icon': '',
maxlength: null,
'show-word-limit': false,
readonly: false,
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ disabled: false
},
{
- label: '计数器',
- tag: 'el-input-number',
- tagIcon: 'number',
+ __config__: {
+ label: '计数器',
+ showLabel: true,
+ changeTag: true,
+ labelWidth: null,
+ tag: 'el-input-number',
+ tagIcon: 'number',
+ defaultValue: undefined,
+ span: 24,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
+ },
placeholder: '',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
min: undefined,
max: undefined,
- step: undefined,
+ step: 1,
'step-strictly': false,
precision: undefined,
'controls-position': '',
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
+ disabled: false
+ },
+ {
+ __config__: {
+ label: '编辑器',
+ showLabel: true,
+ changeTag: true,
+ labelWidth: null,
+ tag: 'tinymce',
+ tagIcon: 'rich-text',
+ defaultValue: null,
+ span: 24,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ document: 'http://tinymce.ax-z.cn'
+ },
+ height: 300, // 编辑器高度
+ branding: false // 隐藏右下角品牌烙印
}
]
+// 选择型组件 【左面板】
export const selectComponents = [
{
- label: '下拉选择',
- tag: 'el-select',
- tagIcon: 'select',
+ __config__: {
+ label: '下拉选择',
+ showLabel: true,
+ labelWidth: null,
+ tag: 'el-select',
+ tagIcon: 'select',
+ defaultValue: undefined,
+ layout: 'colFormItem',
+ span: 24,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/select'
+ },
+ __slot__: {
+ options: [{
+ label: '选项一',
+ value: 1
+ }, {
+ label: '选项二',
+ value: 2
+ }]
+ },
placeholder: '请选择',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
style: { width: '100%' },
clearable: true,
disabled: false,
- required: true,
filterable: false,
- multiple: false,
- options: [{
- label: '选项一',
- value: 1
- }, {
- label: '选项二',
- value: 2
- }],
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/select'
+ multiple: false
},
{
- label: '级联选择',
- tag: 'el-cascader',
- tagIcon: 'cascader',
- placeholder: '请选择',
- defaultValue: [],
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- props: {
- props: {
- multiple: false
- }
+ __config__: {
+ label: '级联选择',
+ showLabel: true,
+ labelWidth: null,
+ tag: 'el-cascader',
+ tagIcon: 'cascader',
+ layout: 'colFormItem',
+ defaultValue: [],
+ dataType: 'dynamic',
+ span: 24,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
},
- 'show-all-levels': true,
- disabled: false,
- clearable: true,
- filterable: false,
- required: true,
options: [{
id: 1,
value: 1,
@@ -159,170 +207,219 @@ export const selectComponents = [
label: '选项1-1'
}]
}],
- dataType: 'dynamic',
- labelKey: 'label',
- valueKey: 'value',
- childrenKey: 'children',
- separator: '/',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
+ placeholder: '请选择',
+ style: { width: '100%' },
+ props: {
+ props: {
+ multiple: false,
+ label: 'label',
+ value: 'value',
+ children: 'children'
+ }
+ },
+ 'show-all-levels': true,
+ disabled: false,
+ clearable: true,
+ filterable: false,
+ separator: '/'
},
{
- label: '单选框组',
- tag: 'el-radio-group',
- tagIcon: 'radio',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
+ __config__: {
+ label: '单选框组',
+ labelWidth: null,
+ showLabel: true,
+ tag: 'el-radio-group',
+ tagIcon: 'radio',
+ changeTag: true,
+ defaultValue: undefined,
+ layout: 'colFormItem',
+ span: 24,
+ optionType: 'default',
+ regList: [],
+ required: true,
+ border: false,
+ document: 'https://element.eleme.cn/#/zh-CN/component/radio'
+ },
+ __slot__: {
+ options: [{
+ label: '选项一',
+ value: 1
+ }, {
+ label: '选项二',
+ value: 2
+ }]
+ },
style: {},
- optionType: 'default',
- border: false,
size: 'medium',
- disabled: false,
- required: true,
- options: [{
- label: '选项一',
- value: 1
- }, {
- label: '选项二',
- value: 2
- }],
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/radio'
+ disabled: false
},
{
- label: '多选框组',
- tag: 'el-checkbox-group',
- tagIcon: 'checkbox',
- defaultValue: [],
- span: 24,
- labelWidth: null,
+ __config__: {
+ label: '多选框组',
+ tag: 'el-checkbox-group',
+ tagIcon: 'checkbox',
+ defaultValue: [],
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ optionType: 'default',
+ required: true,
+ regList: [],
+ changeTag: true,
+ border: false,
+ document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'
+ },
+ __slot__: {
+ options: [{
+ label: '选项一',
+ value: 1
+ }, {
+ label: '选项二',
+ value: 2
+ }]
+ },
style: {},
- optionType: 'default',
- border: false,
size: 'medium',
- disabled: false,
- required: true,
- options: [{
- label: '选项一',
- value: 1
- }, {
- label: '选项二',
- value: 2
- }],
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'
+ min: null,
+ max: null,
+ disabled: false
},
{
- label: '开关',
- tag: 'el-switch',
- tagIcon: 'switch',
- defaultValue: false,
- span: 24,
- labelWidth: null,
+ __config__: {
+ label: '开关',
+ tag: 'el-switch',
+ tagIcon: 'switch',
+ defaultValue: false,
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/switch'
+ },
style: {},
disabled: false,
- required: true,
'active-text': '',
'inactive-text': '',
'active-color': null,
'inactive-color': null,
'active-value': true,
- 'inactive-value': false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/switch'
+ 'inactive-value': false
},
{
- label: '滑块',
- tag: 'el-slider',
- tagIcon: 'slider',
- defaultValue: null,
- span: 24,
- labelWidth: null,
+ __config__: {
+ label: '滑块',
+ tag: 'el-slider',
+ tagIcon: 'slider',
+ defaultValue: null,
+ span: 24,
+ showLabel: true,
+ layout: 'colFormItem',
+ labelWidth: null,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/slider'
+ },
disabled: false,
- required: true,
min: 0,
max: 100,
step: 1,
'show-stops': false,
- range: false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/slider'
+ range: false
},
{
- label: '时间选择',
- tag: 'el-time-picker',
- tagIcon: 'time',
+ __config__: {
+ label: '时间选择',
+ tag: 'el-time-picker',
+ tagIcon: 'time',
+ defaultValue: null,
+ span: 24,
+ showLabel: true,
+ layout: 'colFormItem',
+ labelWidth: null,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+ },
placeholder: '请选择',
- defaultValue: null,
- span: 24,
- labelWidth: null,
style: { width: '100%' },
disabled: false,
clearable: true,
- required: true,
'picker-options': {
selectableRange: '00:00:00-23:59:59'
},
format: 'HH:mm:ss',
- 'value-format': 'HH:mm:ss',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+ 'value-format': 'HH:mm:ss'
},
{
- label: '时间范围',
- tag: 'el-time-picker',
- tagIcon: 'time-range',
- defaultValue: null,
- span: 24,
- labelWidth: null,
+ __config__: {
+ label: '时间范围',
+ tag: 'el-time-picker',
+ tagIcon: 'time-range',
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ defaultValue: null,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+ },
style: { width: '100%' },
disabled: false,
clearable: true,
- required: true,
'is-range': true,
'range-separator': '至',
'start-placeholder': '开始时间',
'end-placeholder': '结束时间',
format: 'HH:mm:ss',
- 'value-format': 'HH:mm:ss',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+ 'value-format': 'HH:mm:ss'
},
{
- label: '日期选择',
- tag: 'el-date-picker',
- tagIcon: 'date',
+ __config__: {
+ label: '日期选择',
+ tag: 'el-date-picker',
+ tagIcon: 'date',
+ defaultValue: null,
+ showLabel: true,
+ labelWidth: null,
+ span: 24,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+ },
placeholder: '请选择',
- defaultValue: null,
type: 'date',
- span: 24,
- labelWidth: null,
style: { width: '100%' },
disabled: false,
clearable: true,
- required: true,
format: 'yyyy-MM-dd',
'value-format': 'yyyy-MM-dd',
- readonly: false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+ readonly: false
},
{
- label: '日期范围',
- tag: 'el-date-picker',
- tagIcon: 'date-range',
- defaultValue: null,
- span: 24,
- labelWidth: null,
+ __config__: {
+ label: '日期范围',
+ tag: 'el-date-picker',
+ tagIcon: 'date-range',
+ defaultValue: null,
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ required: true,
+ layout: 'colFormItem',
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+ },
style: { width: '100%' },
type: 'daterange',
'range-separator': '至',
@@ -330,94 +427,121 @@ export const selectComponents = [
'end-placeholder': '结束日期',
disabled: false,
clearable: true,
- required: true,
format: 'yyyy-MM-dd',
'value-format': 'yyyy-MM-dd',
- readonly: false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+ readonly: false
},
{
- label: '评分',
- tag: 'el-rate',
- tagIcon: 'rate',
- defaultValue: 0,
- span: 24,
- labelWidth: null,
+ __config__: {
+ label: '评分',
+ tag: 'el-rate',
+ tagIcon: 'rate',
+ defaultValue: 0,
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/rate'
+ },
style: {},
max: 5,
'allow-half': false,
'show-text': false,
'show-score': false,
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/rate'
+ disabled: false
},
{
- label: '颜色选择',
- tag: 'el-color-picker',
- tagIcon: 'color',
- defaultValue: null,
- labelWidth: null,
+ __config__: {
+ label: '颜色选择',
+ tag: 'el-color-picker',
+ tagIcon: 'color',
+ span: 24,
+ defaultValue: null,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
+ },
'show-alpha': false,
'color-format': '',
disabled: false,
- required: true,
- size: 'medium',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
+ size: 'medium'
},
{
- label: '上传',
- tag: 'el-upload',
- tagIcon: 'upload',
+ __config__: {
+ label: '上传',
+ tag: 'el-upload',
+ tagIcon: 'upload',
+ layout: 'colFormItem',
+ defaultValue: null,
+ showLabel: true,
+ labelWidth: null,
+ required: true,
+ span: 24,
+ showTip: false,
+ buttonText: '点击上传',
+ regList: [],
+ changeTag: true,
+ fileSize: 2,
+ sizeUnit: 'MB',
+ document: 'https://element.eleme.cn/#/zh-CN/component/upload'
+ },
+ __slot__: {
+ 'list-type': true
+ },
action: 'https://jsonplaceholder.typicode.com/posts/',
- defaultValue: null,
- labelWidth: null,
disabled: false,
- required: true,
accept: '',
name: 'file',
'auto-upload': true,
- showTip: false,
- buttonText: '点击上传',
- fileSize: 2,
- sizeUnit: 'MB',
'list-type': 'text',
- multiple: false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/upload'
+ multiple: false
}
]
+// 布局型组件 【左面板】
export const layoutComponents = [
{
- layout: 'rowFormItem',
- tagIcon: 'row',
+ __config__: {
+ layout: 'rowFormItem',
+ tagIcon: 'row',
+ label: '行容器',
+ layoutTree: true,
+ children: [],
+ document: 'https://element.eleme.cn/#/zh-CN/component/layout'
+ },
type: 'default',
justify: 'start',
- align: 'top',
- label: '行容器',
- layoutTree: true,
- children: [],
- document: 'https://element.eleme.cn/#/zh-CN/component/layout'
+ align: 'top'
+ },
+ {
+ __config__: {
+ label: '按钮',
+ showLabel: true,
+ changeTag: true,
+ labelWidth: null,
+ tag: 'el-button',
+ tagIcon: 'button',
+ defaultValue: undefined,
+ span: 24,
+ layout: 'colFormItem',
+ document: 'https://element.eleme.cn/#/zh-CN/component/button'
+ },
+ __slot__: {
+ default: '主要按钮'
+ },
+ type: 'primary',
+ icon: 'el-icon-search',
+ round: false,
+ size: 'medium',
+ plain: false,
+ circle: false,
+ disabled: false
}
]
-
-// 组件rule的触发方式,无触发方式的组件不生成rule
-export const trigger = {
- 'el-input': 'blur',
- 'el-input-number': 'blur',
- 'el-select': 'change',
- 'el-radio-group': 'change',
- 'el-checkbox-group': 'change',
- 'el-cascader': 'change',
- 'el-time-picker': 'change',
- 'el-date-picker': 'change',
- 'el-rate': 'change'
-}
diff --git a/ruoyi-ui/src/utils/generator/css.js b/ruoyi-ui/src/utils/generator/css.js
index 0d7f07526..71ba31b76 100644
--- a/ruoyi-ui/src/utils/generator/css.js
+++ b/ruoyi-ui/src/utils/generator/css.js
@@ -4,10 +4,10 @@ const styles = {
}
function addCss(cssList, el) {
- const css = styles[el.tag]
+ const css = styles[el.__config__.tag]
css && cssList.indexOf(css) === -1 && cssList.push(css)
- if (el.children) {
- el.children.forEach(el2 => addCss(cssList, el2))
+ if (el.__config__.children) {
+ el.__config__.children.forEach(el2 => addCss(cssList, el2))
}
}
diff --git a/ruoyi-ui/src/utils/generator/db.js b/ruoyi-ui/src/utils/generator/db.js
new file mode 100644
index 000000000..25c551ec4
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/db.js
@@ -0,0 +1,64 @@
+const DRAWING_ITEMS = 'drawingItems'
+const DRAWING_ITEMS_VERSION = '1.1'
+const DRAWING_ITEMS_VERSION_KEY = 'DRAWING_ITEMS_VERSION'
+const DRAWING_ID = 'idGlobal'
+const TREE_NODE_ID = 'treeNodeId'
+const FORM_CONF = 'formConf'
+
+export function getDrawingList() {
+ // 加入缓存版本的概念,保证缓存数据与程序匹配
+ const version = localStorage.getItem(DRAWING_ITEMS_VERSION_KEY)
+ if (version !== DRAWING_ITEMS_VERSION) {
+ localStorage.setItem(DRAWING_ITEMS_VERSION_KEY, DRAWING_ITEMS_VERSION)
+ saveDrawingList([])
+ return null
+ }
+
+ const str = localStorage.getItem(DRAWING_ITEMS)
+ if (str) {
+ let result=null;
+ try {
+ result=JSON.parse(str)
+ } catch(err) {
+ console.log(err)
+ }
+ return result
+ }
+ return null
+}
+
+export function saveDrawingList(list) {
+ if(Array.isArray(list) && list.length > 0){
+ localStorage.setItem(DRAWING_ITEMS, JSON.stringify(list))
+ }
+}
+
+export function getIdGlobal() {
+ const str = localStorage.getItem(DRAWING_ID)
+ if (str) return parseInt(str, 10)
+ return 100
+}
+
+export function saveIdGlobal(id) {
+ localStorage.setItem(DRAWING_ID, `${id}`)
+}
+
+export function getTreeNodeId() {
+ const str = localStorage.getItem(TREE_NODE_ID)
+ if (str) return parseInt(str, 10)
+ return 100
+}
+
+export function saveTreeNodeId(id) {
+ localStorage.setItem(TREE_NODE_ID, `${id}`)
+}
+
+export function getFormConf() {
+ const str = localStorage.getItem(FORM_CONF)
+ if (str) return JSON.parse(str)
+ return null
+}
+
+export function saveFormConf(obj) {
+ localStorage.setItem(FORM_CONF, JSON.stringify(obj))
+}
diff --git a/ruoyi-ui/src/utils/generator/drawingDefalut.js b/ruoyi-ui/src/utils/generator/drawingDefalut.js
index 5f7d1c4ae..f9774d267 100644
--- a/ruoyi-ui/src/utils/generator/drawingDefalut.js
+++ b/ruoyi-ui/src/utils/generator/drawingDefalut.js
@@ -1,29 +1,37 @@
export default [
{
- layout: 'colFormItem',
- tagIcon: 'input',
- label: '手机号',
- vModel: 'mobile',
- formId: 6,
- tag: 'el-input',
+ __config__: {
+ label: '单行文本',
+ labelWidth: null,
+ showLabel: true,
+ changeTag: true,
+ tag: 'el-input',
+ tagIcon: 'input',
+ defaultValue: undefined,
+ required: true,
+ layout: 'colFormItem',
+ span: 24,
+ document: 'https://element.eleme.cn/#/zh-CN/component/input',
+ // 正则校验规则
+ regList: [{
+ pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
+ message: '手机号格式错误'
+ }]
+ },
+ // 组件的插槽属性
+ __slot__: {
+ prepend: '',
+ append: ''
+ },
+ __vModel__: 'mobile',
placeholder: '请输入手机号',
- defaultValue: '',
- span: 24,
style: { width: '100%' },
clearable: true,
- prepend: '',
- append: '',
'prefix-icon': 'el-icon-mobile',
'suffix-icon': '',
maxlength: 11,
'show-word-limit': true,
readonly: false,
- disabled: false,
- required: true,
- changeTag: true,
- regList: [{
- pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
- message: '手机号格式错误'
- }]
+ disabled: false
}
]
diff --git a/ruoyi-ui/src/utils/generator/html.js b/ruoyi-ui/src/utils/generator/html.js
index 8362ae4af..29bf31481 100644
--- a/ruoyi-ui/src/utils/generator/html.js
+++ b/ruoyi-ui/src/utils/generator/html.js
@@ -1,5 +1,5 @@
/* eslint-disable max-len */
-import { trigger } from './config'
+import ruleTrigger from './ruleTrigger'
let confGlobal
let someSpanIsNot24
@@ -34,27 +34,27 @@ export function cssStyle(cssStr) {
`
}
-function buildFormTemplate(conf, child, type) {
+function buildFormTemplate(scheme, child, type) {
let labelPosition = ''
- if (conf.labelPosition !== 'right') {
- labelPosition = `label-position="${conf.labelPosition}"`
+ if (scheme.labelPosition !== 'right') {
+ labelPosition = `label-position="${scheme.labelPosition}"`
}
- const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : ''
- let str = `
+ const disabled = scheme.disabled ? `:disabled="${scheme.disabled}"` : ''
+ let str = `
${child}
- ${buildFromBtns(conf, type)}
+ ${buildFromBtns(scheme, type)}
`
if (someSpanIsNot24) {
- str = `
+ str = `
${str}
`
}
return str
}
-function buildFromBtns(conf, type) {
+function buildFromBtns(scheme, type) {
let str = ''
- if (conf.formBtns && type === 'file') {
+ if (scheme.formBtns && type === 'file') {
str = `
提交
重置
@@ -69,9 +69,9 @@ function buildFromBtns(conf, type) {
}
// span不为24的用el-col包裹
-function colWrapper(element, str) {
- if (someSpanIsNot24 || element.span !== 24) {
- return `
+function colWrapper(scheme, str) {
+ if (someSpanIsNot24 || scheme.__config__.span !== 24) {
+ return `
${str}
`
}
@@ -79,37 +79,59 @@ function colWrapper(element, str) {
}
const layouts = {
- colFormItem(element) {
+ colFormItem(scheme) {
+ const config = scheme.__config__
let labelWidth = ''
- if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) {
- labelWidth = `label-width="${element.labelWidth}px"`
+ let label = `label="${config.label}"`
+ if (config.labelWidth && config.labelWidth !== confGlobal.labelWidth) {
+ labelWidth = `label-width="${config.labelWidth}px"`
}
- const required = !trigger[element.tag] && element.required ? 'required' : ''
- const tagDom = tags[element.tag] ? tags[element.tag](element) : null
- let str = `
+ if (config.showLabel === false) {
+ labelWidth = 'label-width="0"'
+ label = ''
+ }
+ const required = !ruleTrigger[config.tag] && config.required ? 'required' : ''
+ const tagDom = tags[config.tag] ? tags[config.tag](scheme) : null
+ let str = `
${tagDom}
`
- str = colWrapper(element, str)
+ str = colWrapper(scheme, 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))
+ rowFormItem(scheme) {
+ const config = scheme.__config__
+ const type = scheme.type === 'default' ? '' : `type="${scheme.type}"`
+ const justify = scheme.type === 'default' ? '' : `justify="${scheme.justify}"`
+ const align = scheme.type === 'default' ? '' : `align="${scheme.align}"`
+ const gutter = scheme.gutter ? `:gutter="${scheme.gutter}"` : ''
+ const children = config.children.map(el => layouts[el.__config__.layout](el))
let str = `
${children.join('\n')}
`
- str = colWrapper(element, str)
+ str = colWrapper(scheme, str)
return str
}
}
const tags = {
+ 'el-button': el => {
+ const {
+ tag, disabled
+ } = attrBuilder(el)
+ const type = el.type ? `type="${el.type}"` : ''
+ const icon = el.icon ? `icon="${el.icon}"` : ''
+ const round = el.round ? 'round' : ''
+ const size = el.size ? `size="${el.size}"` : ''
+ const plain = el.plain ? 'plain' : ''
+ const circle = el.circle ? 'circle' : ''
+ let child = buildElButtonChild(el)
+
+ if (child) child = `\n${child}\n` // 换行
+ return `<${tag} ${type} ${icon} ${round} ${size} ${plain} ${disabled} ${circle}>${child}${tag}>`
+ },
'el-input': el => {
const {
- disabled, vModel, clearable, placeholder, width
+ tag, disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''
const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''
@@ -124,10 +146,12 @@ const tags = {
let child = buildElInputChild(el)
if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}${el.tag}>`
+ return `<${tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}${tag}>`
},
'el-input-number': el => {
- const { disabled, vModel, placeholder } = attrBuilder(el)
+ const {
+ tag, disabled, vModel, placeholder
+ } = attrBuilder(el)
const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : ''
const min = el.min ? `:min='${el.min}'` : ''
const max = el.max ? `:max='${el.max}'` : ''
@@ -135,39 +159,39 @@ const tags = {
const stepStrictly = el['step-strictly'] ? 'step-strictly' : ''
const precision = el.precision ? `:precision='${el.precision}'` : ''
- return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}>${el.tag}>`
+ return `<${tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}>${tag}>`
},
'el-select': el => {
const {
- disabled, vModel, clearable, placeholder, width
+ tag, disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const filterable = el.filterable ? 'filterable' : ''
const multiple = el.multiple ? 'multiple' : ''
let child = buildElSelectChild(el)
if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}${el.tag}>`
+ return `<${tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}${tag}>`
},
'el-radio-group': el => {
- const { disabled, vModel } = attrBuilder(el)
+ const { tag, disabled, vModel } = attrBuilder(el)
const size = `size="${el.size}"`
let child = buildElRadioGroupChild(el)
if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${vModel} ${size} ${disabled}>${child}${el.tag}>`
+ return `<${tag} ${vModel} ${size} ${disabled}>${child}${tag}>`
},
'el-checkbox-group': el => {
- const { disabled, vModel } = attrBuilder(el)
+ const { tag, disabled, vModel } = attrBuilder(el)
const size = `size="${el.size}"`
const min = el.min ? `:min="${el.min}"` : ''
const max = el.max ? `:max="${el.max}"` : ''
let child = buildElCheckboxGroupChild(el)
if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}${el.tag}>`
+ return `<${tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}${tag}>`
},
'el-switch': el => {
- const { disabled, vModel } = attrBuilder(el)
+ const { tag, disabled, vModel } = attrBuilder(el)
const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : ''
const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : ''
const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : ''
@@ -175,33 +199,33 @@ const tags = {
const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : ''
const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : ''
- return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}>${el.tag}>`
+ return `<${tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}>${tag}>`
},
'el-cascader': el => {
const {
- disabled, vModel, clearable, placeholder, width
+ tag, disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
- const options = el.options ? `:options="${el.vModel}Options"` : ''
- const props = el.props ? `:props="${el.vModel}Props"` : ''
+ const options = el.options ? `:options="${el.__vModel__}Options"` : ''
+ const props = el.props ? `:props="${el.__vModel__}Props"` : ''
const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"'
const filterable = el.filterable ? 'filterable' : ''
const separator = el.separator === '/' ? '' : `separator="${el.separator}"`
- return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}>${el.tag}>`
+ return `<${tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}>${tag}>`
},
'el-slider': el => {
- const { disabled, vModel } = attrBuilder(el)
+ const { tag, disabled, vModel } = attrBuilder(el)
const min = el.min ? `:min='${el.min}'` : ''
const max = el.max ? `:max='${el.max}'` : ''
const step = el.step ? `:step='${el.step}'` : ''
const range = el.range ? 'range' : ''
const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : ''
- return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}>${el.tag}>`
+ return `<${tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}>${tag}>`
},
'el-time-picker': el => {
const {
- disabled, vModel, clearable, placeholder, width
+ tag, disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
@@ -211,11 +235,11 @@ const tags = {
const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : ''
- return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}>${el.tag}>`
+ return `<${tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}>${tag}>`
},
'el-date-picker': el => {
const {
- disabled, vModel, clearable, placeholder, width
+ tag, disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
@@ -225,46 +249,54 @@ const tags = {
const type = el.type === 'date' ? '' : `type="${el.type}"`
const readonly = el.readonly ? 'readonly' : ''
- return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}>${el.tag}>`
+ return `<${tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}>${tag}>`
},
'el-rate': el => {
- const { disabled, vModel } = attrBuilder(el)
+ const { tag, disabled, vModel } = attrBuilder(el)
const max = el.max ? `:max='${el.max}'` : ''
const allowHalf = el['allow-half'] ? 'allow-half' : ''
const showText = el['show-text'] ? 'show-text' : ''
const showScore = el['show-score'] ? 'show-score' : ''
- return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}>${el.tag}>`
+ return `<${tag} ${vModel} ${max} ${allowHalf} ${showText} ${showScore} ${disabled}>${tag}>`
},
'el-color-picker': el => {
- const { disabled, vModel } = attrBuilder(el)
+ const { tag, disabled, vModel } = attrBuilder(el)
const size = `size="${el.size}"`
const showAlpha = el['show-alpha'] ? 'show-alpha' : ''
const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : ''
- return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}>${el.tag}>`
+ return `<${tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}>${tag}>`
},
'el-upload': el => {
+ const { tag } = el.__config__
const disabled = el.disabled ? ':disabled=\'true\'' : ''
- const action = el.action ? `:action="${el.vModel}Action"` : ''
+ 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}"`
+ const beforeUpload = `:before-upload="${el.__vModel__}BeforeUpload"`
+ const fileList = `:file-list="${el.__vModel__}fileList"`
+ const ref = `ref="${el.__vModel__}"`
let child = buildElUploadChild(el)
if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}${el.tag}>`
+ return `<${tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}${tag}>`
+ },
+ tinymce: el => {
+ const { tag, vModel } = attrBuilder(el)
+ const height = el.height ? `:height="${el.height}"` : ''
+ const branding = el.branding ? `:branding="${el.branding}"` : ''
+ return `<${tag} ${vModel} ${height} ${branding}>${tag}>`
}
}
function attrBuilder(el) {
return {
- vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`,
+ tag: el.__config__.tag,
+ vModel: `v-model="${confGlobal.formModel}.${el.__vModel__}"`,
clearable: el.clearable ? 'clearable' : '',
placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '',
width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '',
@@ -272,64 +304,93 @@ function attrBuilder(el) {
}
}
-// el-input innerHTML
-function buildElInputChild(conf) {
+// el-buttin 子级
+function buildElButtonChild(scheme) {
const children = []
- if (conf.prepend) {
- children.push(`${conf.prepend}`)
- }
- if (conf.append) {
- children.push(`${conf.append}`)
+ const slot = scheme.__slot__ || {}
+ if (slot.default) {
+ children.push(slot.default)
}
return children.join('\n')
}
-function buildElSelectChild(conf) {
+// el-input 子级
+function buildElInputChild(scheme) {
const children = []
- if (conf.options && conf.options.length) {
- children.push(``)
+ const slot = scheme.__slot__
+ if (slot && slot.prepend) {
+ children.push(`${slot.prepend}`)
+ }
+ if (slot && slot.append) {
+ children.push(`${slot.append}`)
}
return children.join('\n')
}
-function buildElRadioGroupChild(conf) {
+// el-select 子级
+function buildElSelectChild(scheme) {
const children = []
- if (conf.options && conf.options.length) {
- const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio'
- const border = conf.border ? 'border' : ''
- children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}${tag}>`)
+ const slot = scheme.__slot__
+ if (slot && slot.options && slot.options.length) {
+ children.push(``)
}
return children.join('\n')
}
-function buildElCheckboxGroupChild(conf) {
+// el-radio-group 子级
+function buildElRadioGroupChild(scheme) {
const children = []
- if (conf.options && conf.options.length) {
- const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox'
- const border = conf.border ? 'border' : ''
- children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}${tag}>`)
+ const slot = scheme.__slot__
+ const config = scheme.__config__
+ if (slot && slot.options && slot.options.length) {
+ const tag = config.optionType === 'button' ? 'el-radio-button' : 'el-radio'
+ const border = config.border ? 'border' : ''
+ children.push(`<${tag} v-for="(item, index) in ${scheme.__vModel__}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}${tag}>`)
}
return children.join('\n')
}
-function buildElUploadChild(conf) {
+// el-checkbox-group 子级
+function buildElCheckboxGroupChild(scheme) {
+ const children = []
+ const slot = scheme.__slot__
+ const config = scheme.__config__
+ if (slot && slot.options && slot.options.length) {
+ const tag = config.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox'
+ const border = config.border ? 'border' : ''
+ children.push(`<${tag} v-for="(item, index) in ${scheme.__vModel__}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}${tag}>`)
+ }
+ return children.join('\n')
+}
+
+// el-upload 子级
+function buildElUploadChild(scheme) {
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}文件
`)
+ const config = scheme.__config__
+ if (scheme['list-type'] === 'picture-card') list.push('')
+ else list.push(`${config.buttonText}`)
+ if (config.showTip) list.push(`只能上传不超过 ${config.fileSize}${config.sizeUnit} 的${scheme.accept}文件
`)
return list.join('\n')
}
-export function makeUpHtml(conf, type) {
+/**
+ * 组装html代码。【入口函数】
+ * @param {Object} formConfig 整个表单配置
+ * @param {String} type 生成类型,文件或弹窗等
+ */
+export function makeUpHtml(formConfig, type) {
const htmlList = []
- confGlobal = conf
- someSpanIsNot24 = conf.fields.some(item => item.span !== 24)
- conf.fields.forEach(el => {
- htmlList.push(layouts[el.layout](el))
+ confGlobal = formConfig
+ // 判断布局是否都沾满了24个栅格,以备后续简化代码结构
+ someSpanIsNot24 = formConfig.fields.some(item => item.__config__.span !== 24)
+ // 遍历渲染每个组件成html
+ formConfig.fields.forEach(el => {
+ htmlList.push(layouts[el.__config__.layout](el))
})
const htmlStr = htmlList.join('\n')
-
- let temp = buildFormTemplate(conf, htmlStr, type)
+ // 将组件代码放进form标签
+ let temp = buildFormTemplate(formConfig, htmlStr, type)
+ // dialog标签包裹代码
if (type === 'dialog') {
temp = dialogWrapper(temp)
}
diff --git a/ruoyi-ui/src/utils/generator/index.js b/ruoyi-ui/src/utils/generator/index.js
new file mode 100644
index 000000000..dd03aea54
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/index.js
@@ -0,0 +1,102 @@
+/**
+ * num 小于0,左缩进num*2个空格; 大于0,右缩进num*2个空格。
+ * @param {string} str 代码
+ * @param {number} num 缩进次数
+ * @param {number} len 【可选】缩进单位,空格数
+ */
+export function indent(str, num, len = 2) {
+ if (num === 0) return str
+ const isLeft = num < 0; const result = []; let reg; let
+ spaces = ''
+ if (isLeft) {
+ num *= -1
+ reg = new RegExp(`(^\\s{0,${num * len}})`, 'g')
+ } else {
+ for (let i = 0; i < num * len; i++) spaces += ' '
+ }
+
+ str.split('\n').forEach(line => {
+ line = isLeft ? line.replace(reg, '') : spaces + line
+ result.push(line)
+ })
+ return result.join('\n')
+}
+
+// 首字母大小
+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)
+}
+
+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
+ }
+}
+
+function stringify(obj) {
+ return JSON.stringify(obj, (key, val) => {
+ if (typeof val === 'function') {
+ return `${val}`
+ }
+ return val
+ })
+}
+
+function parse(str) {
+ JSON.parse(str, (k, v) => {
+ if (v.indexOf && v.indexOf('function') > -1) {
+ return eval(`(${v})`)
+ }
+ return v
+ })
+}
+
+export function jsonClone(obj) {
+ return parse(stringify(obj))
+}
diff --git a/ruoyi-ui/src/utils/generator/js.js b/ruoyi-ui/src/utils/generator/js.js
index 81afc7004..b5e4f9b3f 100644
--- a/ruoyi-ui/src/utils/generator/js.js
+++ b/ruoyi-ui/src/utils/generator/js.js
@@ -1,6 +1,6 @@
import { isArray } from 'util'
-import { exportDefault, titleCase } from '@/utils/index'
-import { trigger } from './config'
+import { exportDefault, titleCase } from '@/utils/generator/index'
+import ruleTrigger from './ruleTrigger'
const units = {
KB: '1024',
@@ -13,9 +13,13 @@ const inheritAttrs = {
dialog: 'inheritAttrs: false,'
}
-
-export function makeUpJs(conf, type) {
- confGlobal = conf = JSON.parse(JSON.stringify(conf))
+/**
+ * 组装js 【入口函数】
+ * @param {Object} formConfig 整个表单配置
+ * @param {String} type 生成类型,文件或弹窗等
+ */
+export function makeUpJs(formConfig, type) {
+ confGlobal = formConfig = JSON.parse(JSON.stringify(formConfig))
const dataList = []
const ruleList = []
const optionsList = []
@@ -23,12 +27,12 @@ export function makeUpJs(conf, type) {
const methodList = mixinMethod(type)
const uploadVarList = []
- conf.fields.forEach(el => {
+ formConfig.fields.forEach(el => {
buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
})
const script = buildexport(
- conf,
+ formConfig,
type,
dataList.join('\n'),
ruleList.join('\n'),
@@ -41,41 +45,50 @@ export function makeUpJs(conf, type) {
return script
}
-function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) {
- buildData(el, dataList)
- buildRules(el, ruleList)
+// 构建组件属性
+function buildAttributes(scheme, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) {
+ const config = scheme.__config__
+ const slot = scheme.__slot__
+ buildData(scheme, dataList)
+ buildRules(scheme, ruleList)
- if (el.options && el.options.length) {
- buildOptions(el, optionsList)
- if (el.dataType === 'dynamic') {
- const model = `${el.vModel}Options`
+ // 特殊处理options属性
+ if (scheme.options || (slot && slot.options && slot.options.length)) {
+ buildOptions(scheme, optionsList)
+ if (config.dataType === 'dynamic') {
+ const model = `${scheme.__vModel__}Options`
const options = titleCase(model)
buildOptionMethod(`get${options}`, model, methodList)
}
}
- if (el.props && el.props.props) {
- buildProps(el, propsList)
+ // 处理props
+ if (scheme.props && scheme.props.props) {
+ buildProps(scheme, propsList)
}
- if (el.action && el.tag === 'el-upload') {
+ // 处理el-upload的action
+ if (scheme.action && config.tag === 'el-upload') {
uploadVarList.push(
- `${el.vModel}Action: '${el.action}',
- ${el.vModel}fileList: [],`
+ `${scheme.__vModel__}Action: '${scheme.action}',
+ ${scheme.__vModel__}fileList: [],`
)
- methodList.push(buildBeforeUpload(el))
- if (!el['auto-upload']) {
- methodList.push(buildSubmitUpload(el))
+ methodList.push(buildBeforeUpload(scheme))
+ // 非自动上传时,生成手动上传的函数
+ if (!scheme['auto-upload']) {
+ methodList.push(buildSubmitUpload(scheme))
}
}
- if (el.children) {
- el.children.forEach(el2 => {
- buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
+ // 构建子级组件属性
+ if (config.children) {
+ config.children.forEach(item => {
+ buildAttributes(item, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
})
}
}
+// 混入处理函数
function mixinMethod(type) {
const list = []; const
minxins = {
@@ -117,73 +130,75 @@ function mixinMethod(type) {
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},`)
+// 构建data
+function buildData(scheme, dataList) {
+ const config = scheme.__config__
+ if (scheme.__vModel__ === undefined) return
+ const defaultValue = JSON.stringify(config.defaultValue)
+ dataList.push(`${scheme.__vModel__}: ${defaultValue},`)
}
-function buildRules(conf, ruleList) {
- if (conf.vModel === undefined) return
+// 构建校验规则
+function buildRules(scheme, ruleList) {
+ const config = scheme.__config__
+ if (scheme.__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 (ruleTrigger[config.tag]) {
+ if (config.required) {
+ const type = isArray(config.defaultValue) ? 'type: \'array\',' : ''
+ let message = isArray(config.defaultValue) ? `请至少选择一个${config.label}` : scheme.placeholder
+ if (message === undefined) message = `${config.label}不能为空`
+ rules.push(`{ required: true, ${type} message: '${message}', trigger: '${ruleTrigger[config.tag]}' }`)
}
- if (conf.regList && isArray(conf.regList)) {
- conf.regList.forEach(item => {
+ if (config.regList && isArray(config.regList)) {
+ config.regList.forEach(item => {
if (item.pattern) {
- rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`)
+ rules.push(
+ `{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${ruleTrigger[config.tag]}' }`
+ )
}
})
}
- ruleList.push(`${conf.vModel}: [${rules.join(',')}],`)
+ ruleList.push(`${scheme.__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)},`
+// 构建options
+function buildOptions(scheme, optionsList) {
+ if (scheme.__vModel__ === undefined) return
+ // el-cascader直接有options属性,其他组件都是定义在slot中,所以有两处判断
+ let { options } = scheme
+ if (!options) options = scheme.__slot__.options
+ if (scheme.__config__.dataType === 'dynamic') { options = [] }
+ const str = `${scheme.__vModel__}Options: ${JSON.stringify(options)},`
optionsList.push(str)
}
-function buildProps(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)},`
+function buildProps(scheme, propsList) {
+ const str = `${scheme.__vModel__}Props: ${JSON.stringify(scheme.props.props)},`
propsList.push(str)
}
-function buildBeforeUpload(conf) {
- const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const
+// el-upload的BeforeUpload
+function buildBeforeUpload(scheme) {
+ const config = scheme.__config__
+ const unitNum = units[config.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const
returnList = []
- if (conf.fileSize) {
- rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize}
+ if (config.fileSize) {
+ rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${config.fileSize}
if(!isRightSize){
- this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}')
+ this.$message.error('文件大小超过 ${config.fileSize}${config.sizeUnit}')
}`
returnList.push('isRightSize')
}
- if (conf.accept) {
- acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type)
+ if (scheme.accept) {
+ acceptCode = `let isAccept = new RegExp('${scheme.accept}').test(file.type)
if(!isAccept){
- this.$message.error('应该选择${conf.accept}类型的文件')
+ this.$message.error('应该选择${scheme.accept}类型的文件')
}`
returnList.push('isAccept')
}
- const str = `${conf.vModel}BeforeUpload(file) {
+ const str = `${scheme.__vModel__}BeforeUpload(file) {
${rightSizeCode}
${acceptCode}
return ${returnList.join('&&')}
@@ -191,9 +206,10 @@ function buildBeforeUpload(conf) {
return returnList.length ? str : ''
}
-function buildSubmitUpload(conf) {
+// el-upload的submit
+function buildSubmitUpload(scheme) {
const str = `submitUpload() {
- this.$refs['${conf.vModel}'].submit()
+ this.$refs['${scheme.__vModel__}'].submit()
},`
return str
}
@@ -206,6 +222,7 @@ function buildOptionMethod(methodName, model, methodList) {
methodList.push(str)
}
+// js整体拼接
function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) {
const str = `${exportDefault}{
${inheritAttrs[type]}
diff --git a/ruoyi-ui/src/utils/generator/loadBeautifier.js b/ruoyi-ui/src/utils/generator/loadBeautifier.js
new file mode 100644
index 000000000..001bbabb0
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/loadBeautifier.js
@@ -0,0 +1,26 @@
+import loadScript from './loadScript'
+import ELEMENT from 'element-ui'
+
+let beautifierObj
+
+export default function loadBeautifier(cb) {
+ if (beautifierObj) {
+ cb(beautifierObj)
+ return
+ }
+
+ const loading = ELEMENT.Loading.service({
+ fullscreen: true,
+ lock: true,
+ text: '格式化资源加载中...',
+ spinner: 'el-icon-loading',
+ background: 'rgba(255, 255, 255, 0.5)'
+ })
+
+ loadScript('https://cdn.bootcss.com/js-beautify/1.10.2/beautifier.min.js', () => {
+ loading.close()
+ // eslint-disable-next-line no-undef
+ beautifierObj = beautifier
+ cb(beautifierObj)
+ })
+}
diff --git a/ruoyi-ui/src/utils/generator/loadMonaco.js b/ruoyi-ui/src/utils/generator/loadMonaco.js
new file mode 100644
index 000000000..a15bfbdd2
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/loadMonaco.js
@@ -0,0 +1,42 @@
+import { loadScriptQueue } from './loadScript'
+import ELEMENT from 'element-ui'
+
+// monaco-editor单例
+let monacoEidtor
+
+/**
+ * 动态加载monaco-editor cdn资源
+ * @param {Function} cb 回调,必填
+ */
+export default function loadMonaco(cb) {
+ if (monacoEidtor) {
+ cb(monacoEidtor)
+ return
+ }
+
+ const vs = 'https://cdn.bootcss.com/monaco-editor/0.18.0/min/vs'
+
+ // 使用element ui实现加载提示
+ const loading = ELEMENT.Loading.service({
+ fullscreen: true,
+ lock: true,
+ text: '编辑器资源初始化中...',
+ spinner: 'el-icon-loading',
+ background: 'rgba(255, 255, 255, 0.5)'
+ })
+
+ !window.require && (window.require = {})
+ !window.require.paths && (window.require.paths = {})
+ window.require.paths.vs = vs
+
+ loadScriptQueue([
+ `${vs}/loader.js`,
+ `${vs}/editor/editor.main.nls.js`,
+ `${vs}/editor/editor.main.js`
+ ], () => {
+ loading.close()
+ // eslint-disable-next-line no-undef
+ monacoEidtor = monaco
+ cb(monacoEidtor)
+ })
+}
diff --git a/ruoyi-ui/src/utils/generator/loadScript.js b/ruoyi-ui/src/utils/generator/loadScript.js
new file mode 100644
index 000000000..18112fd73
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/loadScript.js
@@ -0,0 +1,60 @@
+const callbacks = {}
+
+/**
+ * 加载一个远程脚本
+ * @param {String} src 一个远程脚本
+ * @param {Function} callback 回调
+ */
+function loadScript(src, callback) {
+ const existingScript = document.getElementById(src)
+ const cb = callback || (() => {})
+ if (!existingScript) {
+ callbacks[src] = []
+ const $script = document.createElement('script')
+ $script.src = src
+ $script.id = src
+ $script.async = 1
+ document.body.appendChild($script)
+ const onEnd = 'onload' in $script ? stdOnEnd.bind($script) : ieOnEnd.bind($script)
+ onEnd($script)
+ }
+
+ callbacks[src].push(cb)
+
+ function stdOnEnd(script) {
+ script.onload = () => {
+ this.onerror = this.onload = null
+ callbacks[src].forEach(item => {
+ item(null, script)
+ })
+ delete callbacks[src]
+ }
+ script.onerror = () => {
+ this.onerror = this.onload = null
+ cb(new Error(`Failed to load ${src}`), script)
+ }
+ }
+
+ function ieOnEnd(script) {
+ script.onreadystatechange = () => {
+ if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
+ this.onreadystatechange = null
+ callbacks[src].forEach(item => {
+ item(null, script)
+ })
+ delete callbacks[src]
+ }
+ }
+}
+
+/**
+ * 顺序加载一组远程脚本
+ * @param {Array} list 一组远程脚本
+ * @param {Function} cb 回调
+ */
+export function loadScriptQueue(list, cb) {
+ const first = list.shift()
+ list.length ? loadScript(first, () => loadScriptQueue(list, cb)) : loadScript(first, cb)
+}
+
+export default loadScript
diff --git a/ruoyi-ui/src/utils/generator/loadTinymce.js b/ruoyi-ui/src/utils/generator/loadTinymce.js
new file mode 100644
index 000000000..969cece7b
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/loadTinymce.js
@@ -0,0 +1,26 @@
+import loadScript from './loadScript'
+import ELEMENT from 'element-ui'
+
+let tinymceObj
+
+export default function loadTinymce(cb) {
+ if (tinymceObj) {
+ cb(tinymceObj)
+ return
+ }
+
+ const loading = ELEMENT.Loading.service({
+ fullscreen: true,
+ lock: true,
+ text: '富文本资源加载中...',
+ spinner: 'el-icon-loading',
+ background: 'rgba(255, 255, 255, 0.5)'
+ })
+
+ loadScript('https://cdn.bootcdn.net/ajax/libs/tinymce/5.2.2/tinymce.min.js', () => {
+ loading.close()
+ // eslint-disable-next-line no-undef
+ tinymceObj = tinymce
+ cb(tinymceObj)
+ })
+}
diff --git a/ruoyi-ui/src/utils/generator/parser/Parser.vue b/ruoyi-ui/src/utils/generator/parser/Parser.vue
new file mode 100644
index 000000000..fbbb72749
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/parser/Parser.vue
@@ -0,0 +1,166 @@
+
diff --git a/ruoyi-ui/src/utils/generator/parser/README.md b/ruoyi-ui/src/utils/generator/parser/README.md
new file mode 100644
index 000000000..b91be7e8a
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/parser/README.md
@@ -0,0 +1,17 @@
+## form-generator JSON 解析器
+>用于将form-generator导出的JSON解析成一个表单。
+
+### 安装组件
+```
+npm i form-gen-parser
+```
+或者
+```
+yarn add form-gen-parser
+```
+
+### 使用示例
+> [查看在线示例](https://mrhj.gitee.io/form-generator/#/parser)
+
+示例代码:
+> [src\components\parser\example\Index.vue](https://github.com/JakHuang/form-generator/blob/dev/src/components/parser/example/Index.vue)
diff --git a/ruoyi-ui/src/utils/generator/parser/example/Index.vue b/ruoyi-ui/src/utils/generator/parser/example/Index.vue
new file mode 100644
index 000000000..47cc49a33
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/parser/example/Index.vue
@@ -0,0 +1,264 @@
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/utils/generator/parser/index.js b/ruoyi-ui/src/utils/generator/parser/index.js
new file mode 100644
index 000000000..0a44b2ccc
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/parser/index.js
@@ -0,0 +1,3 @@
+import Parser from './Parser'
+
+export default Parser
diff --git a/ruoyi-ui/src/utils/generator/parser/package.json b/ruoyi-ui/src/utils/generator/parser/package.json
new file mode 100644
index 000000000..c31d3a3a9
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/parser/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "form-gen-parser",
+ "version": "1.0.3",
+ "description": "表单json解析器",
+ "main": "lib/form-gen-parser.umd.js",
+ "directories": {
+ "example": "example"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/JakHuang/form-generator.git"
+ },
+ "dependencies": {
+ "form-gen-render": "^1.0.0"
+ },
+ "author": "jakHuang",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/JakHuang/form-generator/issues"
+ },
+ "homepage": "https://github.com/JakHuang/form-generator#readme"
+}
diff --git a/ruoyi-ui/src/utils/generator/render.js b/ruoyi-ui/src/utils/generator/render.js
index 42cd6646d..d25dc0451 100644
--- a/ruoyi-ui/src/utils/generator/render.js
+++ b/ruoyi-ui/src/utils/generator/render.js
@@ -1,4 +1,4 @@
-import { makeMap } from '@/utils/index'
+import { makeMap } from '@/utils/generator/index'
// 参考https://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js
const isAttr = makeMap(
diff --git a/ruoyi-ui/src/utils/generator/render/package.json b/ruoyi-ui/src/utils/generator/render/package.json
new file mode 100644
index 000000000..96bffcfec
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/render/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "form-gen-render",
+ "version": "1.0.4",
+ "description": "表单核心render",
+ "main": "lib/form-gen-render.umd.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/JakHuang/form-generator.git"
+ },
+ "author": "jakhuang",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/JakHuang/form-generator/issues"
+ },
+ "homepage": "https://github.com/JakHuang/form-generator#readme"
+}
diff --git a/ruoyi-ui/src/utils/generator/render/render.js b/ruoyi-ui/src/utils/generator/render/render.js
new file mode 100644
index 000000000..c1f9f6d88
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/render/render.js
@@ -0,0 +1,59 @@
+function vModel(self, dataObject, defaultValue) {
+ dataObject.props.value = defaultValue
+
+ dataObject.on.input = val => {
+ self.$emit('input', val)
+ }
+}
+
+const componentChild = {}
+/**
+ * 将./slots中的文件挂载到对象componentChild上
+ * 文件名为key,对应JSON配置中的__config__.tag
+ * 文件内容为value,解析JSON配置中的__slot__
+ */
+const slotsFiles = require.context('./slots', true, /\.js$/)
+const keys = slotsFiles.keys() || []
+keys.forEach(key => {
+ const tag = key.replace(/^\.\/(.*)\.\w+$/, '$1')
+ const value = slotsFiles(key).default
+ componentChild[tag] = value
+})
+
+export default {
+ render(h) {
+ const dataObject = {
+ attrs: {},
+ props: {},
+ on: {},
+ style: {}
+ }
+ const confClone = JSON.parse(JSON.stringify(this.conf))
+ const children = []
+
+ const childObjs = componentChild[confClone.__config__.tag]
+ if (childObjs) {
+ Object.keys(childObjs).forEach(key => {
+ const childFunc = childObjs[key]
+ if (confClone.__slot__ && confClone.__slot__[key]) {
+ children.push(childFunc(h, confClone, key))
+ }
+ })
+ }
+
+ Object.keys(confClone).forEach(key => {
+ const val = confClone[key]
+ if (key === '__vModel__') {
+ vModel(this, dataObject, confClone.__config__.defaultValue)
+ } else if (dataObject[key]) {
+ dataObject[key] = { ...dataObject[key], ...val }
+ } else {
+ dataObject.attrs[key] = val
+ }
+ })
+ delete dataObject.attrs.__config__
+ delete dataObject.attrs.__slot__
+ return h(this.conf.__config__.tag, dataObject, children)
+ },
+ props: ['conf']
+}
diff --git a/ruoyi-ui/src/utils/generator/render/slots/el-button.js b/ruoyi-ui/src/utils/generator/render/slots/el-button.js
new file mode 100644
index 000000000..a2d9684eb
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/render/slots/el-button.js
@@ -0,0 +1,5 @@
+export default {
+ default(h, conf, key) {
+ return conf.__slot__[key]
+ }
+}
diff --git a/ruoyi-ui/src/utils/generator/render/slots/el-checkbox-group.js b/ruoyi-ui/src/utils/generator/render/slots/el-checkbox-group.js
new file mode 100644
index 000000000..0a85c8e75
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/render/slots/el-checkbox-group.js
@@ -0,0 +1,13 @@
+export default {
+ options(h, conf, key) {
+ const list = []
+ conf.__slot__.options.forEach(item => {
+ if (conf.__config__.optionType === 'button') {
+ list.push({item.label})
+ } else {
+ list.push({item.label})
+ }
+ })
+ return list
+ }
+}
diff --git a/ruoyi-ui/src/utils/generator/render/slots/el-input.js b/ruoyi-ui/src/utils/generator/render/slots/el-input.js
new file mode 100644
index 000000000..8bd02db2a
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/render/slots/el-input.js
@@ -0,0 +1,8 @@
+export default {
+ prepend(h, conf, key) {
+ return {conf.__slot__[key]}
+ },
+ append(h, conf, key) {
+ return {conf.__slot__[key]}
+ }
+}
diff --git a/ruoyi-ui/src/utils/generator/render/slots/el-radio-group.js b/ruoyi-ui/src/utils/generator/render/slots/el-radio-group.js
new file mode 100644
index 000000000..c78506f9a
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/render/slots/el-radio-group.js
@@ -0,0 +1,13 @@
+export default {
+ options(h, conf, key) {
+ const list = []
+ conf.__slot__.options.forEach(item => {
+ if (conf.__config__.optionType === 'button') {
+ list.push({item.label})
+ } else {
+ list.push({item.label})
+ }
+ })
+ return list
+ }
+}
diff --git a/ruoyi-ui/src/utils/generator/render/slots/el-select.js b/ruoyi-ui/src/utils/generator/render/slots/el-select.js
new file mode 100644
index 000000000..cbf4a2030
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/render/slots/el-select.js
@@ -0,0 +1,9 @@
+export default {
+ options(h, conf, key) {
+ const list = []
+ conf.__slot__.options.forEach(item => {
+ list.push()
+ })
+ return list
+ }
+}
diff --git a/ruoyi-ui/src/utils/generator/render/slots/el-upload.js b/ruoyi-ui/src/utils/generator/render/slots/el-upload.js
new file mode 100644
index 000000000..8ce3c351c
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/render/slots/el-upload.js
@@ -0,0 +1,17 @@
+export default {
+ 'list-type': (h, conf, key) => {
+ const list = []
+ const config = conf.__config__
+ if (conf['list-type'] === 'picture-card') {
+ list.push()
+ } else {
+ list.push({config.buttonText})
+ }
+ if (config.showTip) {
+ list.push(
+ 只能上传不超过 {config.fileSize}{config.sizeUnit} 的{conf.accept}文件
+ )
+ }
+ return list
+ }
+}
diff --git a/ruoyi-ui/src/utils/generator/ruleTrigger.js b/ruoyi-ui/src/utils/generator/ruleTrigger.js
new file mode 100644
index 000000000..7f33f1a82
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/ruleTrigger.js
@@ -0,0 +1,17 @@
+
+/**
+ * 用于生成表单校验,指定正则规则的触发方式。
+ * 未在此处声明无触发方式的组件将不生成rule!!
+ */
+export default {
+ 'el-input': 'blur',
+ 'el-input-number': 'blur',
+ 'el-select': 'change',
+ 'el-radio-group': 'change',
+ 'el-checkbox-group': 'change',
+ 'el-cascader': 'change',
+ 'el-time-picker': 'change',
+ 'el-date-picker': 'change',
+ 'el-rate': 'change',
+ tinymce: 'blur'
+}
diff --git a/ruoyi-ui/src/utils/generator/tinymce/config.js b/ruoyi-ui/src/utils/generator/tinymce/config.js
new file mode 100644
index 000000000..fc6155447
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/tinymce/config.js
@@ -0,0 +1,8 @@
+/* eslint-disable max-len */
+
+export const plugins = [
+ 'advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks visualchars wordcount'
+]
+export const toolbar = [
+ 'code searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote removeformat subscript superscript codesample hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen'
+]
diff --git a/ruoyi-ui/src/utils/generator/tinymce/index.vue b/ruoyi-ui/src/utils/generator/tinymce/index.vue
new file mode 100644
index 000000000..6c4516112
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/tinymce/index.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/utils/generator/tinymce/zh_CN.js b/ruoyi-ui/src/utils/generator/tinymce/zh_CN.js
new file mode 100644
index 000000000..4f494d634
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/tinymce/zh_CN.js
@@ -0,0 +1,420 @@
+/* eslint-disable */
+tinymce.addI18n('zh_CN',{
+"Redo": "\u91cd\u505a",
+"Undo": "\u64a4\u9500",
+"Cut": "\u526a\u5207",
+"Copy": "\u590d\u5236",
+"Paste": "\u7c98\u8d34",
+"Select all": "\u5168\u9009",
+"New document": "\u65b0\u6587\u4ef6",
+"Ok": "\u786e\u5b9a",
+"Cancel": "\u53d6\u6d88",
+"Visual aids": "\u7f51\u683c\u7ebf",
+"Bold": "\u7c97\u4f53",
+"Italic": "\u659c\u4f53",
+"Underline": "\u4e0b\u5212\u7ebf",
+"Strikethrough": "\u5220\u9664\u7ebf",
+"Superscript": "\u4e0a\u6807",
+"Subscript": "\u4e0b\u6807",
+"Clear formatting": "\u6e05\u9664\u683c\u5f0f",
+"Align left": "\u5de6\u8fb9\u5bf9\u9f50",
+"Align center": "\u4e2d\u95f4\u5bf9\u9f50",
+"Align right": "\u53f3\u8fb9\u5bf9\u9f50",
+"Justify": "\u4e24\u7aef\u5bf9\u9f50",
+"Bullet list": "\u9879\u76ee\u7b26\u53f7",
+"Numbered list": "\u7f16\u53f7\u5217\u8868",
+"Decrease indent": "\u51cf\u5c11\u7f29\u8fdb",
+"Increase indent": "\u589e\u52a0\u7f29\u8fdb",
+"Close": "\u5173\u95ed",
+"Formats": "\u683c\u5f0f",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u6253\u5f00\u526a\u8d34\u677f\uff0c\u8bf7\u4f7f\u7528Ctrl+X\/C\/V\u7b49\u5feb\u6377\u952e\u3002",
+"Headers": "\u6807\u9898",
+"Header 1": "\u6807\u98981",
+"Header 2": "\u6807\u98982",
+"Header 3": "\u6807\u98983",
+"Header 4": "\u6807\u98984",
+"Header 5": "\u6807\u98985",
+"Header 6": "\u6807\u98986",
+"Headings": "\u6807\u9898",
+"Heading 1": "\u6807\u98981",
+"Heading 2": "\u6807\u98982",
+"Heading 3": "\u6807\u98983",
+"Heading 4": "\u6807\u98984",
+"Heading 5": "\u6807\u98985",
+"Heading 6": "\u6807\u98986",
+"Preformatted": "\u9884\u5148\u683c\u5f0f\u5316\u7684",
+"Div": "Div",
+"Pre": "Pre",
+"Code": "\u4ee3\u7801",
+"Paragraph": "\u6bb5\u843d",
+"Blockquote": "\u5f15\u6587\u533a\u5757",
+"Inline": "\u6587\u672c",
+"Blocks": "\u57fa\u5757",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002",
+"Fonts": "\u5b57\u4f53",
+"Font Sizes": "\u5b57\u53f7",
+"Class": "\u7c7b\u578b",
+"Browse for an image": "\u6d4f\u89c8\u56fe\u50cf",
+"OR": "\u6216",
+"Drop an image here": "\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64",
+"Upload": "\u4e0a\u4f20",
+"Block": "\u5757",
+"Align": "\u5bf9\u9f50",
+"Default": "\u9ed8\u8ba4",
+"Circle": "\u7a7a\u5fc3\u5706",
+"Disc": "\u5b9e\u5fc3\u5706",
+"Square": "\u65b9\u5757",
+"Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd",
+"Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd",
+"Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd",
+"Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd",
+"Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd",
+"Anchor...": "\u951a\u70b9...",
+"Name": "\u540d\u79f0",
+"Id": "\u6807\u8bc6\u7b26",
+"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002",
+"You have unsaved changes are you sure you want to navigate away?": "\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f",
+"Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f",
+"Special character...": "\u7279\u6b8a\u5b57\u7b26...",
+"Source code": "\u6e90\u4ee3\u7801",
+"Insert\/Edit code sample": "\u63d2\u5165\/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b",
+"Language": "\u8bed\u8a00",
+"Code sample...": "\u793a\u4f8b\u4ee3\u7801...",
+"Color Picker": "\u9009\u8272\u5668",
+"R": "R",
+"G": "G",
+"B": "B",
+"Left to right": "\u4ece\u5de6\u5230\u53f3",
+"Right to left": "\u4ece\u53f3\u5230\u5de6",
+"Emoticons...": "\u8868\u60c5\u7b26\u53f7...",
+"Metadata and Document Properties": "\u5143\u6570\u636e\u548c\u6587\u6863\u5c5e\u6027",
+"Title": "\u6807\u9898",
+"Keywords": "\u5173\u952e\u8bcd",
+"Description": "\u63cf\u8ff0",
+"Robots": "\u673a\u5668\u4eba",
+"Author": "\u4f5c\u8005",
+"Encoding": "\u7f16\u7801",
+"Fullscreen": "\u5168\u5c4f",
+"Action": "\u64cd\u4f5c",
+"Shortcut": "\u5feb\u6377\u952e",
+"Help": "\u5e2e\u52a9",
+"Address": "\u5730\u5740",
+"Focus to menubar": "\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f",
+"Focus to toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f",
+"Focus to element path": "\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84",
+"Focus to contextual toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355",
+"Insert link (if link plugin activated)": "\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)",
+"Save (if save plugin activated)": "\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)",
+"Find (if searchreplace plugin activated)": "\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)",
+"Plugins installed ({0}):": "\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):",
+"Premium plugins:": "\u4f18\u79c0\u63d2\u4ef6\uff1a",
+"Learn more...": "\u4e86\u89e3\u66f4\u591a...",
+"You are using {0}": "\u4f60\u6b63\u5728\u4f7f\u7528 {0}",
+"Plugins": "\u63d2\u4ef6",
+"Handy Shortcuts": "\u5feb\u6377\u952e",
+"Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf",
+"Insert\/edit image": "\u63d2\u5165\/\u7f16\u8f91\u56fe\u7247",
+"Image description": "\u56fe\u7247\u63cf\u8ff0",
+"Source": "\u5730\u5740",
+"Dimensions": "\u5927\u5c0f",
+"Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4",
+"General": "\u666e\u901a",
+"Advanced": "\u9ad8\u7ea7",
+"Style": "\u6837\u5f0f",
+"Vertical space": "\u5782\u76f4\u8fb9\u8ddd",
+"Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd",
+"Border": "\u8fb9\u6846",
+"Insert image": "\u63d2\u5165\u56fe\u7247",
+"Image...": "\u56fe\u7247...",
+"Image list": "\u56fe\u7247\u5217\u8868",
+"Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c",
+"Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c",
+"Flip vertically": "\u5782\u76f4\u7ffb\u8f6c",
+"Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c",
+"Edit image": "\u7f16\u8f91\u56fe\u7247",
+"Image options": "\u56fe\u7247\u9009\u9879",
+"Zoom in": "\u653e\u5927",
+"Zoom out": "\u7f29\u5c0f",
+"Crop": "\u88c1\u526a",
+"Resize": "\u8c03\u6574\u5927\u5c0f",
+"Orientation": "\u65b9\u5411",
+"Brightness": "\u4eae\u5ea6",
+"Sharpen": "\u9510\u5316",
+"Contrast": "\u5bf9\u6bd4\u5ea6",
+"Color levels": "\u989c\u8272\u5c42\u6b21",
+"Gamma": "\u4f3d\u9a6c\u503c",
+"Invert": "\u53cd\u8f6c",
+"Apply": "\u5e94\u7528",
+"Back": "\u540e\u9000",
+"Insert date\/time": "\u63d2\u5165\u65e5\u671f\/\u65f6\u95f4",
+"Date\/time": "\u65e5\u671f\/\u65f6\u95f4",
+"Insert\/Edit Link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5",
+"Insert\/edit link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5",
+"Text to display": "\u663e\u793a\u6587\u5b57",
+"Url": "\u5730\u5740",
+"Open link in...": "\u94fe\u63a5\u6253\u5f00\u4f4d\u7f6e...",
+"Current window": "\u5f53\u524d\u7a97\u53e3",
+"None": "\u65e0",
+"New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00",
+"Remove link": "\u5220\u9664\u94fe\u63a5",
+"Anchors": "\u951a\u70b9",
+"Link...": "\u94fe\u63a5...",
+"Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5",
+"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f",
+"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7f00\u5417\uff1f",
+"Link list": "\u94fe\u63a5\u5217\u8868",
+"Insert video": "\u63d2\u5165\u89c6\u9891",
+"Insert\/edit video": "\u63d2\u5165\/\u7f16\u8f91\u89c6\u9891",
+"Insert\/edit media": "\u63d2\u5165\/\u7f16\u8f91\u5a92\u4f53",
+"Alternative source": "\u955c\u50cf",
+"Alternative source URL": "\u66ff\u4ee3\u6765\u6e90\u7f51\u5740",
+"Media poster (Image URL)": "\u5c01\u9762(\u56fe\u7247\u5730\u5740)",
+"Paste your embed code below:": "\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:",
+"Embed": "\u5185\u5d4c",
+"Media...": "\u591a\u5a92\u4f53...",
+"Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c",
+"Page break": "\u5206\u9875\u7b26",
+"Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c",
+"Preview": "\u9884\u89c8",
+"Print...": "\u6253\u5370...",
+"Save": "\u4fdd\u5b58",
+"Find": "\u67e5\u627e",
+"Replace with": "\u66ff\u6362\u4e3a",
+"Replace": "\u66ff\u6362",
+"Replace all": "\u5168\u90e8\u66ff\u6362",
+"Previous": "\u4e0a\u4e00\u4e2a",
+"Next": "\u4e0b\u4e00\u4e2a",
+"Find and replace...": "\u67e5\u627e\u5e76\u66ff\u6362...",
+"Could not find the specified string.": "\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.",
+"Match case": "\u533a\u5206\u5927\u5c0f\u5199",
+"Find whole words only": "\u5168\u5b57\u5339\u914d",
+"Spell check": "\u62fc\u5199\u68c0\u67e5",
+"Ignore": "\u5ffd\u7565",
+"Ignore all": "\u5168\u90e8\u5ffd\u7565",
+"Finish": "\u5b8c\u6210",
+"Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178",
+"Insert table": "\u63d2\u5165\u8868\u683c",
+"Table properties": "\u8868\u683c\u5c5e\u6027",
+"Delete table": "\u5220\u9664\u8868\u683c",
+"Cell": "\u5355\u5143\u683c",
+"Row": "\u884c",
+"Column": "\u5217",
+"Cell properties": "\u5355\u5143\u683c\u5c5e\u6027",
+"Merge cells": "\u5408\u5e76\u5355\u5143\u683c",
+"Split cell": "\u62c6\u5206\u5355\u5143\u683c",
+"Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165",
+"Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165",
+"Delete row": "\u5220\u9664\u884c",
+"Row properties": "\u884c\u5c5e\u6027",
+"Cut row": "\u526a\u5207\u884c",
+"Copy row": "\u590d\u5236\u884c",
+"Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9",
+"Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9",
+"Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165",
+"Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165",
+"Delete column": "\u5220\u9664\u5217",
+"Cols": "\u5217",
+"Rows": "\u884c",
+"Width": "\u5bbd",
+"Height": "\u9ad8",
+"Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd",
+"Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd",
+"Show caption": "\u663e\u793a\u6807\u9898",
+"Left": "\u5de6\u5bf9\u9f50",
+"Center": "\u5c45\u4e2d",
+"Right": "\u53f3\u5bf9\u9f50",
+"Cell type": "\u5355\u5143\u683c\u7c7b\u578b",
+"Scope": "\u8303\u56f4",
+"Alignment": "\u5bf9\u9f50\u65b9\u5f0f",
+"H Align": "\u6c34\u5e73\u5bf9\u9f50",
+"V Align": "\u5782\u76f4\u5bf9\u9f50",
+"Top": "\u9876\u90e8\u5bf9\u9f50",
+"Middle": "\u5782\u76f4\u5c45\u4e2d",
+"Bottom": "\u5e95\u90e8\u5bf9\u9f50",
+"Header cell": "\u8868\u5934\u5355\u5143\u683c",
+"Row group": "\u884c\u7ec4",
+"Column group": "\u5217\u7ec4",
+"Row type": "\u884c\u7c7b\u578b",
+"Header": "\u8868\u5934",
+"Body": "\u8868\u4f53",
+"Footer": "\u8868\u5c3e",
+"Border color": "\u8fb9\u6846\u989c\u8272",
+"Insert template...": "\u63d2\u5165\u6a21\u677f...",
+"Templates": "\u6a21\u677f",
+"Template": "\u6a21\u677f",
+"Text color": "\u6587\u5b57\u989c\u8272",
+"Background color": "\u80cc\u666f\u8272",
+"Custom...": "\u81ea\u5b9a\u4e49...",
+"Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272",
+"No color": "\u65e0",
+"Remove color": "\u79fb\u9664\u989c\u8272",
+"Table of Contents": "\u5185\u5bb9\u5217\u8868",
+"Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846",
+"Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26",
+"Word count": "\u5b57\u6570",
+"Count": "\u8ba1\u6570",
+"Document": "\u6587\u6863",
+"Selection": "\u9009\u62e9",
+"Words": "\u5355\u8bcd",
+"Words: {0}": "\u5b57\u6570\uff1a{0}",
+"{0} words": "{0} \u5b57",
+"File": "\u6587\u4ef6",
+"Edit": "\u7f16\u8f91",
+"Insert": "\u63d2\u5165",
+"View": "\u89c6\u56fe",
+"Format": "\u683c\u5f0f",
+"Table": "\u8868\u683c",
+"Tools": "\u5de5\u5177",
+"Powered by {0}": "\u7531{0}\u9a71\u52a8",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9",
+"Image title": "\u56fe\u7247\u6807\u9898",
+"Border width": "\u8fb9\u6846\u5bbd\u5ea6",
+"Border style": "\u8fb9\u6846\u6837\u5f0f",
+"Error": "\u9519\u8bef",
+"Warn": "\u8b66\u544a",
+"Valid": "\u6709\u6548",
+"To open the popup, press Shift+Enter": "\u6309Shitf+Enter\u952e\u6253\u5f00\u5bf9\u8bdd\u6846",
+"Rich Text Area. Press ALT-0 for help.": "\u7f16\u8f91\u533a\u3002\u6309Alt+0\u952e\u6253\u5f00\u5e2e\u52a9\u3002",
+"System Font": "\u7cfb\u7edf\u5b57\u4f53",
+"Failed to upload image: {0}": "\u56fe\u7247\u4e0a\u4f20\u5931\u8d25: {0}",
+"Failed to load plugin: {0} from url {1}": "\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25: {0} \u6765\u81ea\u94fe\u63a5 {1}",
+"Failed to load plugin url: {0}": "\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25 \u94fe\u63a5: {0}",
+"Failed to initialize plugin: {0}": "\u63d2\u4ef6\u521d\u59cb\u5316\u5931\u8d25: {0}",
+"example": "\u793a\u4f8b",
+"Search": "\u641c\u7d22",
+"All": "\u5168\u90e8",
+"Currency": "\u8d27\u5e01",
+"Text": "\u6587\u5b57",
+"Quotations": "\u5f15\u7528",
+"Mathematical": "\u6570\u5b66",
+"Extended Latin": "\u62c9\u4e01\u8bed\u6269\u5145",
+"Symbols": "\u7b26\u53f7",
+"Arrows": "\u7bad\u5934",
+"User Defined": "\u81ea\u5b9a\u4e49",
+"dollar sign": "\u7f8e\u5143\u7b26\u53f7",
+"currency sign": "\u8d27\u5e01\u7b26\u53f7",
+"euro-currency sign": "\u6b27\u5143\u7b26\u53f7",
+"colon sign": "\u5192\u53f7",
+"cruzeiro sign": "\u514b\u9c81\u8d5b\u7f57\u5e01\u7b26\u53f7",
+"french franc sign": "\u6cd5\u90ce\u7b26\u53f7",
+"lira sign": "\u91cc\u62c9\u7b26\u53f7",
+"mill sign": "\u5bc6\u5c14\u7b26\u53f7",
+"naira sign": "\u5948\u62c9\u7b26\u53f7",
+"peseta sign": "\u6bd4\u585e\u5854\u7b26\u53f7",
+"rupee sign": "\u5362\u6bd4\u7b26\u53f7",
+"won sign": "\u97e9\u5143\u7b26\u53f7",
+"new sheqel sign": "\u65b0\u8c22\u514b\u5c14\u7b26\u53f7",
+"dong sign": "\u8d8a\u5357\u76fe\u7b26\u53f7",
+"kip sign": "\u8001\u631d\u57fa\u666e\u7b26\u53f7",
+"tugrik sign": "\u56fe\u683c\u91cc\u514b\u7b26\u53f7",
+"drachma sign": "\u5fb7\u62c9\u514b\u9a6c\u7b26\u53f7",
+"german penny symbol": "\u5fb7\u56fd\u4fbf\u58eb\u7b26\u53f7",
+"peso sign": "\u6bd4\u7d22\u7b26\u53f7",
+"guarani sign": "\u74dc\u62c9\u5c3c\u7b26\u53f7",
+"austral sign": "\u6fb3\u5143\u7b26\u53f7",
+"hryvnia sign": "\u683c\u91cc\u592b\u5c3c\u4e9a\u7b26\u53f7",
+"cedi sign": "\u585e\u5730\u7b26\u53f7",
+"livre tournois sign": "\u91cc\u5f17\u5f17\u5c14\u7b26\u53f7",
+"spesmilo sign": "spesmilo\u7b26\u53f7",
+"tenge sign": "\u575a\u6208\u7b26\u53f7",
+"indian rupee sign": "\u5370\u5ea6\u5362\u6bd4",
+"turkish lira sign": "\u571f\u8033\u5176\u91cc\u62c9",
+"nordic mark sign": "\u5317\u6b27\u9a6c\u514b",
+"manat sign": "\u9a6c\u7eb3\u7279\u7b26\u53f7",
+"ruble sign": "\u5362\u5e03\u7b26\u53f7",
+"yen character": "\u65e5\u5143\u5b57\u6837",
+"yuan character": "\u4eba\u6c11\u5e01\u5143\u5b57\u6837",
+"yuan character, in hong kong and taiwan": "\u5143\u5b57\u6837\uff08\u6e2f\u53f0\u5730\u533a\uff09",
+"yen\/yuan character variant one": "\u5143\u5b57\u6837\uff08\u5927\u5199\uff09",
+"Loading emoticons...": "\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7...",
+"Could not load emoticons": "\u4e0d\u80fd\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7",
+"People": "\u4eba\u7c7b",
+"Animals and Nature": "\u52a8\u7269\u548c\u81ea\u7136",
+"Food and Drink": "\u98df\u7269\u548c\u996e\u54c1",
+"Activity": "\u6d3b\u52a8",
+"Travel and Places": "\u65c5\u6e38\u548c\u5730\u70b9",
+"Objects": "\u7269\u4ef6",
+"Flags": "\u65d7\u5e1c",
+"Characters": "\u5b57\u7b26",
+"Characters (no spaces)": "\u5b57\u7b26(\u65e0\u7a7a\u683c)",
+"{0} characters": "{0} \u4e2a\u5b57\u7b26",
+"Error: Form submit field collision.": "\u9519\u8bef: \u8868\u5355\u63d0\u4ea4\u5b57\u6bb5\u51b2\u7a81\u3002",
+"Error: No form element found.": "\u9519\u8bef: \u6ca1\u6709\u8868\u5355\u63a7\u4ef6\u3002",
+"Update": "\u66f4\u65b0",
+"Color swatch": "\u989c\u8272\u6837\u672c",
+"Turquoise": "\u9752\u7eff\u8272",
+"Green": "\u7eff\u8272",
+"Blue": "\u84dd\u8272",
+"Purple": "\u7d2b\u8272",
+"Navy Blue": "\u6d77\u519b\u84dd",
+"Dark Turquoise": "\u6df1\u84dd\u7eff\u8272",
+"Dark Green": "\u6df1\u7eff\u8272",
+"Medium Blue": "\u4e2d\u84dd\u8272",
+"Medium Purple": "\u4e2d\u7d2b\u8272",
+"Midnight Blue": "\u6df1\u84dd\u8272",
+"Yellow": "\u9ec4\u8272",
+"Orange": "\u6a59\u8272",
+"Red": "\u7ea2\u8272",
+"Light Gray": "\u6d45\u7070\u8272",
+"Gray": "\u7070\u8272",
+"Dark Yellow": "\u6697\u9ec4\u8272",
+"Dark Orange": "\u6df1\u6a59\u8272",
+"Dark Red": "\u6df1\u7ea2\u8272",
+"Medium Gray": "\u4e2d\u7070\u8272",
+"Dark Gray": "\u6df1\u7070\u8272",
+"Light Green": "\u6d45\u7eff\u8272",
+"Light Yellow": "\u6d45\u9ec4\u8272",
+"Light Red": "\u6d45\u7ea2\u8272",
+"Light Purple": "\u6d45\u7d2b\u8272",
+"Light Blue": "\u6d45\u84dd\u8272",
+"Dark Purple": "\u6df1\u7d2b\u8272",
+"Dark Blue": "\u6df1\u84dd\u8272",
+"Black": "\u9ed1\u8272",
+"White": "\u767d\u8272",
+"Switch to or from fullscreen mode": "\u5207\u6362\u5168\u5c4f\u6a21\u5f0f",
+"Open help dialog": "\u6253\u5f00\u5e2e\u52a9\u5bf9\u8bdd\u6846",
+"history": "\u5386\u53f2",
+"styles": "\u6837\u5f0f",
+"formatting": "\u683c\u5f0f\u5316",
+"alignment": "\u5bf9\u9f50",
+"indentation": "\u7f29\u8fdb",
+"permanent pen": "\u8bb0\u53f7\u7b14",
+"comments": "\u5907\u6ce8",
+"Format Painter": "\u683c\u5f0f\u5237",
+"Insert\/edit iframe": "\u63d2\u5165\/\u7f16\u8f91\u6846\u67b6",
+"Capitalization": "\u5927\u5199",
+"lowercase": "\u5c0f\u5199",
+"UPPERCASE": "\u5927\u5199",
+"Title Case": "\u9996\u5b57\u6bcd\u5927\u5199",
+"Permanent Pen Properties": "\u6c38\u4e45\u7b14\u5c5e\u6027",
+"Permanent pen properties...": "\u6c38\u4e45\u7b14\u5c5e\u6027...",
+"Font": "\u5b57\u4f53",
+"Size": "\u5b57\u53f7",
+"More...": "\u66f4\u591a...",
+"Spellcheck Language": "\u62fc\u5199\u68c0\u67e5\u8bed\u8a00",
+"Select...": "\u9009\u62e9...",
+"Preferences": "\u9996\u9009\u9879",
+"Yes": "\u662f",
+"No": "\u5426",
+"Keyboard Navigation": "\u952e\u76d8\u6307\u5f15",
+"Version": "\u7248\u672c",
+"Anchor": "\u951a\u70b9",
+"Special character": "\u7279\u6b8a\u7b26\u53f7",
+"Code sample": "\u4ee3\u7801\u793a\u4f8b",
+"Color": "\u989c\u8272",
+"Emoticons": "\u8868\u60c5",
+"Document properties": "\u6587\u6863\u5c5e\u6027",
+"Image": "\u56fe\u7247",
+"Insert link": "\u63d2\u5165\u94fe\u63a5",
+"Target": "\u6253\u5f00\u65b9\u5f0f",
+"Link": "\u94fe\u63a5",
+"Poster": "\u5c01\u9762",
+"Media": "\u5a92\u4f53",
+"Print": "\u6253\u5370",
+"Prev": "\u4e0a\u4e00\u4e2a",
+"Find and replace": "\u67e5\u627e\u548c\u66ff\u6362",
+"Whole words": "\u5168\u5b57\u5339\u914d",
+"Spellcheck": "\u62fc\u5199\u68c0\u67e5",
+"Caption": "\u6807\u9898",
+"Insert template": "\u63d2\u5165\u6a21\u677f"
+});
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/form/index.vue b/ruoyi-ui/src/views/system/form/index.vue
new file mode 100644
index 000000000..e65a359b5
--- /dev/null
+++ b/ruoyi-ui/src/views/system/form/index.vue
@@ -0,0 +1,325 @@
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 新增
+
+
+ 修改
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+
+ {{scope.row.formName}}
+
+
+
+
+
+
+
+ 设计表单
+ 修改
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue b/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
index 99f9eb2dc..89572f3f3 100644
--- a/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
+++ b/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
@@ -104,3 +104,7 @@ export default {
}
}
+
+
diff --git a/ruoyi-ui/src/views/tool/build/DraggableItem.vue b/ruoyi-ui/src/views/tool/build/DraggableItem.vue
index f669ac0e6..3858cf69b 100644
--- a/ruoyi-ui/src/views/tool/build/DraggableItem.vue
+++ b/ruoyi-ui/src/views/tool/build/DraggableItem.vue
@@ -1,6 +1,6 @@
diff --git a/ruoyi-ui/src/views/tool/build/FormDrawer.vue b/ruoyi-ui/src/views/tool/build/FormDrawer.vue
new file mode 100644
index 000000000..4c704674f
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/FormDrawer.vue
@@ -0,0 +1,341 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ template
+
+
+
+
+
+
+ script
+
+
+
+
+
+
+ css
+
+
+
+
+
+
+
+
+
+
+
+ 刷新
+
+
+
+ 导出vue文件
+
+
+
+ 复制代码
+
+
+
+ 关闭
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/tool/build/JsonDrawer.vue b/ruoyi-ui/src/views/tool/build/JsonDrawer.vue
new file mode 100644
index 000000000..4d74235e8
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/JsonDrawer.vue
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+ 刷新
+
+
+
+ 复制JSON
+
+
+
+ 导出JSON文件
+
+
+
+ 关闭
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/tool/build/ResourceDialog.vue b/ruoyi-ui/src/views/tool/build/ResourceDialog.vue
new file mode 100644
index 000000000..38f72b69e
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/ResourceDialog.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+ jQuery1.8.3
+
+
+ http-vue-loader
+
+
+ 添加其他
+
+
+
+
+ 取消
+
+
+ 确定
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/tool/build/RightPanel.vue b/ruoyi-ui/src/views/tool/build/RightPanel.vue
index 1acdc5794..2f33189c5 100644
--- a/ruoyi-ui/src/views/tool/build/RightPanel.vue
+++ b/ruoyi-ui/src/views/tool/build/RightPanel.vue
@@ -11,9 +11,9 @@
-
+
-
- {{ item.label }}
+
+ {{ item.__config__.label }}
-
-
+
+
-
- {{ activeData.componentName }}
+
+ {{ activeData.__config__.componentName }}
-
-
+
+
@@ -49,13 +49,13 @@
-
-
+
+
-
+
-
+
@@ -78,20 +78,20 @@
-
-
+
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
@@ -127,7 +127,17 @@
-
+
+
+
+ 选择
+
+
+
+
@@ -136,19 +146,22 @@
-
+
-
+
-
+
+
+
+
-
+
-
+
默认
@@ -186,7 +199,7 @@
/>
-
-
-
+
+
+
@@ -248,11 +261,24 @@
+
+
+
+
+
+
+
+
+
+
-
+
@@ -270,15 +296,15 @@
@input="setTimeValue($event)"
/>
-
+
选项
-
+
@@ -289,7 +315,7 @@
:value="item.value"
@input="setOptionValue(item, $event)"
/>
-
@@ -307,10 +333,10 @@
-
+
选项
-
+
动态数据
@@ -320,27 +346,28 @@
-
+
-
+
-
+
-
+
+
-
+
-
-
+
+
默认
@@ -370,6 +397,14 @@
+
+
+
+
+
+
@@ -386,16 +421,17 @@
-
+
-
+
@@ -428,25 +465,25 @@
-
+
-
+
-
+
-
+
-
-
+
+
-
+
@@ -458,20 +495,20 @@
-
+
-
+
-
-
+
+
-
+
布局结构树
-
+
{{ node.label }}
-
+
正则校验
-
+
@@ -548,7 +585,7 @@
-
+
@@ -574,13 +611,12 @@
+
+
diff --git a/ruoyi-ui/src/views/tool/build/index.vue b/ruoyi-ui/src/views/tool/build/index.vue
index 4548012de..56bad804c 100644
--- a/ruoyi-ui/src/views/tool/build/index.vue
+++ b/ruoyi-ui/src/views/tool/build/index.vue
@@ -1,83 +1,59 @@
+
![logo]()
Form Generator
+
+
+
-
- 输入型组件
-
-
-
-
-
- {{ element.label }}
-
+
+
+
+ {{ item.title }}
-
-
- 选择型组件
-
-
-
-
-
- {{ element.label }}
+
+
+
+ {{ element.__config__.label }}
+
-
-
-
- 布局型组件
+
-
-
-
-
- {{ element.label }}
-
-
-
+
+ 保存
+
+
+ 运行
+
+
+ 查看json
+
导出vue文件
@@ -125,6 +101,18 @@
@tag-change="tagChange"
/>
+
+
import draggable from 'vuedraggable'
+import { debounce } from 'throttle-debounce'
import { saveAs } from 'file-saver'
-import beautifier from 'js-beautify'
import ClipboardJS from 'clipboard'
-import render from '@/utils/generator/render'
+import render from '@/utils/generator/render/render'
+import FormDrawer from './FormDrawer'
+import JsonDrawer from './JsonDrawer'
import RightPanel from './RightPanel'
import {
- inputComponents,
- selectComponents,
- layoutComponents,
- formConf
+ inputComponents, selectComponents, layoutComponents, formConf
} from '@/utils/generator/config'
import {
exportDefault, beautifierConf, isNumberStr, titleCase
-} from '@/utils/index'
+} from '@/utils/generator/index'
import {
makeUpHtml, vueTemplate, vueScript, cssStyle
} from '@/utils/generator/html'
@@ -160,23 +147,46 @@ import drawingDefalut from '@/utils/generator/drawingDefalut'
import logo from '@/assets/logo/logo.png'
import CodeTypeDialog from './CodeTypeDialog'
import DraggableItem from './DraggableItem'
+import {
+ getDrawingList, saveDrawingList, getIdGlobal, saveIdGlobal, getFormConf
+} from '@/utils/generator/db'
+import loadBeautifier from '@/utils/generator/loadBeautifier'
+//数据模型api
+import { listForm, getForm, delForm, addForm, updateForm, exportForm } from "@/api/system/form";
+let beautifier
const emptyActiveData = { style: {}, autosize: {} }
let oldActiveId
let tempActiveData
+const drawingListInDB = getDrawingList()
+const formConfInDB = getFormConf()
+const idGlobal = getIdGlobal()
export default {
+ props:{
+ //后台form数据
+ form:{
+ 'type':Object,
+ //对象默认值必须是函数返回的
+ default: function () {
+ return {}
+ }
+ }
+ },
components: {
draggable,
render,
+ FormDrawer,
+ JsonDrawer,
RightPanel,
CodeTypeDialog,
DraggableItem
},
data() {
return {
+ isForm:false,
logo,
- idGlobal: 100,
+ idGlobal,
formConf,
inputComponents,
selectComponents,
@@ -188,19 +198,36 @@ export default {
drawerVisible: false,
formData: {},
dialogVisible: false,
+ jsonDrawerVisible: false,
generateConf: null,
showFileName: false,
- activeData: drawingDefalut[0]
+ activeData: drawingDefalut[0],
+ saveDrawingListDebounce: debounce(340, saveDrawingList),
+ saveIdGlobalDebounce: debounce(340, saveIdGlobal),
+ leftComponents: [
+ {
+ title: '输入型组件',
+ list: inputComponents
+ },
+ {
+ title: '选择型组件',
+ list: selectComponents
+ },
+ {
+ title: '布局型组件',
+ list: layoutComponents
+ }
+ ]
}
},
computed: {
},
watch: {
// eslint-disable-next-line func-names
- 'activeData.label': function (val, oldVal) {
+ 'activeData.__config__.label': function (val, oldVal) {
if (
this.activeData.placeholder === undefined
- || !this.activeData.tag
+ || !this.activeData.__config__.tag
|| oldActiveId !== this.activeId
) {
return
@@ -212,9 +239,51 @@ export default {
oldActiveId = val
},
immediate: true
+ },
+ drawingList: {
+ handler(val) {
+ this.saveDrawingListDebounce(val)
+ if (val.length === 0) this.idGlobal = 100
+ },
+ deep: true
+ },
+ idGlobal: {
+ handler(val) {
+ this.saveIdGlobalDebounce(val)
+ },
+ immediate: true
}
},
+ //页面初始化完成
mounted() {
+ //默认加载组件
+ if(Object.keys(this.form).length > 0){
+ this.drawingList = [];
+ this.isForm = true
+ console.log(this.form)
+ const formOptions = JSON.parse(this.form.options);
+ if(formOptions){
+ this.drawingList = formOptions.fields
+ //默认选中
+ this.activeFormItem(this.drawingList[0])
+ this.formConf = formOptions
+ }
+ }else{
+ if (Array.isArray(drawingListInDB) && drawingListInDB.length > 0) {
+ this.drawingList = drawingListInDB
+ } else {
+ this.drawingList = drawingDefalut
+ }
+ //默认选中
+ this.activeFormItem(this.drawingList[0])
+ if (formConfInDB) {
+ this.formConf = formConfInDB
+ }
+ loadBeautifier(btf => {
+ beautifier = btf
+ })
+ }
+ //初始化复制版
const clipboard = new ClipboardJS('#copyNode', {
text: trigger => {
const codeStr = this.generateCode()
@@ -233,9 +302,9 @@ export default {
methods: {
activeFormItem(element) {
this.activeData = element
- this.activeId = element.formId
+ this.activeId = element.__config__.formId
},
- onEnd(obj, a) {
+ onEnd(obj) {
if (obj.from !== obj.to) {
this.activeData = tempActiveData
this.activeId = this.idGlobal
@@ -248,20 +317,18 @@ export default {
},
cloneComponent(origin) {
const clone = JSON.parse(JSON.stringify(origin))
- clone.formId = ++this.idGlobal
- clone.span = formConf.span
- clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件
- if (!clone.layout) clone.layout = 'colFormItem'
- if (clone.layout === 'colFormItem') {
- clone.vModel = `field${this.idGlobal}`
- clone.placeholder !== undefined && (clone.placeholder += clone.label)
- tempActiveData = clone
- } else if (clone.layout === 'rowFormItem') {
- delete clone.label
- clone.componentName = `row${this.idGlobal}`
- clone.gutter = this.formConf.gutter
- tempActiveData = clone
+ const config = clone.__config__
+ config.formId = ++this.idGlobal
+ config.span = this.formConf.span
+ config.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件
+ if (config.layout === 'colFormItem') {
+ clone.__vModel__ = `field${this.idGlobal}`
+ clone.placeholder !== undefined && (clone.placeholder += config.label)
+ } else if (config.layout === 'rowFormItem') {
+ config.componentName = `row${this.idGlobal}`
+ config.gutter = this.formConf.gutter
}
+ tempActiveData = clone
return tempActiveData
},
AssembleFormData() {
@@ -291,6 +358,7 @@ export default {
this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(
() => {
this.drawingList = []
+ this.idGlobal = 100
}
)
},
@@ -301,15 +369,16 @@ export default {
this.activeFormItem(clone)
},
createIdAndKey(item) {
- item.formId = ++this.idGlobal
- item.renderKey = +new Date()
- if (item.layout === 'colFormItem') {
- item.vModel = `field${this.idGlobal}`
- } else if (item.layout === 'rowFormItem') {
- item.componentName = `row${this.idGlobal}`
+ const config = item.__config__
+ config.formId = ++this.idGlobal
+ config.renderKey = +new Date()
+ if (config.layout === 'colFormItem') {
+ item.__vModel__ = `field${this.idGlobal}`
+ } else if (config.layout === 'rowFormItem') {
+ config.componentName = `row${this.idGlobal}`
}
- if (Array.isArray(item.children)) {
- item.children = item.children.map(childItem => this.createIdAndKey(childItem))
+ if (Array.isArray(config.children)) {
+ config.children = config.children.map(childItem => this.createIdAndKey(childItem))
}
return item
},
@@ -330,6 +399,10 @@ export default {
const css = cssStyle(makeUpCss(this.formData))
return beautifier.html(html + script + css, beautifierConf.html)
},
+ showJson() {
+ this.AssembleFormData()
+ this.jsonDrawerVisible = true
+ },
download() {
this.dialogVisible = true
this.showFileName = true
@@ -340,6 +413,23 @@ export default {
this.showFileName = false
this.operationType = 'run'
},
+ save(){
+ let options = {
+ fields: this.drawingList,
+ //遍历属性
+ ...this.formConf
+ }
+ this.form.options = JSON.stringify(options)
+ updateForm(this.form).then(response => {
+ if (response.code === 200) {
+ this.msgSuccess("保存成功");
+ //关闭窗口 不推荐用$parent 未来变更麻烦
+ //this.$parent.designOpen = false;
+ } else {
+ this.msgError(response.msg);
+ }
+ });
+ },
copy() {
this.dialogVisible = true
this.showFileName = false
@@ -347,15 +437,18 @@ export default {
},
tagChange(newTag) {
newTag = this.cloneComponent(newTag)
- newTag.vModel = this.activeData.vModel
- newTag.formId = this.activeId
- newTag.span = this.activeData.span
- delete this.activeData.tag
- delete this.activeData.tagIcon
- delete this.activeData.document
+ const config = newTag.__config__
+ newTag.__vModel__ = this.activeData.__vModel__
+ config.formId = this.activeId
+ config.span = this.activeData.__config__.span
+ this.activeData.__config__.tag = config.tag
+ this.activeData.__config__.tagIcon = config.tagIcon
+ this.activeData.__config__.document = config.document
+ if (typeof this.activeData.__config__.defaultValue === typeof config.defaultValue) {
+ config.defaultValue = this.activeData.__config__.defaultValue
+ }
Object.keys(newTag).forEach(key => {
- if (this.activeData[key] !== undefined
- && typeof this.activeData[key] === typeof newTag[key]) {
+ if (this.activeData[key] !== undefined) {
newTag[key] = this.activeData[key]
}
})
@@ -363,157 +456,25 @@ export default {
this.updateDrawingList(newTag, this.drawingList)
},
updateDrawingList(newTag, list) {
- const index = list.findIndex(item => item.formId === this.activeId)
+ const index = list.findIndex(item => item.__config__.formId === this.activeId)
if (index > -1) {
list.splice(index, 1, newTag)
} else {
list.forEach(item => {
- if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children)
+ if (Array.isArray(item.__config__.children)) this.updateDrawingList(newTag, item.__config__.children)
})
}
+ },
+ refreshJson(data) {
+ this.drawingList = JSON.parse(JSON.stringify(data.fields))
+ delete data.fields
+ this.formConf = data
}
}
}
`
+
+ if (Array.isArray(code.scripts) && code.scripts.length > 0) {
+ loadScriptQueue(code.scripts, () => {
+ newVue(attrs, code.js, code.html)
+ })
+ } else {
+ newVue(attrs, code.js, code.html)
+ }
+ }
+}
+
+function newVue(attrs, main, html) {
+ main = eval(`(${main})`)
+ main.template = `${html}
`
+ new Vue({
+ components: {
+ child: main
+ },
+ data() {
+ return {
+ visible: true
+ }
+ },
+ template: `
`
+ }).$mount('#app')
+}
diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
index 5dce8d694..bc5d6f2ab 100644
--- a/ruoyi-ui/vue.config.js
+++ b/ruoyi-ui/vue.config.js
@@ -9,6 +9,19 @@ function resolve(dir) {
const name = defaultSettings.title || '若依管理系统' // 标题
const port = process.env.port || process.env.npm_config_port || 80 // 端口
+//monaco webpack 插件
+const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
+
+const minify = process.env.NODE_ENV === 'development' ? false : {
+ collapseWhitespace: true,
+ removeComments: true,
+ removeRedundantAttributes: true,
+ removeScriptTypeAttributes: true,
+ removeStyleLinkTypeAttributes: true,
+ useShortDoctype: true,
+ minifyCSS: true,
+ minifyJS: true
+}
// vue.config.js 配置说明
//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
@@ -26,6 +39,25 @@ module.exports = {
lintOnSave: process.env.NODE_ENV === 'development',
// 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
productionSourceMap: false,
+ //运行时编译
+ runtimeCompiler: true,
+ //构建多页面配置
+ pages: {
+ index: {
+ entry: 'src/main.js',
+ template: 'public/index.html',
+ filename: 'index.html',
+ chunks: ['chunk-vendors', 'chunk-common', 'index'],
+ minify
+ },
+ preview: {
+ entry: 'src/views/tool/build/preview/main.js',
+ template: 'public/preview.html',
+ filename: 'preview.html',
+ chunks: ['chunk-vendors', 'chunk-common', 'preview'],
+ minify
+ }
+ },
// webpack-dev-server 相关配置
devServer: {
host: '0.0.0.0',
@@ -33,7 +65,7 @@ module.exports = {
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
- target: `http://localhost:8080`,
+ target: `http://localhost:8888`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
@@ -48,7 +80,10 @@ module.exports = {
alias: {
'@': resolve('src')
}
- }
+ },
+ plugins: [
+ new MonacoWebpackPlugin()
+ ]
},
chainWebpack(config) {
config.plugins.delete('preload') // TODO: need test
@@ -81,7 +116,6 @@ module.exports = {
return options
})
.end()
-
config
// https://webpack.js.org/configuration/devtool/#development
.when(process.env.NODE_ENV === 'development',
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/PCommFormController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/PCommFormController.java
new file mode 100644
index 000000000..1f8461795
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/PCommFormController.java
@@ -0,0 +1,103 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.project.system.domain.PCommForm;
+import com.ruoyi.project.system.service.IPCommFormService;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.framework.web.page.TableDataInfo;
+
+/**
+ * 数据模型Controller
+ *
+ * @author ruoyi
+ * @date 2020-05-14
+ */
+@RestController
+@RequestMapping("/system/form")
+public class PCommFormController extends BaseController
+{
+ @Autowired
+ private IPCommFormService pCommFormService;
+
+ /**
+ * 查询数据模型列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:form:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(PCommForm pCommForm)
+ {
+ startPage();
+ List list = pCommFormService.selectPCommFormList(pCommForm);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出数据模型列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:form:export')")
+ @Log(title = "数据模型", businessType = BusinessType.EXPORT)
+ @GetMapping("/export")
+ public AjaxResult export(PCommForm pCommForm)
+ {
+ List list = pCommFormService.selectPCommFormList(pCommForm);
+ ExcelUtil util = new ExcelUtil(PCommForm.class);
+ return util.exportExcel(list, "form");
+ }
+
+ /**
+ * 获取数据模型详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('system:form:query')")
+ @GetMapping(value = "/{formId}")
+ public AjaxResult getInfo(@PathVariable("formId") Long formId)
+ {
+ return AjaxResult.success(pCommFormService.selectPCommFormById(formId));
+ }
+
+ /**
+ * 新增数据模型
+ */
+ @PreAuthorize("@ss.hasPermi('system:form:add')")
+ @Log(title = "数据模型", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody PCommForm pCommForm)
+ {
+ return toAjax(pCommFormService.insertPCommForm(pCommForm));
+ }
+
+ /**
+ * 修改数据模型
+ */
+ @PreAuthorize("@ss.hasPermi('system:form:edit')")
+ @Log(title = "数据模型", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody PCommForm pCommForm)
+ {
+ return toAjax(pCommFormService.updatePCommForm(pCommForm));
+ }
+
+ /**
+ * 删除数据模型
+ */
+ @PreAuthorize("@ss.hasPermi('system:form:remove')")
+ @Log(title = "数据模型", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{formIds}")
+ public AjaxResult remove(@PathVariable Long[] formIds)
+ {
+ return toAjax(pCommFormService.deletePCommFormByIds(formIds));
+ }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/PCommForm.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/PCommForm.java
new file mode 100644
index 000000000..55e431c52
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/PCommForm.java
@@ -0,0 +1,112 @@
+package com.ruoyi.project.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 数据模型对象 p_comm_form
+ *
+ * @author ruoyi
+ * @date 2020-05-14
+ */
+public class PCommForm extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 编号 */
+ private Long formId;
+
+ /** 表单名称 */
+ @Excel(name = "表单名称")
+ private String formName;
+
+ /** 表单描述 */
+ @Excel(name = "表单描述")
+ private String formComment;
+
+ /** 实体类名称 */
+ @Excel(name = "实体类名称")
+ private String tableName;
+
+ /** 表单配置json */
+ @Excel(name = "表单配置json")
+ private String options;
+
+ /** 版本号 */
+ @Excel(name = "版本号")
+ private String versionName;
+
+ public void setFormId(Long formId)
+ {
+ this.formId = formId;
+ }
+
+ public Long getFormId()
+ {
+ return formId;
+ }
+ public void setFormName(String formName)
+ {
+ this.formName = formName;
+ }
+
+ public String getFormName()
+ {
+ return formName;
+ }
+ public void setFormComment(String formComment)
+ {
+ this.formComment = formComment;
+ }
+
+ public String getFormComment()
+ {
+ return formComment;
+ }
+ public void setTableName(String tableName)
+ {
+ this.tableName = tableName;
+ }
+
+ public String getTableName()
+ {
+ return tableName;
+ }
+ public void setOptions(String options)
+ {
+ this.options = options;
+ }
+
+ public String getOptions()
+ {
+ return options;
+ }
+ public void setVersionName(String versionName)
+ {
+ this.versionName = versionName;
+ }
+
+ public String getVersionName()
+ {
+ return versionName;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("formId", getFormId())
+ .append("formName", getFormName())
+ .append("formComment", getFormComment())
+ .append("tableName", getTableName())
+ .append("options", getOptions())
+ .append("versionName", getVersionName())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/PCommFormMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/PCommFormMapper.java
new file mode 100644
index 000000000..aaac96869
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/PCommFormMapper.java
@@ -0,0 +1,61 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.PCommForm;
+
+/**
+ * 数据模型Mapper接口
+ *
+ * @author ruoyi
+ * @date 2020-05-14
+ */
+public interface PCommFormMapper
+{
+ /**
+ * 查询数据模型
+ *
+ * @param formId 数据模型ID
+ * @return 数据模型
+ */
+ public PCommForm selectPCommFormById(Long formId);
+
+ /**
+ * 查询数据模型列表
+ *
+ * @param pCommForm 数据模型
+ * @return 数据模型集合
+ */
+ public List selectPCommFormList(PCommForm pCommForm);
+
+ /**
+ * 新增数据模型
+ *
+ * @param pCommForm 数据模型
+ * @return 结果
+ */
+ public int insertPCommForm(PCommForm pCommForm);
+
+ /**
+ * 修改数据模型
+ *
+ * @param pCommForm 数据模型
+ * @return 结果
+ */
+ public int updatePCommForm(PCommForm pCommForm);
+
+ /**
+ * 删除数据模型
+ *
+ * @param formId 数据模型ID
+ * @return 结果
+ */
+ public int deletePCommFormById(Long formId);
+
+ /**
+ * 批量删除数据模型
+ *
+ * @param formIds 需要删除的数据ID
+ * @return 结果
+ */
+ public int deletePCommFormByIds(Long[] formIds);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/IPCommFormService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/IPCommFormService.java
new file mode 100644
index 000000000..d8c4e6c94
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/IPCommFormService.java
@@ -0,0 +1,61 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.PCommForm;
+
+/**
+ * 数据模型Service接口
+ *
+ * @author ruoyi
+ * @date 2020-05-14
+ */
+public interface IPCommFormService
+{
+ /**
+ * 查询数据模型
+ *
+ * @param formId 数据模型ID
+ * @return 数据模型
+ */
+ public PCommForm selectPCommFormById(Long formId);
+
+ /**
+ * 查询数据模型列表
+ *
+ * @param pCommForm 数据模型
+ * @return 数据模型集合
+ */
+ public List selectPCommFormList(PCommForm pCommForm);
+
+ /**
+ * 新增数据模型
+ *
+ * @param pCommForm 数据模型
+ * @return 结果
+ */
+ public int insertPCommForm(PCommForm pCommForm);
+
+ /**
+ * 修改数据模型
+ *
+ * @param pCommForm 数据模型
+ * @return 结果
+ */
+ public int updatePCommForm(PCommForm pCommForm);
+
+ /**
+ * 批量删除数据模型
+ *
+ * @param formIds 需要删除的数据模型ID
+ * @return 结果
+ */
+ public int deletePCommFormByIds(Long[] formIds);
+
+ /**
+ * 删除数据模型信息
+ *
+ * @param formId 数据模型ID
+ * @return 结果
+ */
+ public int deletePCommFormById(Long formId);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/PCommFormServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/PCommFormServiceImpl.java
new file mode 100644
index 000000000..cd14f76c3
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/PCommFormServiceImpl.java
@@ -0,0 +1,96 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.project.system.mapper.PCommFormMapper;
+import com.ruoyi.project.system.domain.PCommForm;
+import com.ruoyi.project.system.service.IPCommFormService;
+
+/**
+ * 数据模型Service业务层处理
+ *
+ * @author ruoyi
+ * @date 2020-05-14
+ */
+@Service
+public class PCommFormServiceImpl implements IPCommFormService
+{
+ @Autowired
+ private PCommFormMapper pCommFormMapper;
+
+ /**
+ * 查询数据模型
+ *
+ * @param formId 数据模型ID
+ * @return 数据模型
+ */
+ @Override
+ public PCommForm selectPCommFormById(Long formId)
+ {
+ return pCommFormMapper.selectPCommFormById(formId);
+ }
+
+ /**
+ * 查询数据模型列表
+ *
+ * @param pCommForm 数据模型
+ * @return 数据模型
+ */
+ @Override
+ public List selectPCommFormList(PCommForm pCommForm)
+ {
+ return pCommFormMapper.selectPCommFormList(pCommForm);
+ }
+
+ /**
+ * 新增数据模型
+ *
+ * @param pCommForm 数据模型
+ * @return 结果
+ */
+ @Override
+ public int insertPCommForm(PCommForm pCommForm)
+ {
+ pCommForm.setCreateTime(DateUtils.getNowDate());
+ return pCommFormMapper.insertPCommForm(pCommForm);
+ }
+
+ /**
+ * 修改数据模型
+ *
+ * @param pCommForm 数据模型
+ * @return 结果
+ */
+ @Override
+ public int updatePCommForm(PCommForm pCommForm)
+ {
+ pCommForm.setUpdateTime(DateUtils.getNowDate());
+ return pCommFormMapper.updatePCommForm(pCommForm);
+ }
+
+ /**
+ * 批量删除数据模型
+ *
+ * @param formIds 需要删除的数据模型ID
+ * @return 结果
+ */
+ @Override
+ public int deletePCommFormByIds(Long[] formIds)
+ {
+ return pCommFormMapper.deletePCommFormByIds(formIds);
+ }
+
+ /**
+ * 删除数据模型信息
+ *
+ * @param formId 数据模型ID
+ * @return 结果
+ */
+ @Override
+ public int deletePCommFormById(Long formId)
+ {
+ return pCommFormMapper.deletePCommFormById(formId);
+ }
+}
diff --git a/ruoyi/src/main/resources/application-druid.yml b/ruoyi/src/main/resources/application-druid.yml
index cdfb3390b..0598f2f95 100644
--- a/ruoyi/src/main/resources/application-druid.yml
+++ b/ruoyi/src/main/resources/application-druid.yml
@@ -6,9 +6,9 @@ spring:
druid:
# 主库数据源
master:
- url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
- username: root
- password: password
+ url: jdbc:mysql://49.233.38.252:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: ckma
+ password: ckma
# 从库数据源
slave:
# 从数据源开关/默认关闭
diff --git a/ruoyi/src/main/resources/application.yml b/ruoyi/src/main/resources/application.yml
index 34b1f4324..3085ad8ab 100644
--- a/ruoyi/src/main/resources/application.yml
+++ b/ruoyi/src/main/resources/application.yml
@@ -16,7 +16,7 @@ ruoyi:
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
- port: 8080
+ port: 8888
servlet:
# 应用的访问路径
context-path: /
@@ -57,14 +57,14 @@ spring:
# redis 配置
redis:
# 地址
- host: localhost
+ host: 49.233.38.252
# 端口,默认为6379
- port: 6379
+ port: 16379
# 密码
- password:
+ password: ckma
# 连接超时时间
timeout: 10s
- lettuce:
+ jedis:
pool:
# 连接池中的最小空闲连接
min-idle: 0
diff --git a/ruoyi/src/main/resources/mybatis/system/PCommFormMapper.xml b/ruoyi/src/main/resources/mybatis/system/PCommFormMapper.xml
new file mode 100644
index 000000000..58f974ef0
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/PCommFormMapper.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select form_id, form_name, form_comment, table_name, options, version_name, create_by, create_time, update_by, update_time, remark from p_comm_form
+
+
+
+
+
+
+
+ insert into p_comm_form
+
+ form_name,
+ form_comment,
+ table_name,
+ options,
+ version_name,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ remark,
+
+
+ #{formName},
+ #{formComment},
+ #{tableName},
+ #{options},
+ #{versionName},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+ #{remark},
+
+
+
+
+ update p_comm_form
+
+ form_name = #{formName},
+ form_comment = #{formComment},
+ table_name = #{tableName},
+ options = #{options},
+ version_name = #{versionName},
+ create_by = #{createBy},
+ create_time = #{createTime},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+ remark = #{remark},
+
+ where form_id = #{formId}
+
+
+
+ delete from p_comm_form where form_id = #{formId}
+
+
+
+ delete from p_comm_form where form_id in
+
+ #{formId}
+
+
+
+
\ No newline at end of file