增加三方接口管理
This commit is contained in:
parent
dde2ad27ae
commit
f52f1bed8b
362
frontend/frontend-guide.md
Normal file
362
frontend/frontend-guide.md
Normal file
@ -0,0 +1,362 @@
|
||||
# 工作流平台前端开发指南
|
||||
|
||||
## 一、项目概述
|
||||
|
||||
### 1.1 技术栈
|
||||
- 框架:Ant Design Pro
|
||||
- 语言:TypeScript
|
||||
- HTTP请求:Umi Request
|
||||
- 流程设计器:LogicFlow
|
||||
- 表单设计器:FormRender
|
||||
- 图表库:ECharts
|
||||
|
||||
### 1.2 开发环境
|
||||
- Node.js >= 16
|
||||
- yarn >= 1.22
|
||||
- TypeScript >= 4.x
|
||||
|
||||
## 二、接口定义
|
||||
|
||||
### 2.1 工作流定义管理
|
||||
```typescript
|
||||
// 工作流定义相关接口
|
||||
interface WorkflowDefinitionAPI {
|
||||
// 基础CRUD接口
|
||||
list: '/api/v1/workflow-definitions' // GET 查询列表
|
||||
create: '/api/v1/workflow-definitions' // POST 创建
|
||||
update: '/api/v1/workflow-definitions/{id}' // PUT 更新
|
||||
delete: '/api/v1/workflow-definitions/{id}' // DELETE 删除
|
||||
get: '/api/v1/workflow-definitions/{id}' // GET 获取详情
|
||||
|
||||
// 特殊操作接口
|
||||
publish: '/api/v1/workflow-definitions/{id}/publish' // POST 发布
|
||||
disable: '/api/v1/workflow-definitions/{id}/disable' // POST 禁用
|
||||
enable: '/api/v1/workflow-definitions/{id}/enable' // POST 启用
|
||||
}
|
||||
|
||||
// 工作流定义数据结构
|
||||
interface WorkflowDefinitionDTO {
|
||||
id: number
|
||||
code: string // 工作流编码
|
||||
name: string // 工作流名称
|
||||
description: string // 描述
|
||||
status: 'DRAFT' | 'PUBLISHED' | 'DISABLED' // 状态
|
||||
version: number // 版本号
|
||||
nodeConfig: string // 节点配置(JSON)
|
||||
transitionConfig: string // 流转配置(JSON)
|
||||
formDefinition: string // 表单定义
|
||||
graphDefinition: string // 图形信息
|
||||
enabled: boolean // 是否启用
|
||||
remark: string // 备注
|
||||
nodes: NodeDefinitionDTO[] // 节点定义列表
|
||||
}
|
||||
|
||||
// 节点定义数据结构
|
||||
interface NodeDefinitionDTO {
|
||||
id: number
|
||||
nodeId: string // 节点ID
|
||||
name: string // 节点名称
|
||||
type: 'START' | 'END' | 'TASK' | 'GATEWAY' | 'SUB_PROCESS' | 'SHELL' // 节点类型
|
||||
config: string // 节点配置(JSON)
|
||||
description: string // 节点描述
|
||||
workflowDefinitionId: number // 工作流定义ID
|
||||
orderNum: number // 排序号
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 工作流实例管理
|
||||
```typescript
|
||||
// 工作流实例相关接口
|
||||
interface WorkflowInstanceAPI {
|
||||
// 基础CRUD接口
|
||||
list: '/api/v1/workflow-instance' // GET 查询列表
|
||||
get: '/api/v1/workflow-instance/{id}' // GET 获取详情
|
||||
|
||||
// 实例操作接口
|
||||
create: '/api/v1/workflow-instance' // POST 创建实例
|
||||
start: '/api/v1/workflow-instance/{id}/start' // POST 启动
|
||||
cancel: '/api/v1/workflow-instance/{id}/cancel' // POST 取消
|
||||
pause: '/api/v1/workflow-instance/{id}/pause' // POST 暂停
|
||||
resume: '/api/v1/workflow-instance/{id}/resume' // POST 恢复
|
||||
}
|
||||
|
||||
// 工作流实例数据结构
|
||||
interface WorkflowInstanceDTO {
|
||||
id: number
|
||||
definitionId: number // 工作流定义ID
|
||||
businessKey: string // 业务标识
|
||||
status: 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'PAUSED' // 状态
|
||||
startTime: string // 开始时间
|
||||
endTime: string // 结束时间
|
||||
variables: string // 工作流变量(JSON)
|
||||
error: string // 错误信息
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 节点实例管理
|
||||
```typescript
|
||||
// 节点实例相关接口
|
||||
interface NodeInstanceAPI {
|
||||
// 查询接口
|
||||
list: '/api/v1/node-instance' // GET 查询列表
|
||||
get: '/api/v1/node-instance/{id}' // GET 获取详情
|
||||
findByWorkflow: '/api/v1/node-instance/workflow/{workflowInstanceId}' // GET 查询工作流下的节点
|
||||
findByStatus: '/api/v1/node-instance/workflow/{workflowInstanceId}/status/{status}' // GET 查询指定状态的节点
|
||||
|
||||
// 节点操作
|
||||
updateStatus: '/api/v1/node-instance/{id}/status' // PUT 更新状态
|
||||
}
|
||||
|
||||
// 节点实例数据结构
|
||||
interface NodeInstanceDTO {
|
||||
id: number
|
||||
workflowInstanceId: number // 工作流实例ID
|
||||
nodeId: string // 节点ID
|
||||
nodeType: 'START' | 'END' | 'TASK' | 'GATEWAY' | 'SUB_PROCESS' | 'SHELL' // 节点类型
|
||||
name: string // 节点名称
|
||||
status: 'PENDING' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'PAUSED' | 'SKIPPED' // 状态
|
||||
startTime: string // 开始时间
|
||||
endTime: string // 结束时间
|
||||
config: string // 节点配置(JSON)
|
||||
input: string // 输入参数(JSON)
|
||||
output: string // 输出结果(JSON)
|
||||
error: string // 错误信息
|
||||
preNodeId: string // 前置节点ID
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 工作流日志管理
|
||||
```typescript
|
||||
// 日志相关接口
|
||||
interface WorkflowLogAPI {
|
||||
// 基础CRUD接口
|
||||
list: '/api/v1/workflow-logs' // GET 查询列表
|
||||
create: '/api/v1/workflow-logs' // POST 创建
|
||||
|
||||
// 特殊查询接口
|
||||
getWorkflowLogs: '/api/v1/workflow-logs/workflow/{workflowInstanceId}' // GET 查询工作流日志
|
||||
getNodeLogs: '/api/v1/workflow-logs/node/{workflowInstanceId}/{nodeId}' // GET 查询节点日志
|
||||
record: '/api/v1/workflow-logs/record' // POST 记录日志
|
||||
}
|
||||
|
||||
// 日志数据结构
|
||||
interface WorkflowLogDTO {
|
||||
id: number
|
||||
workflowInstanceId: number // 工作流实例ID
|
||||
nodeId: string // 节点ID
|
||||
message: string // 日志内容
|
||||
level: 'INFO' | 'WARN' | 'ERROR' // 日志级别
|
||||
detail: string // 详细信息
|
||||
createTime: string // 创建时间
|
||||
}
|
||||
```
|
||||
|
||||
## 三、页面功能
|
||||
|
||||
### 3.1 工作流定义管理(/workflow/definition)
|
||||
|
||||
#### 3.1.1 列表页(/workflow/definition/list)
|
||||
- 功能点:
|
||||
- 工作流定义列表展示
|
||||
- 支持按名称、编码、状态搜索
|
||||
- 支持创建、编辑、删除操作
|
||||
- 支持发布、禁用操作
|
||||
- 支持查看历史版本
|
||||
- 列表字段:
|
||||
- 工作流编码
|
||||
- 工作流名称
|
||||
- 版本号
|
||||
- 状态
|
||||
- 创建时间
|
||||
- 更新时间
|
||||
- 操作按钮
|
||||
|
||||
#### 3.1.2 编辑页(/workflow/definition/edit)
|
||||
- 功能点:
|
||||
1. 基本信息编辑
|
||||
- 工作流编码
|
||||
- 工作流名称
|
||||
- 描述
|
||||
- 备注
|
||||
2. 流程设计器
|
||||
- 节点拖拽
|
||||
- 连线绘制
|
||||
- 节点配置
|
||||
- 流程校验
|
||||
3. 表单设计器
|
||||
- 表单字段配置
|
||||
- 字段验证规则
|
||||
- 表单预览
|
||||
4. 节点配置面板
|
||||
- 节点基本信息
|
||||
- 节点类型配置
|
||||
- 执行条件配置
|
||||
- 表单关联配置
|
||||
|
||||
### 3.2 工作流实例管理(/workflow/instance)
|
||||
|
||||
#### 3.2.1 列表页(/workflow/instance/list)
|
||||
- 功能点:
|
||||
- 工作流实例列表展示
|
||||
- 支持按工作流名称、状态、时间搜索
|
||||
- 支持启动、暂停、恢复、取消操作
|
||||
- 列表字段:
|
||||
- 实例ID
|
||||
- 工作流名称
|
||||
- 业务标识
|
||||
- 状态
|
||||
- 开始时间
|
||||
- 结束时间
|
||||
- 操作按钮
|
||||
|
||||
#### 3.2.2 详情页(/workflow/instance/detail)
|
||||
- 功能点:
|
||||
1. 基本信息展示
|
||||
- 实例ID
|
||||
- 工作流名称
|
||||
- 状态
|
||||
- 时间信息
|
||||
2. 流程图展示
|
||||
- 显示当前节点
|
||||
- 节点状态标识
|
||||
- 流程进度展示
|
||||
3. 变量信息
|
||||
- 变量列表
|
||||
- 变量历史值
|
||||
4. 日志信息
|
||||
- 操作日志
|
||||
- 执行日志
|
||||
- 错误日志
|
||||
|
||||
### 3.3 监控大盘(/workflow/monitor)
|
||||
- 功能点:
|
||||
1. 统计信息
|
||||
- 总工作流数
|
||||
- 运行中实例数
|
||||
- 完成实例数
|
||||
- 失败实例数
|
||||
2. 状态分布
|
||||
- 饼图展示各状态占比
|
||||
- 支持时间范围筛选
|
||||
3. 执行时长统计
|
||||
- 平均执行时长
|
||||
- 最长执行时长
|
||||
- 执行时长分布
|
||||
4. 异常情况统计
|
||||
- 异常类型分布
|
||||
- 异常趋势图
|
||||
- 异常节点TOP5
|
||||
|
||||
## 四、开发规范
|
||||
|
||||
### 4.1 项目结构
|
||||
```
|
||||
src/
|
||||
├── components/ # 公共组件
|
||||
│ ├── FlowDesigner/ # 流程设计器组件
|
||||
│ ├── FormDesigner/ # 表单设计器组件
|
||||
│ └── NodeConfig/ # 节点配置组件
|
||||
├── pages/ # 页面组件
|
||||
│ └── workflow/ # 工作流相关页面
|
||||
├── services/ # API服务
|
||||
│ └── workflow/ # 工作流相关API
|
||||
├── models/ # 数据模型
|
||||
├── utils/ # 工具函数
|
||||
├── constants/ # 常量定义
|
||||
├── types/ # TypeScript类型
|
||||
└── locales/ # 国际化资源
|
||||
```
|
||||
|
||||
### 4.2 命名规范
|
||||
- 文件命名:使用 PascalCase
|
||||
- 组件文件:`FlowDesigner.tsx`
|
||||
- 类型文件:`WorkflowTypes.ts`
|
||||
- 工具文件:`FlowUtils.ts`
|
||||
- 变量命名:使用 camelCase
|
||||
- 普通变量:`flowInstance`
|
||||
- 布尔值:`isRunning`、`hasError`
|
||||
- 常量命名:使用 UPPER_CASE
|
||||
- `MAX_NODE_COUNT`
|
||||
- `DEFAULT_CONFIG`
|
||||
|
||||
### 4.3 组件开发规范
|
||||
1. 使用函数组件和 Hooks
|
||||
2. 使用 TypeScript 类型声明
|
||||
3. 添加必要的注释
|
||||
4. 实现错误处理
|
||||
5. 添加加载状态
|
||||
6. 做好性能优化
|
||||
|
||||
### 4.4 代码提交规范
|
||||
- feat: 新功能
|
||||
- fix: 修复bug
|
||||
- docs: 文档更新
|
||||
- style: 代码格式
|
||||
- refactor: 重构
|
||||
- test: 测试
|
||||
- chore: 构建过程或辅助工具的变动
|
||||
|
||||
## 五、开发流程
|
||||
|
||||
### 5.1 环境搭建
|
||||
1. 创建项目
|
||||
```bash
|
||||
yarn create umi
|
||||
```
|
||||
|
||||
2. 安装依赖
|
||||
```bash
|
||||
yarn add @ant-design/pro-components @logicflow/core @logicflow/extension form-render echarts
|
||||
```
|
||||
|
||||
### 5.2 开发步骤
|
||||
1. 搭建基础框架和路由(2天)
|
||||
2. 实现工作流定义CRUD(3天)
|
||||
3. 开发流程设计器(5天)
|
||||
4. 开发表单设计器(3天)
|
||||
5. 实现工作流实例管理(3天)
|
||||
6. 实现节点实例管理(2天)
|
||||
7. 实现日志管理(2天)
|
||||
8. 开发监控大盘(3天)
|
||||
9. 测试和优化(2天)
|
||||
|
||||
### 5.3 测试要求
|
||||
1. 单元测试覆盖率 > 80%
|
||||
2. 必须包含组件测试
|
||||
3. 必须包含集成测试
|
||||
4. 必须进行性能测试
|
||||
|
||||
### 5.4 部署要求
|
||||
1. 使用 Docker 部署
|
||||
2. 配置 Nginx 代理
|
||||
3. 启用 GZIP 压缩
|
||||
4. 配置缓存策略
|
||||
|
||||
## 六、注意事项
|
||||
|
||||
### 6.1 性能优化
|
||||
1. 使用路由懒加载
|
||||
2. 组件按需加载
|
||||
3. 大数据列表虚拟化
|
||||
4. 合理使用缓存
|
||||
5. 避免不必要的渲染
|
||||
|
||||
### 6.2 安全性
|
||||
1. 添加权限控制
|
||||
2. 防止XSS攻击
|
||||
3. 添加数据验证
|
||||
4. 敏感信息加密
|
||||
|
||||
### 6.3 用户体验
|
||||
1. 添加适当的加载状态
|
||||
2. 提供操作反馈
|
||||
3. 添加错误处理
|
||||
4. 支持快捷键操作
|
||||
5. 添加操作确认
|
||||
6. 支持数据导出
|
||||
|
||||
### 6.4 兼容性
|
||||
1. 支持主流浏览器最新版本
|
||||
2. 支持响应式布局
|
||||
3. 支持暗黑模式
|
||||
4. 支持国际化
|
||||
563
frontend/package-lock.json
generated
563
frontend/package-lock.json
generated
@ -10,9 +10,12 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.2.6",
|
||||
"@antv/x6": "^2.18.1",
|
||||
"@logicflow/core": "^2.0.9",
|
||||
"@logicflow/extension": "^2.0.13",
|
||||
"@reduxjs/toolkit": "^2.0.1",
|
||||
"antd": "^5.22.2",
|
||||
"axios": "^1.6.2",
|
||||
"form-render": "^2.5.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^9.0.4",
|
||||
@ -135,6 +138,11 @@
|
||||
"react": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@antv/hierarchy": {
|
||||
"version": "0.6.14",
|
||||
"resolved": "https://registry.npmmirror.com/@antv/hierarchy/-/hierarchy-0.6.14.tgz",
|
||||
"integrity": "sha512-V3uknf7bhynOqQDw2sg+9r9DwZ9pc6k/EcqyTFdfXB1+ydr7urisP0MipIuimucvQKN+Qkd+d6w601r1UIroqQ=="
|
||||
},
|
||||
"node_modules/@antv/x6": {
|
||||
"version": "2.18.1",
|
||||
"resolved": "https://registry.npmmirror.com/@antv/x6/-/x6-2.18.1.tgz",
|
||||
@ -1032,6 +1040,40 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@logicflow/core": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmmirror.com/@logicflow/core/-/core-2.0.9.tgz",
|
||||
"integrity": "sha512-HRc3W+XbcXbq9E3wElFNkaxNBja7Ga+FK6LYbsoOGWDWzZ7gSBCaYTpKPUlQsfUK0EvztqzCuer2DRJQQ77Ylg==",
|
||||
"dependencies": {
|
||||
"classnames": "^2.3.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mobx": "^5.15.7",
|
||||
"mobx-preact": "^3.0.0",
|
||||
"mobx-utils": "^5.6.1",
|
||||
"mousetrap": "^1.6.5",
|
||||
"preact": "^10.17.1",
|
||||
"uuid": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@logicflow/extension": {
|
||||
"version": "2.0.13",
|
||||
"resolved": "https://registry.npmmirror.com/@logicflow/extension/-/extension-2.0.13.tgz",
|
||||
"integrity": "sha512-1csZP2RYyGItvOMxVSpzrP7MguPrMRQYV+PUbm+8jZLrFbt3LcOQCNdHsEFU0cfuaiBF6Nx4qBdBeo0kog0eCw==",
|
||||
"dependencies": {
|
||||
"@antv/hierarchy": "^0.6.11",
|
||||
"@logicflow/core": "2.0.9",
|
||||
"classnames": "^2.3.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"medium-editor": "^5.23.3",
|
||||
"mobx": "^5.15.7",
|
||||
"preact": "^10.17.1",
|
||||
"rangy": "^1.3.1",
|
||||
"vanilla-picker": "^2.12.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@logicflow/core": "2.0.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@ -1472,6 +1514,11 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@sphinxxxx/color-conversion": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz",
|
||||
"integrity": "sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw=="
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
@ -1806,6 +1853,36 @@
|
||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/add-dom-event-listener": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz",
|
||||
"integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==",
|
||||
"dependencies": {
|
||||
"object-assign": "4.x"
|
||||
}
|
||||
},
|
||||
"node_modules/ahooks": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/ahooks/-/ahooks-3.8.1.tgz",
|
||||
"integrity": "sha512-JoP9+/RWO7MnI/uSKdvQ8WB10Y3oo1PjLv+4Sv4Vpm19Z86VUMdXh+RhWvMGxZZs06sq2p0xVtFk8Oh5ZObsoA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"dayjs": "^1.9.1",
|
||||
"intersection-observer": "^0.12.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
"lodash": "^4.17.21",
|
||||
"react-fast-compare": "^3.2.2",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"screenfull": "^5.0.0",
|
||||
"tslib": "^2.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
||||
@ -1925,6 +2002,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/async-validator": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-3.5.2.tgz",
|
||||
"integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@ -1940,6 +2022,20 @@
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-runtime": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmmirror.com/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
||||
"integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
|
||||
"dependencies": {
|
||||
"core-js": "^2.4.0",
|
||||
"regenerator-runtime": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-runtime/node_modules/regenerator-runtime": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@ -2049,6 +2145,15 @@
|
||||
"resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz",
|
||||
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
|
||||
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.3",
|
||||
"color-string": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@ -2064,8 +2169,29 @@
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/color-string": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz",
|
||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||
"dependencies": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/color/node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/color/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
@ -2078,6 +2204,19 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/component-classes": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmmirror.com/component-classes/-/component-classes-1.2.6.tgz",
|
||||
"integrity": "sha512-hPFGULxdwugu1QWW3SvVOCUHLzO34+a2J6Wqy0c5ASQkfi9/8nZcBB0ZohaEbXOQlCflMAEMmEWk7u7BVs4koA==",
|
||||
"dependencies": {
|
||||
"component-indexof": "0.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/component-indexof": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/component-indexof/-/component-indexof-0.0.3.tgz",
|
||||
"integrity": "sha512-puDQKvx/64HZXb4hBwIcvQLaLgux8o1CbWl39s41hrIIZDl1lJiD5jc22gj3RBeGK0ovxALDYpIbyjqDUUl0rw=="
|
||||
},
|
||||
"node_modules/compute-scroll-into-view": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
|
||||
@ -2103,6 +2242,22 @@
|
||||
"toggle-selection": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz",
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
|
||||
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
|
||||
"hasInstallScript": true
|
||||
},
|
||||
"node_modules/create-react-class": {
|
||||
"version": "15.7.0",
|
||||
"resolved": "https://registry.npmmirror.com/create-react-class/-/create-react-class-15.7.0.tgz",
|
||||
"integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.3.1",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@ -2117,6 +2272,15 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/css-animation": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmmirror.com/css-animation/-/css-animation-1.6.1.tgz",
|
||||
"integrity": "sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog==",
|
||||
"dependencies": {
|
||||
"babel-runtime": "6.x",
|
||||
"component-classes": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
|
||||
@ -2182,6 +2346,11 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-align": {
|
||||
"version": "1.12.4",
|
||||
"resolved": "https://registry.npmmirror.com/dom-align/-/dom-align-1.12.4.tgz",
|
||||
"integrity": "sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw=="
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.64",
|
||||
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz",
|
||||
@ -2595,6 +2764,89 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/form-render": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/form-render/-/form-render-2.5.1.tgz",
|
||||
"integrity": "sha512-oNbJ+McqB5h1yuyxYAT3ixJF8itmHlnKvqDgQhJT9Tw1c3yGwfRnVXboRxBV+Myz0dkf47zL6lyY1l74yQsWsg==",
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.0.2",
|
||||
"ahooks": "^3.7.5",
|
||||
"async-validator": "^3.5.1",
|
||||
"classnames": "^2.3.1",
|
||||
"color": "^3.1.2",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"rc-color-picker": "^1.2.6",
|
||||
"virtualizedtableforantd4": "^1.1.2",
|
||||
"zustand": "^4.1.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"antd": "4.x || 5.x",
|
||||
"react": ">=16.9.0",
|
||||
"react-dom": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/form-render/node_modules/@ant-design/colors": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/@ant-design/colors/-/colors-6.0.0.tgz",
|
||||
"integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==",
|
||||
"dependencies": {
|
||||
"@ctrl/tinycolor": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/form-render/node_modules/@ant-design/icons": {
|
||||
"version": "4.8.3",
|
||||
"resolved": "https://registry.npmmirror.com/@ant-design/icons/-/icons-4.8.3.tgz",
|
||||
"integrity": "sha512-HGlIQZzrEbAhpJR6+IGdzfbPym94Owr6JZkJ2QCCnOkPVIWMO2xgIVcOKnl8YcpijIo39V7l2qQL5fmtw56cMw==",
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^6.0.0",
|
||||
"@ant-design/icons-svg": "^4.3.0",
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"classnames": "^2.2.6",
|
||||
"lodash": "^4.17.15",
|
||||
"rc-util": "^5.9.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.0.0",
|
||||
"react-dom": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/form-render/node_modules/rc-color-picker": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmmirror.com/rc-color-picker/-/rc-color-picker-1.2.6.tgz",
|
||||
"integrity": "sha512-AaC9Pg7qCHSy5M4eVbqDIaNb2FC4SEw82GOHB2C4R/+vF2FVa/r5XA+Igg5+zLPmAvBLhz9tL4MAfkRA8yWNJw==",
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5",
|
||||
"prop-types": "^15.5.8",
|
||||
"rc-trigger": "1.x",
|
||||
"rc-util": "^4.0.2",
|
||||
"tinycolor2": "^1.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "16.x",
|
||||
"react-dom": "16.x"
|
||||
}
|
||||
},
|
||||
"node_modules/form-render/node_modules/rc-color-picker/node_modules/rc-util": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmmirror.com/rc-util/-/rc-util-4.21.1.tgz",
|
||||
"integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
|
||||
"dependencies": {
|
||||
"add-dom-event-listener": "^1.1.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-is": "^16.12.0",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"shallowequal": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/form-render/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@ -2723,6 +2975,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmmirror.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
|
||||
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz",
|
||||
@ -2783,6 +3040,16 @@
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/intersection-observer": {
|
||||
"version": "0.12.2",
|
||||
"resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
|
||||
"integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@ -2828,6 +3095,14 @@
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -2932,6 +3207,11 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
@ -2964,6 +3244,11 @@
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/medium-editor": {
|
||||
"version": "5.23.3",
|
||||
"resolved": "https://registry.npmmirror.com/medium-editor/-/medium-editor-5.23.3.tgz",
|
||||
"integrity": "sha512-he9/TdjX8f8MGdXGfCs8AllrYnqXJJvjNkDKmPg3aPW/uoIrlRqtkFthrwvmd+u4QyzEiadhCCM0EwTiRdUCJw=="
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz",
|
||||
@ -3020,6 +3305,40 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/mobx": {
|
||||
"version": "5.15.7",
|
||||
"resolved": "https://registry.npmmirror.com/mobx/-/mobx-5.15.7.tgz",
|
||||
"integrity": "sha512-wyM3FghTkhmC+hQjyPGGFdpehrcX1KOXsDuERhfK2YbJemkUhEB+6wzEN639T21onxlfYBmriA1PFnvxTUhcKw==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mobx"
|
||||
}
|
||||
},
|
||||
"node_modules/mobx-preact": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/mobx-preact/-/mobx-preact-3.0.0.tgz",
|
||||
"integrity": "sha512-ijan/cBs3WmRye87E5+3JmoFBB00KDAwNA3pm7bMwYLPHBAXlN86aC3gdrXw8aKzM5RI8V3a993PphzPv6P4FA==",
|
||||
"dependencies": {
|
||||
"hoist-non-react-statics": "^2.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mobx": "5.x",
|
||||
"preact": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/mobx-utils": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmmirror.com/mobx-utils/-/mobx-utils-5.6.2.tgz",
|
||||
"integrity": "sha512-a/WlXyGkp6F12b01sTarENpxbmlRgPHFyR1Xv2bsSjQBm5dcOtd16ONb40/vOqck8L99NHpI+C9MXQ+SZ8f+yw==",
|
||||
"peerDependencies": {
|
||||
"mobx": "^4.13.1 || ^5.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/mousetrap": {
|
||||
"version": "1.6.5",
|
||||
"resolved": "https://registry.npmmirror.com/mousetrap/-/mousetrap-1.6.5.tgz",
|
||||
"integrity": "sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA=="
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
@ -3056,6 +3375,14 @@
|
||||
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
|
||||
@ -3160,6 +3487,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@ -3206,6 +3538,15 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/preact": {
|
||||
"version": "10.25.1",
|
||||
"resolved": "https://registry.npmmirror.com/preact/-/preact-10.25.1.tgz",
|
||||
"integrity": "sha512-frxeZV2vhQSohQwJ7FvlqC40ze89+8friponWUFeVEkaCfhC6Eu4V0iND5C9CXz8JLndV07QRDeXzH1+Anz5Og==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@ -3215,6 +3556,21 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
@ -3249,6 +3605,78 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/raf": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/raf/-/raf-3.4.1.tgz",
|
||||
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||
"dependencies": {
|
||||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rangy": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/rangy/-/rangy-1.3.2.tgz",
|
||||
"integrity": "sha512-fS1C4MOyk8T+ZJZdLcgrukPWxkyDXa+Hd2Kj+Zg4wIK71yrWgmjzHubzPMY1G+WD9EgGxMp3fIL0zQ1ickmSWA=="
|
||||
},
|
||||
"node_modules/rc-align": {
|
||||
"version": "2.4.5",
|
||||
"resolved": "https://registry.npmmirror.com/rc-align/-/rc-align-2.4.5.tgz",
|
||||
"integrity": "sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw==",
|
||||
"dependencies": {
|
||||
"babel-runtime": "^6.26.0",
|
||||
"dom-align": "^1.7.0",
|
||||
"prop-types": "^15.5.8",
|
||||
"rc-util": "^4.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/rc-align/node_modules/rc-util": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmmirror.com/rc-util/-/rc-util-4.21.1.tgz",
|
||||
"integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
|
||||
"dependencies": {
|
||||
"add-dom-event-listener": "^1.1.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-is": "^16.12.0",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"shallowequal": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rc-align/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/rc-animate": {
|
||||
"version": "2.11.1",
|
||||
"resolved": "https://registry.npmmirror.com/rc-animate/-/rc-animate-2.11.1.tgz",
|
||||
"integrity": "sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ==",
|
||||
"dependencies": {
|
||||
"babel-runtime": "6.x",
|
||||
"classnames": "^2.2.6",
|
||||
"css-animation": "^1.3.2",
|
||||
"prop-types": "15.x",
|
||||
"raf": "^3.4.0",
|
||||
"rc-util": "^4.15.3",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/rc-animate/node_modules/rc-util": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmmirror.com/rc-util/-/rc-util-4.21.1.tgz",
|
||||
"integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
|
||||
"dependencies": {
|
||||
"add-dom-event-listener": "^1.1.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-is": "^16.12.0",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"shallowequal": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rc-animate/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/rc-cascader": {
|
||||
"version": "3.30.0",
|
||||
"resolved": "https://registry.npmmirror.com/rc-cascader/-/rc-cascader-3.30.0.tgz",
|
||||
@ -3775,6 +4203,36 @@
|
||||
"react-dom": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/rc-trigger": {
|
||||
"version": "1.11.5",
|
||||
"resolved": "https://registry.npmmirror.com/rc-trigger/-/rc-trigger-1.11.5.tgz",
|
||||
"integrity": "sha512-MBuUPw1nFzA4K7jQOwb7uvFaZFjXGd00EofUYiZ+l/fgKVq8wnLC0lkv36kwqM7vfKyftRo2sh7cWVpdPuNnnw==",
|
||||
"dependencies": {
|
||||
"babel-runtime": "6.x",
|
||||
"create-react-class": "15.x",
|
||||
"prop-types": "15.x",
|
||||
"rc-align": "2.x",
|
||||
"rc-animate": "2.x",
|
||||
"rc-util": "4.x"
|
||||
}
|
||||
},
|
||||
"node_modules/rc-trigger/node_modules/rc-util": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmmirror.com/rc-util/-/rc-util-4.21.1.tgz",
|
||||
"integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
|
||||
"dependencies": {
|
||||
"add-dom-event-listener": "^1.1.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-is": "^16.12.0",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"shallowequal": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rc-trigger/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/rc-upload": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/rc-upload/-/rc-upload-4.8.1.tgz",
|
||||
@ -3843,11 +4301,21 @@
|
||||
"react": "^18.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-fast-compare": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
|
||||
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
|
||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
||||
},
|
||||
"node_modules/react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"node_modules/react-redux": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-9.1.2.tgz",
|
||||
@ -4040,6 +4508,17 @@
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/screenfull": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
|
||||
"integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/scroll-into-view-if-needed": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
|
||||
@ -4060,6 +4539,11 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/shallowequal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/shallowequal/-/shallowequal-1.1.0.tgz",
|
||||
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@ -4081,6 +4565,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz",
|
||||
@ -4159,6 +4651,11 @@
|
||||
"node": ">=12.22"
|
||||
}
|
||||
},
|
||||
"node_modules/tinycolor2": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/tinycolor2/-/tinycolor2-1.6.0.tgz",
|
||||
"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@ -4188,6 +4685,11 @@
|
||||
"typescript": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz",
|
||||
@ -4287,6 +4789,36 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz",
|
||||
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vanilla-picker": {
|
||||
"version": "2.12.3",
|
||||
"resolved": "https://registry.npmmirror.com/vanilla-picker/-/vanilla-picker-2.12.3.tgz",
|
||||
"integrity": "sha512-qVkT1E7yMbUsB2mmJNFmaXMWE2hF8ffqzMMwe9zdAikd8u2VfnsVY2HQcOUi2F38bgbxzlJBEdS1UUhOXdF9GQ==",
|
||||
"dependencies": {
|
||||
"@sphinxxxx/color-conversion": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/virtualizedtableforantd4": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/virtualizedtableforantd4/-/virtualizedtableforantd4-1.3.1.tgz",
|
||||
"integrity": "sha512-rW8KoToI2nt1jNtweXIUIiygi74XMzKLzUrrtZbGsQc7m3v68AaedPuf4CZcte+nosgYuPEWnAgjuI/KR8BVbg==",
|
||||
"peerDependencies": {
|
||||
"antd": "^4.0.0 || ^5.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.11",
|
||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.11.tgz",
|
||||
@ -4393,6 +4925,33 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.5.tgz",
|
||||
"integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==",
|
||||
"dependencies": {
|
||||
"use-sync-external-store": "1.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8",
|
||||
"immer": ">=9.0.6",
|
||||
"react": ">=16.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,9 +12,12 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.2.6",
|
||||
"@antv/x6": "^2.18.1",
|
||||
"@logicflow/core": "^2.0.9",
|
||||
"@logicflow/extension": "^2.0.13",
|
||||
"@reduxjs/toolkit": "^2.0.1",
|
||||
"antd": "^5.22.2",
|
||||
"axios": "^1.6.2",
|
||||
"form-render": "^2.5.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^9.0.4",
|
||||
|
||||
12
frontend/src/components/LoadingComponent/index.tsx
Normal file
12
frontend/src/components/LoadingComponent/index.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Spin } from 'antd';
|
||||
|
||||
const LoadingComponent: React.FC = () => {
|
||||
return (
|
||||
<div style={{ padding: 24, textAlign: 'center' }}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingComponent;
|
||||
@ -1,6 +1,7 @@
|
||||
import request from '@/utils/request';
|
||||
import type { Page } from '@/types/base/page';
|
||||
import type { MenuResponse, MenuRequest } from './types';
|
||||
import { MenuTypeEnum } from './types';
|
||||
|
||||
const BASE_URL = '/api/v1/menu';
|
||||
|
||||
@ -15,6 +16,8 @@ export const getMenuTree = () =>
|
||||
// 获取当前用户菜单
|
||||
export const getCurrentUserMenus = async () => {
|
||||
const menus = await request.get<MenuResponse[]>(`${BASE_URL}/current`);
|
||||
console.log('Backend menus:', menus);
|
||||
|
||||
// 添加首页路由
|
||||
const dashboard: MenuResponse = {
|
||||
id: 0,
|
||||
@ -25,7 +28,7 @@ export const getCurrentUserMenus = async () => {
|
||||
path: "/dashboard",
|
||||
component: "/Dashboard/index",
|
||||
icon: "dashboard",
|
||||
type: 2,
|
||||
type: MenuTypeEnum.MENU,
|
||||
parentId: 0,
|
||||
sort: 0,
|
||||
hidden: false,
|
||||
@ -34,6 +37,77 @@ export const getCurrentUserMenus = async () => {
|
||||
updateBy: "system"
|
||||
};
|
||||
|
||||
// 添加工作流菜单
|
||||
const workflow: MenuResponse = {
|
||||
id: -2,
|
||||
createTime: new Date().toISOString(),
|
||||
updateTime: new Date().toISOString(),
|
||||
version: 0,
|
||||
name: "工作流管理",
|
||||
path: "/workflow",
|
||||
icon: "apartment",
|
||||
type: MenuTypeEnum.DIRECTORY,
|
||||
parentId: 0,
|
||||
sort: 2,
|
||||
hidden: false,
|
||||
enabled: true,
|
||||
createBy: "system",
|
||||
updateBy: "system",
|
||||
children: [
|
||||
{
|
||||
id: -21,
|
||||
createTime: new Date().toISOString(),
|
||||
updateTime: new Date().toISOString(),
|
||||
version: 0,
|
||||
name: "流程定义",
|
||||
path: "/workflow/definition",
|
||||
component: "/pages/Workflow/Definition/index",
|
||||
icon: "apartment",
|
||||
type: MenuTypeEnum.MENU,
|
||||
parentId: -2,
|
||||
sort: 0,
|
||||
hidden: false,
|
||||
enabled: true,
|
||||
createBy: "system",
|
||||
updateBy: "system"
|
||||
},
|
||||
{
|
||||
id: -22,
|
||||
createTime: new Date().toISOString(),
|
||||
updateTime: new Date().toISOString(),
|
||||
version: 0,
|
||||
name: "流程实例",
|
||||
path: "/workflow/instance",
|
||||
component: "/pages/Workflow/Instance/index",
|
||||
icon: "apartment",
|
||||
type: MenuTypeEnum.MENU,
|
||||
parentId: -2,
|
||||
sort: 1,
|
||||
hidden: false,
|
||||
enabled: true,
|
||||
createBy: "system",
|
||||
updateBy: "system"
|
||||
},
|
||||
{
|
||||
id: -23,
|
||||
createTime: new Date().toISOString(),
|
||||
updateTime: new Date().toISOString(),
|
||||
version: 0,
|
||||
name: "流程监控",
|
||||
path: "/workflow/monitor",
|
||||
component: "/pages/Workflow/Monitor/index",
|
||||
icon: "dashboard",
|
||||
type: MenuTypeEnum.MENU,
|
||||
parentId: -2,
|
||||
sort: 2,
|
||||
hidden: false,
|
||||
enabled: true,
|
||||
createBy: "system",
|
||||
updateBy: "system"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// 添加X6测试菜单
|
||||
const x6Test: MenuResponse = {
|
||||
id: -1,
|
||||
@ -44,7 +118,7 @@ export const getCurrentUserMenus = async () => {
|
||||
path: "/x6-test",
|
||||
component: "/X6Test/index",
|
||||
icon: "experiment",
|
||||
type: 2,
|
||||
type: MenuTypeEnum.MENU,
|
||||
parentId: 0,
|
||||
sort: 1,
|
||||
hidden: false,
|
||||
@ -71,7 +145,9 @@ export const getCurrentUserMenus = async () => {
|
||||
};
|
||||
|
||||
const processedMenus = menus.map(processMenu);
|
||||
return [dashboard, x6Test, ...processedMenus];
|
||||
const allMenus = [dashboard, x6Test, workflow, ...processedMenus];
|
||||
console.log('All menus:', allMenus);
|
||||
return allMenus;
|
||||
};
|
||||
|
||||
// 创建菜单
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 2px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canvas {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.configPanel {
|
||||
width: 320px;
|
||||
height: 100%;
|
||||
border-left: 1px solid #e8e8e8;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
:global(.lf-control) {
|
||||
position: absolute;
|
||||
right: 330px;
|
||||
top: 10px;
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Card, Space } from 'antd';
|
||||
import LogicFlow from '@logicflow/core';
|
||||
import { DndPanel, SelectionSelect, Control } from '@logicflow/extension';
|
||||
import '@logicflow/core/es/index.css';
|
||||
import '@logicflow/extension/es/style/index.css';
|
||||
import styles from './index.module.css';
|
||||
import { registerNodes } from './nodes';
|
||||
import NodeConfig from '../NodeConfig';
|
||||
|
||||
interface FlowDesignerProps {
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
const FlowDesigner: React.FC<FlowDesignerProps> = ({
|
||||
value,
|
||||
onChange
|
||||
}) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [lf, setLf] = useState<LogicFlow>();
|
||||
const [selectedNode, setSelectedNode] = useState<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (containerRef.current) {
|
||||
// 初始化 LogicFlow
|
||||
const logicflow = new LogicFlow({
|
||||
container: containerRef.current,
|
||||
grid: true,
|
||||
plugins: [DndPanel, SelectionSelect, Control]
|
||||
});
|
||||
|
||||
// 注册自定义节点
|
||||
registerNodes(logicflow);
|
||||
|
||||
// 注册事件
|
||||
logicflow.on('node:click', ({ data }) => {
|
||||
setSelectedNode(data);
|
||||
});
|
||||
|
||||
logicflow.on('blank:click', () => {
|
||||
setSelectedNode(null);
|
||||
});
|
||||
|
||||
// 如果有初始值,渲染流程图
|
||||
if (value) {
|
||||
try {
|
||||
const graphData = JSON.parse(value);
|
||||
logicflow.render(graphData);
|
||||
} catch (error) {
|
||||
console.error('Failed to parse graph data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
setLf(logicflow);
|
||||
|
||||
return () => {
|
||||
logicflow.destroy();
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 处理节点配置更新
|
||||
const handleNodeConfigSave = (config: any) => {
|
||||
if (lf && selectedNode) {
|
||||
lf.setProperties(selectedNode.id, config);
|
||||
setSelectedNode(null);
|
||||
|
||||
// 触发 onChange
|
||||
const graphData = lf.getGraphData();
|
||||
onChange?.(JSON.stringify(graphData));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.canvas} ref={containerRef} />
|
||||
{selectedNode && (
|
||||
<div className={styles.configPanel}>
|
||||
<NodeConfig
|
||||
node={selectedNode}
|
||||
onSave={handleNodeConfigSave}
|
||||
onCancel={() => setSelectedNode(null)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FlowDesigner;
|
||||
@ -0,0 +1,81 @@
|
||||
import LogicFlow from '@logicflow/core';
|
||||
import { CircleNode, RectNode, DiamondNode } from '@logicflow/core';
|
||||
|
||||
export function registerNodes(lf: LogicFlow) {
|
||||
// 开始节点
|
||||
class StartNode extends CircleNode {
|
||||
static extendKey = 'StartNode';
|
||||
getNodeStyle() {
|
||||
const style = super.getNodeStyle();
|
||||
return {
|
||||
...style,
|
||||
fill: '#C6E5FF',
|
||||
stroke: '#1890FF'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 任务节点
|
||||
class TaskNode extends RectNode {
|
||||
static extendKey = 'TaskNode';
|
||||
getNodeStyle() {
|
||||
const style = super.getNodeStyle();
|
||||
return {
|
||||
...style,
|
||||
fill: '#FFF',
|
||||
stroke: '#1890FF'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 网关节点
|
||||
class GatewayNode extends DiamondNode {
|
||||
static extendKey = 'GatewayNode';
|
||||
getNodeStyle() {
|
||||
const style = super.getNodeStyle();
|
||||
return {
|
||||
...style,
|
||||
fill: '#FFF',
|
||||
stroke: '#1890FF'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 结束节点
|
||||
class EndNode extends CircleNode {
|
||||
static extendKey = 'EndNode';
|
||||
getNodeStyle() {
|
||||
const style = super.getNodeStyle();
|
||||
return {
|
||||
...style,
|
||||
fill: '#FFE7E7',
|
||||
stroke: '#FF4D4F'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 注册节点
|
||||
lf.register({
|
||||
type: 'start',
|
||||
view: StartNode,
|
||||
model: StartNode
|
||||
});
|
||||
|
||||
lf.register({
|
||||
type: 'task',
|
||||
view: TaskNode,
|
||||
model: TaskNode
|
||||
});
|
||||
|
||||
lf.register({
|
||||
type: 'gateway',
|
||||
view: GatewayNode,
|
||||
model: GatewayNode
|
||||
});
|
||||
|
||||
lf.register({
|
||||
type: 'end',
|
||||
view: EndNode,
|
||||
model: EndNode
|
||||
});
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Card, Tabs } from 'antd';
|
||||
import type { TabsProps } from 'antd';
|
||||
import FormRender from 'form-render';
|
||||
|
||||
interface FormDesignerProps {
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
const defaultSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
input1: {
|
||||
title: '输入框',
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const FormDesigner: React.FC<FormDesignerProps> = ({
|
||||
value,
|
||||
onChange,
|
||||
readOnly = false
|
||||
}) => {
|
||||
const [schema, setSchema] = useState<any>(() => {
|
||||
try {
|
||||
return value ? JSON.parse(value) : defaultSchema;
|
||||
} catch (error) {
|
||||
return defaultSchema;
|
||||
}
|
||||
});
|
||||
|
||||
const handleSubmit = (formData: any) => {
|
||||
console.log('Form data:', formData);
|
||||
};
|
||||
|
||||
const handleValidate = (errors: any) => {
|
||||
console.log('Form errors:', errors);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: 24 }}>
|
||||
<Card title="表单预览">
|
||||
<FormRender
|
||||
schema={schema}
|
||||
onFinish={handleSubmit}
|
||||
onValidate={handleValidate}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormDesigner;
|
||||
@ -0,0 +1,90 @@
|
||||
import React from 'react';
|
||||
import { Form, Input, Button, Space } from 'antd';
|
||||
import type { BaseNodeModel } from '@logicflow/core';
|
||||
|
||||
type NodeType = 'start' | 'end' | 'task' | 'gateway';
|
||||
|
||||
interface NodeConfigProps {
|
||||
node: BaseNodeModel & { type: NodeType };
|
||||
onSave: (config: any) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const NodeConfig: React.FC<NodeConfigProps> = ({
|
||||
node,
|
||||
onSave,
|
||||
onCancel
|
||||
}) => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleFinish = (values: any) => {
|
||||
onSave({
|
||||
...values,
|
||||
text: { value: values.text, x: node.text?.x, y: node.text?.y }
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: 16 }}>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={{
|
||||
text: node.text?.value,
|
||||
...node.getProperties()
|
||||
}}
|
||||
onFinish={handleFinish}
|
||||
>
|
||||
<Form.Item
|
||||
label="节点名称"
|
||||
name="text"
|
||||
rules={[{ required: true, message: '请输入节点名称' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
{node.type === 'task' && (
|
||||
<>
|
||||
<Form.Item
|
||||
label="表单Key"
|
||||
name="formKey"
|
||||
rules={[{ required: true, message: '请输入表单Key' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="处理人"
|
||||
name="assignee"
|
||||
rules={[{ required: true, message: '请输入处理人' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
|
||||
{node.type === 'gateway' && (
|
||||
<Form.Item
|
||||
label="条件表达式"
|
||||
name="condition"
|
||||
rules={[{ required: true, message: '请输入条件表达式' }]}
|
||||
>
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
<Form.Item>
|
||||
<Space>
|
||||
<Button type="primary" htmlType="submit">
|
||||
确定
|
||||
</Button>
|
||||
<Button onClick={onCancel}>
|
||||
取消
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NodeConfig;
|
||||
131
frontend/src/pages/Workflow/Definition/Edit/index.tsx
Normal file
131
frontend/src/pages/Workflow/Definition/Edit/index.tsx
Normal file
@ -0,0 +1,131 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Card, Tabs, Button, Form, Input, message } from 'antd';
|
||||
import type { TabsProps } from 'antd';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import FlowDesigner from './components/FlowDesigner';
|
||||
import FormDesigner from './components/FormDesigner';
|
||||
import { getDefinition, createDefinition, updateDefinition } from '../../service';
|
||||
import type { WorkflowDefinitionRequest } from '../../types';
|
||||
|
||||
const Edit: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [graphData, setGraphData] = useState('');
|
||||
const [formData, setFormData] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
setLoading(true);
|
||||
getDefinition(parseInt(id))
|
||||
.then(data => {
|
||||
form.setFieldsValue({
|
||||
name: data.name,
|
||||
code: data.code,
|
||||
description: data.description
|
||||
});
|
||||
setGraphData(data.graphDefinition || '');
|
||||
setFormData(data.formDefinition || '');
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, [id, form]);
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
const data: WorkflowDefinitionRequest = {
|
||||
...values,
|
||||
graphDefinition: graphData,
|
||||
formDefinition: formData,
|
||||
nodeConfig: '{}',
|
||||
transitionConfig: '{}',
|
||||
enabled: true
|
||||
};
|
||||
|
||||
if (id) {
|
||||
await updateDefinition(parseInt(id), data);
|
||||
} else {
|
||||
await createDefinition(data);
|
||||
}
|
||||
|
||||
message.success('保存成功');
|
||||
navigate('/workflow/definition');
|
||||
} catch (error) {
|
||||
console.error('Save failed:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
key: 'basic',
|
||||
label: '基本信息',
|
||||
children: (
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
style={{ maxWidth: 600, margin: '24px auto' }}
|
||||
>
|
||||
<Form.Item
|
||||
label="流程名称"
|
||||
name="name"
|
||||
rules={[{ required: true, message: '请输入流程名称' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="流程编码"
|
||||
name="code"
|
||||
rules={[{ required: true, message: '请输入流程编码' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="描述"
|
||||
name="description"
|
||||
>
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: 'flow',
|
||||
label: '流程设计',
|
||||
children: (
|
||||
<FlowDesigner
|
||||
value={graphData}
|
||||
onChange={setGraphData}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: 'form',
|
||||
label: '表单设计',
|
||||
children: (
|
||||
<FormDesigner
|
||||
value={formData}
|
||||
onChange={setFormData}
|
||||
/>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={id ? '编辑流程' : '新建流程'}
|
||||
extra={
|
||||
<Button type="primary" onClick={handleSave}>
|
||||
保存
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Tabs items={items} />
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default Edit;
|
||||
165
frontend/src/pages/Workflow/Definition/index.tsx
Normal file
165
frontend/src/pages/Workflow/Definition/index.tsx
Normal file
@ -0,0 +1,165 @@
|
||||
import React from 'react';
|
||||
import { Card, Table, Button, Space, Tag, Popconfirm, message } from 'antd';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { useTableData } from '@/hooks/useTableData';
|
||||
import { getDefinitions, deleteDefinition, publishDefinition, disableDefinition, enableDefinition } from '../service';
|
||||
import { WorkflowDefinitionResponse, WorkflowStatus } from '../types';
|
||||
|
||||
const Definition: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { list, loading, pagination, handleTableChange, refresh } = useTableData({
|
||||
service: {
|
||||
list: getDefinitions
|
||||
}
|
||||
});
|
||||
|
||||
const handlePublish = async (id: number) => {
|
||||
try {
|
||||
await publishDefinition(id);
|
||||
message.success('发布成功');
|
||||
refresh();
|
||||
} catch (error) {
|
||||
message.error('发布失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleDisable = async (id: number) => {
|
||||
try {
|
||||
await disableDefinition(id);
|
||||
message.success('禁用成功');
|
||||
refresh();
|
||||
} catch (error) {
|
||||
message.error('禁用失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleEnable = async (id: number) => {
|
||||
try {
|
||||
await enableDefinition(id);
|
||||
message.success('启用成功');
|
||||
refresh();
|
||||
} catch (error) {
|
||||
message.error('启用失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
await deleteDefinition(id);
|
||||
message.success('删除成功');
|
||||
refresh();
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
const columns: ColumnsType<WorkflowDefinitionResponse> = [
|
||||
{
|
||||
title: '流程名称',
|
||||
dataIndex: 'name',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '流程编码',
|
||||
dataIndex: 'code',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 120,
|
||||
render: (status: WorkflowStatus) => {
|
||||
const statusMap = {
|
||||
'DRAFT': { text: '草稿', color: 'default' },
|
||||
'PUBLISHED': { text: '已发布', color: 'success' },
|
||||
'DISABLED': { text: '已禁用', color: 'error' },
|
||||
};
|
||||
const { text, color } = statusMap[status];
|
||||
return <Tag color={color}>{text}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 280,
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => navigate(`/workflow/definition/edit/${record.id}`)}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
{record.status === 'DRAFT' && (
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => handlePublish(record.id)}
|
||||
>
|
||||
发布
|
||||
</Button>
|
||||
)}
|
||||
{record.status === 'PUBLISHED' && (
|
||||
<Button
|
||||
type="link"
|
||||
danger
|
||||
onClick={() => handleDisable(record.id)}
|
||||
>
|
||||
禁用
|
||||
</Button>
|
||||
)}
|
||||
{record.status === 'DISABLED' && (
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => handleEnable(record.id)}
|
||||
>
|
||||
启用
|
||||
</Button>
|
||||
)}
|
||||
<Popconfirm
|
||||
title="确定要删除吗?"
|
||||
onConfirm={() => handleDelete(record.id)}
|
||||
>
|
||||
<Button type="link" danger>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Card
|
||||
title="流程定义"
|
||||
extra={
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => navigate('/workflow/definition/edit')}
|
||||
>
|
||||
新建流程
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={list}
|
||||
loading={loading}
|
||||
pagination={pagination}
|
||||
onChange={handleTableChange}
|
||||
rowKey="id"
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default Definition;
|
||||
12
frontend/src/pages/Workflow/Instance/index.tsx
Normal file
12
frontend/src/pages/Workflow/Instance/index.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Card } from 'antd';
|
||||
|
||||
const WorkflowInstance: React.FC = () => {
|
||||
return (
|
||||
<Card>
|
||||
<div>工作流实例管理(开发中)</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkflowInstance;
|
||||
12
frontend/src/pages/Workflow/Monitor/index.tsx
Normal file
12
frontend/src/pages/Workflow/Monitor/index.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Card } from 'antd';
|
||||
|
||||
const WorkflowMonitor: React.FC = () => {
|
||||
return (
|
||||
<Card>
|
||||
<div>工作流监控大盘(开发中)</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkflowMonitor;
|
||||
97
frontend/src/pages/Workflow/service.ts
Normal file
97
frontend/src/pages/Workflow/service.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import request from '@/utils/request';
|
||||
import type { Page } from '@/types/base/page';
|
||||
import type { BaseResponse } from '@/types/base/response';
|
||||
import type {
|
||||
WorkflowDefinitionResponse,
|
||||
WorkflowDefinitionRequest,
|
||||
WorkflowDefinitionQuery,
|
||||
WorkflowInstanceResponse,
|
||||
WorkflowInstanceQuery,
|
||||
NodeInstanceResponse,
|
||||
WorkflowLogResponse,
|
||||
WorkflowDefinition
|
||||
} from './types';
|
||||
|
||||
const DEFINITION_URL = '/api/v1/workflow-definitions';
|
||||
const INSTANCE_URL = '/api/v1/workflow-instance';
|
||||
const NODE_URL = '/api/v1/node-instance';
|
||||
const LOG_URL = '/api/v1/workflow-logs';
|
||||
|
||||
// 工作流定义相关接口
|
||||
export const getDefinitions = (params?: WorkflowDefinitionQuery) =>
|
||||
request.get<Page<WorkflowDefinitionResponse>>(`${DEFINITION_URL}`, { params });
|
||||
|
||||
export const getDefinition = (id: number) =>
|
||||
request.get<WorkflowDefinitionResponse>(`${DEFINITION_URL}/${id}`);
|
||||
|
||||
export const createDefinition = (data: WorkflowDefinitionRequest) =>
|
||||
request.post<WorkflowDefinitionResponse>(DEFINITION_URL, data);
|
||||
|
||||
export const updateDefinition = (id: number, data: WorkflowDefinitionRequest) =>
|
||||
request.put<WorkflowDefinitionResponse>(`${DEFINITION_URL}/${id}`, data);
|
||||
|
||||
export const deleteDefinition = (id: number) =>
|
||||
request.delete(`${DEFINITION_URL}/${id}`);
|
||||
|
||||
export const publishDefinition = (id: number) =>
|
||||
request.post(`${DEFINITION_URL}/${id}/publish`);
|
||||
|
||||
export const disableDefinition = (id: number) =>
|
||||
request.post(`${DEFINITION_URL}/${id}/disable`);
|
||||
|
||||
export const enableDefinition = (id: number) =>
|
||||
request.post(`${DEFINITION_URL}/${id}/enable`);
|
||||
|
||||
// 工作流实例相关接口
|
||||
export const getInstances = (params?: WorkflowInstanceQuery) =>
|
||||
request.get<Page<WorkflowInstanceResponse>>(`${INSTANCE_URL}`, { params });
|
||||
|
||||
export const getInstance = (id: number) =>
|
||||
request.get<WorkflowInstanceResponse>(`${INSTANCE_URL}/${id}`);
|
||||
|
||||
export const createInstance = (definitionId: number, businessKey: string, variables?: Record<string, any>) =>
|
||||
request.post<WorkflowInstanceResponse>(INSTANCE_URL, { definitionId, businessKey, variables });
|
||||
|
||||
export const startInstance = (id: number) =>
|
||||
request.post(`${INSTANCE_URL}/${id}/start`);
|
||||
|
||||
export const cancelInstance = (id: number) =>
|
||||
request.post(`${INSTANCE_URL}/${id}/cancel`);
|
||||
|
||||
export const pauseInstance = (id: number) =>
|
||||
request.post(`${INSTANCE_URL}/${id}/pause`);
|
||||
|
||||
export const resumeInstance = (id: number) =>
|
||||
request.post(`${INSTANCE_URL}/${id}/resume`);
|
||||
|
||||
// 节点实例相关接口
|
||||
export const getNodeInstances = (workflowInstanceId: number) =>
|
||||
request.get<NodeInstanceResponse[]>(`${NODE_URL}/workflow/${workflowInstanceId}`);
|
||||
|
||||
export const getNodeInstancesByStatus = (workflowInstanceId: number, status: string) =>
|
||||
request.get<NodeInstanceResponse[]>(`${NODE_URL}/workflow/${workflowInstanceId}/status/${status}`);
|
||||
|
||||
export const updateNodeStatus = (id: number, status: string) =>
|
||||
request.put(`${NODE_URL}/${id}/status`, { status });
|
||||
|
||||
// 日志相关接口
|
||||
export const getWorkflowLogs = (workflowInstanceId: number) =>
|
||||
request.get<WorkflowLogResponse[]>(`${LOG_URL}/workflow/${workflowInstanceId}`);
|
||||
|
||||
export const getNodeLogs = (workflowInstanceId: number, nodeId: string) =>
|
||||
request.get<WorkflowLogResponse[]>(`${LOG_URL}/node/${workflowInstanceId}/${nodeId}`);
|
||||
|
||||
export const recordLog = (data: Omit<WorkflowLogResponse, keyof BaseResponse>) =>
|
||||
request.post<WorkflowLogResponse>(`${LOG_URL}/record`, data);
|
||||
|
||||
// 获取工作流定义列表
|
||||
export const getDefinitionList = (params: WorkflowDefinitionQuery) =>
|
||||
request.get<WorkflowDefinitionResponse[]>('/api/v1/workflow/definition', { params });
|
||||
|
||||
// 保存工作流定义
|
||||
export const saveDefinition = (data: WorkflowDefinition) => {
|
||||
if (data.id) {
|
||||
return request.put<WorkflowDefinitionResponse>(`/api/v1/workflow/definition/${data.id}`, data);
|
||||
}
|
||||
return request.post<WorkflowDefinitionResponse>('/api/v1/workflow/definition', data);
|
||||
};
|
||||
146
frontend/src/pages/Workflow/types.ts
Normal file
146
frontend/src/pages/Workflow/types.ts
Normal file
@ -0,0 +1,146 @@
|
||||
import { BaseResponse } from '@/types/base/response';
|
||||
import { BaseQuery } from '@/types/base/query';
|
||||
|
||||
// 工作流状态枚举
|
||||
export enum WorkflowStatus {
|
||||
DRAFT = 'DRAFT',
|
||||
PUBLISHED = 'PUBLISHED',
|
||||
DISABLED = 'DISABLED'
|
||||
}
|
||||
|
||||
// 节点类型枚举
|
||||
export enum NodeType {
|
||||
START = 'START',
|
||||
END = 'END',
|
||||
TASK = 'TASK',
|
||||
GATEWAY = 'GATEWAY',
|
||||
SUB_PROCESS = 'SUB_PROCESS',
|
||||
SHELL = 'SHELL'
|
||||
}
|
||||
|
||||
// 节点状态枚举
|
||||
export enum NodeStatus {
|
||||
PENDING = 'PENDING',
|
||||
RUNNING = 'RUNNING',
|
||||
COMPLETED = 'COMPLETED',
|
||||
FAILED = 'FAILED',
|
||||
CANCELLED = 'CANCELLED',
|
||||
PAUSED = 'PAUSED',
|
||||
SKIPPED = 'SKIPPED'
|
||||
}
|
||||
|
||||
// 工作流实例状态枚举
|
||||
export enum InstanceStatus {
|
||||
RUNNING = 'RUNNING',
|
||||
COMPLETED = 'COMPLETED',
|
||||
FAILED = 'FAILED',
|
||||
CANCELLED = 'CANCELLED',
|
||||
PAUSED = 'PAUSED'
|
||||
}
|
||||
|
||||
// 日志级别枚举
|
||||
export enum LogLevel {
|
||||
INFO = 'INFO',
|
||||
WARN = 'WARN',
|
||||
ERROR = 'ERROR'
|
||||
}
|
||||
|
||||
// 工作流定义基础接口
|
||||
export interface WorkflowDefinition {
|
||||
id?: number;
|
||||
name: string;
|
||||
code: string;
|
||||
description?: string;
|
||||
nodeConfig: string;
|
||||
transitionConfig: string;
|
||||
formDefinition: string;
|
||||
graphDefinition: string;
|
||||
enabled: boolean;
|
||||
remark?: string;
|
||||
status?: WorkflowStatus;
|
||||
createTime?: string;
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
// 工作流定义响应数据
|
||||
export interface WorkflowDefinitionResponse extends BaseResponse, Omit<WorkflowDefinition, 'id' | 'status' | 'createTime' | 'updateTime'> {
|
||||
id: number;
|
||||
status: WorkflowStatus;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
}
|
||||
|
||||
// 工作流定义查询参数
|
||||
export interface WorkflowDefinitionQuery extends BaseQuery {
|
||||
name?: string;
|
||||
code?: string;
|
||||
status?: WorkflowStatus;
|
||||
}
|
||||
|
||||
// 工作流定义请求数据
|
||||
export interface WorkflowDefinitionRequest {
|
||||
code: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
nodeConfig: string;
|
||||
transitionConfig: string;
|
||||
formDefinition: string;
|
||||
graphDefinition: string;
|
||||
enabled: boolean;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
// 节点定义响应数据
|
||||
export interface NodeDefinitionResponse extends BaseResponse {
|
||||
nodeId: string;
|
||||
name: string;
|
||||
type: NodeType;
|
||||
config: string;
|
||||
description?: string;
|
||||
workflowDefinitionId: number;
|
||||
orderNum: number;
|
||||
}
|
||||
|
||||
// 工作流实例查询参数
|
||||
export interface WorkflowInstanceQuery extends BaseQuery {
|
||||
definitionId?: number;
|
||||
status?: InstanceStatus;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
}
|
||||
|
||||
// 工作流实例响应数据
|
||||
export interface WorkflowInstanceResponse extends BaseResponse {
|
||||
definitionId: number;
|
||||
businessKey: string;
|
||||
status: InstanceStatus;
|
||||
startTime: string;
|
||||
endTime?: string;
|
||||
variables: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// 节点实例响应数据
|
||||
export interface NodeInstanceResponse extends BaseResponse {
|
||||
workflowInstanceId: number;
|
||||
nodeId: string;
|
||||
nodeType: NodeType;
|
||||
name: string;
|
||||
status: NodeStatus;
|
||||
startTime: string;
|
||||
endTime?: string;
|
||||
config: string;
|
||||
input: string;
|
||||
output: string;
|
||||
error?: string;
|
||||
preNodeId: string;
|
||||
}
|
||||
|
||||
// 工作流日志响应数据
|
||||
export interface WorkflowLogResponse extends BaseResponse {
|
||||
workflowInstanceId: number;
|
||||
nodeId: string;
|
||||
message: string;
|
||||
level: LogLevel;
|
||||
detail?: string;
|
||||
}
|
||||
@ -6,7 +6,7 @@ import BasicLayout from '../layouts/BasicLayout';
|
||||
import {useSelector} from 'react-redux';
|
||||
import {RootState} from '../store';
|
||||
|
||||
// 加载中组件
|
||||
// 加中组件
|
||||
const LoadingComponent = () => (
|
||||
<div style={{padding: 24, textAlign: 'center'}}>
|
||||
<Spin size="large"/>
|
||||
@ -32,9 +32,17 @@ const Menu = lazy(() => import('../pages/System/Menu'));
|
||||
const Department = lazy(() => import('../pages/System/Department'));
|
||||
const External = lazy(() => import('../pages/System/External'));
|
||||
const X6Test = lazy(() => import('../pages/X6Test'));
|
||||
const WorkflowDefinition = lazy(() => import('../pages/Workflow/Definition'));
|
||||
const WorkflowDefinitionEdit = lazy(() => import('../pages/Workflow/Definition/Edit'));
|
||||
const WorkflowInstance = lazy(() => import('../pages/Workflow/Instance'));
|
||||
const WorkflowMonitor = lazy(() => import('../pages/Workflow/Monitor'));
|
||||
|
||||
// 创建路由
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: '/login',
|
||||
element: <Login/>
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
element: (
|
||||
@ -109,14 +117,52 @@ const router = createBrowserRouter([
|
||||
)
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
element: <Navigate to="/dashboard"/>
|
||||
path: 'workflow',
|
||||
children: [
|
||||
{
|
||||
path: 'definition',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
element: (
|
||||
<Suspense fallback={<LoadingComponent/>}>
|
||||
<WorkflowDefinition/>
|
||||
</Suspense>
|
||||
)
|
||||
},
|
||||
{
|
||||
path: 'edit/:id?',
|
||||
element: (
|
||||
<Suspense fallback={<LoadingComponent/>}>
|
||||
<WorkflowDefinitionEdit/>
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
element: <Login/>
|
||||
path: 'instance',
|
||||
element: (
|
||||
<Suspense fallback={<LoadingComponent/>}>
|
||||
<WorkflowInstance/>
|
||||
</Suspense>
|
||||
)
|
||||
},
|
||||
{
|
||||
path: 'monitor',
|
||||
element: (
|
||||
<Suspense fallback={<LoadingComponent/>}>
|
||||
<WorkflowMonitor/>
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
element: <Navigate to="/dashboard"/>
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user