From ae0226a8f4aab0c0b74f1dc9729eb705ff3cc1f1 Mon Sep 17 00:00:00 2001
From: tony <846249920@qq.com>
Date: Sun, 11 Dec 2022 21:08:14 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20flowable=E5=89=8D=E7=AB=AF=E6=94=B9?=
=?UTF-8?q?=E9=80=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/resources/application.yml | 2 +-
.../flowable}/FlowDeployMapper.xml | 0
.../flowable}/SysTaskFormMapper.xml | 0
ruoyi-ui/package.json | 183 +-
ruoyi-ui/src/api/flowable/definition.js | 122 +
ruoyi-ui/src/api/flowable/finished.js | 80 +
ruoyi-ui/src/api/flowable/form.js | 61 +
ruoyi-ui/src/api/flowable/process.js | 98 +
ruoyi-ui/src/api/flowable/todo.js | 116 +
ruoyi-ui/src/components/Process/BpmData.js | 68 +
.../src/components/Process/PropertyPanel.vue | 169 ++
.../Process/common/customTranslate.js | 20 +
.../Process/common/mixinExecutionListener.js | 24 +
.../components/Process/common/mixinPanel.js | 70 +
.../components/Process/common/mixinXcrud.js | 22 +
.../components/Process/common/parseElement.js | 53 +
.../components/custom/customContextPad.vue | 24 +
.../Process/components/nodePanel/gateway.vue | 81 +
.../Process/components/nodePanel/process.vue | 113 +
.../nodePanel/property/executionListener.vue | 194 ++
.../nodePanel/property/listenerParam.vue | 96 +
.../nodePanel/property/multiInstance.vue | 117 +
.../components/nodePanel/property/signal.vue | 124 +
.../nodePanel/property/taskListener.vue | 196 ++
.../components/nodePanel/sequenceFlow.vue | 92 +
.../Process/components/nodePanel/startEnd.vue | 94 +
.../Process/components/nodePanel/task.vue | 426 ++++
.../components/Process/flowable/flowable.json | 1194 ++++++++++
.../src/components/Process/flowable/init.js | 24 +
.../components/Process/flowable/showConfig.js | 55 +
ruoyi-ui/src/components/Process/index.js | 5 +
ruoyi-ui/src/components/Process/index.vue | 463 ++++
ruoyi-ui/src/components/Process/lang/zh.js | 227 ++
ruoyi-ui/src/components/customBpmn/index.js | 12 +
ruoyi-ui/src/components/parser/Parser.vue | 197 ++
ruoyi-ui/src/components/parser/README.md | 17 +
.../src/components/parser/example/Index.vue | 324 +++
ruoyi-ui/src/components/parser/index.js | 3 +
ruoyi-ui/src/components/parser/package.json | 25 +
ruoyi-ui/src/components/render/package.json | 19 +
ruoyi-ui/src/components/render/render.js | 122 +
.../src/components/render/slots/el-button.js | 5 +
.../render/slots/el-checkbox-group.js | 13 +
.../src/components/render/slots/el-input.js | 8 +
.../components/render/slots/el-radio-group.js | 13 +
.../src/components/render/slots/el-select.js | 9 +
.../src/components/render/slots/el-upload.js | 17 +
ruoyi-ui/src/components/tinymce/README.md | 3 +
ruoyi-ui/src/components/tinymce/config.js | 8 +
.../src/components/tinymce/example/Index.vue | 38 +
ruoyi-ui/src/components/tinymce/index.js | 3 +
ruoyi-ui/src/components/tinymce/index.vue | 88 +
ruoyi-ui/src/components/tinymce/package.json | 28 +
ruoyi-ui/src/components/tinymce/zh_CN.js | 420 ++++
ruoyi-ui/src/icons/index.js | 9 +
ruoyi-ui/src/icons/svg/button.svg | 1 +
ruoyi-ui/src/icons/svg/cascader.svg | 1 +
ruoyi-ui/src/icons/svg/checkbox.svg | 1 +
ruoyi-ui/src/icons/svg/color.svg | 1 +
ruoyi-ui/src/icons/svg/component.svg | 1 +
ruoyi-ui/src/icons/svg/date-range.svg | 1 +
ruoyi-ui/src/icons/svg/date.svg | 1 +
ruoyi-ui/src/icons/svg/input.svg | 1 +
ruoyi-ui/src/icons/svg/number.svg | 1 +
ruoyi-ui/src/icons/svg/password.svg | 1 +
ruoyi-ui/src/icons/svg/radio.svg | 1 +
ruoyi-ui/src/icons/svg/rate.svg | 1 +
ruoyi-ui/src/icons/svg/rich-text.svg | 1 +
ruoyi-ui/src/icons/svg/row.svg | 1 +
ruoyi-ui/src/icons/svg/select.svg | 1 +
ruoyi-ui/src/icons/svg/slider.svg | 1 +
ruoyi-ui/src/icons/svg/switch.svg | 1 +
ruoyi-ui/src/icons/svg/table.svg | 1 +
ruoyi-ui/src/icons/svg/textarea.svg | 1 +
ruoyi-ui/src/icons/svg/time-range.svg | 1 +
ruoyi-ui/src/icons/svg/time.svg | 1 +
ruoyi-ui/src/icons/svg/upload.svg | 1 +
ruoyi-ui/src/router/index.js | 41 +-
ruoyi-ui/src/styles/home.scss | 271 +++
ruoyi-ui/src/styles/index.scss | 141 ++
ruoyi-ui/src/styles/mixin.scss | 33 +
ruoyi-ui/src/utils/db.js | 56 +
ruoyi-ui/src/utils/generator/config.js | 1067 +++++----
.../src/utils/generator/drawingDefalut.js | 37 +
.../src/utils/generator/drawingDefault.js | 29 -
ruoyi-ui/src/utils/index.js | 825 +++----
ruoyi-ui/src/utils/loadBeautifier.js | 28 +
ruoyi-ui/src/utils/loadMonaco.js | 40 +
ruoyi-ui/src/utils/loadScript.js | 60 +
ruoyi-ui/src/utils/loadTinymce.js | 29 +
ruoyi-ui/src/utils/pluginsConfig.js | 13 +
.../src/views/flowable/definition/index.vue | 548 +++++
.../src/views/flowable/definition/model.vue | 145 ++
.../views/flowable/task/finished/index.vue | 285 +++
.../src/views/flowable/task/form/index.vue | 308 +++
.../src/views/flowable/task/process/index.vue | 403 ++++
.../src/views/flowable/task/record/flow.vue | 36 +
.../views/flowable/task/record/flowview.vue | 243 ++
.../src/views/flowable/task/record/index.vue | 607 +++++
.../src/views/flowable/task/todo/index.vue | 237 ++
ruoyi-ui/src/views/tool/build/App.vue | 22 +
.../src/views/tool/build/CodeTypeDialog.vue | 8 +-
.../src/views/tool/build/DraggableItem.vue | 220 +-
ruoyi-ui/src/views/tool/build/FormDrawer.vue | 332 +++
ruoyi-ui/src/views/tool/build/IconsDialog.vue | 246 +-
ruoyi-ui/src/views/tool/build/JsonDrawer.vue | 144 ++
.../src/views/tool/build/ResourceDialog.vue | 116 +
ruoyi-ui/src/views/tool/build/RightPanel.vue | 1996 +++++++++--------
.../src/views/tool/build/TreeNodeDialog.vue | 15 +-
ruoyi-ui/src/views/tool/build/index.vue | 850 +++----
ruoyi-ui/src/views/tool/build/main.js | 17 +
ruoyi-ui/src/views/tool/preview/main.js | 61 +
112 files changed, 12865 insertions(+), 2660 deletions(-)
rename ruoyi-system/src/main/resources/{ => mapper/flowable}/FlowDeployMapper.xml (100%)
rename ruoyi-system/src/main/resources/{ => mapper/flowable}/SysTaskFormMapper.xml (100%)
create mode 100644 ruoyi-ui/src/api/flowable/definition.js
create mode 100644 ruoyi-ui/src/api/flowable/finished.js
create mode 100644 ruoyi-ui/src/api/flowable/form.js
create mode 100644 ruoyi-ui/src/api/flowable/process.js
create mode 100644 ruoyi-ui/src/api/flowable/todo.js
create mode 100644 ruoyi-ui/src/components/Process/BpmData.js
create mode 100644 ruoyi-ui/src/components/Process/PropertyPanel.vue
create mode 100644 ruoyi-ui/src/components/Process/common/customTranslate.js
create mode 100644 ruoyi-ui/src/components/Process/common/mixinExecutionListener.js
create mode 100644 ruoyi-ui/src/components/Process/common/mixinPanel.js
create mode 100644 ruoyi-ui/src/components/Process/common/mixinXcrud.js
create mode 100644 ruoyi-ui/src/components/Process/common/parseElement.js
create mode 100644 ruoyi-ui/src/components/Process/components/custom/customContextPad.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/gateway.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/process.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/property/executionListener.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/property/listenerParam.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/property/multiInstance.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/property/signal.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/property/taskListener.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/sequenceFlow.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/startEnd.vue
create mode 100644 ruoyi-ui/src/components/Process/components/nodePanel/task.vue
create mode 100644 ruoyi-ui/src/components/Process/flowable/flowable.json
create mode 100644 ruoyi-ui/src/components/Process/flowable/init.js
create mode 100644 ruoyi-ui/src/components/Process/flowable/showConfig.js
create mode 100644 ruoyi-ui/src/components/Process/index.js
create mode 100644 ruoyi-ui/src/components/Process/index.vue
create mode 100644 ruoyi-ui/src/components/Process/lang/zh.js
create mode 100644 ruoyi-ui/src/components/customBpmn/index.js
create mode 100644 ruoyi-ui/src/components/parser/Parser.vue
create mode 100644 ruoyi-ui/src/components/parser/README.md
create mode 100644 ruoyi-ui/src/components/parser/example/Index.vue
create mode 100644 ruoyi-ui/src/components/parser/index.js
create mode 100644 ruoyi-ui/src/components/parser/package.json
create mode 100644 ruoyi-ui/src/components/render/package.json
create mode 100644 ruoyi-ui/src/components/render/render.js
create mode 100644 ruoyi-ui/src/components/render/slots/el-button.js
create mode 100644 ruoyi-ui/src/components/render/slots/el-checkbox-group.js
create mode 100644 ruoyi-ui/src/components/render/slots/el-input.js
create mode 100644 ruoyi-ui/src/components/render/slots/el-radio-group.js
create mode 100644 ruoyi-ui/src/components/render/slots/el-select.js
create mode 100644 ruoyi-ui/src/components/render/slots/el-upload.js
create mode 100644 ruoyi-ui/src/components/tinymce/README.md
create mode 100644 ruoyi-ui/src/components/tinymce/config.js
create mode 100644 ruoyi-ui/src/components/tinymce/example/Index.vue
create mode 100644 ruoyi-ui/src/components/tinymce/index.js
create mode 100644 ruoyi-ui/src/components/tinymce/index.vue
create mode 100644 ruoyi-ui/src/components/tinymce/package.json
create mode 100644 ruoyi-ui/src/components/tinymce/zh_CN.js
create mode 100644 ruoyi-ui/src/icons/index.js
create mode 100644 ruoyi-ui/src/icons/svg/button.svg
create mode 100644 ruoyi-ui/src/icons/svg/cascader.svg
create mode 100644 ruoyi-ui/src/icons/svg/checkbox.svg
create mode 100644 ruoyi-ui/src/icons/svg/color.svg
create mode 100644 ruoyi-ui/src/icons/svg/component.svg
create mode 100644 ruoyi-ui/src/icons/svg/date-range.svg
create mode 100644 ruoyi-ui/src/icons/svg/date.svg
create mode 100644 ruoyi-ui/src/icons/svg/input.svg
create mode 100644 ruoyi-ui/src/icons/svg/number.svg
create mode 100644 ruoyi-ui/src/icons/svg/password.svg
create mode 100644 ruoyi-ui/src/icons/svg/radio.svg
create mode 100644 ruoyi-ui/src/icons/svg/rate.svg
create mode 100644 ruoyi-ui/src/icons/svg/rich-text.svg
create mode 100644 ruoyi-ui/src/icons/svg/row.svg
create mode 100644 ruoyi-ui/src/icons/svg/select.svg
create mode 100644 ruoyi-ui/src/icons/svg/slider.svg
create mode 100644 ruoyi-ui/src/icons/svg/switch.svg
create mode 100644 ruoyi-ui/src/icons/svg/table.svg
create mode 100644 ruoyi-ui/src/icons/svg/textarea.svg
create mode 100644 ruoyi-ui/src/icons/svg/time-range.svg
create mode 100644 ruoyi-ui/src/icons/svg/time.svg
create mode 100644 ruoyi-ui/src/icons/svg/upload.svg
create mode 100644 ruoyi-ui/src/styles/home.scss
create mode 100644 ruoyi-ui/src/styles/index.scss
create mode 100644 ruoyi-ui/src/styles/mixin.scss
create mode 100644 ruoyi-ui/src/utils/db.js
create mode 100644 ruoyi-ui/src/utils/generator/drawingDefalut.js
delete mode 100644 ruoyi-ui/src/utils/generator/drawingDefault.js
create mode 100644 ruoyi-ui/src/utils/loadBeautifier.js
create mode 100644 ruoyi-ui/src/utils/loadMonaco.js
create mode 100644 ruoyi-ui/src/utils/loadScript.js
create mode 100644 ruoyi-ui/src/utils/loadTinymce.js
create mode 100644 ruoyi-ui/src/utils/pluginsConfig.js
create mode 100644 ruoyi-ui/src/views/flowable/definition/index.vue
create mode 100644 ruoyi-ui/src/views/flowable/definition/model.vue
create mode 100644 ruoyi-ui/src/views/flowable/task/finished/index.vue
create mode 100644 ruoyi-ui/src/views/flowable/task/form/index.vue
create mode 100644 ruoyi-ui/src/views/flowable/task/process/index.vue
create mode 100644 ruoyi-ui/src/views/flowable/task/record/flow.vue
create mode 100644 ruoyi-ui/src/views/flowable/task/record/flowview.vue
create mode 100644 ruoyi-ui/src/views/flowable/task/record/index.vue
create mode 100644 ruoyi-ui/src/views/flowable/task/todo/index.vue
create mode 100644 ruoyi-ui/src/views/tool/build/App.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/main.js
create mode 100644 ruoyi-ui/src/views/tool/preview/main.js
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 46d65d10..75b5ba90 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -133,6 +133,6 @@ xss:
# flowable相关表
flowable:
# true 会对数据库中所有表进行更新操作。如果表不存在,则自动创建(建议开发时使用)
- database-schema-update: true
+ database-schema-update: false
# 关闭定时任务JOB
async-executor-activate: false
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/FlowDeployMapper.xml b/ruoyi-system/src/main/resources/mapper/flowable/FlowDeployMapper.xml
similarity index 100%
rename from ruoyi-system/src/main/resources/FlowDeployMapper.xml
rename to ruoyi-system/src/main/resources/mapper/flowable/FlowDeployMapper.xml
diff --git a/ruoyi-system/src/main/resources/SysTaskFormMapper.xml b/ruoyi-system/src/main/resources/mapper/flowable/SysTaskFormMapper.xml
similarity index 100%
rename from ruoyi-system/src/main/resources/SysTaskFormMapper.xml
rename to ruoyi-system/src/main/resources/mapper/flowable/SysTaskFormMapper.xml
diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 190bf2f1..6f8ec776 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -1,90 +1,93 @@
-{
- "name": "ruoyi",
- "version": "3.8.4",
- "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"
- },
- "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.24.0",
- "clipboard": "2.0.8",
- "core-js": "3.25.3",
- "echarts": "5.4.0",
- "element-ui": "2.15.10",
- "file-saver": "2.0.5",
- "fuse.js": "6.4.3",
- "highlight.js": "9.18.5",
- "js-beautify": "1.13.0",
- "js-cookie": "3.0.1",
- "jsencrypt": "3.0.0-rc.1",
- "nprogress": "0.2.0",
- "quill": "1.3.7",
- "screenfull": "5.0.2",
- "sortablejs": "1.10.2",
- "vue": "2.6.12",
- "vue-count-to": "1.0.13",
- "vue-cropper": "0.5.5",
- "vue-meta": "2.4.0",
- "vue-router": "3.4.9",
- "vuedraggable": "2.24.3",
- "vuex": "3.6.0"
- },
- "devDependencies": {
- "@vue/cli-plugin-babel": "4.4.6",
- "@vue/cli-plugin-eslint": "4.4.6",
- "@vue/cli-service": "4.4.6",
- "babel-eslint": "10.1.0",
- "babel-plugin-dynamic-import-node": "2.3.3",
- "chalk": "4.1.0",
- "compression-webpack-plugin": "5.0.2",
- "connect": "3.6.6",
- "eslint": "7.15.0",
- "eslint-plugin-vue": "7.2.0",
- "lint-staged": "10.5.3",
- "runjs": "4.4.2",
- "sass": "1.32.13",
- "sass-loader": "10.1.1",
- "script-ext-html-webpack-plugin": "2.1.5",
- "svg-sprite-loader": "5.1.1",
- "vue-template-compiler": "2.6.12"
- },
- "engines": {
- "node": ">=8.9",
- "npm": ">= 3.0.0"
- },
- "browserslist": [
- "> 1%",
- "last 2 versions"
- ]
-}
+{
+ "name": "ruoyi",
+ "version": "3.8.4",
+ "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"
+ },
+ "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.24.0",
+ "clipboard": "2.0.8",
+ "core-js": "3.25.3",
+ "echarts": "5.4.0",
+ "element-ui": "2.15.10",
+ "file-saver": "2.0.5",
+ "fuse.js": "6.4.3",
+ "highlight.js": "9.18.5",
+ "js-beautify": "1.13.0",
+ "js-cookie": "3.0.1",
+ "jsencrypt": "3.0.0-rc.1",
+ "nprogress": "0.2.0",
+ "quill": "1.3.7",
+ "screenfull": "5.0.2",
+ "sortablejs": "1.10.2",
+ "vue": "2.6.12",
+ "vue-count-to": "1.0.13",
+ "vue-cropper": "0.5.5",
+ "vue-meta": "2.4.0",
+ "vue-router": "3.4.9",
+ "vuedraggable": "2.24.3",
+ "vuex": "3.6.0",
+ "workflow-bpmn-modeler": "^0.2.8",
+ "diagram-js": "^5.0.0",
+ "vkbeautify": "^0.99.3"
+ },
+ "devDependencies": {
+ "@vue/cli-plugin-babel": "4.4.6",
+ "@vue/cli-plugin-eslint": "4.4.6",
+ "@vue/cli-service": "4.4.6",
+ "babel-eslint": "10.1.0",
+ "babel-plugin-dynamic-import-node": "2.3.3",
+ "chalk": "4.1.0",
+ "compression-webpack-plugin": "5.0.2",
+ "connect": "3.6.6",
+ "eslint": "7.15.0",
+ "eslint-plugin-vue": "7.2.0",
+ "lint-staged": "10.5.3",
+ "runjs": "4.4.2",
+ "sass": "1.32.13",
+ "sass-loader": "10.1.1",
+ "script-ext-html-webpack-plugin": "2.1.5",
+ "svg-sprite-loader": "5.1.1",
+ "vue-template-compiler": "2.6.12"
+ },
+ "engines": {
+ "node": ">=8.9",
+ "npm": ">= 3.0.0"
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions"
+ ]
+}
diff --git a/ruoyi-ui/src/api/flowable/definition.js b/ruoyi-ui/src/api/flowable/definition.js
new file mode 100644
index 00000000..d2243df9
--- /dev/null
+++ b/ruoyi-ui/src/api/flowable/definition.js
@@ -0,0 +1,122 @@
+import request from '@/utils/request'
+
+// 查询流程定义列表
+export function listDefinition(query) {
+ return request({
+ url: '/flowable/definition/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 部署流程实例
+export function definitionStart(procDefId, data) {
+ return request({
+ url: '/flowable/definition/start/' + procDefId,
+ method: 'post',
+ data: data
+ })
+}
+
+// 获取流程变量
+export function getProcessVariables(taskId) {
+ return request({
+ url: '/flowable/task/processVariables/' + taskId,
+ method: 'get'
+ })
+}
+
+// 激活/挂起流程
+export function updateState(params) {
+ return request({
+ url: '/flowable/definition/updateState',
+ method: 'put',
+ params: params
+ })
+}
+
+// 指定流程办理人员列表
+export function userList(query) {
+ return request({
+ url: '/flowable/definition/userList',
+ method: 'get',
+ params: query
+ })
+}
+
+// 指定流程办理组列表
+export function roleList(query) {
+ return request({
+ url: '/flowable/definition/roleList',
+ method: 'get',
+ params: query
+ })
+}
+
+// 读取xml文件
+export function readXml(deployId) {
+ return request({
+ url: '/flowable/definition/readXml/' + deployId,
+ method: 'get'
+ })
+}
+
+// 读取image文件
+export function readImage(deployId) {
+ return request({
+ url: '/flowable/definition/readImage/' + deployId,
+ method: 'get'
+ })
+}
+
+// 读取image文件
+export function getFlowViewer(procInsId, executionId) {
+ return request({
+ url: '/flowable/task/flowViewer/' + procInsId + '/' + executionId,
+ method: 'get'
+ })
+}
+
+// 读取xml文件
+export function saveXml(data) {
+ return request({
+ url: '/flowable/definition/save',
+ method: 'post',
+ data: data
+ })
+}
+
+// 新增流程定义
+export function addDeployment(data) {
+ return request({
+ url: '/system/deployment',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改流程定义
+export function updateDeployment(data) {
+ return request({
+ url: '/system/deployment',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除流程定义
+export function delDeployment(deployId) {
+ return request({
+ url: '/flowable/definition/' + deployId,
+ method: 'delete',
+ })
+}
+
+// 导出流程定义
+export function exportDeployment(query) {
+ return request({
+ url: '/system/deployment/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/ruoyi-ui/src/api/flowable/finished.js b/ruoyi-ui/src/api/flowable/finished.js
new file mode 100644
index 00000000..806b14fc
--- /dev/null
+++ b/ruoyi-ui/src/api/flowable/finished.js
@@ -0,0 +1,80 @@
+import request from '@/utils/request'
+import da from "element-ui/src/locale/lang/da";
+
+// 查询已办任务列表
+export function finishedList(query) {
+ return request({
+ url: '/flowable/task/finishedList',
+ method: 'get',
+ params: query
+ })
+}
+
+// 任务流转记录
+export function flowRecord(query) {
+ return request({
+ url: '/flowable/task/flowRecord',
+ method: 'get',
+ params: query
+ })
+}
+
+// 撤回任务
+export function revokeProcess(data) {
+ return request({
+ url: '/flowable/task/revokeProcess',
+ method: 'post',
+ data: data
+ })
+}
+
+// 部署流程实例
+export function deployStart(deployId) {
+ return request({
+ url: '/flowable/process/startFlow/' + deployId,
+ method: 'get',
+ })
+}
+
+// 查询流程定义详细
+export function getDeployment(id) {
+ return request({
+ url: '/system/deployment/' + id,
+ method: 'get'
+ })
+}
+
+// 新增流程定义
+export function addDeployment(data) {
+ return request({
+ url: '/system/deployment',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改流程定义
+export function updateDeployment(data) {
+ return request({
+ url: '/system/deployment',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除流程定义
+export function delDeployment(id) {
+ return request({
+ url: '/flowable/instance/delete/?instanceId=' + id,
+ method: 'delete'
+ })
+}
+
+// 导出流程定义
+export function exportDeployment(query) {
+ return request({
+ url: '/system/deployment/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/ruoyi-ui/src/api/flowable/form.js b/ruoyi-ui/src/api/flowable/form.js
new file mode 100644
index 00000000..fcc46d61
--- /dev/null
+++ b/ruoyi-ui/src/api/flowable/form.js
@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 查询流程表单列表
+export function listForm(query) {
+ return request({
+ url: '/flowable/form/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询流程表单详细
+export function getForm(formId) {
+ return request({
+ url: '/flowable/form/' + formId,
+ method: 'get'
+ })
+}
+
+// 新增流程表单
+export function addForm(data) {
+ return request({
+ url: '/flowable/form',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改流程表单
+export function updateForm(data) {
+ return request({
+ url: '/flowable/form',
+ method: 'put',
+ data: data
+ })
+}
+// 挂载表单
+export function addDeployForm(data) {
+ return request({
+ url: '/flowable/form/addDeployForm',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除流程表单
+export function delForm(formId) {
+ return request({
+ url: '/flowable/form/' + formId,
+ method: 'delete'
+ })
+}
+
+// 导出流程表单
+export function exportForm(query) {
+ return request({
+ url: '/flowable/form/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/ruoyi-ui/src/api/flowable/process.js b/ruoyi-ui/src/api/flowable/process.js
new file mode 100644
index 00000000..effce341
--- /dev/null
+++ b/ruoyi-ui/src/api/flowable/process.js
@@ -0,0 +1,98 @@
+import request from '@/utils/request'
+import da from "element-ui/src/locale/lang/da";
+
+// 我的发起的流程
+export function myProcessList(query) {
+ return request({
+ url: '/flowable/task/myProcess',
+ method: 'get',
+ params: query
+ })
+}
+
+// 完成任务
+export function complete(data) {
+ return request({
+ url: '/flowable/task/complete',
+ method: 'post',
+ data: data
+ })
+}
+
+// 取消申请
+export function stopProcess(data) {
+ return request({
+ url: '/flowable/task/stopProcess',
+ method: 'post',
+ data: data
+ })
+}
+
+// 驳回任务
+export function rejectTask(data) {
+ return request({
+ url: '/flowable/task/reject',
+ method: 'post',
+ data: data
+ })
+}
+
+// 可退回任务列表
+export function returnList(data) {
+ return request({
+ url: '/flowable/task/returnList',
+ method: 'post',
+ data: data
+ })
+}
+
+// 部署流程实例
+export function deployStart(deployId) {
+ return request({
+ url: '/flowable/process/startFlow/' + deployId,
+ method: 'get',
+ })
+}
+
+// 查询流程定义详细
+export function getDeployment(id) {
+ return request({
+ url: '/system/deployment/' + id,
+ method: 'get'
+ })
+}
+
+// 新增流程定义
+export function addDeployment(data) {
+ return request({
+ url: '/system/deployment',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改流程定义
+export function updateDeployment(data) {
+ return request({
+ url: '/system/deployment',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除流程定义
+export function delDeployment(id) {
+ return request({
+ url: '/system/deployment/' + id,
+ method: 'delete'
+ })
+}
+
+// 导出流程定义
+export function exportDeployment(query) {
+ return request({
+ url: '/system/deployment/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/ruoyi-ui/src/api/flowable/todo.js b/ruoyi-ui/src/api/flowable/todo.js
new file mode 100644
index 00000000..16e78797
--- /dev/null
+++ b/ruoyi-ui/src/api/flowable/todo.js
@@ -0,0 +1,116 @@
+import request from '@/utils/request'
+import da from "element-ui/src/locale/lang/da";
+
+// 查询待办任务列表
+export function todoList(query) {
+ return request({
+ url: '/flowable/task/todoList',
+ method: 'get',
+ params: query
+ })
+}
+
+// 完成任务
+export function complete(data) {
+ return request({
+ url: '/flowable/task/complete',
+ method: 'post',
+ data: data
+ })
+}
+
+// 委派任务
+export function delegate(data) {
+ return request({
+ url: '/flowable/task/delegate',
+ method: 'post',
+ data: data
+ })
+}
+
+// 退回任务
+export function returnTask(data) {
+ return request({
+ url: '/flowable/task/return',
+ method: 'post',
+ data: data
+ })
+}
+
+// 驳回任务
+export function rejectTask(data) {
+ return request({
+ url: '/flowable/task/reject',
+ method: 'post',
+ data: data
+ })
+}
+
+// 可退回任务列表
+export function returnList(data) {
+ return request({
+ url: '/flowable/task/returnList',
+ method: 'post',
+ data: data
+ })
+}
+
+// 下一节点
+export function getNextFlowNode(data) {
+ return request({
+ url: '/flowable/task/nextFlowNode',
+ method: 'post',
+ data: data
+ })
+}
+
+// 部署流程实例
+export function deployStart(deployId) {
+ return request({
+ url: '/flowable/process/startFlow/' + deployId,
+ method: 'get',
+ })
+}
+
+// 查询流程定义详细
+export function getDeployment(id) {
+ return request({
+ url: '/system/deployment/' + id,
+ method: 'get'
+ })
+}
+
+// 新增流程定义
+export function addDeployment(data) {
+ return request({
+ url: '/system/deployment',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改流程定义
+export function updateDeployment(data) {
+ return request({
+ url: '/system/deployment',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除流程定义
+export function delDeployment(id) {
+ return request({
+ url: '/system/deployment/' + id,
+ method: 'delete'
+ })
+}
+
+// 导出流程定义
+export function exportDeployment(query) {
+ return request({
+ url: '/system/deployment/export',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/ruoyi-ui/src/components/Process/BpmData.js b/ruoyi-ui/src/components/Process/BpmData.js
new file mode 100644
index 00000000..672ca449
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/BpmData.js
@@ -0,0 +1,68 @@
+/**
+ * 存储流程设计相关参数
+ */
+export default class BpmData {
+ constructor() {
+ this.controls = [] // 设计器控件
+ this.init()
+ }
+
+ init() {
+ this.controls = [
+ {
+ action: 'create.start-event',
+ title: '开始'
+ },
+ {
+ action: 'create.intermediate-event',
+ title: '中间'
+ },
+ {
+ action: 'create.end-event',
+ title: '结束'
+ },
+ {
+ action: 'create.exclusive-gateway',
+ title: '网关'
+ },
+ {
+ action: 'create.task',
+ title: '任务'
+ },
+ {
+ action: 'create.user-task',
+ title: '用户任务'
+ },
+ {
+ action: 'create.user-sign-task',
+ title: '会签任务'
+ },
+ {
+ action: 'create.subprocess-expanded',
+ title: '子流程'
+ },
+ {
+ action: 'create.data-object',
+ title: '数据对象'
+ },
+ {
+ action: 'create.data-store',
+ title: '数据存储'
+ },
+ {
+ action: 'create.participant-expanded',
+ title: '扩展流程'
+ },
+ {
+ action: 'create.group',
+ title: '分组'
+ }
+ ]
+ }
+
+ // 获取控件配置信息
+ getControl(action) {
+ const result = this.controls.filter(item => item.action === action)
+ return result[0] || {}
+ }
+}
diff --git a/ruoyi-ui/src/components/Process/PropertyPanel.vue b/ruoyi-ui/src/components/Process/PropertyPanel.vue
new file mode 100644
index 00000000..970bd0f8
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/PropertyPanel.vue
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/common/customTranslate.js b/ruoyi-ui/src/components/Process/common/customTranslate.js
new file mode 100644
index 00000000..fa05f9d6
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/common/customTranslate.js
@@ -0,0 +1,20 @@
+import translations from '../lang/zh'
+
+export default function customTranslate(template, replacements) {
+ replacements = replacements || {}
+
+ // Translate
+ template = translations[template] || template
+
+ // Replace
+ return template.replace(/{([^}]+)}/g, function(_, key) {
+ var str = replacements[key]
+ if (
+ translations[replacements[key]] !== null &&
+ translations[replacements[key]] !== 'undefined'
+ ) {
+ str = translations[replacements[key]]
+ }
+ return str || '{' + key + '}'
+ })
+}
diff --git a/ruoyi-ui/src/components/Process/common/mixinExecutionListener.js b/ruoyi-ui/src/components/Process/common/mixinExecutionListener.js
new file mode 100644
index 00000000..23295b00
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/common/mixinExecutionListener.js
@@ -0,0 +1,24 @@
+
+import executionListenerDialog from '../components/nodePanel/property/executionListener'
+export default {
+ components: {
+ executionListenerDialog
+ },
+ data() {
+ return {
+ executionListenerLength: 0,
+ dialogName: null
+ }
+ },
+ methods: {
+ computedExecutionListenerLength() {
+ this.executionListenerLength = this.element.businessObject.extensionElements?.values?.length ?? 0
+ },
+ finishExecutionListener() {
+ if (this.dialogName === 'executionListenerDialog') {
+ this.computedExecutionListenerLength()
+ }
+ this.dialogName = ''
+ }
+ }
+}
diff --git a/ruoyi-ui/src/components/Process/common/mixinPanel.js b/ruoyi-ui/src/components/Process/common/mixinPanel.js
new file mode 100644
index 00000000..8686b983
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/common/mixinPanel.js
@@ -0,0 +1,70 @@
+import xcrud from 'xcrud'
+import golbalConfig from 'xcrud/package/common/config'
+import showConfig from '../flowable/showConfig'
+golbalConfig.set({
+ input: {
+ // size: 'mini'
+ },
+ select: {
+ // size: 'mini'
+ },
+ colorPicker: {
+ showAlpha: true
+ },
+ xform: {
+ form: {
+ labelWidth: 'auto'
+ // size: 'mini'
+ }
+ }
+})
+export default {
+ components: { xForm: xcrud.xForm },
+ props: {
+ modeler: {
+ type: Object,
+ required: true
+ },
+ element: {
+ type: Object,
+ required: true
+ },
+ categorys: {
+ type: Array,
+ default: () => []
+ }
+ },
+ watch: {
+ 'formData.id': function(val) {
+ this.updateProperties({ id: val })
+ },
+ 'formData.name': function(val) {
+ this.updateProperties({ name: val })
+ },
+ 'formData.documentation': function(val) {
+ if (!val) {
+ this.updateProperties({ documentation: [] })
+ return
+ }
+ const documentationElement = this.modeler.get('moddle').create('bpmn:Documentation', { text: val })
+ this.updateProperties({ documentation: [documentationElement] })
+ }
+ },
+ methods: {
+ updateProperties(properties) {
+ const modeling = this.modeler.get('modeling')
+ modeling.updateProperties(this.element, properties)
+ }
+ },
+ computed: {
+ elementType() {
+ const bizObj = this.element.businessObject
+ return bizObj.eventDefinitions
+ ? bizObj.eventDefinitions[0].$type
+ : bizObj.$type
+ },
+ showConfig() {
+ return showConfig[this.elementType] || {}
+ }
+ }
+}
diff --git a/ruoyi-ui/src/components/Process/common/mixinXcrud.js b/ruoyi-ui/src/components/Process/common/mixinXcrud.js
new file mode 100644
index 00000000..1f7ee5b5
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/common/mixinXcrud.js
@@ -0,0 +1,22 @@
+import xcrud from 'xcrud'
+import golbalConfig from 'xcrud/package/common/config'
+golbalConfig.set({
+ input: {
+ // size: 'mini'
+ },
+ select: {
+ // size: 'mini'
+ },
+ colorPicker: {
+ showAlpha: true
+ },
+ xform: {
+ form: {
+ labelWidth: 'auto'
+ // size: 'mini'
+ }
+ }
+})
+export default {
+ components: { xForm: xcrud.xForm }
+}
diff --git a/ruoyi-ui/src/components/Process/common/parseElement.js b/ruoyi-ui/src/components/Process/common/parseElement.js
new file mode 100644
index 00000000..63cf336e
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/common/parseElement.js
@@ -0,0 +1,53 @@
+export function commonParse(element) {
+ const result = {
+ ...element.businessObject,
+ ...element.businessObject.$attrs
+ }
+ return formatJsonKeyValue(result)
+}
+
+export function formatJsonKeyValue(result) {
+ // 移除flowable前缀,格式化数组
+ for (const key in result) {
+ if (key.indexOf('flowable:') === 0) {
+ const newKey = key.replace('flowable:', '')
+ result[newKey] = result[key]
+ delete result[key]
+ }
+ }
+ result = documentationParse(result)
+ return result
+}
+
+export function documentationParse(obj) {
+ if ('documentation' in obj) {
+ let str = ''
+ obj.documentation.forEach(item => {
+ str += item.text
+ })
+ obj.documentation = str
+ }
+ return obj
+}
+
+export function conditionExpressionParse(obj) {
+ if ('conditionExpression' in obj) {
+ obj.conditionExpression = obj.conditionExpression.body
+ }
+ return obj
+}
+
+export function userTaskParse(obj) {
+ for (const key in obj) {
+ if (key === 'candidateUsers') {
+ obj.userType = 'candidateUsers'
+ obj[key] = obj[key]?.split(',') || []
+ } else if (key === 'candidateGroups') {
+ obj.userType = 'candidateGroups'
+ obj[key] = obj[key]?.split(',') || []
+ } else if (key === 'assignee') {
+ obj.userType = 'assignee'
+ }
+ }
+ return obj
+}
diff --git a/ruoyi-ui/src/components/Process/components/custom/customContextPad.vue b/ruoyi-ui/src/components/Process/components/custom/customContextPad.vue
new file mode 100644
index 00000000..89c2f684
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/custom/customContextPad.vue
@@ -0,0 +1,24 @@
+export default class CustomContextPad {
+ constructor(config, contextPad, create, elementFactory, injector, translate) {
+ this.create = create;
+ this.elementFactory = elementFactory;
+ this.translate = translate;
+
+ if (config.autoPlace !== false) {
+ this.autoPlace = injector.get('autoPlace', false);
+ }
+
+ contextPad.registerProvider(this); // 定义这是一个contextPad
+ }
+
+ getContextPadEntries(element) {}
+}
+
+CustomContextPad.$inject = [
+ 'config',
+ 'contextPad',
+ 'create',
+ 'elementFactory',
+ 'injector',
+ 'translate'
+];
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/gateway.vue b/ruoyi-ui/src/components/Process/components/nodePanel/gateway.vue
new file mode 100644
index 00000000..db181531
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/gateway.vue
@@ -0,0 +1,81 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/process.vue b/ruoyi-ui/src/components/Process/components/nodePanel/process.vue
new file mode 100644
index 00000000..6946f1e3
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/process.vue
@@ -0,0 +1,113 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/property/executionListener.vue b/ruoyi-ui/src/components/Process/components/nodePanel/property/executionListener.vue
new file mode 100644
index 00000000..1a15b8a1
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/property/executionListener.vue
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+ 配置
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/property/listenerParam.vue b/ruoyi-ui/src/components/Process/components/nodePanel/property/listenerParam.vue
new file mode 100644
index 00000000..dd8ace18
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/property/listenerParam.vue
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/property/multiInstance.vue b/ruoyi-ui/src/components/Process/components/nodePanel/property/multiInstance.vue
new file mode 100644
index 00000000..357b7167
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/property/multiInstance.vue
@@ -0,0 +1,117 @@
+
+
+
+
+
+ 按照BPMN2.0规范的要求,用于为每个实例创建执行的父执行,会提供下列变量:
+ nrOfInstances:实例总数。
+ nrOfActiveInstances:当前活动的(即未完成的),实例数量。对于顺序多实例,这个值总为1。
+ nrOfCompletedInstances:已完成的实例数量。
+ loopCounter:给定实例在for-each循环中的index。
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/property/signal.vue b/ruoyi-ui/src/components/Process/components/nodePanel/property/signal.vue
new file mode 100644
index 00000000..2c29d734
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/property/signal.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/property/taskListener.vue b/ruoyi-ui/src/components/Process/components/nodePanel/property/taskListener.vue
new file mode 100644
index 00000000..0f72a89a
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/property/taskListener.vue
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+ 配置
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/sequenceFlow.vue b/ruoyi-ui/src/components/Process/components/nodePanel/sequenceFlow.vue
new file mode 100644
index 00000000..178cd7d4
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/sequenceFlow.vue
@@ -0,0 +1,92 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/startEnd.vue b/ruoyi-ui/src/components/Process/components/nodePanel/startEnd.vue
new file mode 100644
index 00000000..2740bf6a
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/startEnd.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/components/nodePanel/task.vue b/ruoyi-ui/src/components/Process/components/nodePanel/task.vue
new file mode 100644
index 00000000..dae7e303
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/components/nodePanel/task.vue
@@ -0,0 +1,426 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+ 编辑
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/flowable/flowable.json b/ruoyi-ui/src/components/Process/flowable/flowable.json
new file mode 100644
index 00000000..bffad659
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/flowable/flowable.json
@@ -0,0 +1,1194 @@
+{
+ "name": "Flowable",
+ "uri": "http://flowable.org/bpmn",
+ "prefix": "flowable",
+ "xml": {
+ "tagAlias": "lowerCase"
+ },
+ "associations": [],
+ "types": [
+ {
+ "name": "InOutBinding",
+ "superClass": ["Element"],
+ "isAbstract": true,
+ "properties": [
+ {
+ "name": "source",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "sourceExpression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "target",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "businessKey",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "local",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ },
+ {
+ "name": "variables",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "In",
+ "superClass": ["InOutBinding"],
+ "meta": {
+ "allowedIn": ["bpmn:CallActivity"]
+ }
+ },
+ {
+ "name": "Out",
+ "superClass": ["InOutBinding"],
+ "meta": {
+ "allowedIn": ["bpmn:CallActivity"]
+ }
+ },
+ {
+ "name": "AsyncCapable",
+ "isAbstract": true,
+ "extends": ["bpmn:Activity", "bpmn:Gateway", "bpmn:Event"],
+ "properties": [
+ {
+ "name": "async",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ },
+ {
+ "name": "asyncBefore",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ },
+ {
+ "name": "asyncAfter",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ },
+ {
+ "name": "exclusive",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": true
+ }
+ ]
+ },
+ {
+ "name": "flowable:in",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "source",
+ "type": "string",
+ "isAttr": true
+ },
+ {
+ "name": "target",
+ "type": "string",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "flowable:out",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "source",
+ "type": "string",
+ "isAttr": true
+ },
+ {
+ "name": "target",
+ "type": "string",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "BoundaryEvent",
+ "superClass": ["CatchEvent"],
+ "properties": [
+ {
+ "name": "cancelActivity",
+ "default": true,
+ "isAttr": true,
+ "type": "Boolean"
+ },
+ {
+ "name": "attachedToRef",
+ "type": "Activity",
+ "isAttr": true,
+ "isReference": true
+ }
+ ]
+ },
+ {
+ "name": "JobPriorized",
+ "isAbstract": true,
+ "extends": ["bpmn:Process", "flowable:AsyncCapable"],
+ "properties": [
+ {
+ "name": "jobPriority",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "SignalEventDefinition",
+ "isAbstract": true,
+ "extends": ["bpmn:SignalEventDefinition"],
+ "properties": [
+ {
+ "name": "async",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ }
+ ]
+ },
+ {
+ "name": "ErrorEventDefinition",
+ "isAbstract": true,
+ "extends": ["bpmn:ErrorEventDefinition"],
+ "properties": [
+ {
+ "name": "errorCodeVariable",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "errorMessageVariable",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Error",
+ "isAbstract": true,
+ "extends": ["bpmn:Error"],
+ "properties": [
+ {
+ "name": "flowable:errorMessage",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "PotentialStarter",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "resourceAssignmentExpression",
+ "type": "bpmn:ResourceAssignmentExpression"
+ }
+ ]
+ },
+ {
+ "name": "UserTask",
+ "isAbstract": true,
+ "extends": ["bpmn:UserTask"],
+ "properties": [
+ {
+ "name": "timerEventDefinition",
+ "type": "Expression"
+ },
+ {
+ "name": "multiInstanceLoopCharacteristics",
+ "type": "MultiInstanceLoopCharacteristics"
+ }
+ ]
+ },
+ {
+ "name": "StartEvent",
+ "isAbstract": true,
+ "extends": ["bpmn:StartEvent"],
+ "properties": [
+ {
+ "name": "timerEventDefinition",
+ "type": "Expression"
+ }
+ ]
+ },
+ {
+ "name": "FormSupported",
+ "isAbstract": true,
+ "extends": ["bpmn:StartEvent", "bpmn:UserTask"],
+ "properties": [
+ {
+ "name": "formHandlerClass",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "formKey",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "TemplateSupported",
+ "isAbstract": true,
+ "extends": ["bpmn:Process", "bpmn:FlowElement"],
+ "properties": [
+ {
+ "name": "modelerTemplate",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Initiator",
+ "isAbstract": true,
+ "extends": ["bpmn:StartEvent"],
+ "properties": [
+ {
+ "name": "initiator",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ScriptTask",
+ "isAbstract": true,
+ "extends": ["bpmn:ScriptTask"],
+ "properties": [
+ {
+ "name": "resultVariable",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "resource",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Process",
+ "isAbstract": true,
+ "extends": ["bpmn:Process"],
+ "properties": [
+ {
+ "name": "candidateStarterGroups",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "candidateStarterUsers",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "versionTag",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "historyTimeToLive",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "isStartableInTasklist",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": true
+ }
+ ]
+ },
+ {
+ "name": "EscalationEventDefinition",
+ "isAbstract": true,
+ "extends": ["bpmn:EscalationEventDefinition"],
+ "properties": [
+ {
+ "name": "escalationCodeVariable",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "FormalExpression",
+ "isAbstract": true,
+ "extends": ["bpmn:FormalExpression"],
+ "properties": [
+ {
+ "name": "resource",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Assignable",
+ "extends": ["bpmn:UserTask"],
+ "properties": [
+ {
+ "name": "candidateGroups",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "dueDate",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "followUpDate",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "priority",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "CallActivity",
+ "extends": ["bpmn:CallActivity"],
+ "properties": [
+ {
+ "name": "calledElementBinding",
+ "isAttr": true,
+ "type": "String",
+ "default": "latest"
+ },
+ {
+ "name": "calledElementVersion",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "calledElementVersionTag",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "calledElementTenantId",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "caseRef",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "caseBinding",
+ "isAttr": true,
+ "type": "String",
+ "default": "latest"
+ },
+ {
+ "name": "caseVersion",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "caseTenantId",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "variableMappingClass",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "variableMappingDelegateExpression",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ServiceTaskLike",
+ "extends": [
+ "bpmn:ServiceTask",
+ "bpmn:BusinessRuleTask",
+ "bpmn:SendTask",
+ "bpmn:MessageEventDefinition"
+ ],
+ "properties": [
+ {
+ "name": "expression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "class",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "delegateExpression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "resultVariable",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ExclusiveGateway",
+ "isAbstract": true,
+ "extends": ["bpmn:ExclusiveGateway"],
+ "properties": [
+ {
+ "name": "serviceClass",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "DmnCapable",
+ "extends": ["bpmn:BusinessRuleTask"],
+ "properties": [
+ {
+ "name": "decisionRef",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "decisionRefBinding",
+ "isAttr": true,
+ "type": "String",
+ "default": "latest"
+ },
+ {
+ "name": "decisionRefVersion",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "mapDecisionResult",
+ "isAttr": true,
+ "type": "String",
+ "default": "resultList"
+ },
+ {
+ "name": "decisionRefTenantId",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ExternalCapable",
+ "extends": ["flowable:ServiceTaskLike"],
+ "properties": [
+ {
+ "name": "type",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "topic",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "TaskPriorized",
+ "extends": ["bpmn:Process", "flowable:ExternalCapable"],
+ "properties": [
+ {
+ "name": "taskPriority",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Properties",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["*"]
+ },
+ "properties": [
+ {
+ "name": "values",
+ "type": "Property",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "Property",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "id",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "name",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "value",
+ "type": "String",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "Connector",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["flowable:ServiceTaskLike"]
+ },
+ "properties": [
+ {
+ "name": "inputOutput",
+ "type": "InputOutput"
+ },
+ {
+ "name": "connectorId",
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "InputOutput",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["bpmn:FlowNode", "flowable:Connector"]
+ },
+ "properties": [
+ {
+ "name": "inputOutput",
+ "type": "InputOutput"
+ },
+ {
+ "name": "connectorId",
+ "type": "String"
+ },
+ {
+ "name": "inputParameters",
+ "isMany": true,
+ "type": "InputParameter"
+ },
+ {
+ "name": "outputParameters",
+ "isMany": true,
+ "type": "OutputParameter"
+ }
+ ]
+ },
+ {
+ "name": "InputOutputParameter",
+ "properties": [
+ {
+ "name": "name",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "value",
+ "isBody": true,
+ "type": "String"
+ },
+ {
+ "name": "definition",
+ "type": "InputOutputParameterDefinition"
+ }
+ ]
+ },
+ {
+ "name": "InputOutputParameterDefinition",
+ "isAbstract": true
+ },
+ {
+ "name": "List",
+ "superClass": ["InputOutputParameterDefinition"],
+ "properties": [
+ {
+ "name": "items",
+ "isMany": true,
+ "type": "InputOutputParameterDefinition"
+ }
+ ]
+ },
+ {
+ "name": "Map",
+ "superClass": ["InputOutputParameterDefinition"],
+ "properties": [
+ {
+ "name": "entries",
+ "isMany": true,
+ "type": "Entry"
+ }
+ ]
+ },
+ {
+ "name": "Entry",
+ "properties": [
+ {
+ "name": "key",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "value",
+ "isBody": true,
+ "type": "String"
+ },
+ {
+ "name": "definition",
+ "type": "InputOutputParameterDefinition"
+ }
+ ]
+ },
+ {
+ "name": "Value",
+ "superClass": ["InputOutputParameterDefinition"],
+ "properties": [
+ {
+ "name": "id",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "name",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "value",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Script",
+ "superClass": ["InputOutputParameterDefinition"],
+ "properties": [
+ {
+ "name": "scriptFormat",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "resource",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "value",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Field",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": [
+ "flowable:ServiceTaskLike",
+ "flowable:ExecutionListener",
+ "flowable:TaskListener"
+ ]
+ },
+ "properties": [
+ {
+ "name": "name",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "expression",
+ "isAttr": true,
+ "type": "expression"
+ },
+ {
+ "name": "string",
+ "type": "string"
+ },
+ {
+ "name": "stringValue",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "string",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": [
+ "flowable:Field"
+ ]
+ },
+ "properties": [
+ {
+ "name": "body",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "expression",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": [
+ "flowable:Field"
+ ]
+ },
+ "properties": [
+ {
+ "name": "body",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "InputParameter",
+ "superClass": ["InputOutputParameter"]
+ },
+ {
+ "name": "OutputParameter",
+ "superClass": ["InputOutputParameter"]
+ },
+ {
+ "name": "Collectable",
+ "isAbstract": true,
+ "extends": ["bpmn:MultiInstanceLoopCharacteristics"],
+ "superClass": ["flowable:AsyncCapable"],
+ "properties": [
+ {
+ "name": "collection",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "elementVariable",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "SequenceFlow",
+ "superClass": ["FlowElement"],
+ "properties": [
+ {
+ "name": "isImmediate",
+ "isAttr": true,
+ "type": "Boolean"
+ },
+ {
+ "name": "conditionExpression",
+ "type": "Expression"
+ },
+ {
+ "name": "sourceRef",
+ "type": "FlowNode",
+ "isAttr": true,
+ "isReference": true
+ },
+ {
+ "name": "targetRef",
+ "type": "FlowNode",
+ "isAttr": true,
+ "isReference": true
+ }
+ ]
+ },
+ {
+ "name": "MultiInstanceLoopCharacteristics",
+ "superClass": ["LoopCharacteristics"],
+ "properties": [
+ {
+ "name": "isSequential",
+ "default": false,
+ "isAttr": true,
+ "type": "Boolean"
+ },
+ {
+ "name": "behavior",
+ "type": "MultiInstanceBehavior",
+ "default": "All",
+ "isAttr": true
+ },
+ {
+ "name": "loopCardinality",
+ "type": "Expression",
+ "xml": {
+ "serialize": "xsi:type"
+ }
+ },
+ {
+ "name": "loopDataInputRef",
+ "type": "ItemAwareElement",
+ "isReference": true
+ },
+ {
+ "name": "loopDataOutputRef",
+ "type": "ItemAwareElement",
+ "isReference": true
+ },
+ {
+ "name": "inputDataItem",
+ "type": "DataInput",
+ "xml": {
+ "serialize": "property"
+ }
+ },
+ {
+ "name": "outputDataItem",
+ "type": "DataOutput",
+ "xml": {
+ "serialize": "property"
+ }
+ },
+ {
+ "name": "complexBehaviorDefinition",
+ "type": "ComplexBehaviorDefinition",
+ "isMany": true
+ },
+ {
+ "name": "completionCondition",
+ "type": "Expression",
+ "xml": {
+ "serialize": "xsi:type"
+ }
+ },
+ {
+ "name": "oneBehaviorEventRef",
+ "type": "EventDefinition",
+ "isAttr": true,
+ "isReference": true
+ },
+ {
+ "name": "noneBehaviorEventRef",
+ "type": "EventDefinition",
+ "isAttr": true,
+ "isReference": true
+ }
+ ]
+ },
+ {
+ "name": "FailedJobRetryTimeCycle",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["flowable:AsyncCapable", "bpmn:MultiInstanceLoopCharacteristics"]
+ },
+ "properties": [
+ {
+ "name": "body",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ExecutionListener",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": [
+ "bpmn:Task",
+ "bpmn:ServiceTask",
+ "bpmn:UserTask",
+ "bpmn:BusinessRuleTask",
+ "bpmn:ScriptTask",
+ "bpmn:ReceiveTask",
+ "bpmn:ManualTask",
+ "bpmn:ExclusiveGateway",
+ "bpmn:SequenceFlow",
+ "bpmn:ParallelGateway",
+ "bpmn:InclusiveGateway",
+ "bpmn:EventBasedGateway",
+ "bpmn:StartEvent",
+ "bpmn:IntermediateCatchEvent",
+ "bpmn:IntermediateThrowEvent",
+ "bpmn:EndEvent",
+ "bpmn:BoundaryEvent",
+ "bpmn:CallActivity",
+ "bpmn:SubProcess",
+ "bpmn:Process"
+ ]
+ },
+ "properties": [
+ {
+ "name": "expression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "class",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "delegateExpression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "event",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "script",
+ "type": "Script"
+ },
+ {
+ "name": "fields",
+ "type": "Field",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "TaskListener",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["bpmn:UserTask"]
+ },
+ "properties": [
+ {
+ "name": "expression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "class",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "delegateExpression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "event",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "script",
+ "type": "Script"
+ },
+ {
+ "name": "fields",
+ "type": "Field",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "FormProperty",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["bpmn:StartEvent", "bpmn:UserTask"]
+ },
+ "properties": [
+ {
+ "name": "id",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "name",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "type",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "required",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "readable",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "writable",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "variable",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "expression",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "datePattern",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "default",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "values",
+ "type": "Value",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "FormData",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["bpmn:StartEvent", "bpmn:UserTask"]
+ },
+ "properties": [
+ {
+ "name": "fields",
+ "type": "FormField",
+ "isMany": true
+ },
+ {
+ "name": "businessKey",
+ "type": "String",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "FormField",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "id",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "label",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "type",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "datePattern",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "defaultValue",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "properties",
+ "type": "Properties"
+ },
+ {
+ "name": "validation",
+ "type": "Validation"
+ },
+ {
+ "name": "values",
+ "type": "Value",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "Validation",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "constraints",
+ "type": "Constraint",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "Constraint",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "name",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "config",
+ "type": "String",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "ConditionalEventDefinition",
+ "isAbstract": true,
+ "extends": ["bpmn:ConditionalEventDefinition"],
+ "properties": [
+ {
+ "name": "variableName",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "variableEvent",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ }
+ ],
+ "emumerations": []
+ }
\ No newline at end of file
diff --git a/ruoyi-ui/src/components/Process/flowable/init.js b/ruoyi-ui/src/components/Process/flowable/init.js
new file mode 100644
index 00000000..ec9e282d
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/flowable/init.js
@@ -0,0 +1,24 @@
+
+function randomStr() {
+ return Math.random().toString(36).slice(-8)
+}
+
+export default function() {
+ return `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+}
diff --git a/ruoyi-ui/src/components/Process/flowable/showConfig.js b/ruoyi-ui/src/components/Process/flowable/showConfig.js
new file mode 100644
index 00000000..69ba83e5
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/flowable/showConfig.js
@@ -0,0 +1,55 @@
+export default {
+ 'bpmn:EndEvent': {},
+ 'bpmn:StartEvent': {
+ initiator: true,
+ formKey: true
+ },
+ 'bpmn:UserTask': {
+ userType: true,
+ dataType: true,
+ assignee: true,
+ candidateUsers: true,
+ candidateGroups: true,
+ // assigneeFixed: true,
+ // candidateUsersFixed: true,
+ // candidateGroupsFixed: true,
+ async: true,
+ priority: true,
+ formKey: true,
+ skipExpression: true,
+ dueDate: true,
+ taskListener: true
+ },
+ 'bpmn:ServiceTask': {
+ async: true,
+ skipExpression: true,
+ isForCompensation: true,
+ triggerable: true,
+ class: true
+ },
+ 'bpmn:ScriptTask': {
+ async: true,
+ isForCompensation: true,
+ autoStoreVariables: true
+ },
+ 'bpmn:ManualTask': {
+ async: true,
+ isForCompensation: true
+ },
+ 'bpmn:ReceiveTask': {
+ async: true,
+ isForCompensation: true
+ },
+ 'bpmn:SendTask': {
+ async: true,
+ isForCompensation: true
+ },
+ 'bpmn:BusinessRuleTask': {
+ async: true,
+ isForCompensation: true,
+ ruleVariablesInput: true,
+ rules: true,
+ resultVariable: true,
+ exclude: true
+ }
+}
diff --git a/ruoyi-ui/src/components/Process/index.js b/ruoyi-ui/src/components/Process/index.js
new file mode 100644
index 00000000..f78489d2
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/index.js
@@ -0,0 +1,5 @@
+import workflowBpmnModeler from './index.vue'
+
+workflowBpmnModeler.install = Vue => Vue.component(workflowBpmnModeler.name, workflowBpmnModeler) // 给组件配置install方法
+
+export default workflowBpmnModeler
diff --git a/ruoyi-ui/src/components/Process/index.vue b/ruoyi-ui/src/components/Process/index.vue
new file mode 100644
index 00000000..e5857d03
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/index.vue
@@ -0,0 +1,463 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查看xml
+ 下载xml
+ 下载svg
+ 保存模型
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/Process/lang/zh.js b/ruoyi-ui/src/components/Process/lang/zh.js
new file mode 100644
index 00000000..003c0cc5
--- /dev/null
+++ b/ruoyi-ui/src/components/Process/lang/zh.js
@@ -0,0 +1,227 @@
+export default {
+ // Labels
+ 'Activate the global connect tool': '激活全局连接工具',
+ 'Append {type}': '添加 {type}',
+ 'Add Lane above': '在上面添加道',
+ 'Divide into two Lanes': '分割成两个道',
+ 'Divide into three Lanes': '分割成三个道',
+ 'Add Lane below': '在下面添加道',
+ 'Append compensation activity': '追加补偿活动',
+ 'Change type': '修改类型',
+ 'Connect using Association': '使用关联连接',
+ 'Connect using Sequence/MessageFlow or Association': '使用顺序/消息流或者关联连接',
+ 'Connect using DataInputAssociation': '使用数据输入关联连接',
+ 'Remove': '移除',
+ 'Activate the hand tool': '激活抓手工具',
+ 'Activate the lasso tool': '激活套索工具',
+ 'Activate the create/remove space tool': '激活创建/删除空间工具',
+ 'Create expanded SubProcess': '创建扩展子过程',
+ 'Create IntermediateThrowEvent/BoundaryEvent': '创建中间抛出事件/边界事件',
+ 'Create Pool/Participant': '创建池/参与者',
+ 'Parallel Multi Instance': '并行多重事件',
+ 'Sequential Multi Instance': '时序多重事件',
+ 'DataObjectReference': '数据对象参考',
+ 'DataStoreReference': '数据存储参考',
+ 'Loop': '循环',
+ 'Ad-hoc': '即席',
+ 'Create {type}': '创建 {type}',
+ 'Task': '任务',
+ 'Send Task': '发送任务',
+ 'Receive Task': '接收任务',
+ 'User Task': '用户任务',
+ 'Manual Task': '手工任务',
+ 'Business Rule Task': '业务规则任务',
+ 'Service Task': '服务任务',
+ 'Script Task': '脚本任务',
+ 'Call Activity': '调用活动',
+ 'Sub Process (collapsed)': '子流程(折叠的)',
+ 'Sub Process (expanded)': '子流程(展开的)',
+ 'Start Event': '开始事件',
+ 'StartEvent': '开始事件',
+ 'Intermediate Throw Event': '中间事件',
+ 'End Event': '结束事件',
+ 'EndEvent': '结束事件',
+ 'Create Gateway': '创建网关',
+ 'Create Intermediate/Boundary Event': '创建中间/边界事件',
+ 'Message Start Event': '消息开始事件',
+ 'Timer Start Event': '定时开始事件',
+ 'Conditional Start Event': '条件开始事件',
+ 'Signal Start Event': '信号开始事件',
+ 'Error Start Event': '错误开始事件',
+ 'Escalation Start Event': '升级开始事件',
+ 'Compensation Start Event': '补偿开始事件',
+ 'Message Start Event (non-interrupting)': '消息开始事件(非中断)',
+ 'Timer Start Event (non-interrupting)': '定时开始事件(非中断)',
+ 'Conditional Start Event (non-interrupting)': '条件开始事件(非中断)',
+ 'Signal Start Event (non-interrupting)': '信号开始事件(非中断)',
+ 'Escalation Start Event (non-interrupting)': '升级开始事件(非中断)',
+ 'Message Intermediate Catch Event': '消息中间捕获事件',
+ 'Message Intermediate Throw Event': '消息中间抛出事件',
+ 'Timer Intermediate Catch Event': '定时中间捕获事件',
+ 'Escalation Intermediate Throw Event': '升级中间抛出事件',
+ 'Conditional Intermediate Catch Event': '条件中间捕获事件',
+ 'Link Intermediate Catch Event': '链接中间捕获事件',
+ 'Link Intermediate Throw Event': '链接中间抛出事件',
+ 'Compensation Intermediate Throw Event': '补偿中间抛出事件',
+ 'Signal Intermediate Catch Event': '信号中间捕获事件',
+ 'Signal Intermediate Throw Event': '信号中间抛出事件',
+ 'Message End Event': '消息结束事件',
+ 'Escalation End Event': '定时结束事件',
+ 'Error End Event': '错误结束事件',
+ 'Cancel End Event': '取消结束事件',
+ 'Compensation End Event': '补偿结束事件',
+ 'Signal End Event': '信号结束事件',
+ 'Terminate End Event': '终止结束事件',
+ 'Message Boundary Event': '消息边界事件',
+ 'Message Boundary Event (non-interrupting)': '消息边界事件(非中断)',
+ 'Timer Boundary Event': '定时边界事件',
+ 'Timer Boundary Event (non-interrupting)': '定时边界事件(非中断)',
+ 'Escalation Boundary Event': '升级边界事件',
+ 'Escalation Boundary Event (non-interrupting)': '升级边界事件(非中断)',
+ 'Conditional Boundary Event': '条件边界事件',
+ 'Conditional Boundary Event (non-interrupting)': '条件边界事件(非中断)',
+ 'Error Boundary Event': '错误边界事件',
+ 'Cancel Boundary Event': '取消边界事件',
+ 'Signal Boundary Event': '信号边界事件',
+ 'Signal Boundary Event (non-interrupting)': '信号边界事件(非中断)',
+ 'Compensation Boundary Event': '补偿边界事件',
+ 'Exclusive Gateway': '互斥网关',
+ 'Parallel Gateway': '并行网关',
+ 'Inclusive Gateway': '相容网关',
+ 'Complex Gateway': '复杂网关',
+ 'Event based Gateway': '事件网关',
+ 'Transaction': '转运',
+ 'Sub Process': '子流程',
+ 'Event Sub Process': '事件子流程',
+ 'Collapsed Pool': '折叠池',
+ 'Expanded Pool': '展开池',
+ // Errors
+ 'no parent for {element} in {parent}': '在{parent}里,{element}没有父类',
+ 'no shape type specified': '没有指定的形状类型',
+ 'flow elements must be children of pools/participants': '流元素必须是池/参与者的子类',
+ 'out of bounds release': 'out of bounds release',
+ 'more than {count} child lanes': '子道大于{count} ',
+ 'element required': '元素不能为空',
+ 'diagram not part of bpmn:Definitions': '流程图不符合bpmn规范',
+ 'no diagram to display': '没有可展示的流程图',
+ 'no process or collaboration to display': '没有可展示的流程/协作',
+ 'element {element} referenced by {referenced}#{property} not yet drawn': '由{referenced}#{property}引用的{element}元素仍未绘制',
+ 'already rendered {element}': '{element} 已被渲染',
+ 'failed to import {element}': '导入{element}失败',
+ // 属性面板的参数
+ 'Id': '标识',
+ 'Name': '名称',
+ 'General': '常规',
+ 'Details': '详情',
+ 'Message Name': '消息名称',
+ 'Message': '消息',
+ 'Initiator': '创建者',
+ 'Asynchronous Continuations': '持续异步',
+ 'Asynchronous Before': '异步前',
+ 'Asynchronous After': '异步后',
+ 'Job Configuration': '工作配置',
+ 'Exclusive': '排除',
+ 'Job Priority': '工作优先级',
+ 'Retry Time Cycle': '重试时间周期',
+ 'Documentation': '文档',
+ 'Element Documentation': '元素文档',
+ 'History Configuration': '历史配置',
+ 'History Time To Live': '历史的生存时间',
+ 'Forms': '表单',
+ 'Form Key': '表单key',
+ 'Form Fields': '表单字段',
+ 'Business Key': '业务key',
+ 'Form Field': '表单字段',
+ 'ID': '编号',
+ 'Type': '类型',
+ 'Label': '名称',
+ 'Default Value': '默认值',
+ 'Validation': '校验',
+ 'Add Constraint': '添加约束',
+ 'Config': '配置',
+ 'Properties': '属性',
+ 'Add Property': '添加属性',
+ 'Value': '值',
+ 'Listeners': '监听器',
+ 'Execution Listener': '执行监听',
+ 'Event Type': '事件类型',
+ 'Listener Type': '监听器类型',
+ 'Java Class': 'Java类',
+ 'Expression': '表达式',
+ 'Must provide a value': '必须提供一个值',
+ 'Delegate Expression': '代理表达式',
+ 'Script': '脚本',
+ 'Script Format': '脚本格式',
+ 'Script Type': '脚本类型',
+ 'Inline Script': '内联脚本',
+ 'External Script': '外部脚本',
+ 'Resource': '资源',
+ 'Field Injection': '字段注入',
+ 'Extensions': '扩展',
+ 'Input/Output': '输入/输出',
+ 'Input Parameters': '输入参数',
+ 'Output Parameters': '输出参数',
+ 'Parameters': '参数',
+ 'Output Parameter': '输出参数',
+ 'Timer Definition Type': '定时器定义类型',
+ 'Timer Definition': '定时器定义',
+ 'Date': '日期',
+ 'Duration': '持续',
+ 'Cycle': '循环',
+ 'Signal': '信号',
+ 'Signal Name': '信号名称',
+ 'Escalation': '升级',
+ 'Error': '错误',
+ 'Link Name': '链接名称',
+ 'Condition': '条件名称',
+ 'Variable Name': '变量名称',
+ 'Variable Event': '变量事件',
+ 'Specify more than one variable change event as a comma separated list.': '多个变量事件以逗号隔开',
+ 'Wait for Completion': '等待完成',
+ 'Activity Ref': '活动参考',
+ 'Version Tag': '版本标签',
+ 'Executable': '可执行文件',
+ 'External Task Configuration': '扩展任务配置',
+ 'Task Priority': '任务优先级',
+ 'External': '外部',
+ 'Connector': '连接器',
+ 'Must configure Connector': '必须配置连接器',
+ 'Connector Id': '连接器编号',
+ 'Implementation': '实现方式',
+ 'Field Injections': '字段注入',
+ 'Fields': '字段',
+ 'Result Variable': '结果变量',
+ 'Topic': '主题',
+ 'Configure Connector': '配置连接器',
+ 'Input Parameter': '输入参数',
+ 'Assignee': '代理人',
+ 'Candidate Users': '候选用户',
+ 'Candidate Groups': '候选组',
+ 'Due Date': '到期时间',
+ 'Follow Up Date': '跟踪日期',
+ 'Priority': '优先级',
+ 'The follow up date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)': '跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00',
+ 'The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)': '跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00',
+ 'Variables': '变量'
+}
+
+export const NodeName = {
+ 'bpmn:Process': '流程',
+ 'bpmn:StartEvent': '开始事件',
+ 'bpmn:IntermediateThrowEvent': '中间事件',
+ 'bpmn:Task': '任务',
+ 'bpmn:SendTask': '发送任务',
+ 'bpmn:ReceiveTask': '接收任务',
+ 'bpmn:UserTask': '用户任务',
+ 'bpmn:ManualTask': '手工任务',
+ 'bpmn:BusinessRuleTask': '业务规则任务',
+ 'bpmn:ServiceTask': '服务任务',
+ 'bpmn:ScriptTask': '脚本任务',
+ 'bpmn:EndEvent': '结束事件',
+ 'bpmn:SequenceFlow': '流程线',
+ 'bpmn:ExclusiveGateway': '互斥网关',
+ 'bpmn:ParallelGateway': '并行网关',
+ 'bpmn:InclusiveGateway': '相容网关',
+ 'bpmn:ComplexGateway': '复杂网关',
+ 'bpmn:EventBasedGateway': '事件网关'
+}
diff --git a/ruoyi-ui/src/components/customBpmn/index.js b/ruoyi-ui/src/components/customBpmn/index.js
new file mode 100644
index 00000000..ec9540b2
--- /dev/null
+++ b/ruoyi-ui/src/components/customBpmn/index.js
@@ -0,0 +1,12 @@
+import inherits from "inherits";
+import Viewer from "bpmn-js/lib/Viewer";
+import ZoomScrollModule from "diagram-js/lib/navigation/zoomscroll";
+import MoveCanvasModule from "diagram-js/lib/navigation/movecanvas";
+function CustomViewer(options) {
+ Viewer.call(this, options);
+}
+inherits(CustomViewer, Viewer);
+CustomViewer.prototype._modules = [].concat(Viewer.prototype._modules, [ZoomScrollModule, MoveCanvasModule]);
+export {
+ CustomViewer
+};
diff --git a/ruoyi-ui/src/components/parser/Parser.vue b/ruoyi-ui/src/components/parser/Parser.vue
new file mode 100644
index 00000000..b6b99445
--- /dev/null
+++ b/ruoyi-ui/src/components/parser/Parser.vue
@@ -0,0 +1,197 @@
+
diff --git a/ruoyi-ui/src/components/parser/README.md b/ruoyi-ui/src/components/parser/README.md
new file mode 100644
index 00000000..b91be7e8
--- /dev/null
+++ b/ruoyi-ui/src/components/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/components/parser/example/Index.vue b/ruoyi-ui/src/components/parser/example/Index.vue
new file mode 100644
index 00000000..d218509c
--- /dev/null
+++ b/ruoyi-ui/src/components/parser/example/Index.vue
@@ -0,0 +1,324 @@
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/parser/index.js b/ruoyi-ui/src/components/parser/index.js
new file mode 100644
index 00000000..0a44b2cc
--- /dev/null
+++ b/ruoyi-ui/src/components/parser/index.js
@@ -0,0 +1,3 @@
+import Parser from './Parser'
+
+export default Parser
diff --git a/ruoyi-ui/src/components/parser/package.json b/ruoyi-ui/src/components/parser/package.json
new file mode 100644
index 00000000..ffeaba32
--- /dev/null
+++ b/ruoyi-ui/src/components/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/blob/dev/src/components/parser"
+}
diff --git a/ruoyi-ui/src/components/render/package.json b/ruoyi-ui/src/components/render/package.json
new file mode 100644
index 00000000..96bffcfe
--- /dev/null
+++ b/ruoyi-ui/src/components/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/components/render/render.js b/ruoyi-ui/src/components/render/render.js
new file mode 100644
index 00000000..f3325dcd
--- /dev/null
+++ b/ruoyi-ui/src/components/render/render.js
@@ -0,0 +1,122 @@
+import { deepClone } from '@/utils/index'
+
+const componentChild = {}
+/**
+ * 将./slots中的文件挂载到对象componentChild上
+ * 文件名为key,对应JSON配置中的__config__.tag
+ * 文件内容为value,解析JSON配置中的__slot__
+ */
+const slotsFiles = require.context('./slots', false, /\.js$/)
+const keys = slotsFiles.keys() || []
+keys.forEach(key => {
+ const tag = key.replace(/^\.\/(.*)\.\w+$/, '$1')
+ const value = slotsFiles(key).default
+ componentChild[tag] = value
+})
+
+function vModel(dataObject, defaultValue) {
+ dataObject.props.value = defaultValue
+
+ dataObject.on.input = val => {
+ this.$emit('input', val)
+ }
+}
+
+function mountSlotFiles(h, confClone, 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))
+ }
+ })
+ }
+}
+
+function emitEvents(confClone) {
+ ['on', 'nativeOn'].forEach(attr => {
+ const eventKeyList = Object.keys(confClone[attr] || {})
+ eventKeyList.forEach(key => {
+ const val = confClone[attr][key]
+ if (typeof val === 'string') {
+ confClone[attr][key] = event => this.$emit(val, event)
+ }
+ })
+ })
+}
+
+function buildDataObject(confClone, dataObject) {
+ Object.keys(confClone).forEach(key => {
+ const val = confClone[key]
+ if (key === '__vModel__') {
+ vModel.call(this, dataObject, confClone.__config__.defaultValue)
+ } else if (dataObject[key] !== undefined) {
+ if (dataObject[key] === null
+ || dataObject[key] instanceof RegExp
+ || ['boolean', 'string', 'number', 'function'].includes(typeof dataObject[key])) {
+ dataObject[key] = val
+ } else if (Array.isArray(dataObject[key])) {
+ dataObject[key] = [...dataObject[key], ...val]
+ } else {
+ dataObject[key] = { ...dataObject[key], ...val }
+ }
+ } else {
+ dataObject.attrs[key] = val
+ }
+ })
+
+ // 清理属性
+ clearAttrs(dataObject)
+}
+
+function clearAttrs(dataObject) {
+ delete dataObject.attrs.__config__
+ delete dataObject.attrs.__slot__
+ delete dataObject.attrs.__methods__
+}
+
+function makeDataObject() {
+ // 深入数据对象:
+ // https://cn.vuejs.org/v2/guide/render-function.html#%E6%B7%B1%E5%85%A5%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1
+ return {
+ class: {},
+ attrs: {},
+ props: {},
+ domProps: {},
+ nativeOn: {},
+ on: {},
+ style: {},
+ directives: [],
+ scopedSlots: {},
+ slot: null,
+ key: null,
+ ref: null,
+ refInFor: true
+ }
+}
+
+export default {
+ props: {
+ conf: {
+ type: Object,
+ required: true
+ }
+ },
+ render(h) {
+ const dataObject = makeDataObject()
+ const confClone = deepClone(this.conf)
+ const children = this.$slots.default || []
+
+ // 如果slots文件夹存在与当前tag同名的文件,则执行文件中的代码
+ mountSlotFiles.call(this, h, confClone, children)
+
+ // 将字符串类型的事件,发送为消息
+ emitEvents.call(this, confClone)
+
+ // 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)”
+ buildDataObject.call(this, confClone, dataObject)
+
+ return h(this.conf.__config__.tag, dataObject, children)
+ }
+}
diff --git a/ruoyi-ui/src/components/render/slots/el-button.js b/ruoyi-ui/src/components/render/slots/el-button.js
new file mode 100644
index 00000000..a2d9684e
--- /dev/null
+++ b/ruoyi-ui/src/components/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/components/render/slots/el-checkbox-group.js b/ruoyi-ui/src/components/render/slots/el-checkbox-group.js
new file mode 100644
index 00000000..0a85c8e7
--- /dev/null
+++ b/ruoyi-ui/src/components/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/components/render/slots/el-input.js b/ruoyi-ui/src/components/render/slots/el-input.js
new file mode 100644
index 00000000..8bd02db2
--- /dev/null
+++ b/ruoyi-ui/src/components/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/components/render/slots/el-radio-group.js b/ruoyi-ui/src/components/render/slots/el-radio-group.js
new file mode 100644
index 00000000..c78506f9
--- /dev/null
+++ b/ruoyi-ui/src/components/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/components/render/slots/el-select.js b/ruoyi-ui/src/components/render/slots/el-select.js
new file mode 100644
index 00000000..cbf4a203
--- /dev/null
+++ b/ruoyi-ui/src/components/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/components/render/slots/el-upload.js b/ruoyi-ui/src/components/render/slots/el-upload.js
new file mode 100644
index 00000000..8ce3c351
--- /dev/null
+++ b/ruoyi-ui/src/components/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/components/tinymce/README.md b/ruoyi-ui/src/components/tinymce/README.md
new file mode 100644
index 00000000..65c01e21
--- /dev/null
+++ b/ruoyi-ui/src/components/tinymce/README.md
@@ -0,0 +1,3 @@
+## 简介
+富文本编辑器tinymce的一个vue版本封装。使用cdn动态脚本引入的方式加载。
+
diff --git a/ruoyi-ui/src/components/tinymce/config.js b/ruoyi-ui/src/components/tinymce/config.js
new file mode 100644
index 00000000..fc615544
--- /dev/null
+++ b/ruoyi-ui/src/components/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/components/tinymce/example/Index.vue b/ruoyi-ui/src/components/tinymce/example/Index.vue
new file mode 100644
index 00000000..e5a9f65d
--- /dev/null
+++ b/ruoyi-ui/src/components/tinymce/example/Index.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/tinymce/index.js b/ruoyi-ui/src/components/tinymce/index.js
new file mode 100644
index 00000000..1e831794
--- /dev/null
+++ b/ruoyi-ui/src/components/tinymce/index.js
@@ -0,0 +1,3 @@
+import Index from './index.vue'
+
+export default Index
diff --git a/ruoyi-ui/src/components/tinymce/index.vue b/ruoyi-ui/src/components/tinymce/index.vue
new file mode 100644
index 00000000..2eda1a1c
--- /dev/null
+++ b/ruoyi-ui/src/components/tinymce/index.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
diff --git a/ruoyi-ui/src/components/tinymce/package.json b/ruoyi-ui/src/components/tinymce/package.json
new file mode 100644
index 00000000..3d2d2d4b
--- /dev/null
+++ b/ruoyi-ui/src/components/tinymce/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "form-gen-tinymce",
+ "version": "1.0.0",
+ "description": "富文本编辑器tinymce的一个vue版本封装。使用cdn动态脚本引入的方式加载。",
+ "main": "lib/form-gen-tinymce.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"
+ },
+ "keywords": [
+ "tinymce-vue"
+ ],
+ "dependencies": {
+ "throttle-debounce": "^2.1.0"
+ },
+ "author": "jakHuang",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/JakHuang/form-generator/issues"
+ },
+ "homepage": "https://github.com/JakHuang/form-generator/blob/dev/src/components/tinymce"
+}
diff --git a/ruoyi-ui/src/components/tinymce/zh_CN.js b/ruoyi-ui/src/components/tinymce/zh_CN.js
new file mode 100644
index 00000000..4f494d63
--- /dev/null
+++ b/ruoyi-ui/src/components/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/icons/index.js b/ruoyi-ui/src/icons/index.js
new file mode 100644
index 00000000..2c6b309c
--- /dev/null
+++ b/ruoyi-ui/src/icons/index.js
@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg component
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const req = require.context('./svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+requireAll(req)
diff --git a/ruoyi-ui/src/icons/svg/button.svg b/ruoyi-ui/src/icons/svg/button.svg
new file mode 100644
index 00000000..904fddc8
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/button.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/cascader.svg b/ruoyi-ui/src/icons/svg/cascader.svg
new file mode 100644
index 00000000..e256024f
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/cascader.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/checkbox.svg b/ruoyi-ui/src/icons/svg/checkbox.svg
new file mode 100644
index 00000000..013fd3a2
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/checkbox.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/color.svg b/ruoyi-ui/src/icons/svg/color.svg
new file mode 100644
index 00000000..44a81aab
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/component.svg b/ruoyi-ui/src/icons/svg/component.svg
new file mode 100644
index 00000000..29c34580
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/component.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/date-range.svg b/ruoyi-ui/src/icons/svg/date-range.svg
new file mode 100644
index 00000000..fda571e7
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/date-range.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/date.svg b/ruoyi-ui/src/icons/svg/date.svg
new file mode 100644
index 00000000..52dc73ee
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/date.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/input.svg b/ruoyi-ui/src/icons/svg/input.svg
new file mode 100644
index 00000000..ab91381e
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/input.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/number.svg b/ruoyi-ui/src/icons/svg/number.svg
new file mode 100644
index 00000000..ad5ce9af
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/number.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/password.svg b/ruoyi-ui/src/icons/svg/password.svg
new file mode 100644
index 00000000..6c64defe
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/password.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/radio.svg b/ruoyi-ui/src/icons/svg/radio.svg
new file mode 100644
index 00000000..0cde3452
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/radio.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/rate.svg b/ruoyi-ui/src/icons/svg/rate.svg
new file mode 100644
index 00000000..aa3b14d7
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/rate.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/rich-text.svg b/ruoyi-ui/src/icons/svg/rich-text.svg
new file mode 100644
index 00000000..76c45bfe
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/rich-text.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/row.svg b/ruoyi-ui/src/icons/svg/row.svg
new file mode 100644
index 00000000..07809922
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/row.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/select.svg b/ruoyi-ui/src/icons/svg/select.svg
new file mode 100644
index 00000000..d6283828
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/select.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/slider.svg b/ruoyi-ui/src/icons/svg/slider.svg
new file mode 100644
index 00000000..fbe4f39f
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/slider.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/switch.svg b/ruoyi-ui/src/icons/svg/switch.svg
new file mode 100644
index 00000000..0ba61e38
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/switch.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/table.svg b/ruoyi-ui/src/icons/svg/table.svg
new file mode 100644
index 00000000..e8068454
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/table.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/textarea.svg b/ruoyi-ui/src/icons/svg/textarea.svg
new file mode 100644
index 00000000..2709f292
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/textarea.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/time-range.svg b/ruoyi-ui/src/icons/svg/time-range.svg
new file mode 100644
index 00000000..13c1202b
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/time-range.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/time.svg b/ruoyi-ui/src/icons/svg/time.svg
new file mode 100644
index 00000000..b376e32a
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/time.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/icons/svg/upload.svg b/ruoyi-ui/src/icons/svg/upload.svg
new file mode 100644
index 00000000..bae49c0a
--- /dev/null
+++ b/ruoyi-ui/src/icons/svg/upload.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index b370bdd9..6047c83c 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -87,7 +87,46 @@ export const constantRoutes = [
meta: { title: '个人中心', icon: 'user' }
}
]
- }
+ },
+ {
+ path: '/flowable',
+ component: Layout,
+ hidden: true,
+ children: [
+ {
+ path: 'definition/model/',
+ component: () => import('@/views/flowable/definition/model'),
+ name: 'Model',
+ meta: { title: '流程设计', icon: '' }
+ }
+ ]
+ },
+ {
+ path: '/flowable',
+ component: Layout,
+ hidden: true,
+ children: [
+ {
+ path: 'task/record/index',
+ component: () => import('@/views/flowable/task/record/index'),
+ name: 'Record',
+ meta: { title: '流程处理', icon: '' }
+ }
+ ]
+ },
+ {
+ path: '/tool',
+ component: Layout,
+ hidden: true,
+ children: [
+ {
+ path: 'build/index',
+ component: () => import('@/views/tool/build/index'),
+ name: 'FormBuild',
+ meta: { title: '表单配置', icon: '' }
+ }
+ ]
+ },
]
// 动态路由,基于用户权限动态去加载
diff --git a/ruoyi-ui/src/styles/home.scss b/ruoyi-ui/src/styles/home.scss
new file mode 100644
index 00000000..8792bc93
--- /dev/null
+++ b/ruoyi-ui/src/styles/home.scss
@@ -0,0 +1,271 @@
+$selectedColor: #f6f7ff;
+$lighterBlue: #409EFF;
+
+.container {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.components-list {
+ padding: 8px;
+ box-sizing: border-box;
+ height: 100%;
+ .components-item {
+ display: inline-block;
+ width: 48%;
+ margin: 1%;
+ transition: transform 0ms !important;
+ }
+}
+.components-draggable{
+ padding-bottom: 20px;
+}
+.components-title{
+ font-size: 14px;
+ color: #222;
+ margin: 6px 2px;
+ .svg-icon{
+ color: #666;
+ font-size: 18px;
+ }
+}
+
+.components-body {
+ padding: 8px 10px;
+ background: $selectedColor;
+ font-size: 12px;
+ cursor: move;
+ border: 1px dashed $selectedColor;
+ border-radius: 3px;
+ .svg-icon{
+ color: #777;
+ font-size: 15px;
+ }
+ &:hover {
+ border: 1px dashed #787be8;
+ color: #787be8;
+ .svg-icon {
+ color: #787be8;
+ }
+ }
+}
+
+.left-board {
+ width: 260px;
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 100vh;
+}
+.left-scrollbar{
+ height: calc(100vh - 42px);
+ overflow: hidden;
+}
+.center-scrollbar {
+ height: calc(100vh - 42px);
+ overflow: hidden;
+ border-left: 1px solid #f1e8e8;
+ border-right: 1px solid #f1e8e8;
+ box-sizing: border-box;
+}
+.center-board {
+ height: 100vh;
+ width: auto;
+ margin: 0 350px 0 260px;
+ box-sizing: border-box;
+}
+.empty-info{
+ position: absolute;
+ top: 46%;
+ left: 0;
+ right: 0;
+ text-align: center;
+ font-size: 18px;
+ color: #ccb1ea;
+ letter-spacing: 4px;
+}
+.action-bar{
+ position: relative;
+ height: 42px;
+ text-align: right;
+ padding: 0 15px;
+ box-sizing: border-box;;
+ border: 1px solid #f1e8e8;
+ border-top: none;
+ border-left: none;
+ .delete-btn{
+ color: #F56C6C;
+ }
+}
+.logo-wrapper{
+ position: relative;
+ height: 42px;
+ background: #fff;
+ border-bottom: 1px solid #f1e8e8;
+ box-sizing: border-box;
+}
+.logo{
+ position: absolute;
+ left: 12px;
+ top: 6px;
+ line-height: 30px;
+ color: #00afff;
+ font-weight: 600;
+ font-size: 17px;
+ white-space: nowrap;
+ > img{
+ width: 30px;
+ height: 30px;
+ vertical-align: top;
+ }
+ .github{
+ display: inline-block;
+ vertical-align: sub;
+ margin-left: 15px;
+ > img{
+ height: 22px;
+ }
+ }
+}
+
+.center-board-row {
+ padding: 12px 12px 15px 12px;
+ box-sizing: border-box;
+ & > .el-form {
+ // 69 = 12+15+42
+ height: calc(100vh - 69px);
+ }
+}
+.drawing-board {
+ height: 100%;
+ position: relative;
+ .components-body {
+ padding: 0;
+ margin: 0;
+ font-size: 0;
+ }
+ .sortable-ghost {
+ position: relative;
+ display: block;
+ overflow: hidden;
+ &::before {
+ content: " ";
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ height: 3px;
+ background: rgb(89, 89, 223);
+ z-index: 2;
+ }
+ }
+ .components-item.sortable-ghost {
+ width: 100%;
+ height: 60px;
+ background-color: $selectedColor;
+ }
+ .active-from-item {
+ & > .el-form-item{
+ background: $selectedColor;
+ border-radius: 6px;
+ }
+ & > .drawing-item-copy, & > .drawing-item-delete{
+ display: initial;
+ }
+ & > .component-name{
+ color: $lighterBlue;
+ }
+ }
+ .el-form-item{
+ margin-bottom: 15px;
+ }
+}
+.drawing-item{
+ position: relative;
+ cursor: move;
+ &.unfocus-bordered:not(.active-from-item) > div:first-child {
+ border: 1px dashed #ccc;
+ }
+ .el-form-item{
+ padding: 12px 10px;
+ }
+}
+.drawing-row-item{
+ position: relative;
+ cursor: move;
+ box-sizing: border-box;
+ border: 1px dashed #ccc;
+ border-radius: 3px;
+ padding: 0 2px;
+ margin-bottom: 15px;
+ .drawing-row-item {
+ margin-bottom: 2px;
+ }
+ .el-col{
+ margin-top: 22px;
+ }
+ .el-form-item{
+ margin-bottom: 0;
+ }
+ .drag-wrapper{
+ min-height: 80px;
+ }
+ &.active-from-item{
+ border: 1px dashed $lighterBlue;
+ }
+ .component-name{
+ position: absolute;
+ top: 0;
+ left: 0;
+ font-size: 12px;
+ color: #bbb;
+ display: inline-block;
+ padding: 0 6px;
+ }
+}
+.drawing-item, .drawing-row-item{
+ &:hover {
+ & > .el-form-item{
+ background: $selectedColor;
+ border-radius: 6px;
+ }
+ & > .drawing-item-copy, & > .drawing-item-delete{
+ display: initial;
+ }
+ }
+ & > .drawing-item-copy, & > .drawing-item-delete{
+ display: none;
+ position: absolute;
+ top: -10px;
+ width: 22px;
+ height: 22px;
+ line-height: 22px;
+ text-align: center;
+ border-radius: 50%;
+ font-size: 12px;
+ border: 1px solid;
+ cursor: pointer;
+ z-index: 1;
+ }
+ & > .drawing-item-copy{
+ right: 56px;
+ border-color: $lighterBlue;
+ color: $lighterBlue;
+ background: #fff;
+ &:hover{
+ background: $lighterBlue;
+ color: #fff;
+ }
+ }
+ & > .drawing-item-delete{
+ right: 24px;
+ border-color: #F56C6C;
+ color: #F56C6C;
+ background: #fff;
+ &:hover{
+ background: #F56C6C;
+ color: #fff;
+ }
+ }
+}
diff --git a/ruoyi-ui/src/styles/index.scss b/ruoyi-ui/src/styles/index.scss
new file mode 100644
index 00000000..c659c11f
--- /dev/null
+++ b/ruoyi-ui/src/styles/index.scss
@@ -0,0 +1,141 @@
+$editorTabsborderColor: #121315;
+body, html{
+ margin: 0;
+ padding: 0;
+ background: #fff;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
+}
+
+input, textarea{
+ font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
+}
+
+.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;
+ }
+ :focus.is-active.is-focus:not(:active) {
+ box-shadow: none;
+ border-radius: 0;
+ }
+}
+
+// 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/styles/mixin.scss b/ruoyi-ui/src/styles/mixin.scss
new file mode 100644
index 00000000..d5d1bd61
--- /dev/null
+++ b/ruoyi-ui/src/styles/mixin.scss
@@ -0,0 +1,33 @@
+@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;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/utils/db.js b/ruoyi-ui/src/utils/db.js
new file mode 100644
index 00000000..000d80da
--- /dev/null
+++ b/ruoyi-ui/src/utils/db.js
@@ -0,0 +1,56 @@
+import de from "element-ui/src/locale/lang/de";
+
+const DRAWING_ITEMS = 'drawingItems'
+const DRAWING_ITEMS_VERSION = '1.2'
+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) return JSON.parse(str)
+ return null
+}
+
+export function saveDrawingList(list) {
+ 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/config.js b/ruoyi-ui/src/utils/generator/config.js
index 005140a8..872b0237 100644
--- a/ruoyi-ui/src/utils/generator/config.js
+++ b/ruoyi-ui/src/utils/generator/config.js
@@ -1,438 +1,629 @@
-export const formConf = {
- formRef: 'elForm',
- formModel: 'formData',
- size: 'medium',
- labelPosition: 'right',
- labelWidth: 100,
- formRules: 'rules',
- gutter: 15,
- disabled: false,
- span: 24,
- formBtns: true
-}
-
-export const inputComponents = [
- {
- label: '单行文本',
- tag: 'el-input',
- tagIcon: 'input',
- 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'
- },
- {
- label: '多行文本',
- tag: 'el-input',
- tagIcon: 'textarea',
- type: 'textarea',
- placeholder: '请输入',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
- autosize: {
- minRows: 4,
- maxRows: 4
- },
- style: { width: '100%' },
- maxlength: null,
- 'show-word-limit': false,
- readonly: false,
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input'
- },
- {
- label: '密码',
- tag: 'el-input',
- tagIcon: 'password',
- 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'
- },
- {
- label: '计数器',
- tag: 'el-input-number',
- tagIcon: 'number',
- placeholder: '',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
- min: undefined,
- max: undefined,
- step: undefined,
- 'step-strictly': false,
- precision: undefined,
- 'controls-position': '',
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
- }
-]
-
-export const selectComponents = [
- {
- label: '下拉选择',
- tag: 'el-select',
- tagIcon: 'select',
- 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'
- },
- {
- label: '级联选择',
- tag: 'el-cascader',
- tagIcon: 'cascader',
- placeholder: '请选择',
- defaultValue: [],
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- props: {
- props: {
- multiple: false
- }
- },
- 'show-all-levels': true,
- disabled: false,
- clearable: true,
- filterable: false,
- required: true,
- options: [{
- id: 1,
- value: 1,
- label: '选项1',
- children: [{
- id: 2,
- value: 2,
- label: '选项1-1'
- }]
- }],
- dataType: 'dynamic',
- labelKey: 'label',
- valueKey: 'value',
- childrenKey: 'children',
- separator: '/',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
- },
- {
- label: '单选框组',
- tag: 'el-radio-group',
- tagIcon: 'radio',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
- 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'
- },
- {
- label: '多选框组',
- tag: 'el-checkbox-group',
- tagIcon: 'checkbox',
- defaultValue: [],
- span: 24,
- labelWidth: null,
- 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'
- },
- {
- label: '开关',
- tag: 'el-switch',
- tagIcon: 'switch',
- defaultValue: false,
- span: 24,
- labelWidth: null,
- 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'
- },
- {
- label: '滑块',
- tag: 'el-slider',
- tagIcon: 'slider',
- defaultValue: null,
- span: 24,
- labelWidth: null,
- 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'
- },
- {
- label: '时间选择',
- tag: 'el-time-picker',
- tagIcon: 'time',
- 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'
- },
- {
- label: '时间范围',
- tag: 'el-time-picker',
- tagIcon: 'time-range',
- defaultValue: null,
- span: 24,
- labelWidth: null,
- 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'
- },
- {
- label: '日期选择',
- tag: 'el-date-picker',
- tagIcon: 'date',
- 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'
- },
- {
- label: '日期范围',
- tag: 'el-date-picker',
- tagIcon: 'date-range',
- defaultValue: null,
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- type: 'daterange',
- 'range-separator': '至',
- 'start-placeholder': '开始日期',
- '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'
- },
- {
- label: '评分',
- tag: 'el-rate',
- tagIcon: 'rate',
- defaultValue: 0,
- span: 24,
- labelWidth: null,
- 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'
- },
- {
- label: '颜色选择',
- tag: 'el-color-picker',
- tagIcon: 'color',
- defaultValue: null,
- labelWidth: null,
- 'show-alpha': false,
- 'color-format': '',
- disabled: false,
- required: true,
- size: 'medium',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
- },
- {
- label: '上传',
- tag: 'el-upload',
- tagIcon: 'upload',
- 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'
- }
-]
-
-export const layoutComponents = [
- {
- layout: 'rowFormItem',
- tagIcon: 'row',
- type: 'default',
- justify: 'start',
- align: 'top',
- label: '行容器',
- layoutTree: true,
- children: [],
- document: 'https://element.eleme.cn/#/zh-CN/component/layout'
- },
- {
- layout: 'colFormItem',
- label: '按钮',
- changeTag: true,
- labelWidth: null,
- tag: 'el-button',
- tagIcon: 'button',
- span: 24,
- default: '主要按钮',
- type: 'primary',
- icon: 'el-icon-search',
- size: 'medium',
- disabled: false,
- document: 'https://element.eleme.cn/#/zh-CN/component/button'
- }
-]
-
-// 组件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'
-}
+// 表单属性【右面板】
+export const formConf = {
+ formRef: 'elForm',
+ formModel: 'formData',
+ size: 'medium',
+ labelPosition: 'right',
+ labelWidth: 100,
+ formRules: 'rules',
+ gutter: 15,
+ disabled: false,
+ span: 24,
+ formBtns: true
+}
+
+// 输入型组件 【左面板】
+export const inputComponents = [
+ {
+ // 组件的自定义配置
+ __config__: {
+ label: '单行文本',
+ labelWidth: null,
+ showLabel: true,
+ changeTag: true,
+ tag: 'el-input',
+ tagIcon: 'input',
+ defaultValue: undefined,
+ required: true,
+ layout: 'colFormItem',
+ span: 24,
+ document: 'https://element.eleme.cn/#/zh-CN/component/input',
+ // 正则校验规则
+ regList: []
+ },
+ // 组件的插槽属性
+ __slot__: {
+ prepend: '',
+ append: ''
+ },
+ // 其余的为可直接写在组件标签上的属性
+ placeholder: '请输入',
+ style: {width: '100%'},
+ clearable: true,
+ 'prefix-icon': '',
+ 'suffix-icon': '',
+ maxlength: null,
+ 'show-word-limit': false,
+ readonly: false,
+ disabled: false
+ },
+ {
+ __config__: {
+ label: '多行文本',
+ labelWidth: null,
+ showLabel: true,
+ tag: 'el-input',
+ tagIcon: 'textarea',
+ defaultValue: undefined,
+ required: true,
+ layout: 'colFormItem',
+ span: 24,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ },
+ type: 'textarea',
+ placeholder: '请输入',
+ autosize: {
+ minRows: 4,
+ maxRows: 4
+ },
+ style: {width: '100%'},
+ maxlength: null,
+ 'show-word-limit': false,
+ readonly: false,
+ disabled: false
+ },
+ {
+ __config__: {
+ label: '密码',
+ showLabel: true,
+ labelWidth: null,
+ changeTag: true,
+ tag: 'el-input',
+ tagIcon: 'password',
+ defaultValue: undefined,
+ layout: 'colFormItem',
+ span: 24,
+ required: true,
+ regList: [],
+ document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ },
+ __slot__: {
+ prepend: '',
+ append: ''
+ },
+ placeholder: '请输入',
+ 'show-password': true,
+ style: {width: '100%'},
+ clearable: true,
+ 'prefix-icon': '',
+ 'suffix-icon': '',
+ maxlength: null,
+ 'show-word-limit': false,
+ readonly: false,
+ disabled: false
+ },
+ {
+ __config__: {
+ label: '计数器',
+ showLabel: true,
+ changeTag: true,
+ labelWidth: null,
+ tag: 'el-input-number',
+ tagIcon: 'number',
+ defaultValue: undefined,
+ span: 24,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
+ },
+ placeholder: '',
+ min: undefined,
+ max: undefined,
+ step: 1,
+ 'step-strictly': false,
+ precision: undefined,
+ 'controls-position': '',
+ disabled: false
+ },
+ {
+ __config__: {
+ label: '编辑器',
+ showLabel: true,
+ changeTag: true,
+ labelWidth: null,
+ tag: 'tinymce',
+ tagIcon: 'rich-text',
+ defaultValue: null,
+ span: 24,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ document: 'http://tinymce.ax-z.cn'
+ },
+ placeholder: '请输入',
+ height: 300, // 编辑器高度
+ branding: false // 隐藏右下角品牌烙印
+ }
+]
+
+// 选择型组件 【左面板】
+export const selectComponents = [
+ {
+ __config__: {
+ label: '下拉选择',
+ showLabel: true,
+ labelWidth: null,
+ tag: 'el-select',
+ tagIcon: 'select',
+ 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: '请选择',
+ style: {width: '100%'},
+ clearable: true,
+ disabled: false,
+ filterable: false,
+ multiple: false
+ },
+ {
+ __config__: {
+ label: '级联选择',
+ url: 'https://www.fastmock.site/mock/f8d7a54fb1e60561e2f720d5a810009d/fg/cascaderList',
+ method: 'get',
+ dataPath: 'list',
+ dataConsumer: 'options',
+ showLabel: true,
+ labelWidth: null,
+ tag: 'el-cascader',
+ tagIcon: 'cascader',
+ layout: 'colFormItem',
+ defaultValue: [],
+ dataType: 'dynamic',
+ span: 24,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
+ },
+ options: [{
+ id: 1,
+ value: 1,
+ label: '选项1',
+ children: [{
+ id: 2,
+ value: 2,
+ label: '选项1-1'
+ }]
+ }],
+ placeholder: '请选择',
+ style: {width: '100%'},
+ props: {
+ props: {
+ multiple: false,
+ label: 'label',
+ value: 'value',
+ children: 'children'
+ }
+ },
+ 'show-all-levels': true,
+ disabled: false,
+ clearable: true,
+ filterable: false,
+ separator: '/'
+ },
+ {
+ __config__: {
+ label: '单选框组',
+ labelWidth: null,
+ showLabel: true,
+ tag: 'el-radio-group',
+ tagIcon: 'radio',
+ changeTag: true,
+ defaultValue: undefined,
+ layout: 'colFormItem',
+ span: 24,
+ optionType: 'default',
+ regList: [],
+ required: true,
+ border: false,
+ document: 'https://element.eleme.cn/#/zh-CN/component/radio'
+ },
+ __slot__: {
+ options: [{
+ label: '选项一',
+ value: 1
+ }, {
+ label: '选项二',
+ value: 2
+ }]
+ },
+ style: {},
+ size: 'medium',
+ disabled: false
+ },
+ {
+ __config__: {
+ label: '多选框组',
+ tag: 'el-checkbox-group',
+ tagIcon: 'checkbox',
+ defaultValue: [],
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ optionType: 'default',
+ required: true,
+ regList: [],
+ changeTag: true,
+ border: false,
+ document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'
+ },
+ __slot__: {
+ options: [{
+ label: '选项一',
+ value: 1
+ }, {
+ label: '选项二',
+ value: 2
+ }]
+ },
+ style: {},
+ size: 'medium',
+ min: null,
+ max: null,
+ disabled: false
+ },
+ {
+ __config__: {
+ label: '开关',
+ tag: 'el-switch',
+ tagIcon: 'switch',
+ defaultValue: false,
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/switch'
+ },
+ style: {},
+ disabled: false,
+ 'active-text': '',
+ 'inactive-text': '',
+ 'active-color': null,
+ 'inactive-color': null,
+ 'active-value': true,
+ 'inactive-value': false
+ },
+ {
+ __config__: {
+ label: '滑块',
+ tag: 'el-slider',
+ tagIcon: 'slider',
+ defaultValue: null,
+ span: 24,
+ showLabel: true,
+ layout: 'colFormItem',
+ labelWidth: null,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/slider'
+ },
+ disabled: false,
+ min: 0,
+ max: 100,
+ step: 1,
+ 'show-stops': false,
+ range: false
+ },
+ {
+ __config__: {
+ label: '时间选择',
+ tag: 'el-time-picker',
+ tagIcon: 'time',
+ defaultValue: null,
+ span: 24,
+ showLabel: true,
+ layout: 'colFormItem',
+ labelWidth: null,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+ },
+ placeholder: '请选择',
+ style: {width: '100%'},
+ disabled: false,
+ clearable: true,
+ 'picker-options': {
+ selectableRange: '00:00:00-23:59:59'
+ },
+ format: 'HH:mm:ss',
+ 'value-format': 'HH:mm:ss'
+ },
+ {
+ __config__: {
+ label: '时间范围',
+ tag: 'el-time-picker',
+ tagIcon: 'time-range',
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ defaultValue: null,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+ },
+ style: {width: '100%'},
+ disabled: false,
+ clearable: true,
+ 'is-range': true,
+ 'range-separator': '至',
+ 'start-placeholder': '开始时间',
+ 'end-placeholder': '结束时间',
+ format: 'HH:mm:ss',
+ 'value-format': 'HH:mm:ss'
+ },
+ {
+ __config__: {
+ label: '日期选择',
+ tag: 'el-date-picker',
+ tagIcon: 'date',
+ defaultValue: null,
+ showLabel: true,
+ labelWidth: null,
+ span: 24,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+ },
+ placeholder: '请选择',
+ type: 'date',
+ style: {width: '100%'},
+ disabled: false,
+ clearable: true,
+ format: 'yyyy-MM-dd',
+ 'value-format': 'yyyy-MM-dd',
+ readonly: false
+ },
+ {
+ __config__: {
+ label: '日期范围',
+ tag: 'el-date-picker',
+ tagIcon: 'date-range',
+ defaultValue: null,
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ required: true,
+ layout: 'colFormItem',
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+ },
+ style: {width: '100%'},
+ type: 'daterange',
+ 'range-separator': '至',
+ 'start-placeholder': '开始日期',
+ 'end-placeholder': '结束日期',
+ disabled: false,
+ clearable: true,
+ format: 'yyyy-MM-dd',
+ 'value-format': 'yyyy-MM-dd',
+ readonly: false
+ },
+ {
+ __config__: {
+ label: '评分',
+ tag: 'el-rate',
+ tagIcon: 'rate',
+ defaultValue: 0,
+ span: 24,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/rate'
+ },
+ style: {},
+ max: 5,
+ 'allow-half': false,
+ 'show-text': false,
+ 'show-score': false,
+ disabled: false
+ },
+ {
+ __config__: {
+ label: '颜色选择',
+ tag: 'el-color-picker',
+ tagIcon: 'color',
+ span: 24,
+ defaultValue: null,
+ showLabel: true,
+ labelWidth: null,
+ layout: 'colFormItem',
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
+ },
+ 'show-alpha': false,
+ 'color-format': '',
+ disabled: false,
+ size: 'medium'
+ },
+ {
+ __config__: {
+ label: '上传',
+ tag: 'el-upload',
+ tagIcon: 'upload',
+ layout: 'colFormItem',
+ defaultValue: null,
+ showLabel: true,
+ labelWidth: null,
+ required: true,
+ span: 24,
+ showTip: false,
+ buttonText: '点击上传',
+ regList: [],
+ changeTag: true,
+ fileSize: 2,
+ sizeUnit: 'MB',
+ document: 'https://element.eleme.cn/#/zh-CN/component/upload'
+ },
+ __slot__: {
+ 'list-type': true
+ },
+ action: 'https://jsonplaceholder.typicode.com/posts/',
+ disabled: false,
+ accept: '',
+ name: 'file',
+ 'auto-upload': true,
+ 'list-type': 'text',
+ multiple: false
+ }
+]
+
+// 布局型组件 【左面板】
+export const layoutComponents = [
+ {
+ __config__: {
+ layout: 'rowFormItem',
+ tagIcon: 'row',
+ label: '行容器',
+ layoutTree: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/layout#row-attributes'
+ },
+ type: 'default',
+ justify: 'start',
+ align: 'top'
+ },
+ {
+ __config__: {
+ label: '按钮',
+ showLabel: true,
+ changeTag: true,
+ labelWidth: null,
+ tag: 'el-button',
+ tagIcon: 'button',
+ span: 24,
+ layout: 'colFormItem',
+ document: 'https://element.eleme.cn/#/zh-CN/component/button'
+ },
+ __slot__: {
+ default: '主要按钮'
+ },
+ type: 'primary',
+ icon: 'el-icon-search',
+ round: false,
+ size: 'medium',
+ plain: false,
+ circle: false,
+ disabled: false
+ },
+ {
+ __config__: {
+ layout: 'colFormItem',
+ tagIcon: 'table',
+ tag: 'el-table',
+ document: 'https://element.eleme.cn/#/zh-CN/component/table',
+ span: 24,
+ formId: 101,
+ renderKey: 1595761764203,
+ componentName: 'row101',
+ showLabel: true,
+ changeTag: true,
+ labelWidth: null,
+ label: '表格[开发中]',
+ dataType: 'dynamic',
+ method: 'get',
+ dataPath: 'list',
+ dataConsumer: 'data',
+ url: 'https://www.fastmock.site/mock/f8d7a54fb1e60561e2f720d5a810009d/fg/tableData',
+ children: [{
+ __config__: {
+ layout: 'raw',
+ tag: 'el-table-column',
+ renderKey: 15957617660153
+ },
+ prop: 'date',
+ label: '日期'
+ }, {
+ __config__: {
+ layout: 'raw',
+ tag: 'el-table-column',
+ renderKey: 15957617660152
+ },
+ prop: 'address',
+ label: '地址'
+ }, {
+ __config__: {
+ layout: 'raw',
+ tag: 'el-table-column',
+ renderKey: 15957617660151
+ },
+ prop: 'name',
+ label: '名称'
+ }, {
+ __config__: {
+ layout: 'raw',
+ tag: 'el-table-column',
+ renderKey: 1595774496335,
+ children: [
+ {
+ __config__: {
+ label: '按钮',
+ tag: 'el-button',
+ tagIcon: 'button',
+ layout: 'raw',
+ renderKey: 1595779809901
+ },
+ __slot__: {
+ default: '主要按钮'
+ },
+ type: 'primary',
+ icon: 'el-icon-search',
+ round: false,
+ size: 'medium'
+ }
+ ]
+ },
+ label: '操作'
+ }]
+ },
+ data: [],
+ directives: [{
+ name: 'loading',
+ value: true
+ }],
+ border: true,
+ type: 'default',
+ justify: 'start',
+ align: 'top'
+ }
+]
diff --git a/ruoyi-ui/src/utils/generator/drawingDefalut.js b/ruoyi-ui/src/utils/generator/drawingDefalut.js
new file mode 100644
index 00000000..dbc1daf2
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/drawingDefalut.js
@@ -0,0 +1,37 @@
+export default [
+ {
+ __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: '请输入手机号',
+ style: { width: '100%' },
+ clearable: true,
+ 'prefix-icon': 'el-icon-mobile',
+ 'suffix-icon': '',
+ maxlength: 11,
+ 'show-word-limit': true,
+ readonly: false,
+ disabled: false
+ }
+]
diff --git a/ruoyi-ui/src/utils/generator/drawingDefault.js b/ruoyi-ui/src/utils/generator/drawingDefault.js
deleted file mode 100644
index 09f133ca..00000000
--- a/ruoyi-ui/src/utils/generator/drawingDefault.js
+++ /dev/null
@@ -1,29 +0,0 @@
-export default [
- {
- layout: 'colFormItem',
- tagIcon: 'input',
- label: '手机号',
- vModel: 'mobile',
- formId: 6,
- tag: 'el-input',
- 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: '手机号格式错误'
- }]
- }
-]
diff --git a/ruoyi-ui/src/utils/index.js b/ruoyi-ui/src/utils/index.js
index 9679e757..18741169 100644
--- a/ruoyi-ui/src/utils/index.js
+++ b/ruoyi-ui/src/utils/index.js
@@ -1,390 +1,435 @@
-import { parseTime } from './ruoyi'
-
-/**
- * 表格时间格式化
- */
-export function formatDate(cellValue) {
- if (cellValue == null || cellValue == "") return "";
- var date = new Date(cellValue)
- var year = date.getFullYear()
- var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
- var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
- var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
- var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
- var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
- return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
-}
-
-/**
- * @param {number} time
- * @param {string} option
- * @returns {string}
- */
-export function formatTime(time, option) {
- if (('' + time).length === 10) {
- time = parseInt(time) * 1000
- } else {
- time = +time
- }
- const d = new Date(time)
- const now = Date.now()
-
- const diff = (now - d) / 1000
-
- if (diff < 30) {
- return '刚刚'
- } else if (diff < 3600) {
- // less 1 hour
- return Math.ceil(diff / 60) + '分钟前'
- } else if (diff < 3600 * 24) {
- return Math.ceil(diff / 3600) + '小时前'
- } else if (diff < 3600 * 24 * 2) {
- return '1天前'
- }
- if (option) {
- return parseTime(time, option)
- } else {
- return (
- d.getMonth() +
- 1 +
- '月' +
- d.getDate() +
- '日' +
- d.getHours() +
- '时' +
- d.getMinutes() +
- '分'
- )
- }
-}
-
-/**
- * @param {string} url
- * @returns {Object}
- */
-export function getQueryObject(url) {
- url = url == null ? window.location.href : url
- const search = url.substring(url.lastIndexOf('?') + 1)
- const obj = {}
- const reg = /([^?&=]+)=([^?&=]*)/g
- search.replace(reg, (rs, $1, $2) => {
- const name = decodeURIComponent($1)
- let val = decodeURIComponent($2)
- val = String(val)
- obj[name] = val
- return rs
- })
- return obj
-}
-
-/**
- * @param {string} input value
- * @returns {number} output value
- */
-export function byteLength(str) {
- // returns the byte length of an utf8 string
- let s = str.length
- for (var i = str.length - 1; i >= 0; i--) {
- const code = str.charCodeAt(i)
- if (code > 0x7f && code <= 0x7ff) s++
- else if (code > 0x7ff && code <= 0xffff) s += 2
- if (code >= 0xDC00 && code <= 0xDFFF) i--
- }
- return s
-}
-
-/**
- * @param {Array} actual
- * @returns {Array}
- */
-export function cleanArray(actual) {
- const newArray = []
- for (let i = 0; i < actual.length; i++) {
- if (actual[i]) {
- newArray.push(actual[i])
- }
- }
- return newArray
-}
-
-/**
- * @param {Object} json
- * @returns {Array}
- */
-export function param(json) {
- if (!json) return ''
- return cleanArray(
- Object.keys(json).map(key => {
- if (json[key] === undefined) return ''
- return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
- })
- ).join('&')
-}
-
-/**
- * @param {string} url
- * @returns {Object}
- */
-export function param2Obj(url) {
- const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
- if (!search) {
- return {}
- }
- const obj = {}
- const searchArr = search.split('&')
- searchArr.forEach(v => {
- const index = v.indexOf('=')
- if (index !== -1) {
- const name = v.substring(0, index)
- const val = v.substring(index + 1, v.length)
- obj[name] = val
- }
- })
- return obj
-}
-
-/**
- * @param {string} val
- * @returns {string}
- */
-export function html2Text(val) {
- const div = document.createElement('div')
- div.innerHTML = val
- return div.textContent || div.innerText
-}
-
-/**
- * Merges two objects, giving the last one precedence
- * @param {Object} target
- * @param {(Object|Array)} source
- * @returns {Object}
- */
-export function objectMerge(target, source) {
- if (typeof target !== 'object') {
- target = {}
- }
- if (Array.isArray(source)) {
- return source.slice()
- }
- Object.keys(source).forEach(property => {
- const sourceProperty = source[property]
- if (typeof sourceProperty === 'object') {
- target[property] = objectMerge(target[property], sourceProperty)
- } else {
- target[property] = sourceProperty
- }
- })
- return target
-}
-
-/**
- * @param {HTMLElement} element
- * @param {string} className
- */
-export function toggleClass(element, className) {
- if (!element || !className) {
- return
- }
- let classString = element.className
- const nameIndex = classString.indexOf(className)
- if (nameIndex === -1) {
- classString += '' + className
- } else {
- classString =
- classString.substr(0, nameIndex) +
- classString.substr(nameIndex + className.length)
- }
- element.className = classString
-}
-
-/**
- * @param {string} type
- * @returns {Date}
- */
-export function getTime(type) {
- if (type === 'start') {
- return new Date().getTime() - 3600 * 1000 * 24 * 90
- } else {
- return new Date(new Date().toDateString())
- }
-}
-
-/**
- * @param {Function} func
- * @param {number} wait
- * @param {boolean} immediate
- * @return {*}
- */
-export function debounce(func, wait, immediate) {
- let timeout, args, context, timestamp, result
-
- const later = function() {
- // 据上一次触发时间间隔
- const last = +new Date() - timestamp
-
- // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
- if (last < wait && last > 0) {
- timeout = setTimeout(later, wait - last)
- } else {
- timeout = null
- // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
- if (!immediate) {
- result = func.apply(context, args)
- if (!timeout) context = args = null
- }
- }
- }
-
- return function(...args) {
- context = this
- timestamp = +new Date()
- const callNow = immediate && !timeout
- // 如果延时不存在,重新设定延时
- if (!timeout) timeout = setTimeout(later, wait)
- if (callNow) {
- result = func.apply(context, args)
- context = args = null
- }
-
- return result
- }
-}
-
-/**
- * This is just a simple version of deep copy
- * Has a lot of edge cases bug
- * If you want to use a perfect deep copy, use lodash's _.cloneDeep
- * @param {Object} source
- * @returns {Object}
- */
-export function deepClone(source) {
- if (!source && typeof source !== 'object') {
- throw new Error('error arguments', 'deepClone')
- }
- const targetObj = source.constructor === Array ? [] : {}
- Object.keys(source).forEach(keys => {
- if (source[keys] && typeof source[keys] === 'object') {
- targetObj[keys] = deepClone(source[keys])
- } else {
- targetObj[keys] = source[keys]
- }
- })
- return targetObj
-}
-
-/**
- * @param {Array} arr
- * @returns {Array}
- */
-export function uniqueArr(arr) {
- return Array.from(new Set(arr))
-}
-
-/**
- * @returns {string}
- */
-export function createUniqueString() {
- const timestamp = +new Date() + ''
- const randomNum = parseInt((1 + Math.random()) * 65536) + ''
- return (+(randomNum + timestamp)).toString(32)
-}
-
-/**
- * Check if an element has a class
- * @param {HTMLElement} elm
- * @param {string} cls
- * @returns {boolean}
- */
-export function hasClass(ele, cls) {
- return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
-}
-
-/**
- * Add class to element
- * @param {HTMLElement} elm
- * @param {string} cls
- */
-export function addClass(ele, cls) {
- if (!hasClass(ele, cls)) ele.className += ' ' + cls
-}
-
-/**
- * Remove class from element
- * @param {HTMLElement} elm
- * @param {string} cls
- */
-export function removeClass(ele, cls) {
- if (hasClass(ele, cls)) {
- const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
- ele.className = ele.className.replace(reg, ' ')
- }
-}
-
-export function makeMap(str, expectsLowerCase) {
- const map = Object.create(null)
- const list = str.split(',')
- for (let i = 0; i < list.length; i++) {
- map[list[i]] = true
- }
- return expectsLowerCase
- ? val => map[val.toLowerCase()]
- : val => map[val]
-}
-
-export const exportDefault = 'export default '
-
-export const beautifierConf = {
- html: {
- indent_size: '2',
- indent_char: ' ',
- max_preserve_newlines: '-1',
- preserve_newlines: false,
- keep_array_indentation: false,
- break_chained_methods: false,
- indent_scripts: 'separate',
- brace_style: 'end-expand',
- space_before_conditional: true,
- unescape_strings: false,
- jslint_happy: false,
- end_with_newline: true,
- wrap_line_length: '110',
- indent_inner_html: true,
- comma_first: false,
- e4x: true,
- indent_empty_lines: true
- },
- js: {
- indent_size: '2',
- indent_char: ' ',
- max_preserve_newlines: '-1',
- preserve_newlines: false,
- keep_array_indentation: false,
- break_chained_methods: false,
- indent_scripts: 'normal',
- brace_style: 'end-expand',
- space_before_conditional: true,
- unescape_strings: false,
- jslint_happy: true,
- end_with_newline: true,
- wrap_line_length: '110',
- indent_inner_html: true,
- comma_first: false,
- e4x: true,
- indent_empty_lines: true
- }
-}
-
-// 首字母大小
-export function titleCase(str) {
- return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
-}
-
-// 下划转驼峰
-export function camelCase(str) {
- return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
-}
-
-export function isNumberStr(str) {
- return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
-}
-
+import { parseTime } from './ruoyi'
+
+/**
+ * 表格时间格式化
+ */
+export function formatDate(cellValue) {
+ if (cellValue == null || cellValue == "") return "";
+ var date = new Date(cellValue)
+ var year = date.getFullYear()
+ var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
+ var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
+ var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
+ var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
+ var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
+ return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
+}
+
+/**
+ * @param {number} time
+ * @param {string} option
+ * @returns {string}
+ */
+export function formatTime(time, option) {
+ if (('' + time).length === 10) {
+ time = parseInt(time) * 1000
+ } else {
+ time = +time
+ }
+ const d = new Date(time)
+ const now = Date.now()
+
+ const diff = (now - d) / 1000
+
+ if (diff < 30) {
+ return '刚刚'
+ } else if (diff < 3600) {
+ // less 1 hour
+ return Math.ceil(diff / 60) + '分钟前'
+ } else if (diff < 3600 * 24) {
+ return Math.ceil(diff / 3600) + '小时前'
+ } else if (diff < 3600 * 24 * 2) {
+ return '1天前'
+ }
+ if (option) {
+ return parseTime(time, option)
+ } else {
+ return (
+ d.getMonth() +
+ 1 +
+ '月' +
+ d.getDate() +
+ '日' +
+ d.getHours() +
+ '时' +
+ d.getMinutes() +
+ '分'
+ )
+ }
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function getQueryObject(url) {
+ url = url == null ? window.location.href : url
+ const search = url.substring(url.lastIndexOf('?') + 1)
+ const obj = {}
+ const reg = /([^?&=]+)=([^?&=]*)/g
+ search.replace(reg, (rs, $1, $2) => {
+ const name = decodeURIComponent($1)
+ let val = decodeURIComponent($2)
+ val = String(val)
+ obj[name] = val
+ return rs
+ })
+ return obj
+}
+
+/**
+ * @param {string} input value
+ * @returns {number} output value
+ */
+export function byteLength(str) {
+ // returns the byte length of an utf8 string
+ let s = str.length
+ for (var i = str.length - 1; i >= 0; i--) {
+ const code = str.charCodeAt(i)
+ if (code > 0x7f && code <= 0x7ff) s++
+ else if (code > 0x7ff && code <= 0xffff) s += 2
+ if (code >= 0xDC00 && code <= 0xDFFF) i--
+ }
+ return s
+}
+
+/**
+ * @param {Array} actual
+ * @returns {Array}
+ */
+export function cleanArray(actual) {
+ const newArray = []
+ for (let i = 0; i < actual.length; i++) {
+ if (actual[i]) {
+ newArray.push(actual[i])
+ }
+ }
+ return newArray
+}
+
+/**
+ * @param {Object} json
+ * @returns {Array}
+ */
+export function param(json) {
+ if (!json) return ''
+ return cleanArray(
+ Object.keys(json).map(key => {
+ if (json[key] === undefined) return ''
+ return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
+ })
+ ).join('&')
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function param2Obj(url) {
+ const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
+ if (!search) {
+ return {}
+ }
+ const obj = {}
+ const searchArr = search.split('&')
+ searchArr.forEach(v => {
+ const index = v.indexOf('=')
+ if (index !== -1) {
+ const name = v.substring(0, index)
+ const val = v.substring(index + 1, v.length)
+ obj[name] = val
+ }
+ })
+ return obj
+}
+
+/**
+ * @param {string} val
+ * @returns {string}
+ */
+export function html2Text(val) {
+ const div = document.createElement('div')
+ div.innerHTML = val
+ return div.textContent || div.innerText
+}
+
+/**
+ * Merges two objects, giving the last one precedence
+ * @param {Object} target
+ * @param {(Object|Array)} source
+ * @returns {Object}
+ */
+export function objectMerge(target, source) {
+ if (typeof target !== 'object') {
+ target = {}
+ }
+ if (Array.isArray(source)) {
+ return source.slice()
+ }
+ Object.keys(source).forEach(property => {
+ const sourceProperty = source[property]
+ if (typeof sourceProperty === 'object') {
+ target[property] = objectMerge(target[property], sourceProperty)
+ } else {
+ target[property] = sourceProperty
+ }
+ })
+ return target
+}
+
+/**
+ * @param {HTMLElement} element
+ * @param {string} className
+ */
+export function toggleClass(element, className) {
+ if (!element || !className) {
+ return
+ }
+ let classString = element.className
+ const nameIndex = classString.indexOf(className)
+ if (nameIndex === -1) {
+ classString += '' + className
+ } else {
+ classString =
+ classString.substr(0, nameIndex) +
+ classString.substr(nameIndex + className.length)
+ }
+ element.className = classString
+}
+
+/**
+ * @param {string} type
+ * @returns {Date}
+ */
+export function getTime(type) {
+ if (type === 'start') {
+ return new Date().getTime() - 3600 * 1000 * 24 * 90
+ } else {
+ return new Date(new Date().toDateString())
+ }
+}
+
+/**
+ * @param {Function} func
+ * @param {number} wait
+ * @param {boolean} immediate
+ * @return {*}
+ */
+export function debounce(func, wait, immediate) {
+ let timeout, args, context, timestamp, result
+
+ const later = function() {
+ // 据上一次触发时间间隔
+ const last = +new Date() - timestamp
+
+ // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
+ if (last < wait && last > 0) {
+ timeout = setTimeout(later, wait - last)
+ } else {
+ timeout = null
+ // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
+ if (!immediate) {
+ result = func.apply(context, args)
+ if (!timeout) context = args = null
+ }
+ }
+ }
+
+ return function(...args) {
+ context = this
+ timestamp = +new Date()
+ const callNow = immediate && !timeout
+ // 如果延时不存在,重新设定延时
+ if (!timeout) timeout = setTimeout(later, wait)
+ if (callNow) {
+ result = func.apply(context, args)
+ context = args = null
+ }
+
+ return result
+ }
+}
+
+/**
+ * This is just a simple version of deep copy
+ * Has a lot of edge cases bug
+ * If you want to use a perfect deep copy, use lodash's _.cloneDeep
+ * @param {Object} source
+ * @returns {Object}
+ */
+// export function deepClone(source) {
+// if (!source && typeof source !== 'object') {
+// throw new Error('error arguments', 'deepClone')
+// }
+// const targetObj = source.constructor === Array ? [] : {}
+// Object.keys(source).forEach(keys => {
+// if (source[keys] && typeof source[keys] === 'object') {
+// targetObj[keys] = deepClone(source[keys])
+// } else {
+// targetObj[keys] = source[keys]
+// }
+// })
+// return targetObj
+// }
+
+/**
+ * @param {Array} arr
+ * @returns {Array}
+ */
+export function uniqueArr(arr) {
+ return Array.from(new Set(arr))
+}
+
+/**
+ * @returns {string}
+ */
+export function createUniqueString() {
+ const timestamp = +new Date() + ''
+ const randomNum = parseInt((1 + Math.random()) * 65536) + ''
+ return (+(randomNum + timestamp)).toString(32)
+}
+
+/**
+ * Check if an element has a class
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ * @returns {boolean}
+ */
+export function hasClass(ele, cls) {
+ return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
+}
+
+/**
+ * Add class to element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function addClass(ele, cls) {
+ if (!hasClass(ele, cls)) ele.className += ' ' + cls
+}
+
+/**
+ * Remove class from element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function removeClass(ele, cls) {
+ if (hasClass(ele, cls)) {
+ const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
+ ele.className = ele.className.replace(reg, ' ')
+ }
+}
+
+export function makeMap(str, expectsLowerCase) {
+ const map = Object.create(null)
+ const list = str.split(',')
+ for (let i = 0; i < list.length; i++) {
+ map[list[i]] = true
+ }
+ return expectsLowerCase
+ ? val => map[val.toLowerCase()]
+ : val => map[val]
+}
+
+export const exportDefault = 'export default '
+
+export const beautifierConf = {
+ html: {
+ indent_size: '2',
+ indent_char: ' ',
+ max_preserve_newlines: '-1',
+ preserve_newlines: false,
+ keep_array_indentation: false,
+ break_chained_methods: false,
+ indent_scripts: 'separate',
+ brace_style: 'end-expand',
+ space_before_conditional: true,
+ unescape_strings: false,
+ jslint_happy: false,
+ end_with_newline: true,
+ wrap_line_length: '110',
+ indent_inner_html: true,
+ comma_first: false,
+ e4x: true,
+ indent_empty_lines: true
+ },
+ js: {
+ indent_size: '2',
+ indent_char: ' ',
+ max_preserve_newlines: '-1',
+ preserve_newlines: false,
+ keep_array_indentation: false,
+ break_chained_methods: false,
+ indent_scripts: 'normal',
+ brace_style: 'end-expand',
+ space_before_conditional: true,
+ unescape_strings: false,
+ jslint_happy: true,
+ end_with_newline: true,
+ wrap_line_length: '110',
+ indent_inner_html: true,
+ comma_first: false,
+ e4x: true,
+ indent_empty_lines: true
+ }
+}
+
+// 首字母大小
+export function titleCase(str) {
+ return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
+}
+
+// 下划转驼峰
+export function camelCase(str) {
+ return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
+}
+
+export function isNumberStr(str) {
+ return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
+}
+
+
+// 深拷贝对象
+export function deepClone(obj) {
+ const _toString = Object.prototype.toString
+
+ // null, undefined, non-object, function
+ if (!obj || typeof obj !== 'object') {
+ return obj
+ }
+
+ // DOM Node
+ if (obj.nodeType && 'cloneNode' in obj) {
+ return obj.cloneNode(true)
+ }
+
+ // Date
+ if (_toString.call(obj) === '[object Date]') {
+ return new Date(obj.getTime())
+ }
+
+ // RegExp
+ if (_toString.call(obj) === '[object RegExp]') {
+ const flags = []
+ if (obj.global) { flags.push('g') }
+ if (obj.multiline) { flags.push('m') }
+ if (obj.ignoreCase) { flags.push('i') }
+
+ return new RegExp(obj.source, flags.join(''))
+ }
+
+ const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {}
+
+ for (const key in obj) {
+ result[key] = deepClone(obj[key])
+ }
+
+ return result
+}
+
+const toStr = Function.prototype.call.bind(Object.prototype.toString)
+
+export function isObjectObject(t) {
+ return toStr(t) === '[object Object]'
+}
+
diff --git a/ruoyi-ui/src/utils/loadBeautifier.js b/ruoyi-ui/src/utils/loadBeautifier.js
new file mode 100644
index 00000000..cec9ccd2
--- /dev/null
+++ b/ruoyi-ui/src/utils/loadBeautifier.js
@@ -0,0 +1,28 @@
+import loadScript from './loadScript'
+import ELEMENT from 'element-ui'
+import pluginsConfig from './pluginsConfig'
+
+let beautifierObj
+
+export default function loadBeautifier(cb) {
+ const { beautifierUrl } = pluginsConfig
+ 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(beautifierUrl, () => {
+ loading.close()
+ // eslint-disable-next-line no-undef
+ beautifierObj = beautifier
+ cb(beautifierObj)
+ })
+}
diff --git a/ruoyi-ui/src/utils/loadMonaco.js b/ruoyi-ui/src/utils/loadMonaco.js
new file mode 100644
index 00000000..9bb64f14
--- /dev/null
+++ b/ruoyi-ui/src/utils/loadMonaco.js
@@ -0,0 +1,40 @@
+import loadScript from './loadScript'
+import ELEMENT from 'element-ui'
+import pluginsConfig from './pluginsConfig'
+
+// monaco-editor单例
+let monacoEidtor
+
+/**
+ * 动态加载monaco-editor cdn资源
+ * @param {Function} cb 回调,必填
+ */
+export default function loadMonaco(cb) {
+ if (monacoEidtor) {
+ cb(monacoEidtor)
+ return
+ }
+
+ const { monacoEditorUrl: vs } = pluginsConfig
+
+ // 使用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
+
+ loadScript(`${vs}/loader.js`, () => {
+ window.require(['vs/editor/editor.main'], () => {
+ loading.close()
+ monacoEidtor = window.monaco
+ cb(monacoEidtor)
+ })
+ })
+}
diff --git a/ruoyi-ui/src/utils/loadScript.js b/ruoyi-ui/src/utils/loadScript.js
new file mode 100644
index 00000000..18112fd7
--- /dev/null
+++ b/ruoyi-ui/src/utils/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/loadTinymce.js b/ruoyi-ui/src/utils/loadTinymce.js
new file mode 100644
index 00000000..e2455fc8
--- /dev/null
+++ b/ruoyi-ui/src/utils/loadTinymce.js
@@ -0,0 +1,29 @@
+import loadScript from './loadScript'
+import ELEMENT from 'element-ui'
+import pluginsConfig from './pluginsConfig'
+
+let tinymceObj
+
+export default function loadTinymce(cb) {
+ const { tinymceUrl } = pluginsConfig
+
+ 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(tinymceUrl, () => {
+ loading.close()
+ // eslint-disable-next-line no-undef
+ tinymceObj = tinymce
+ cb(tinymceObj)
+ })
+}
diff --git a/ruoyi-ui/src/utils/pluginsConfig.js b/ruoyi-ui/src/utils/pluginsConfig.js
new file mode 100644
index 00000000..e7f4882a
--- /dev/null
+++ b/ruoyi-ui/src/utils/pluginsConfig.js
@@ -0,0 +1,13 @@
+const CDN = 'https://lib.baomitu.com/' // CDN Homepage: https://cdn.baomitu.com/
+const publicPath = process.env.BASE_URL
+
+function splicingPluginUrl(PluginName, version, fileName) {
+ return `${CDN}${PluginName}/${version}/${fileName}`
+}
+
+export default {
+ beautifierUrl: splicingPluginUrl('js-beautify', '1.13.5', 'beautifier.min.js'),
+ // monacoEditorUrl: splicingPluginUrl('monaco-editor', '0.19.3', 'min/vs'), // 使用 monaco-editor CDN 链接
+ monacoEditorUrl: `${publicPath}libs/monaco-editor/vs`, // 使用 monaco-editor 本地代码
+ tinymceUrl: splicingPluginUrl('tinymce', '5.7.0', 'tinymce.min.js')
+}
diff --git a/ruoyi-ui/src/views/flowable/definition/index.vue b/ruoyi-ui/src/views/flowable/definition/index.vue
new file mode 100644
index 00000000..55c2d6c6
--- /dev/null
+++ b/ruoyi-ui/src/views/flowable/definition/index.vue
@@ -0,0 +1,548 @@
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 导入
+
+
+ 新增
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.name }}
+
+
+
+
+
+
+ {{ scope.row.formName }}
+
+
+
+
+
+
+ v{{ scope.row.version }}
+
+
+
+
+ 激活
+ 挂起
+
+
+
+
+
+
+
+ 更多操作
+
+
+
+ 编辑
+
+
+ 配置表单
+
+
+ 挂起
+
+
+ 激活
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 将文件拖到此处,或
+ 点击上传
+
+
+ 流程名称:
+ 流程分类:
+
+ 提示:仅允许导入“bpmn20.xml”格式文件!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 确定
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/flowable/definition/model.vue b/ruoyi-ui/src/views/flowable/definition/model.vue
new file mode 100644
index 00000000..e56a949a
--- /dev/null
+++ b/ruoyi-ui/src/views/flowable/definition/model.vue
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+ {{xmlContent}}
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/flowable/task/finished/index.vue b/ruoyi-ui/src/views/flowable/task/finished/index.vue
new file mode 100644
index 00000000..95e92a3f
--- /dev/null
+++ b/ruoyi-ui/src/views/flowable/task/finished/index.vue
@@ -0,0 +1,285 @@
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 流转记录
+ 撤回
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/flowable/task/form/index.vue b/ruoyi-ui/src/views/flowable/task/form/index.vue
new file mode 100644
index 00000000..ae39c5cd
--- /dev/null
+++ b/ruoyi-ui/src/views/flowable/task/form/index.vue
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 新增
+
+
+ 修改
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+ 详情
+ 修改
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/flowable/task/process/index.vue b/ruoyi-ui/src/views/flowable/task/process/index.vue
new file mode 100644
index 00000000..68b63bc6
--- /dev/null
+++ b/ruoyi-ui/src/views/flowable/task/process/index.vue
@@ -0,0 +1,403 @@
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 新增流程
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+ v{{ scope.row.procDefVersion }}
+
+
+
+
+
+ 进行中
+ 已完成
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 更多操作
+
+
+
+ 详情
+
+
+ 取消申请
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+
+ v{{ scope.row.version }}
+
+
+
+
+
+ 发起流程
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/flowable/task/record/flow.vue b/ruoyi-ui/src/views/flowable/task/record/flow.vue
new file mode 100644
index 00000000..7cd8334b
--- /dev/null
+++ b/ruoyi-ui/src/views/flowable/task/record/flow.vue
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/flowable/task/record/flowview.vue b/ruoyi-ui/src/views/flowable/task/record/flowview.vue
new file mode 100644
index 00000000..e3064879
--- /dev/null
+++ b/ruoyi-ui/src/views/flowable/task/record/flowview.vue
@@ -0,0 +1,243 @@
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/flowable/task/record/index.vue b/ruoyi-ui/src/views/flowable/task/record/index.vue
new file mode 100644
index 00000000..90ace8c7
--- /dev/null
+++ b/ruoyi-ui/src/views/flowable/task/record/index.vue
@@ -0,0 +1,607 @@
+
+
+
+
+ 基础信息
+ 返回
+
+
+
+
+
+
+ 审批
+
+
+
+ 退回
+ 驳回
+
+
+
+
+
+
+
+
+
+
+
+
+ 审批记录
+
+
+
+
+
+ {{item.taskName}}
+
+
+
+ 实际办理
+ {{item.assigneeName}}
+ {{item.deptName}}
+
+
+ 候选办理
+ {{item.candidate}}
+
+
+ 接收时间
+ {{item.createTime}}
+
+
+ 处理时间
+ {{item.finishTime}}
+
+
+ 耗时
+ {{item.duration}}
+
+
+ 处理意见
+ {{item.comment.comment}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 流程图
+
+
+
+
+
+
+
+
+
+
+
+ 部门列表
+
+
+
+
+
+
+
+
+ 待选人员
+
+
+
+
+
+
+
+ 已选人员
+
+ {{user.nickName}} {{user.dept.deptName}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/flowable/task/todo/index.vue b/ruoyi-ui/src/views/flowable/task/todo/index.vue
new file mode 100644
index 00000000..52a7eb36
--- /dev/null
+++ b/ruoyi-ui/src/views/flowable/task/todo/index.vue
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+ v{{scope.row.procDefVersion}}
+
+
+
+
+
+
+
+
+
+
+ 处理
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/tool/build/App.vue b/ruoyi-ui/src/views/tool/build/App.vue
new file mode 100644
index 00000000..b25f0b56
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/App.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue b/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
index b5c2e2e4..6f0c0d19 100644
--- a/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
+++ b/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
@@ -41,7 +41,7 @@
取消
-
+
确定
@@ -94,7 +94,7 @@ export default {
close(e) {
this.$emit('update:visible', false)
},
- handleConfirm() {
+ handelConfirm() {
this.$refs.elForm.validate(valid => {
if (!valid) return
this.$emit('confirm', { ...this.formData })
@@ -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 f669ac0e..96e37604 100644
--- a/ruoyi-ui/src/views/tool/build/DraggableItem.vue
+++ b/ruoyi-ui/src/views/tool/build/DraggableItem.vue
@@ -1,100 +1,120 @@
-
+
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 00000000..6fdde43a
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/FormDrawer.vue
@@ -0,0 +1,332 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ template
+
+
+
+
+
+
+ script
+
+
+
+
+
+
+ css
+
+
+
+
+
+
+
+
+
+
+
+ 刷新
+
+
+
+ 导出vue文件
+
+
+
+ 复制代码
+
+
+
+ 关闭
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/tool/build/IconsDialog.vue b/ruoyi-ui/src/views/tool/build/IconsDialog.vue
index 0d127783..958be50c 100644
--- a/ruoyi-ui/src/views/tool/build/IconsDialog.vue
+++ b/ruoyi-ui/src/views/tool/build/IconsDialog.vue
@@ -1,123 +1,123 @@
-
-
-
-
-
+
+
+
+
+
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 00000000..8a4378d9
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/JsonDrawer.vue
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+ 刷新
+
+
+
+ 复制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 00000000..e9a2c92d
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/ResourceDialog.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+ 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 863d74c0..225a9135 100644
--- a/ruoyi-ui/src/views/tool/build/RightPanel.vue
+++ b/ruoyi-ui/src/views/tool/build/RightPanel.vue
@@ -1,946 +1,1050 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ item.label }}
-
-
-
-
-
-
-
-
- {{ activeData.componentName }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 选择
-
-
-
-
-
-
- 选择
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 默认
-
-
- 右侧
-
-
-
-
-
-
- 个字符
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text
-
-
- picture
-
-
- picture-card
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 选项
-
-
-
-
-
- 添加选项
-
-
-
-
-
-
- 选项
-
-
-
- 动态数据
-
-
- 静态数据
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 添加父级
-
-
-
-
-
-
-
-
- 默认
-
-
- 按钮
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 中等
-
-
- 较小
-
-
- 迷你
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 布局结构树
-
-
-
-
- {{ node.label }}
-
-
-
-
-
-
- 正则校验
-
-
-
-
-
-
-
-
-
-
-
-
-
- 添加规则
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 中等
-
-
- 较小
-
-
- 迷你
-
-
-
-
-
-
- 左对齐
-
-
- 右对齐
-
-
- 顶部对齐
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.__config__.label }}
+
+
+
+
+
+
+
+
+ {{ activeData.__config__.componentName }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 选择
+
+
+
+
+
+
+ 选择
+
+
+
+
+
+
+ 选择
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 默认
+
+
+ 右侧
+
+
+
+
+
+
+ 个字符
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text
+
+
+ picture
+
+
+ picture-card
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 选项
+
+
+
+
+
+ 添加选项
+
+
+
+
+
+
+ 选项
+
+
+
+ 动态数据
+
+
+ 静态数据
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 添加父级
+
+
+
+
+
+
+
+
+ 默认
+
+
+ 按钮
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 中等
+
+
+ 较小
+
+
+ 迷你
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 布局结构树
+
+
+
+
+ {{ node.label }}
+
+
+
+
+
+
+ 正则校验
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 添加规则
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 中等
+
+
+ 较小
+
+
+ 迷你
+
+
+
+
+
+
+ 左对齐
+
+
+ 右对齐
+
+
+ 顶部对齐
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue b/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue
index fa7f0b28..e089c0bc 100644
--- a/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue
+++ b/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue
@@ -59,7 +59,7 @@
确定
@@ -72,6 +72,9 @@
+
+
diff --git a/ruoyi-ui/src/views/tool/build/index.vue b/ruoyi-ui/src/views/tool/build/index.vue
index d679422e..37db40cd 100644
--- a/ruoyi-ui/src/views/tool/build/index.vue
+++ b/ruoyi-ui/src/views/tool/build/index.vue
@@ -8,76 +8,48 @@
-
- 输入型组件
-
-
-
-
-
- {{ element.label }}
-
+
+
+
+ {{ item.title }}
-
-
- 选择型组件
-
-
-
-
-
- {{ element.label }}
+
+
+
+ {{ element.__config__.label }}
+
-
-
-
- 布局型组件
+
-
-
-
-
- {{ element.label }}
-
-
-
+
+ 保存
+
+
+ 运行
+
+
+ 查看json
+
导出vue文件
@@ -98,10 +70,10 @@
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/views/tool/build/main.js b/ruoyi-ui/src/views/tool/build/main.js
new file mode 100644
index 00000000..19297145
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/main.js
@@ -0,0 +1,17 @@
+import Vue from 'vue'
+import App from './App.vue'
+import router from '@/router'
+import '@/styles/index.scss'
+import '@/icons'
+import axios from 'axios'
+import Tinymce from '@/components/tinymce/index.vue'
+
+Vue.component('tinymce', Tinymce)
+
+Vue.config.productionTip = false
+Vue.prototype.$axios = axios
+
+new Vue({
+ router,
+ render: h => h(App)
+}).$mount('#app')
diff --git a/ruoyi-ui/src/views/tool/preview/main.js b/ruoyi-ui/src/views/tool/preview/main.js
new file mode 100644
index 00000000..98fa1074
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/preview/main.js
@@ -0,0 +1,61 @@
+import Vue from 'vue'
+import { loadScriptQueue } from '@/utils/loadScript'
+import axios from 'axios'
+import Tinymce from '@/components/tinymce/index.vue'
+
+Vue.component('tinymce', Tinymce)
+Vue.prototype.$axios = axios
+
+const $previewApp = document.getElementById('previewApp')
+const childAttrs = {
+ file: '',
+ dialog: ' width="600px" class="dialog-width" v-if="visible" :visible.sync="visible" :modal-append-to-body="false" '
+}
+
+window.addEventListener('message', init, false)
+
+function buildLinks(links) {
+ let strs = ''
+ links.forEach(url => {
+ strs += `
`
+ })
+ return strs
+}
+
+function init(event) {
+ if (event.data.type === 'refreshFrame') {
+ const code = event.data.data
+ const attrs = childAttrs[code.generateConf.type]
+ let links = ''
+
+ if (Array.isArray(code.links) && code.links.length > 0) {
+ links = buildLinks(code.links)
+ }
+
+ $previewApp.innerHTML = `${links}
`
+
+ 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')
+}