├── mock └── .gitkeep ├── public └── favicon.ico ├── assets └── react-bpmn.png ├── doc └── favicon_io │ ├── favicon.ico │ ├── react-bpmn.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ └── site.webmanifest ├── .prettierignore ├── src ├── components │ └── ProcessDesigner │ │ └── components │ │ ├── Previewer │ │ ├── index.less │ │ └── Previewer.tsx │ │ ├── ConfigServer │ │ └── ConfigServer.tsx │ │ └── PropertyPanel │ │ └── PropertyPanel.tsx ├── bpmn │ ├── moddle │ │ ├── camunda │ │ │ ├── index.js │ │ │ └── camundaExtension.js │ │ ├── flowable │ │ │ ├── index.js │ │ │ └── flowableExtension.js │ │ └── activiti │ │ │ ├── index.js │ │ │ └── activitiExtension.js │ ├── util │ │ ├── xmlUtil.ts │ │ ├── windowUtil.ts │ │ ├── idUtil.ts │ │ └── panelUtil.ts │ ├── constant │ │ ├── constants.ts │ │ ├── emptyXml.ts │ │ └── testXml.ts │ ├── panel │ │ ├── MultiInstance │ │ │ ├── dataSelf.ts │ │ │ └── MultiInstance.tsx │ │ ├── ElementTask │ │ │ ├── mockData.ts │ │ │ ├── ElementTask.tsx │ │ │ ├── ScriptTask │ │ │ │ └── ScriptTask.tsx │ │ │ ├── UserTask │ │ │ │ └── UserTask.tsx │ │ │ └── ReceiveTask │ │ │ │ └── ReceiveTask.tsx │ │ ├── FlowCondition │ │ │ ├── dataSelf.ts │ │ │ └── FlowCondition.tsx │ │ ├── ElementForm │ │ │ ├── dataSelf.ts │ │ │ ├── EditFormField │ │ │ │ ├── EditProperty │ │ │ │ │ └── EditProperty.tsx │ │ │ │ ├── EditConstraint │ │ │ │ │ └── EditConstraint.tsx │ │ │ │ └── EditEnumValues │ │ │ │ │ └── EditEnumValues.tsx │ │ │ └── ElementForm.tsx │ │ ├── ElementDocument │ │ │ └── ElementDocument.tsx │ │ ├── ExtensionProperties │ │ │ ├── EditProperty │ │ │ │ └── EditProperty.tsx │ │ │ └── ExtensionProperties.tsx │ │ ├── ElementListener │ │ │ ├── EditListener │ │ │ │ ├── EditField │ │ │ │ │ └── EditField.tsx │ │ │ │ └── EditListener.tsx │ │ │ ├── dataSelf.ts │ │ │ └── ElementListener.tsx │ │ ├── SignalMessage │ │ │ ├── SignalMessage.tsx │ │ │ └── EditSignalMessage │ │ │ │ └── EditSignalMessage.tsx │ │ └── ElementBaseInfo │ │ │ └── ElementBaseInfo.tsx │ └── translate │ │ ├── customTranslate.js │ │ └── zh.js ├── redux │ ├── hook │ │ └── hooks.ts │ ├── store │ │ └── store.ts │ └── slice │ │ ├── themeSlice.ts │ │ └── bpmnSlice.ts └── pages │ ├── index.tsx │ ├── globalTheme.ts │ └── index.less ├── .prettierrc ├── .editorconfig ├── .umirc.ts ├── typings.d.ts ├── .gitignore ├── tsconfig.json ├── LICENSE ├── package.json └── README.md /mock/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pangchun/react-bpmn/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /assets/react-bpmn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pangchun/react-bpmn/HEAD/assets/react-bpmn.png -------------------------------------------------------------------------------- /doc/favicon_io/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pangchun/react-bpmn/HEAD/doc/favicon_io/favicon.ico -------------------------------------------------------------------------------- /doc/favicon_io/react-bpmn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pangchun/react-bpmn/HEAD/doc/favicon_io/react-bpmn.png -------------------------------------------------------------------------------- /doc/favicon_io/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pangchun/react-bpmn/HEAD/doc/favicon_io/favicon-16x16.png -------------------------------------------------------------------------------- /doc/favicon_io/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pangchun/react-bpmn/HEAD/doc/favicon_io/favicon-32x32.png -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.md 2 | **/*.svg 3 | **/*.ejs 4 | **/*.html 5 | package.json 6 | .umi 7 | .umi-production 8 | .umi-test 9 | -------------------------------------------------------------------------------- /doc/favicon_io/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pangchun/react-bpmn/HEAD/doc/favicon_io/apple-touch-icon.png -------------------------------------------------------------------------------- /doc/favicon_io/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pangchun/react-bpmn/HEAD/doc/favicon_io/android-chrome-192x192.png -------------------------------------------------------------------------------- /doc/favicon_io/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pangchun/react-bpmn/HEAD/doc/favicon_io/android-chrome-512x512.png -------------------------------------------------------------------------------- /src/components/ProcessDesigner/components/Previewer/index.less: -------------------------------------------------------------------------------- 1 | .codePreWrap > pre > code { 2 | word-break: break-word !important; 3 | white-space: pre-wrap !important; 4 | } 5 | -------------------------------------------------------------------------------- /src/bpmn/moddle/camunda/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | __init__: ['camundaExtension'], 5 | camundaExtension: ['type', require('./camundaExtension')], 6 | }; 7 | -------------------------------------------------------------------------------- /src/bpmn/moddle/flowable/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | __init__: ['flowableExtension'], 5 | flowableExtension: ['type', require('./flowableExtension')], 6 | }; 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "printWidth": 80, 5 | "overrides": [ 6 | { 7 | "files": ".prettierrc", 8 | "options": { "parser": "json" } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/bpmn/moddle/activiti/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @author igdianov 3 | * address https://github.com/igdianov/activiti-bpmn-moddle 4 | * */ 5 | 6 | module.exports = { 7 | __init__: ['activitiExtension'], 8 | activitiExtension: ['type', require('./activitiExtension')], 9 | }; 10 | -------------------------------------------------------------------------------- /doc/favicon_io/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.umirc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'umi'; 2 | 3 | export default defineConfig({ 4 | nodeModulesTransform: { 5 | type: 'none', 6 | }, 7 | routes: [{ path: '/', component: '@/pages/index' }], 8 | fastRefresh: {}, 9 | favicon: '/favicon.ico', 10 | title: 'Bpmn Process Designer', 11 | // mfsu: {}, 12 | }); 13 | -------------------------------------------------------------------------------- /src/redux/hook/hooks.ts: -------------------------------------------------------------------------------- 1 | import { AppDispatch, RootState } from '@/redux/store/store'; 2 | import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; 3 | 4 | // 在整个应用程序中使用,而不是简单的 `useDispatch` 和 `useSelector` 5 | export const useAppDispatch: () => AppDispatch = useDispatch; 6 | export const useAppSelector: TypedUseSelectorHook = useSelector; 7 | -------------------------------------------------------------------------------- /typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.css'; 2 | declare module '*.less'; 3 | declare module '*.png'; 4 | declare module '*.svg' { 5 | export function ReactComponent( 6 | props: React.SVGProps, 7 | ): React.ReactElement; 8 | const url: string; 9 | export default url; 10 | } 11 | 12 | // tsx 默认不引入js,设置忽略类型 todo 2022/12/4 查询react怎么引入js可以点击跳转方法的 13 | declare module '*'; 14 | -------------------------------------------------------------------------------- /src/bpmn/util/xmlUtil.ts: -------------------------------------------------------------------------------- 1 | // ts: xml操作工具 2 | 3 | /** 4 | * 获取最新的xml 5 | */ 6 | export async function getXml() { 7 | let result = await window.bpmnInstance?.modeler?.saveXML({ format: true }); 8 | return result.xml; 9 | } 10 | 11 | /** 12 | * xml字符串解析为json字符串 13 | */ 14 | export function xml2json(xmlStr: string) { 15 | const parseString = require('xml2js').parseString; 16 | let jsonStr: string = ''; 17 | parseString(xmlStr, function (err: any, result: any) { 18 | jsonStr = JSON.stringify(result, null, 4); 19 | }); 20 | return jsonStr; 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | .idea 4 | 5 | # dependencies 6 | /node_modules 7 | /npm-debug.log* 8 | /yarn-error.log 9 | /package-lock.json 10 | 11 | 12 | # testing 13 | /coverage 14 | 15 | # production 16 | /dist 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | .env.local 22 | .env.development.local 23 | .env.test.local 24 | .env.production.local 25 | 26 | # umi 27 | /src/.umi 28 | /src/.umi-production 29 | /src/.umi-test 30 | /.env.local 31 | 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | -------------------------------------------------------------------------------- /src/bpmn/constant/constants.ts: -------------------------------------------------------------------------------- 1 | // ts:常量池 2 | 3 | /** 4 | * 流程类型 5 | */ 6 | export const PROCESS_TYPE = { 7 | flowable: 'flowable', 8 | activiti: 'activiti', 9 | camunda: 'camunda', 10 | }; 11 | 12 | /** 13 | * 流程前缀 14 | */ 15 | export const FLOWABLE_PREFIX: string = PROCESS_TYPE.flowable; 16 | export const ACTIVITI_PREFIX: string = PROCESS_TYPE.activiti; 17 | export const CAMUNDA_PREFIX: string = PROCESS_TYPE.camunda; 18 | 19 | /** 20 | * 流程类型对应命名空间 21 | */ 22 | export const TYPE_TARGET = { 23 | activiti: 'http://activiti.org/bpmn', 24 | camunda: 'http://bpmn.io/schema/bpmn', 25 | flowable: 'http://flowable.org/bpmn', 26 | }; 27 | -------------------------------------------------------------------------------- /src/redux/store/store.ts: -------------------------------------------------------------------------------- 1 | import { configureStore } from '@reduxjs/toolkit'; 2 | import bpmnReducer from '@/redux/slice/bpmnSlice'; 3 | import themeReducer from '@/redux/slice/themeSlice'; 4 | 5 | /** 6 | * 创建一个 Redux 存储,并自动配置 Redux DevTools 扩展,并在开发时检查存储 7 | */ 8 | export const store = configureStore({ 9 | // 将Slice Reducers添加到Store中 10 | reducer: { 11 | bpmn: bpmnReducer, 12 | theme: themeReducer, 13 | }, 14 | }); 15 | 16 | // 从 store 本身推断出 `RootState` 和 `AppDispatch` 类型 17 | export type RootState = ReturnType; 18 | // 推断出类型: {counter: counterReducer} 19 | export type AppDispatch = typeof store.dispatch; 20 | -------------------------------------------------------------------------------- /src/bpmn/util/windowUtil.ts: -------------------------------------------------------------------------------- 1 | // ts: 全局变量定义工具 2 | 3 | declare global { 4 | interface Window { 5 | // bpmn实例 6 | bpmnInstance: { 7 | element: any; 8 | modeler: any; 9 | modeling: any; 10 | elementRegistry: any; 11 | bpmnFactory: any; 12 | moddle: any; 13 | rootElements: any[]; // todo 删除这个属性,rootEl是一个数组 14 | }; 15 | } 16 | } 17 | 18 | /** 19 | * 初始化bpmn实例,设置默认值 20 | */ 21 | export function initBpmnInstance() { 22 | console.log('【初始化bpmn实例】1、设置默认值为null'); 23 | window.bpmnInstance = { 24 | element: null, 25 | modeler: null, 26 | modeling: null, 27 | elementRegistry: null, 28 | bpmnFactory: null, 29 | moddle: null, 30 | rootElements: [], 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/bpmn/panel/MultiInstance/dataSelf.ts: -------------------------------------------------------------------------------- 1 | //tips: 这些数据是从bpmn-js包下的bpmn-js-properties-panel源码中获取的 2 | 3 | /** 4 | * 回路特性类型 5 | */ 6 | export const loop_characteristics_type = { 7 | parallelMultiInstance: 'parallelMultiInstance', 8 | sequentialMultiInstance: 'sequentialMultiInstance', 9 | standardLoop: 'standardLoop', 10 | }; 11 | 12 | /** 13 | * 回路特性下拉选 14 | */ 15 | export const loop_characteristics_type_options = [ 16 | { 17 | name: '并行多重事件', 18 | value: loop_characteristics_type.parallelMultiInstance, 19 | }, 20 | { 21 | name: '时序多重事件', 22 | value: loop_characteristics_type.sequentialMultiInstance, 23 | }, 24 | { 25 | name: '循环事件', 26 | value: loop_characteristics_type.standardLoop, 27 | }, 28 | { 29 | name: '无', 30 | value: '-1', 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "resolveJsonModule": true, 7 | "importHelpers": true, 8 | "jsx": "react-jsx", 9 | "esModuleInterop": true, 10 | "sourceMap": true, 11 | "baseUrl": "./", 12 | "strict": true, 13 | "paths": { 14 | "@/*": ["src/*"], 15 | "@@/*": ["src/.umi/*"] 16 | }, 17 | "allowSyntheticDefaultImports": true 18 | }, 19 | "include": [ 20 | "mock/**/*", 21 | "src/**/*", 22 | "config/**/*", 23 | ".umirc.ts", 24 | "typings.d.ts" 25 | ], 26 | "exclude": [ 27 | "node_modules", 28 | "lib", 29 | "es", 30 | "dist", 31 | "typings", 32 | "**/__test__", 33 | "test", 34 | "docs", 35 | "tests" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /src/redux/slice/themeSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from '@reduxjs/toolkit'; 2 | 3 | export interface ThemeState { 4 | borderRadius: number; 5 | // 基础主题色 6 | colorPrimary: string; 7 | // 暗夜模式 8 | darkMode: boolean; 9 | } 10 | 11 | const initialState: ThemeState = { 12 | borderRadius: 6, 13 | colorPrimary: '#FF33CC', 14 | darkMode: false, 15 | }; 16 | 17 | export const themeSlice = createSlice({ 18 | name: 'theme', 19 | initialState, 20 | reducers: { 21 | handleColorPrimary: (state, action: PayloadAction) => { 22 | state.colorPrimary = action.payload; 23 | }, 24 | handleDarkMode: (state, action: PayloadAction) => { 25 | state.darkMode = action.payload; 26 | }, 27 | }, 28 | }); 29 | 30 | export const { handleColorPrimary, handleDarkMode } = themeSlice.actions; 31 | 32 | export default themeSlice.reducer; 33 | -------------------------------------------------------------------------------- /src/bpmn/util/idUtil.ts: -------------------------------------------------------------------------------- 1 | // ts: uuid生成 2 | 3 | /** 4 | * 手动生成唯一id 5 | * 6 | * @param prefix 前缀 7 | * @param length 长度,默认8 8 | * @constructor 9 | */ 10 | export function UUIdGenerator(prefix: string, length: number = 8) { 11 | let id: string = prefix ? prefix + '_' : ''; 12 | let chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 13 | for (let i = length; i > 0; --i) { 14 | id += chars[Math.floor(Math.random() * chars.length)]; 15 | } 16 | return id; 17 | } 18 | 19 | /** 20 | * 根据当前时间生成唯一id 21 | * 1、返回格式如:process_1667396671442 (前缀为process) 22 | * 23 | * @param prefix 前缀 24 | * @constructor 25 | */ 26 | export function TimeIdGenerator(prefix: string) { 27 | let id: string = prefix ? prefix + '_' : ''; 28 | return `${prefix}_${new Date().getTime()}`; 29 | } 30 | 31 | /** 32 | * 根据时间生成流程id 33 | * 1、返回格式如:Process_1667396671442 34 | * 35 | * @constructor 36 | */ 37 | export function ProcessIdGenerator() { 38 | return TimeIdGenerator('Process'); 39 | } 40 | -------------------------------------------------------------------------------- /src/bpmn/panel/ElementTask/mockData.ts: -------------------------------------------------------------------------------- 1 | //tips: 任务组件的mock数据,因为没有集成后端服务,所以下拉框的数据使用本地mock数据 2 | 3 | // 处理用户 4 | export const assignee_mock = [ 5 | { 6 | name: '张三', 7 | value: '11111111111', 8 | }, 9 | { 10 | name: '李四', 11 | value: '22222222222', 12 | }, 13 | { 14 | name: '王五', 15 | value: '33333333333', 16 | }, 17 | { 18 | name: '赵六', 19 | value: '44444444444', 20 | }, 21 | ]; 22 | 23 | // 候选用户 24 | export const candidateUsers_mock = [ 25 | { 26 | name: '张三', 27 | value: '11111111111', 28 | }, 29 | { 30 | name: '李四', 31 | value: '22222222222', 32 | }, 33 | { 34 | name: '王五', 35 | value: '33333333333', 36 | }, 37 | { 38 | name: '赵六', 39 | value: '44444444444', 40 | }, 41 | ]; 42 | 43 | // 候选分组 44 | export const candidateGroups_mock = [ 45 | { 46 | name: '分组一', 47 | value: '11111111111', 48 | }, 49 | { 50 | name: '分组二', 51 | value: '22222222222', 52 | }, 53 | { 54 | name: '分组三', 55 | value: '33333333333', 56 | }, 57 | { 58 | name: '分组四', 59 | value: '44444444444', 60 | }, 61 | ]; 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 pangchun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import ProcessDesigner from '@/components/ProcessDesigner/ProcessDesigner'; 2 | import { Provider } from 'react-redux'; 3 | import { store } from '@/redux/store/store'; 4 | import { message } from 'antd'; 5 | 6 | // 引入样式 7 | import './index.less'; 8 | import { useEffect, useState } from 'react'; 9 | 10 | export default function IndexPage() { 11 | const [visible, setVisible] = useState( 12 | document.documentElement.clientWidth > 1080, 13 | ); 14 | 15 | useEffect(() => { 16 | watchClientWidth(); 17 | window.addEventListener('resize', watchClientWidth); 18 | }, []); 19 | 20 | function watchClientWidth() { 21 | let clientWidth = document.documentElement.clientWidth; 22 | if (clientWidth < 1080) { 23 | if (visible) { 24 | setVisible(false); 25 | message.warning('请保证您的窗口宽带大于1080').then(() => {}); 26 | } 27 | } else { 28 | setVisible(true); 29 | } 30 | } 31 | 32 | return ( 33 | 34 |
35 | 36 |
37 |
38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /src/redux/slice/bpmnSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from '@reduxjs/toolkit'; 2 | import { FLOWABLE_PREFIX } from '@/bpmn/constant/constants'; 3 | 4 | // 定义redux属性的名称和类型 5 | export interface BpmnState { 6 | // 流程引擎前缀 7 | prefix: string; 8 | // 流程id 9 | processId: string | undefined; 10 | // 流程名称 11 | processName: string | undefined; 12 | } 13 | 14 | // 定义redux属性的默认值 15 | const initialState: BpmnState = { 16 | prefix: FLOWABLE_PREFIX, 17 | processId: undefined, 18 | processName: undefined, 19 | }; 20 | 21 | /** 22 | * 定义修改redux属性的方法 23 | */ 24 | export const bpmnSlice = createSlice({ 25 | name: 'bpmn', 26 | initialState, 27 | reducers: { 28 | handlePrefix: (state, action: PayloadAction) => { 29 | state.prefix = action.payload; 30 | }, 31 | handleProcessId: (state, action: PayloadAction) => { 32 | state.processId = action.payload || undefined; 33 | }, 34 | handleProcessName: (state, action: PayloadAction) => { 35 | state.processName = action.payload || undefined; 36 | }, 37 | }, 38 | }); 39 | 40 | export const { 41 | handlePrefix, 42 | handleProcessId, 43 | handleProcessName, 44 | } = bpmnSlice.actions; 45 | 46 | export default bpmnSlice.reducer; 47 | -------------------------------------------------------------------------------- /src/bpmn/constant/emptyXml.ts: -------------------------------------------------------------------------------- 1 | import { PROCESS_TYPE, TYPE_TARGET } from '@/bpmn/constant/constants'; 2 | 3 | /** 4 | * 新建空流程 5 | * @param key 流程id 6 | * @param name 流程名称 7 | * @param type 流程类型 8 | */ 9 | export default (key: string, name: string, type: string) => { 10 | let type_target: string; 11 | if (type === PROCESS_TYPE.activiti) { 12 | type_target = TYPE_TARGET.activiti; 13 | } else if (type === PROCESS_TYPE.flowable) { 14 | type_target = TYPE_TARGET.flowable; 15 | } else { 16 | type_target = TYPE_TARGET.camunda; 17 | } 18 | return ` 19 | 20 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | `; 35 | }; 36 | -------------------------------------------------------------------------------- /src/bpmn/panel/FlowCondition/dataSelf.ts: -------------------------------------------------------------------------------- 1 | //tips: 这些数据是从bpmn-js包下的bpmn-js-properties-panel源码中获取的,搜索FormField与FormDataProps可以查看 2 | 3 | // 流转类型 4 | export const flow_type = { 5 | normalFlow: 'normalFlow', 6 | defaultFlow: 'defaultFlow', 7 | conditionalFlow: 'conditionalFlow', 8 | }; 9 | 10 | // 流转类型下拉项 11 | export const flow_type_options = [ 12 | { 13 | name: '普通流转路径', 14 | value: flow_type.normalFlow, 15 | }, 16 | { 17 | name: '默认流转路径', 18 | value: flow_type.defaultFlow, 19 | }, 20 | { 21 | name: '条件流转路径', 22 | value: flow_type.conditionalFlow, 23 | }, 24 | ]; 25 | 26 | // 条件格式 27 | export const condition_type = { 28 | script: 'script', 29 | expression: 'expression', 30 | }; 31 | 32 | // 条件格式下拉项 33 | export const condition_type_options = [ 34 | { 35 | name: '脚本', 36 | value: condition_type.script, 37 | }, 38 | { 39 | name: '表达式', 40 | value: condition_type.expression, 41 | }, 42 | ]; 43 | 44 | // 脚本类型 45 | export const script_type = { 46 | inlineScript: 'inlineScript', 47 | externalResource: 'externalResource', 48 | }; 49 | 50 | // 脚本类型下拉项 51 | export const script_type_options = [ 52 | { 53 | name: '内联脚本', 54 | value: script_type.inlineScript, 55 | }, 56 | { 57 | name: '外部资源', 58 | value: script_type.externalResource, 59 | }, 60 | ]; 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "umi dev", 5 | "build": "umi build", 6 | "postinstall": "umi generate tmp", 7 | "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'", 8 | "test": "umi-test", 9 | "test:coverage": "umi-test --coverage" 10 | }, 11 | "gitHooks": { 12 | "pre-commit": "lint-staged" 13 | }, 14 | "lint-staged": { 15 | "*.{js,jsx,less,md,json}": [ 16 | "prettier --write" 17 | ], 18 | "*.ts?(x)": [ 19 | "prettier --parser=typescript --write" 20 | ] 21 | }, 22 | "dependencies": { 23 | "@ant-design/icons": "^4.7.0", 24 | "@ant-design/pro-layout": "^6.5.0", 25 | "@bpmn-io/properties-panel": "^0.13.2", 26 | "@reduxjs/toolkit": "^1.8.5", 27 | "ahooks": "^3.4.0", 28 | "antd": "5.x", 29 | "bpmn-js": "^9.0.3", 30 | "bpmn-js-properties-panel": "^1.0.0", 31 | "bpmn-js-token-simulation": "^0.28.0", 32 | "camunda-bpmn-moddle": "^6.1.2", 33 | "moment": "^2.29.3", 34 | "react": "^17.0.2", 35 | "react-color": "^2.19.3", 36 | "react-dom": "^17.0.2", 37 | "react-redux": "^7.2.8", 38 | "react-syntax-highlighter": "^15.5.0", 39 | "umi": "^3.5.23", 40 | "uuid": "^8.3.2", 41 | "xml2js": "^0.4.23" 42 | }, 43 | "devDependencies": { 44 | "@types/react": "^18.0.12", 45 | "@types/react-dom": "^18.0.5", 46 | "@umijs/preset-react": "1.x", 47 | "@umijs/test": "^3.5.23", 48 | "lint-staged": "^10.0.7", 49 | "prettier": "^2.2.0", 50 | "typescript": "^4.1.2", 51 | "yorkie": "^2.0.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/bpmn/translate/customTranslate.js: -------------------------------------------------------------------------------- 1 | // import translations from "./zh"; 2 | // 3 | // export default function customTranslate(template, replacements) { 4 | // replacements = replacements || {}; 5 | // 6 | // // Translate 7 | // template = translations[template] || template; 8 | // 9 | // // Replace 10 | // return template.replace(/{([^}]+)}/g, function(_, key) { 11 | // let str = replacements[key]; 12 | // if ( 13 | // translations[replacements[key]] !== null && 14 | // translations[replacements[key]] !== "undefined" 15 | // ) { 16 | // // eslint-disable-next-line no-mixed-spaces-and-tabs 17 | // str = translations[replacements[key]]; 18 | // // eslint-disable-next-line no-mixed-spaces-and-tabs 19 | // } 20 | // return str || "{" + key + "}"; 21 | // }); 22 | // } 23 | 24 | export default function customTranslate(translations) { 25 | return function (template, replacements) { 26 | replacements = replacements || {}; 27 | // Translate 28 | template = translations[template] || template; 29 | 30 | // Replace 31 | return template.replace(/{([^}]+)}/g, function (_, key) { 32 | let str = replacements[key]; 33 | if ( 34 | translations[replacements[key]] !== null && 35 | translations[replacements[key]] !== undefined 36 | ) { 37 | // eslint-disable-next-line no-mixed-spaces-and-tabs 38 | str = translations[replacements[key]]; 39 | // eslint-disable-next-line no-mixed-spaces-and-tabs 40 | } 41 | return str || '{' + key + '}'; 42 | }); 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/bpmn/panel/ElementForm/dataSelf.ts: -------------------------------------------------------------------------------- 1 | //tips: 这些数据是从bpmn-js包下的bpmn-js-properties-panel源码中获取的,搜索FormField与FormDataProps可以查看 2 | 3 | // 表单字段类型 4 | export const form_field_type = { 5 | long: 'long', 6 | string: 'string', 7 | boolean: 'boolean', 8 | enum: 'enum', 9 | date: 'date', 10 | custom: 'custom', 11 | }; 12 | 13 | // 表单字段类型下拉项 14 | export const form_field_type_options = [ 15 | { 16 | name: '长整型', 17 | value: form_field_type.long, 18 | }, 19 | { 20 | name: '字符串', 21 | value: form_field_type.string, 22 | }, 23 | { 24 | name: '布尔值', 25 | value: form_field_type.boolean, 26 | }, 27 | { 28 | name: '枚举值', 29 | value: form_field_type.enum, 30 | }, 31 | { 32 | name: '日期', 33 | value: form_field_type.date, 34 | }, 35 | { 36 | name: '自定义类型', 37 | value: form_field_type.custom, 38 | }, 39 | ]; 40 | 41 | /** 42 | * 校验是否为自定义类型 43 | * 44 | * @param type 45 | */ 46 | export function checkIsCustomType(type: string) { 47 | return ( 48 | type !== form_field_type.boolean && 49 | type !== form_field_type.long && 50 | type !== form_field_type.date && 51 | type !== form_field_type.string && 52 | type !== form_field_type.enum 53 | ); 54 | } 55 | 56 | /** 57 | * 通过字段类型查询字段类型下拉项 58 | * 59 | * @param type 60 | */ 61 | export function getFormFieldNameByType(type: string) { 62 | let option = form_field_type_options.find((e) => e.value === type); 63 | if (!option) { 64 | option = form_field_type_options.find( 65 | (e) => e.value === form_field_type.custom, 66 | ); 67 | } 68 | return option; 69 | } 70 | -------------------------------------------------------------------------------- /src/pages/globalTheme.ts: -------------------------------------------------------------------------------- 1 | // ts: 全局主题常量 2 | 3 | export type ThemeData = { 4 | borderRadius: number; 5 | colorPrimary: string; 6 | darkBgColor: string; 7 | lightBgColor: string; 8 | darkPaletteBgColor: string; 9 | lightPaletteBgColor: string; 10 | darkCanvasBgColor: string; 11 | lightCanvasBgColor: string; 12 | }; 13 | 14 | // 默认主题变量 15 | export const defaultThemeData: ThemeData = { 16 | borderRadius: 6, 17 | // 基础主题色 18 | colorPrimary: '#FF33CC', 19 | // 背景色:dark模式 20 | darkBgColor: '#000000', 21 | // 背景色:light模式 22 | lightBgColor: '#ffffff', 23 | // palette背景色:dark模式 24 | darkPaletteBgColor: '#000000', 25 | // palette背景色:light模式 26 | lightPaletteBgColor: '#ffffff', 27 | // Canvas背景色:dark模式 28 | darkCanvasBgColor: '#424242', 29 | // Canvas背景色:light模式 30 | lightCanvasBgColor: '#dbdbdb', 31 | }; 32 | 33 | // 暗夜主题变量 34 | export const darkThemeData: any = { 35 | // 文本色 36 | colorText: 'rgba(255, 255, 255, 0.85)', 37 | colorTextSecondary: 'rgba(255, 255, 255, 0.65)', 38 | colorTextTertiary: 'rgba(255, 255, 255, 0.45)', 39 | colorTextQuaternary: 'rgba(255, 255, 255, 0.25)', 40 | // 描边色 41 | colorBorder: '#424242', 42 | colorBorderSecondary: '#303030', 43 | 44 | // 填充色 45 | colorFill: 'rgba(255, 255, 255, 0.18)', 46 | colorFillSecondary: 'rgba(255, 255, 255, 0.12)', 47 | colorFillTertiary: 'rgba(255, 255, 255, 0.08)', 48 | colorFillQuaternary: 'rgba(255, 255, 255, 0.04)', 49 | // 背景色 50 | colorBgContainer: '#141414', 51 | colorBgElevated: '#000000', 52 | colorBgLayout: '#000000', 53 | colorBgSpotlight: '#424242', 54 | colorBgMask: 'rgba(0, 0, 0, 0.45)', 55 | 56 | // 品牌主色 57 | colorPrimaryBg: '#111a2c', 58 | }; 59 | -------------------------------------------------------------------------------- /src/bpmn/panel/ElementDocument/ElementDocument.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import { Form, Input } from 'antd'; 3 | 4 | const { TextArea } = Input; 5 | 6 | interface IProps { 7 | businessObject: any; 8 | } 9 | 10 | /** 11 | * 元素文档 组件 12 | * 13 | * @param props 14 | * @constructor 15 | */ 16 | export default function ElementDocument(props: IProps) { 17 | // props 18 | const { businessObject } = props; 19 | // form 20 | const [form] = Form.useForm<{ 21 | documentation: string; 22 | }>(); 23 | 24 | /** 25 | * 初始化 26 | */ 27 | useEffect(() => { 28 | if (businessObject) { 29 | initPageData(); 30 | } 31 | }, [businessObject?.id]); 32 | 33 | /** 34 | * 初始化页面数据 35 | */ 36 | function initPageData() { 37 | form.setFieldsValue({ 38 | documentation: businessObject?.documentation?.at(0).text, 39 | }); 40 | } 41 | 42 | /** 43 | * 更新元素文档 44 | * 45 | * @param value 46 | */ 47 | function updateDocumentation(value: string) { 48 | const documentation = window.bpmnInstance.bpmnFactory?.create( 49 | 'bpmn:Documentation', 50 | { 51 | text: value, 52 | }, 53 | ); 54 | window.bpmnInstance.modeling.updateProperties(window.bpmnInstance.element, { 55 | documentation: value ? [documentation] : undefined, 56 | }); 57 | } 58 | 59 | return ( 60 | <> 61 |
67 | 68 |