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 @@ + + + + + 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 @@ + + + + + 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 + }, + append(h, conf, key) { + return + } +} 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 @@ +