From 45e05fd9356f84b0aa7bb30b9ac6fbd5a6fa3650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=9A=E8=BE=B0=E5=85=88=E7=94=9F?= Date: Thu, 5 Dec 2024 12:31:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B7=A5=E4=BD=9C=E6=B5=81?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=8F=AF=E6=AD=A3=E5=B8=B8=E5=90=AF=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/docs/frontend-guide.md | 341 ++++++++++++++++-- .../backend/framework/enums/ResponseCode.java | 15 +- .../NodeInstanceApiController.java | 2 +- .../workflow/api/NodeTypeApiController.java | 48 +++ .../WorkflowDefinitionApiController.java | 2 +- .../WorkflowInstanceApiController.java | 2 +- .../WorkflowLogApiController.java | 2 +- .../workflow/api/dto/NodeInstanceDTO.java | 84 ----- .../workflow/converter/JsonConverter.java | 28 ++ .../converter/NodeInstanceConverter.java | 2 +- .../workflow/converter/NodeTypeConverter.java | 36 ++ .../converter/impl/DefaultJsonConverter.java | 50 +++ .../backend/workflow/dto/NodeInstanceDTO.java | 14 + .../backend/workflow/dto/NodeTypeDTO.java | 88 +++++ .../{api => dto}/query/NodeInstanceQuery.java | 2 +- .../workflow/dto/query/NodeTypeQuery.java | 34 ++ .../definition/TaskExecutorDefinition.java | 93 +++++ .../backend/workflow/entity/NodeType.java | 81 +++++ .../workflow/entity/WorkflowDefinition.java | 12 + .../backend/workflow/enums/NodeCategory.java | 38 ++ .../repository/INodeTypeRepository.java | 30 ++ .../service/INodeInstanceService.java | 2 +- .../workflow/service/INodeTypeService.java | 53 +++ .../service/impl/NodeInstanceServiceImpl.java | 2 +- .../service/impl/NodeTypeServiceImpl.java | 81 +++++ .../impl/WorkflowDefinitionServiceImpl.java | 33 +- .../db/migration/V1.0.0__init_schema.sql | 187 +++++----- .../db/migration/V1.0.1__init_data.sql | 99 ++++- .../src/main/resources/messages.properties | 15 +- .../main/resources/messages_en_US.properties | 9 +- 30 files changed, 1277 insertions(+), 208 deletions(-) rename backend/src/main/java/com/qqchen/deploy/backend/workflow/{controller => api}/NodeInstanceApiController.java (97%) create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/api/NodeTypeApiController.java rename backend/src/main/java/com/qqchen/deploy/backend/workflow/{controller => api}/WorkflowDefinitionApiController.java (97%) rename backend/src/main/java/com/qqchen/deploy/backend/workflow/{controller => api}/WorkflowInstanceApiController.java (98%) rename backend/src/main/java/com/qqchen/deploy/backend/workflow/{controller => api}/WorkflowLogApiController.java (98%) delete mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/api/dto/NodeInstanceDTO.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/JsonConverter.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/NodeTypeConverter.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/impl/DefaultJsonConverter.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/NodeTypeDTO.java rename backend/src/main/java/com/qqchen/deploy/backend/workflow/{api => dto}/query/NodeInstanceQuery.java (95%) create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/query/NodeTypeQuery.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/definition/TaskExecutorDefinition.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/NodeType.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/NodeCategory.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/INodeTypeRepository.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/service/INodeTypeService.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/NodeTypeServiceImpl.java diff --git a/backend/docs/frontend-guide.md b/backend/docs/frontend-guide.md index 60f753c8..3998c972 100644 --- a/backend/docs/frontend-guide.md +++ b/backend/docs/frontend-guide.md @@ -22,7 +22,8 @@ // 工作流定义相关接口 interface WorkflowDefinitionAPI { // 基础CRUD接口 - list: '/api/v1/workflow-definitions' // GET 查询列表 + page: '/api/v1/workflow-definitions/page' // GET 分页查询,支持条件筛选 + list: '/api/v1/workflow-definitions/list' // GET 查询所有(不分页) create: '/api/v1/workflow-definitions' // POST 创建 update: '/api/v1/workflow-definitions/{id}' // PUT 更新 delete: '/api/v1/workflow-definitions/{id}' // DELETE 删除 @@ -32,6 +33,31 @@ interface WorkflowDefinitionAPI { publish: '/api/v1/workflow-definitions/{id}/publish' // POST 发布 disable: '/api/v1/workflow-definitions/{id}/disable' // POST 禁用 enable: '/api/v1/workflow-definitions/{id}/enable' // POST 启用 + versions: '/api/v1/workflow-definitions/{code}/versions' // GET 查询所有版本(不分页) +} + +// 节点类型相关接口 +interface NodeTypeAPI { + // 查询接口 + list: '/api/v1/node-types' // GET 获取所有可用的节点类型列表(不分页) + getExecutors: '/api/v1/node-types/{type}/executors' // GET 获取指定节点类型支持的执行器列表 +} + +// 分页请求参数 +interface PageQuery { + pageNum: number // 页码,从1开始 + pageSize: number // 每页大小 + sortField?: string // 排序字段 + sortOrder?: 'ascend' | 'descend' // 排序方向 +} + +// 分页响应结构 +interface PageResponse { + records: T[] // 数据列表 + total: number // 总记录数 + pages: number // 总页数 + pageNum: number // 当前页码 + pageSize: number // 每页大小 } // 工作流定义数据结构 @@ -42,10 +68,10 @@ interface WorkflowDefinitionDTO { description: string // 描述 status: 'DRAFT' | 'PUBLISHED' | 'DISABLED' // 状态 version: number // 版本号 - nodeConfig: string // 节点配置(JSON) - transitionConfig: string // 流转配置(JSON) - formDefinition: string // 表单定义 - graphDefinition: string // 图形信息 + nodeConfig: string // 节点配置(JSON),包含节点的基本信息和执行配置 + transitionConfig: string // 流转配置(JSON),定义节点间的连接和条件 + formDefinition: string // 表单定义(JSON),定义工作流的表单字段和验证规则 + graphDefinition: string // 图形信息(JSON),定义节点的位置和连线的样式 enabled: boolean // 是否启用 remark: string // 备注 nodes: NodeDefinitionDTO[] // 节点定义列表 @@ -62,6 +88,173 @@ interface NodeDefinitionDTO { workflowDefinitionId: number // 工作流定义ID orderNum: number // 排序号 } + +// 节点配置示例 +interface NodeConfig { + startNode: { + type: 'START' + name: string + } + endNode: { + type: 'END' + name: string + } + taskNodes: Array<{ + id: string + type: 'TASK' + name: string + executor?: string // 执行器类型 + config?: any // 执行器配置 + }> +} + +// 流转配置示例 +interface TransitionConfig { + transitions: Array<{ + from: string // 源节点ID + to: string // 目标节点ID + condition?: string // 流转条件 + }> +} + +// 表单定义示例 +interface FormDefinition { + fields: Array<{ + name: string // 字段名 + label: string // 字段标签 + type: 'input' | 'select' | 'date' | 'number' // 字段类型 + required?: boolean // 是否必填 + options?: Array<{ // 选项(用于select类型) + label: string + value: any + }> + rules?: Array<{ // 验证规则 + type: string + message: string + }> + }> +} + +// 图形定义示例 +interface GraphDefinition { + nodes: Array<{ + id: string + type: string + x: number // 节点X坐标 + y: number // 节点Y坐标 + properties?: any // 节点属性 + }> + edges: Array<{ + source: string // 源节点ID + target: string // 目标节点ID + properties?: any // 连线属性 + }> +} + +// 节点类型数据结构 +interface NodeTypeDTO { + code: string // 节点类型编码 + name: string // 节点类型名称 + description: string // 节点类型描述 + category: 'BASIC' | 'TASK' | 'GATEWAY' | 'EVENT' // 节点类型分类 + icon: string // 节点图标 + color: string // 节点颜色 + executors?: Array<{ // 支持的执行器列表 + code: string // 执行器编码 + name: string // 执行器名称 + description: string // 执行器描述 + configSchema: any // 执行器配置模式 + }> + configSchema?: any // 节点配置模式 + defaultConfig?: any // 默认配置 +} + +// 节点类型示例数据 +const nodeTypes = [ + { + code: 'START', + name: '开始节点', + description: '工作流的开始节点', + category: 'BASIC', + icon: 'play-circle', + color: '#52c41a' + }, + { + code: 'END', + name: '结束节点', + description: '工作流的结束节点', + category: 'BASIC', + icon: 'stop', + color: '#ff4d4f' + }, + { + code: 'TASK', + name: '任务节点', + description: '执行具体任务的节点', + category: 'TASK', + icon: 'code', + color: '#1890ff', + executors: [ + { + code: 'SHELL', + name: 'Shell脚本', + description: '执行Shell脚本', + configSchema: { + type: 'object', + properties: { + script: { + type: 'string', + title: '脚本内容', + format: 'shell' + }, + timeout: { + type: 'number', + title: '超时时间(秒)', + default: 300 + } + } + } + }, + { + code: 'JENKINS', + name: 'Jenkins任务', + description: '触发Jenkins构建任务', + configSchema: { + type: 'object', + properties: { + job: { + type: 'string', + title: 'Job名称' + }, + parameters: { + type: 'object', + title: '构建参数' + } + } + } + } + ] + }, + { + code: 'GATEWAY', + name: '网关节点', + description: '控制流程流转的节点', + category: 'GATEWAY', + icon: 'fork', + color: '#faad14', + configSchema: { + type: 'object', + properties: { + type: { + type: 'string', + title: '网关类型', + enum: ['PARALLEL', 'EXCLUSIVE', 'INCLUSIVE'], + enumNames: ['并行网关', '排他网关', '包容网关'] + } + } + } + } +]; ``` ### 2.2 工作流实例管理 @@ -69,7 +262,8 @@ interface NodeDefinitionDTO { // 工作流实例相关接口 interface WorkflowInstanceAPI { // 基础CRUD接口 - list: '/api/v1/workflow-instance' // GET 查询列表 + page: '/api/v1/workflow-instance/page' // GET 分页查询,支持条件筛选 + list: '/api/v1/workflow-instance/list' // GET 查询所有(不分页) get: '/api/v1/workflow-instance/{id}' // GET 获取详情 // 实例操作接口 @@ -98,10 +292,11 @@ interface WorkflowInstanceDTO { // 节点实例相关接口 interface NodeInstanceAPI { // 查询接口 - list: '/api/v1/node-instance' // GET 查询列表 + page: '/api/v1/node-instance/page' // GET 分页查询,支持条件筛选 + list: '/api/v1/node-instance/list' // 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 查询指定状态的节点 + 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 更新状态 @@ -130,12 +325,13 @@ interface NodeInstanceDTO { // 日志相关接口 interface WorkflowLogAPI { // 基础CRUD接口 - list: '/api/v1/workflow-logs' // GET 查询列表 + page: '/api/v1/workflow-logs/page' // GET 分页查询,支持条件筛选 + list: '/api/v1/workflow-logs/list' // GET 查询所有(不分页) create: '/api/v1/workflow-logs' // POST 创建 // 特殊查询接口 - getWorkflowLogs: '/api/v1/workflow-logs/workflow/{workflowInstanceId}' // GET 查询工作流日志 - getNodeLogs: '/api/v1/workflow-logs/node/{workflowInstanceId}/{nodeId}' // GET 查询节点日志 + getWorkflowLogs: '/api/v1/workflow-logs/workflow/{workflowInstanceId}' // GET 查询工作流日志(不分页) + getNodeLogs: '/api/v1/workflow-logs/node/{workflowInstanceId}/{nodeId}' // GET 查询节点日志(不分页) record: '/api/v1/workflow-logs/record' // POST 记录日志 } @@ -179,19 +375,38 @@ interface WorkflowLogDTO { - 描述 - 备注 2. 流程设计器 - - 节点拖拽 - - 连线绘制 - - 节点配置 + - 节点拖拽和布局 + - 连线绘制和调整 + - 节点配置(nodeConfig) + - 基本信息配置 + - 执行器类型选择 + - 执行器参数配置 + - 流转配置(transitionConfig) + - 连线条件配置 + - 优先级设置 + - 条件表达式编辑 - 流程校验 - 3. 表单设计器 + 3. 表单设计器(formDefinition) - 表单字段配置 + - 字段类型选择 + - 字段属性设置 + - 选项配置(针对select类型) - 字段验证规则 + - 必填验证 + - 格式验证 + - 自定义验证 + - 表单布局设计 - 表单预览 - 4. 节点配置面板 - - 节点基本信息 - - 节点类型配置 - - 执行条件配置 - - 表单关联配置 + 4. 图形布局(graphDefinition) + - 节点位置调整 + - 连线样式设置 + - 自动布局 + - 缩放和居中 + 5. 版本管理 + - 版本历史查看 + - 版本对比 + - 版本回滚 + - 创建新版本 ### 3.2 工作流实例管理(/workflow/instance) @@ -247,6 +462,90 @@ interface WorkflowLogDTO { - 异常趋势图 - 异常节点TOP5 +### 3.4 节点类型管理(/workflow/node-type) + +#### 3.4.1 列表页(/workflow/node-type/list) +- 功能点: + - 节点类型列表展示 + - 支持按编码、名称、分类搜索 + - 支持创建、编辑、删除操作 + - 支持启用、禁用操作 +- 列表字段: + - 节点类型编码 + - 节点类型名称 + - 分类 + - 图标 + - 状态 + - 创建时间 + - 更新时间 + - 操作按钮 + +#### 3.4.2 编辑页(/workflow/node-type/edit) +- 功能点: + 1. 基本信息编辑 + - 节点类型编码 + - 节点类型名称 + - 描述 + - 分类 + - 图标 + - 颜色 + 2. 执行器配置 + - 执行器列表管理 + - 添加/删除执行器 + - 配置执行器参数 + - 执行器配置模式定义 + - JSON Schema编辑器 + - 配置项验证规则 + 3. 节点配置 + - 配置模式定义 + - 默认配置设置 + - 配置预览 + +### 3.5 组件升级 +1. NodeTypePanel(节点类型面板) + ```typescript + interface NodeTypePanelProps { + value?: NodeTypeDTO // 节点类型数据 + onChange?: (value: NodeTypeDTO) => void // 数据变更回调 + readOnly?: boolean // 是否只读 + } + ``` + +2. ExecutorConfig(执行器配置) + ```typescript + interface ExecutorConfigProps { + executors: Array<{ + code: string + name: string + description: string + configSchema: any + }> // 执行器列表 + onChange?: (executors: any[]) => void // 配置变更回调 + } + ``` + +3. SchemaEditor(配置模式编辑器) + ```typescript + interface SchemaEditorProps { + value?: any // 配置模式数据 + onChange?: (value: any) => void // 数据变更回调 + onValidate?: (errors: any[]) => void // 验证回调 + } + ``` + +### 3.6 开发计划调整 +1. 节点类型管理开发(3天) + - 实现节点类型CRUD接口 + - 开发节点类型列表页面 + - 开发节点类型编辑页面 + - 实现执行器配置功能 + - 实现配置模式编辑器 + +2. 流程设计器升级(2天) + - 改造节点面板,支持从节点类型创建节点 + - 实现节点配置面板,支持动态表单 + - 添加执行器选择功能 + ## 四、开发规范 ### 4.1 项目结构 diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java index 5fce0eff..67305dc5 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java @@ -123,7 +123,20 @@ public enum ResponseCode { WORKFLOW_CONCURRENT_LIMIT_EXCEEDED(2753, "workflow.concurrent.limit.exceeded"), WORKFLOW_CONFIG_INVALID(2754, "workflow.config.invalid"), WORKFLOW_TRANSITION_INVALID(2755, "workflow.transition.invalid"), - WORKFLOW_CONDITION_INVALID(2756, "workflow.condition.invalid"); + WORKFLOW_CONDITION_INVALID(2756, "workflow.condition.invalid"), + + // 工作流配置相关错误码 (2760-2769) + WORKFLOW_NODE_CONFIG_EMPTY(2760, "workflow.node.config.empty"), + WORKFLOW_TRANSITION_CONFIG_EMPTY(2761, "workflow.transition.config.empty"), + WORKFLOW_FORM_CONFIG_EMPTY(2762, "workflow.form.config.empty"), + WORKFLOW_GRAPH_CONFIG_EMPTY(2763, "workflow.graph.config.empty"), + + // 2200-2299 工作流节点类型错误 + WORKFLOW_NODE_TYPE_NOT_FOUND(2200, "workflow.node.type.not.found"), + WORKFLOW_NODE_TYPE_DISABLED(2201, "workflow.node.type.disabled"), + WORKFLOW_NODE_TYPE_CODE_EXISTS(2202, "workflow.node.type.code.exists"), + WORKFLOW_NODE_TYPE_INVALID_CATEGORY(2203, "workflow.node.type.invalid.category"), + WORKFLOW_NODE_TYPE_INVALID_EXECUTOR(2204, "workflow.node.type.invalid.executor"); private final int code; private final String messageKey; // 国际化消息key diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/NodeInstanceApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/NodeInstanceApiController.java similarity index 97% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/NodeInstanceApiController.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/api/NodeInstanceApiController.java index d43aaed0..4baa88bb 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/NodeInstanceApiController.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/NodeInstanceApiController.java @@ -1,4 +1,4 @@ -package com.qqchen.deploy.backend.workflow.controller; +package com.qqchen.deploy.backend.workflow.api; import com.qqchen.deploy.backend.framework.api.Response; import com.qqchen.deploy.backend.framework.controller.BaseController; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/NodeTypeApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/NodeTypeApiController.java new file mode 100644 index 00000000..c6a8d559 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/NodeTypeApiController.java @@ -0,0 +1,48 @@ +package com.qqchen.deploy.backend.workflow.api; + +import com.qqchen.deploy.backend.framework.api.Response; +import com.qqchen.deploy.backend.framework.controller.BaseController; +import com.qqchen.deploy.backend.workflow.dto.NodeTypeDTO; +import com.qqchen.deploy.backend.workflow.dto.query.NodeTypeQuery; +import com.qqchen.deploy.backend.workflow.engine.definition.TaskExecutorDefinition; +import com.qqchen.deploy.backend.workflow.entity.NodeType; +import com.qqchen.deploy.backend.workflow.service.INodeTypeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 节点类型接口 + */ +@Slf4j +@Tag(name = "节点类型管理", description = "节点类型相关接口") +@RestController +@RequestMapping("/api/v1/node-type") +public class NodeTypeApiController extends BaseController { + + @Resource + private INodeTypeService nodeTypeService; + + @Operation(summary = "获取指定节点类型支持的执行器列表") + @GetMapping("/{type}/executors") + public Response> getExecutors( + @Parameter(description = "节点类型", required = true) @PathVariable String type + ) { + log.debug("获取节点类型[{}]支持的执行器列表", type); + return Response.success(nodeTypeService.getExecutors(type)); + } + + @Override + protected void exportData(HttpServletResponse response, List data) { + + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/WorkflowDefinitionApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/WorkflowDefinitionApiController.java similarity index 97% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/WorkflowDefinitionApiController.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/api/WorkflowDefinitionApiController.java index 4cadabd6..6a4101a5 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/WorkflowDefinitionApiController.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/WorkflowDefinitionApiController.java @@ -1,4 +1,4 @@ -package com.qqchen.deploy.backend.workflow.controller; +package com.qqchen.deploy.backend.workflow.api; import com.qqchen.deploy.backend.framework.api.Response; import com.qqchen.deploy.backend.framework.controller.BaseController; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/WorkflowInstanceApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/WorkflowInstanceApiController.java similarity index 98% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/WorkflowInstanceApiController.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/api/WorkflowInstanceApiController.java index 22323005..0468ac25 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/WorkflowInstanceApiController.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/WorkflowInstanceApiController.java @@ -1,4 +1,4 @@ -package com.qqchen.deploy.backend.workflow.controller; +package com.qqchen.deploy.backend.workflow.api; import com.qqchen.deploy.backend.framework.api.Response; import com.qqchen.deploy.backend.framework.controller.BaseController; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/WorkflowLogApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/WorkflowLogApiController.java similarity index 98% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/WorkflowLogApiController.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/api/WorkflowLogApiController.java index 58829241..c05e822c 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/controller/WorkflowLogApiController.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/WorkflowLogApiController.java @@ -1,4 +1,4 @@ -package com.qqchen.deploy.backend.workflow.controller; +package com.qqchen.deploy.backend.workflow.api; import com.qqchen.deploy.backend.enums.LogLevelEnum; import com.qqchen.deploy.backend.framework.api.Response; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/dto/NodeInstanceDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/dto/NodeInstanceDTO.java deleted file mode 100644 index 6cfe9839..00000000 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/dto/NodeInstanceDTO.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.qqchen.deploy.backend.workflow.api.dto; - -import com.qqchen.deploy.backend.framework.dto.BaseDTO; -import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum; -import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.time.LocalDateTime; - -/** - * 节点实例DTO - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class NodeInstanceDTO extends BaseDTO { - - /** - * 工作流实例ID - */ - @NotNull(message = "工作流实例ID不能为空") - private Long workflowInstanceId; - - /** - * 节点ID - */ - @NotBlank(message = "节点ID不能为空") - private String nodeId; - - /** - * 节点类型 - */ - @NotNull(message = "节点类型不能为空") - private NodeTypeEnum nodeType; - - /** - * 节点名称 - */ - @NotBlank(message = "节点名称不能为空") - private String name; - - /** - * 节点状态 - */ - @NotNull(message = "节点状态不能为空") - private NodeStatusEnum status; - - /** - * 开始时间 - */ - private LocalDateTime startTime; - - /** - * 结束时间 - */ - private LocalDateTime endTime; - - /** - * 节点配置(JSON) - */ - private String config; - - /** - * 输入参数(JSON) - */ - private String input; - - /** - * 输出结果(JSON) - */ - private String output; - - /** - * 错误信息 - */ - private String error; - - /** - * 前置节点ID - */ - private String preNodeId; -} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/JsonConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/JsonConverter.java new file mode 100644 index 00000000..12f8fed4 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/JsonConverter.java @@ -0,0 +1,28 @@ +package com.qqchen.deploy.backend.workflow.converter; + +import com.qqchen.deploy.backend.workflow.engine.definition.TaskExecutorDefinition; + +import java.util.List; + +/** + * JSON转换器接口 + * 用于处理系统中的JSON序列化和反序列化 + */ +public interface JsonConverter { + + /** + * 将JSON字符串转换为执行器定义列表 + * + * @param json JSON字符串 + * @return 执行器定义列表 + */ + List toExecutorList(String json); + + /** + * 将执行器定义列表转换为JSON字符串 + * + * @param executors 执行器定义列表 + * @return JSON字符串 + */ + String fromExecutorList(List executors); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/NodeInstanceConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/NodeInstanceConverter.java index 708875b0..52dd9f63 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/NodeInstanceConverter.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/NodeInstanceConverter.java @@ -1,7 +1,7 @@ package com.qqchen.deploy.backend.workflow.converter; import com.qqchen.deploy.backend.framework.converter.BaseConverter; -import com.qqchen.deploy.backend.workflow.api.dto.NodeInstanceDTO; +import com.qqchen.deploy.backend.workflow.dto.NodeInstanceDTO; import com.qqchen.deploy.backend.workflow.entity.NodeInstance; import org.mapstruct.Mapper; import org.mapstruct.Mapping; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/NodeTypeConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/NodeTypeConverter.java new file mode 100644 index 00000000..bd5f313e --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/NodeTypeConverter.java @@ -0,0 +1,36 @@ +package com.qqchen.deploy.backend.workflow.converter; + +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import com.qqchen.deploy.backend.workflow.dto.NodeTypeDTO; +import com.qqchen.deploy.backend.workflow.entity.NodeType; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * 节点类型转换器 + */ +@Mapper(config = BaseConverter.class, componentModel = "spring", uses = {JsonConverter.class}) +public abstract class NodeTypeConverter implements BaseConverter { + + @Autowired + protected JsonConverter jsonConverter; + + @Override + @Mapping(target = "executors", expression = "java(jsonConverter.toExecutorList(entity.getExecutors()))") + public abstract NodeTypeDTO toDto(NodeType entity); + + @Override + @Mapping(target = "executors", expression = "java(jsonConverter.fromExecutorList(dto.getExecutors()))") + public abstract NodeType toEntity(NodeTypeDTO dto); + + @Override + public void updateEntity(NodeType entity, NodeTypeDTO dto) { + // 使用MapStruct生成的更新方法 + updateEntityInternal(entity, dto); + } + + @Mapping(target = "executors", expression = "java(jsonConverter.fromExecutorList(dto.getExecutors()))") + protected abstract void updateEntityInternal(@MappingTarget NodeType entity, NodeTypeDTO dto); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/impl/DefaultJsonConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/impl/DefaultJsonConverter.java new file mode 100644 index 00000000..4b0ab528 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/converter/impl/DefaultJsonConverter.java @@ -0,0 +1,50 @@ +package com.qqchen.deploy.backend.workflow.converter.impl; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.qqchen.deploy.backend.framework.exception.SystemException; +import com.qqchen.deploy.backend.workflow.converter.JsonConverter; +import com.qqchen.deploy.backend.workflow.engine.definition.TaskExecutorDefinition; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * JSON转换器默认实现 + * 使用Jackson进行JSON序列化和反序列化 + */ +@Component +public class DefaultJsonConverter implements JsonConverter { + + private final ObjectMapper objectMapper; + + public DefaultJsonConverter(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @Override + public List toExecutorList(String json) { + if (json == null || json.isEmpty()) { + return new ArrayList<>(); + } + try { + return objectMapper.readValue(json, new TypeReference>() {}); + } catch (JsonProcessingException e) { + throw new SystemException("Failed to parse executors JSON: " + e.getMessage(), e); + } + } + + @Override + public String fromExecutorList(List executors) { + if (executors == null || executors.isEmpty()) { + return "[]"; + } + try { + return objectMapper.writeValueAsString(executors); + } catch (JsonProcessingException e) { + throw new SystemException("Failed to serialize executors: " + e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/NodeInstanceDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/NodeInstanceDTO.java index 281366f5..c03df50c 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/NodeInstanceDTO.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/NodeInstanceDTO.java @@ -10,6 +10,19 @@ import lombok.EqualsAndHashCode; import java.time.LocalDateTime; +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum; +import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 节点实例DTO + */ @Data @EqualsAndHashCode(callSuper = true) public class NodeInstanceDTO extends BaseDTO { @@ -41,6 +54,7 @@ public class NodeInstanceDTO extends BaseDTO { /** * 节点状态 */ + @NotNull(message = "节点状态不能为空") private NodeStatusEnum status; /** diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/NodeTypeDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/NodeTypeDTO.java new file mode 100644 index 00000000..b76ca169 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/NodeTypeDTO.java @@ -0,0 +1,88 @@ +package com.qqchen.deploy.backend.workflow.dto; + +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import com.qqchen.deploy.backend.workflow.engine.definition.TaskExecutorDefinition; +import com.qqchen.deploy.backend.workflow.enums.NodeCategory; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 节点类型DTO + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class NodeTypeDTO extends BaseDTO { + + /** + * 节点类型编码 + */ + @NotBlank(message = "节点类型编码不能为空") + private String code; + + /** + * 节点类型名称 + */ + @NotBlank(message = "节点类型名称不能为空") + private String name; + + /** + * 节点类型描述 + */ + private String description; + + /** + * 节点类型分类 + */ + @NotNull(message = "节点类型分类不能为空") + private NodeCategory category; + + /** + * 节点图标 + */ + private String icon; + + /** + * 节点颜色 + */ + private String color; + + /** + * 任务执行器定义列表 + * 定义该节点类型支持的所有任务执行器 + * 说明: + * 1. 只有TASK类型的节点才需要配置执行器 + * 2. 一个任务节点可以支持多种执行器 + * 3. 每种执行器都有自己的配置模式 + */ + @Valid + private List executors; + + /** + * 节点配置模式(JSON) + * 使用JSON Schema格式定义节点的配置结构 + * 说明: + * 1. 基础配置:所有类型节点都需要的配置(如节点名称、描述等) + * 2. 分类配置:不同分类节点特有的配置 + * - TASK:任务节点配置(如执行器选择、重试策略等) + * - GATEWAY:网关节点配置(如条件表达式、分支策略等) + * - EVENT:事件节点配置(如事件类型、触发条件等) + */ + private String configSchema; + + /** + * 默认配置(JSON) + * 符合configSchema定义的默认配置值 + */ + private String defaultConfig; + + /** + * 是否启用 + */ + @NotNull(message = "是否启用不能为空") + private Boolean enabled = true; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/query/NodeInstanceQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/query/NodeInstanceQuery.java similarity index 95% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/api/query/NodeInstanceQuery.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/query/NodeInstanceQuery.java index e7d53804..9bd9a6a5 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/api/query/NodeInstanceQuery.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/query/NodeInstanceQuery.java @@ -1,4 +1,4 @@ -package com.qqchen.deploy.backend.workflow.api.query; +package com.qqchen.deploy.backend.workflow.dto.query; import com.qqchen.deploy.backend.framework.annotation.QueryField; import com.qqchen.deploy.backend.framework.enums.QueryType; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/query/NodeTypeQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/query/NodeTypeQuery.java new file mode 100644 index 00000000..fd22c266 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/query/NodeTypeQuery.java @@ -0,0 +1,34 @@ +package com.qqchen.deploy.backend.workflow.dto.query; + +import com.qqchen.deploy.backend.framework.annotation.QueryField; +import com.qqchen.deploy.backend.framework.enums.QueryType; +import com.qqchen.deploy.backend.framework.query.BaseQuery; +import com.qqchen.deploy.backend.workflow.enums.NodeCategory; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 节点类型查询对象 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class NodeTypeQuery extends BaseQuery { + + /** + * 节点类型编码 + */ + @QueryField(field = "code", type = QueryType.LIKE) + private String code; + + /** + * 节点类型名称 + */ + @QueryField(field = "name", type = QueryType.LIKE) + private String name; + + /** + * 节点类型分类 + */ + @QueryField(field = "category") + private NodeCategory category; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/definition/TaskExecutorDefinition.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/definition/TaskExecutorDefinition.java new file mode 100644 index 00000000..c9f7bbbe --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/definition/TaskExecutorDefinition.java @@ -0,0 +1,93 @@ +package com.qqchen.deploy.backend.workflow.engine.definition; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +/** + * 任务执行器定义 + * 用于定义工作流节点支持的任务执行器类型及其配置结构 + * 主要用于: + * 1. 节点类型配置:定义节点类型支持哪些执行器 + * 2. 流程设计:前端根据执行器定义动态渲染配置表单 + * 3. 执行引擎:根据执行器定义验证和执行任务 + */ +@Data +public class TaskExecutorDefinition { + + /** + * 执行器编码 + * 用于标识执行器类型,需要与具体的执行器实现类对应 + * 例如: + * - SHELL:对应ShellTaskExecutor + * - JENKINS:对应JenkinsTaskExecutor + * - HTTP:对应HttpTaskExecutor + */ + @NotBlank(message = "执行器编码不能为空") + private String code; + + /** + * 执行器名称 + * 用于前端展示,应该是用户友好的名称 + * 例如: + * - Shell脚本执行器 + * - Jenkins构建执行器 + * - HTTP接口调用执行器 + */ + @NotBlank(message = "执行器名称不能为空") + private String name; + + /** + * 执行器描述 + * 详细说明执行器的: + * 1. 主要功能和使用场景 + * 2. 配置参数说明 + * 3. 注意事项和限制条件 + */ + private String description; + + /** + * 执行器配置模式 + * 使用JSON Schema格式定义执行器的配置结构 + * 用于: + * 1. 前端动态渲染配置表单 + * 2. 后端验证配置参数 + * + * 示例 - Shell执行器配置模式: + * { + * "type": "object", + * "required": ["script"], + * "properties": { + * "script": { + * "type": "string", + * "title": "脚本内容", + * "format": "shell", + * "description": "需要执行的Shell脚本内容" + * }, + * "timeout": { + * "type": "number", + * "title": "超时时间", + * "description": "脚本执行的最大时间(秒)", + * "minimum": 1, + * "maximum": 3600, + * "default": 300 + * }, + * "workingDir": { + * "type": "string", + * "title": "工作目录", + * "description": "脚本执行的工作目录", + * "default": "/tmp" + * } + * } + * } + */ + private String configSchema; + + /** + * 默认配置 + * 符合configSchema定义的默认配置值 + * 用于: + * 1. 新建节点时的默认值 + * 2. 重置配置时的参考值 + */ + private String defaultConfig; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/NodeType.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/NodeType.java new file mode 100644 index 00000000..c2e80cc0 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/NodeType.java @@ -0,0 +1,81 @@ +package com.qqchen.deploy.backend.workflow.entity; + +import com.qqchen.deploy.backend.framework.annotation.LogicDelete; +import com.qqchen.deploy.backend.framework.domain.Entity; +import com.qqchen.deploy.backend.workflow.enums.NodeCategory; +import jakarta.persistence.Column; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 节点类型实体 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@jakarta.persistence.Entity +@Table(name = "wf_node_type") +@LogicDelete +public class NodeType extends Entity { + + /** + * 节点类型编码 + */ + @Column(nullable = false, unique = true) + private String code; + + /** + * 节点类型名称 + */ + @Column(nullable = false) + private String name; + + /** + * 节点类型描述 + */ + @Column(columnDefinition = "TEXT") + private String description; + + /** + * 节点类型分类 + */ + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private NodeCategory category; + + /** + * 节点图标 + */ + private String icon; + + /** + * 节点颜色 + */ + private String color; + + /** + * 执行器列表(JSON) + */ + @Column(name = "executors", columnDefinition = "TEXT") + private String executors; + + /** + * 节点配置模式(JSON) + */ + @Column(name = "config_schema", columnDefinition = "TEXT") + private String configSchema; + + /** + * 默认配置(JSON) + */ + @Column(name = "default_config", columnDefinition = "TEXT") + private String defaultConfig; + + /** + * 是否启用 + */ + @Column(nullable = false) + private Boolean enabled = true; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowDefinition.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowDefinition.java index b231d67b..db9c3526 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowDefinition.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowDefinition.java @@ -63,6 +63,18 @@ public class WorkflowDefinition extends Entity { @Column(name = "transition_config", columnDefinition = "TEXT") private String transitionConfig; + /** + * 表单定义(JSON) + */ + @Column(name = "form_definition", columnDefinition = "TEXT") + private String formDefinition; + + /** + * 图形信息(JSON) + */ + @Column(name = "graph_definition", columnDefinition = "TEXT") + private String graphDefinition; + /** * 节点定义列表 */ diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/NodeCategory.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/NodeCategory.java new file mode 100644 index 00000000..bc0d4e17 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/enums/NodeCategory.java @@ -0,0 +1,38 @@ +package com.qqchen.deploy.backend.workflow.enums; + +import lombok.Getter; + +/** + * 节点分类枚举 + */ +@Getter +public enum NodeCategory { + /** + * 基础节点(如开始、结束节点) + */ + BASIC("基础节点"), + + /** + * 任务节点(如Shell、Jenkins等执行器节点) + */ + TASK("任务节点"), + + /** + * 网关节点(如并行、排他、包容网关) + */ + GATEWAY("网关节点"), + + /** + * 事件节点(如定时器、消息等事件) + */ + EVENT("事件节点"); + + /** + * 分类名称 + */ + private final String name; + + NodeCategory(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/INodeTypeRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/INodeTypeRepository.java new file mode 100644 index 00000000..1749ae58 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/INodeTypeRepository.java @@ -0,0 +1,30 @@ +package com.qqchen.deploy.backend.workflow.repository; + +import com.qqchen.deploy.backend.framework.repository.IBaseRepository; +import com.qqchen.deploy.backend.workflow.entity.NodeType; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +/** + * 节点类型仓库接口 + */ +@Repository +public interface INodeTypeRepository extends IBaseRepository { + + /** + * 根据编码查询未删除的节点类型 + * + * @param code 节点类型编码 + * @return 节点类型 + */ + Optional findByCodeAndDeletedFalse(String code); + + /** + * 检查编码是否已存在(排除已删除的) + * + * @param code 节点类型编码 + * @return 是否存在 + */ + boolean existsByCodeAndDeletedFalse(String code); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/INodeInstanceService.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/INodeInstanceService.java index a52ed888..b50109da 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/INodeInstanceService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/INodeInstanceService.java @@ -1,7 +1,7 @@ package com.qqchen.deploy.backend.workflow.service; import com.qqchen.deploy.backend.framework.service.IBaseService; -import com.qqchen.deploy.backend.workflow.api.dto.NodeInstanceDTO; +import com.qqchen.deploy.backend.workflow.dto.NodeInstanceDTO; import com.qqchen.deploy.backend.workflow.entity.NodeInstance; import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/INodeTypeService.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/INodeTypeService.java new file mode 100644 index 00000000..c2e1b9af --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/INodeTypeService.java @@ -0,0 +1,53 @@ +package com.qqchen.deploy.backend.workflow.service; + +import com.qqchen.deploy.backend.framework.service.IBaseService; +import com.qqchen.deploy.backend.workflow.dto.NodeTypeDTO; +import com.qqchen.deploy.backend.workflow.engine.definition.TaskExecutorDefinition; +import com.qqchen.deploy.backend.workflow.entity.NodeType; + +import java.util.List; + +/** + * 节点类型服务接口 + */ +public interface INodeTypeService extends IBaseService { + + /** + * 根据编码查询节点类型 + * + * @param code 节点类型编码 + * @return 节点类型 + */ + NodeTypeDTO findByCode(String code); + + /** + * 获取指定节点类型支持的执行器列表 + * 说明: + * 1. 只有TASK类型的节点才有执行器列表 + * 2. 一个任务节点可以支持多种执行器 + * 3. 每个执行器都有自己的配置模式 + * + * 使用场景: + * 1. 流程设计时,选择节点类型后,需要展示该节点支持的执行器列表 + * 2. 根据选择的执行器,动态渲染配置表单 + * 3. 保存节点配置时,验证执行器参数是否符合配置模式 + * + * @param code 节点类型编码 + * @return 执行器列表 + */ + List getExecutors(String code); + + /** + * 启用节点类型 + * + * @param id 节点类型ID + */ + void enable(Long id); + + /** + * 禁用节点类型 + * + * @param id 节点类型ID + */ + void disable(Long id); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/NodeInstanceServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/NodeInstanceServiceImpl.java index 273de477..32686c0f 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/NodeInstanceServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/NodeInstanceServiceImpl.java @@ -3,8 +3,8 @@ package com.qqchen.deploy.backend.workflow.service.impl; import com.qqchen.deploy.backend.framework.enums.ResponseCode; import com.qqchen.deploy.backend.framework.exception.BusinessException; import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; -import com.qqchen.deploy.backend.workflow.api.dto.NodeInstanceDTO; import com.qqchen.deploy.backend.workflow.converter.NodeInstanceConverter; +import com.qqchen.deploy.backend.workflow.dto.NodeInstanceDTO; import com.qqchen.deploy.backend.workflow.entity.NodeInstance; import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum; import com.qqchen.deploy.backend.workflow.repository.INodeInstanceRepository; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/NodeTypeServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/NodeTypeServiceImpl.java new file mode 100644 index 00000000..e6797708 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/NodeTypeServiceImpl.java @@ -0,0 +1,81 @@ +package com.qqchen.deploy.backend.workflow.service.impl; + +import com.qqchen.deploy.backend.framework.enums.ResponseCode; +import com.qqchen.deploy.backend.framework.exception.BusinessException; +import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; +import com.qqchen.deploy.backend.workflow.converter.JsonConverter; +import com.qqchen.deploy.backend.workflow.converter.NodeTypeConverter; +import com.qqchen.deploy.backend.workflow.dto.NodeTypeDTO; +import com.qqchen.deploy.backend.workflow.engine.definition.TaskExecutorDefinition; +import com.qqchen.deploy.backend.workflow.entity.NodeType; +import com.qqchen.deploy.backend.workflow.enums.NodeCategory; +import com.qqchen.deploy.backend.workflow.repository.INodeTypeRepository; +import com.qqchen.deploy.backend.workflow.service.INodeTypeService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; +import java.util.List; + +/** + * 节点类型服务实现类 + */ +@Service +public class NodeTypeServiceImpl extends BaseServiceImpl implements INodeTypeService { + + @Resource + private INodeTypeRepository nodeTypeRepository; + + @Resource + private NodeTypeConverter nodeTypeConverter; + + @Resource + private JsonConverter jsonConverter; + + @Override + public NodeTypeDTO findByCode(String code) { + return nodeTypeRepository.findByCodeAndDeletedFalse(code) + .map(nodeTypeConverter::toDto) + .orElseThrow(() -> new BusinessException(ResponseCode.WORKFLOW_NODE_TYPE_NOT_FOUND)); + } + + @Override + public List getExecutors(String code) { + // 1. 查询节点类型 + NodeType nodeType = nodeTypeRepository.findByCodeAndDeletedFalse(code) + .orElseThrow(() -> new BusinessException(ResponseCode.WORKFLOW_NODE_TYPE_NOT_FOUND)); + + // 2. 检查节点类型是否为任务节点 + if (!NodeCategory.TASK.equals(nodeType.getCategory())) { + // 非任务节点没有执行器列表 + return Collections.emptyList(); + } + + // 3. 检查节点类型是否启用 + if (!nodeType.getEnabled()) { + throw new BusinessException(ResponseCode.WORKFLOW_NODE_TYPE_DISABLED); + } + + // 4. 将JSON字符串转换为执行器列表 + return jsonConverter.toExecutorList(nodeType.getExecutors()); + } + + @Override + @Transactional + public void enable(Long id) { + NodeType nodeType = nodeTypeRepository.findById(id) + .orElseThrow(() -> new BusinessException(ResponseCode.WORKFLOW_NODE_TYPE_NOT_FOUND)); + nodeType.setEnabled(true); + nodeTypeRepository.save(nodeType); + } + + @Override + @Transactional + public void disable(Long id) { + NodeType nodeType = nodeTypeRepository.findById(id) + .orElseThrow(() -> new BusinessException(ResponseCode.WORKFLOW_NODE_TYPE_NOT_FOUND)); + nodeType.setEnabled(false); + nodeTypeRepository.save(nodeType); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowDefinitionServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowDefinitionServiceImpl.java index 614a80dd..208b8d64 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowDefinitionServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowDefinitionServiceImpl.java @@ -77,6 +77,9 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl new BusinessException(ResponseCode.WORKFLOW_NOT_FOUND)); + // 1. 验证节点配置的完整性 - // 2. 验证节点之间的连接关系 + if (definition.getNodeConfig() == null || definition.getNodeConfig().isEmpty()) { + throw new BusinessException(ResponseCode.WORKFLOW_NODE_CONFIG_EMPTY); + } + + // 2. 验证流转配置的完整性 + if (definition.getTransitionConfig() == null || definition.getTransitionConfig().isEmpty()) { + throw new BusinessException(ResponseCode.WORKFLOW_TRANSITION_CONFIG_EMPTY); + } + + // 3. 验证表单定义的完整性 + if (definition.getFormDefinition() == null || definition.getFormDefinition().isEmpty()) { + throw new BusinessException(ResponseCode.WORKFLOW_FORM_CONFIG_EMPTY); + } + + // 4. 验证图形信息的完整性 + if (definition.getGraphDefinition() == null || definition.getGraphDefinition().isEmpty()) { + throw new BusinessException(ResponseCode.WORKFLOW_GRAPH_CONFIG_EMPTY); + } + + // TODO: 实现更详细的验证逻辑 + // 1. 验证节点之间的连接关系 + // 2. 验证表单字段的合法性 + // 3. 验证图形布局的合理性 return true; } @@ -196,6 +223,8 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl