增加工作流代码可正常启动

This commit is contained in:
戚辰先生 2024-12-05 12:31:39 +08:00
parent bdbd4528a5
commit 45e05fd935
30 changed files with 1277 additions and 208 deletions

View File

@ -22,7 +22,8 @@
// 工作流定义相关接口 // 工作流定义相关接口
interface WorkflowDefinitionAPI { interface WorkflowDefinitionAPI {
// 基础CRUD接口 // 基础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 创建 create: '/api/v1/workflow-definitions' // POST 创建
update: '/api/v1/workflow-definitions/{id}' // PUT 更新 update: '/api/v1/workflow-definitions/{id}' // PUT 更新
delete: '/api/v1/workflow-definitions/{id}' // DELETE 删除 delete: '/api/v1/workflow-definitions/{id}' // DELETE 删除
@ -32,6 +33,31 @@ interface WorkflowDefinitionAPI {
publish: '/api/v1/workflow-definitions/{id}/publish' // POST 发布 publish: '/api/v1/workflow-definitions/{id}/publish' // POST 发布
disable: '/api/v1/workflow-definitions/{id}/disable' // POST 禁用 disable: '/api/v1/workflow-definitions/{id}/disable' // POST 禁用
enable: '/api/v1/workflow-definitions/{id}/enable' // 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<T> {
records: T[] // 数据列表
total: number // 总记录数
pages: number // 总页数
pageNum: number // 当前页码
pageSize: number // 每页大小
} }
// 工作流定义数据结构 // 工作流定义数据结构
@ -42,10 +68,10 @@ interface WorkflowDefinitionDTO {
description: string // 描述 description: string // 描述
status: 'DRAFT' | 'PUBLISHED' | 'DISABLED' // 状态 status: 'DRAFT' | 'PUBLISHED' | 'DISABLED' // 状态
version: number // 版本号 version: number // 版本号
nodeConfig: string // 节点配置(JSON) nodeConfig: string // 节点配置(JSON),包含节点的基本信息和执行配置
transitionConfig: string // 流转配置(JSON) transitionConfig: string // 流转配置(JSON),定义节点间的连接和条件
formDefinition: string // 表单定义 formDefinition: string // 表单定义(JSON),定义工作流的表单字段和验证规则
graphDefinition: string // 图形信息 graphDefinition: string // 图形信息(JSON),定义节点的位置和连线的样式
enabled: boolean // 是否启用 enabled: boolean // 是否启用
remark: string // 备注 remark: string // 备注
nodes: NodeDefinitionDTO[] // 节点定义列表 nodes: NodeDefinitionDTO[] // 节点定义列表
@ -62,6 +88,173 @@ interface NodeDefinitionDTO {
workflowDefinitionId: number // 工作流定义ID workflowDefinitionId: number // 工作流定义ID
orderNum: number // 排序号 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 工作流实例管理 ### 2.2 工作流实例管理
@ -69,7 +262,8 @@ interface NodeDefinitionDTO {
// 工作流实例相关接口 // 工作流实例相关接口
interface WorkflowInstanceAPI { interface WorkflowInstanceAPI {
// 基础CRUD接口 // 基础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 获取详情 get: '/api/v1/workflow-instance/{id}' // GET 获取详情
// 实例操作接口 // 实例操作接口
@ -98,10 +292,11 @@ interface WorkflowInstanceDTO {
// 节点实例相关接口 // 节点实例相关接口
interface NodeInstanceAPI { 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 获取详情 get: '/api/v1/node-instance/{id}' // GET 获取详情
findByWorkflow: '/api/v1/node-instance/workflow/{workflowInstanceId}' // GET 查询工作流下的节点 findByWorkflow: '/api/v1/node-instance/workflow/{workflowInstanceId}' // GET 查询工作流下的节点(不分页)
findByStatus: '/api/v1/node-instance/workflow/{workflowInstanceId}/status/{status}' // GET 查询指定状态的节点 findByStatus: '/api/v1/node-instance/workflow/{workflowInstanceId}/status/{status}' // GET 查询指定状态的节点(不分页)
// 节点操作 // 节点操作
updateStatus: '/api/v1/node-instance/{id}/status' // PUT 更新状态 updateStatus: '/api/v1/node-instance/{id}/status' // PUT 更新状态
@ -130,12 +325,13 @@ interface NodeInstanceDTO {
// 日志相关接口 // 日志相关接口
interface WorkflowLogAPI { interface WorkflowLogAPI {
// 基础CRUD接口 // 基础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 创建 create: '/api/v1/workflow-logs' // POST 创建
// 特殊查询接口 // 特殊查询接口
getWorkflowLogs: '/api/v1/workflow-logs/workflow/{workflowInstanceId}' // GET 查询工作流日志 getWorkflowLogs: '/api/v1/workflow-logs/workflow/{workflowInstanceId}' // GET 查询工作流日志(不分页)
getNodeLogs: '/api/v1/workflow-logs/node/{workflowInstanceId}/{nodeId}' // GET 查询节点日志 getNodeLogs: '/api/v1/workflow-logs/node/{workflowInstanceId}/{nodeId}' // GET 查询节点日志(不分页)
record: '/api/v1/workflow-logs/record' // POST 记录日志 record: '/api/v1/workflow-logs/record' // POST 记录日志
} }
@ -179,19 +375,38 @@ interface WorkflowLogDTO {
- 描述 - 描述
- 备注 - 备注
2. 流程设计器 2. 流程设计器
- 节点拖拽 - 节点拖拽和布局
- 连线绘制 - 连线绘制和调整
- 节点配置 - 节点配置nodeConfig
- 基本信息配置
- 执行器类型选择
- 执行器参数配置
- 流转配置transitionConfig
- 连线条件配置
- 优先级设置
- 条件表达式编辑
- 流程校验 - 流程校验
3. 表单设计器 3. 表单设计器formDefinition
- 表单字段配置 - 表单字段配置
- 字段类型选择
- 字段属性设置
- 选项配置针对select类型
- 字段验证规则 - 字段验证规则
- 必填验证
- 格式验证
- 自定义验证
- 表单布局设计
- 表单预览 - 表单预览
4. 节点配置面板 4. 图形布局graphDefinition
- 节点基本信息 - 节点位置调整
- 节点类型配置 - 连线样式设置
- 执行条件配置 - 自动布局
- 表单关联配置 - 缩放和居中
5. 版本管理
- 版本历史查看
- 版本对比
- 版本回滚
- 创建新版本
### 3.2 工作流实例管理(/workflow/instance) ### 3.2 工作流实例管理(/workflow/instance)
@ -247,6 +462,90 @@ interface WorkflowLogDTO {
- 异常趋势图 - 异常趋势图
- 异常节点TOP5 - 异常节点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 项目结构 ### 4.1 项目结构

View File

@ -123,7 +123,20 @@ public enum ResponseCode {
WORKFLOW_CONCURRENT_LIMIT_EXCEEDED(2753, "workflow.concurrent.limit.exceeded"), WORKFLOW_CONCURRENT_LIMIT_EXCEEDED(2753, "workflow.concurrent.limit.exceeded"),
WORKFLOW_CONFIG_INVALID(2754, "workflow.config.invalid"), WORKFLOW_CONFIG_INVALID(2754, "workflow.config.invalid"),
WORKFLOW_TRANSITION_INVALID(2755, "workflow.transition.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 int code;
private final String messageKey; // 国际化消息key private final String messageKey; // 国际化消息key

View File

@ -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.api.Response;
import com.qqchen.deploy.backend.framework.controller.BaseController; import com.qqchen.deploy.backend.framework.controller.BaseController;

View File

@ -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<NodeType, NodeTypeDTO, Long, NodeTypeQuery> {
@Resource
private INodeTypeService nodeTypeService;
@Operation(summary = "获取指定节点类型支持的执行器列表")
@GetMapping("/{type}/executors")
public Response<List<TaskExecutorDefinition>> getExecutors(
@Parameter(description = "节点类型", required = true) @PathVariable String type
) {
log.debug("获取节点类型[{}]支持的执行器列表", type);
return Response.success(nodeTypeService.getExecutors(type));
}
@Override
protected void exportData(HttpServletResponse response, List<NodeTypeDTO> data) {
}
}

View File

@ -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.api.Response;
import com.qqchen.deploy.backend.framework.controller.BaseController; import com.qqchen.deploy.backend.framework.controller.BaseController;

View File

@ -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.api.Response;
import com.qqchen.deploy.backend.framework.controller.BaseController; import com.qqchen.deploy.backend.framework.controller.BaseController;

View File

@ -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.enums.LogLevelEnum;
import com.qqchen.deploy.backend.framework.api.Response; import com.qqchen.deploy.backend.framework.api.Response;

View File

@ -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;
}

View File

@ -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<TaskExecutorDefinition> toExecutorList(String json);
/**
* 将执行器定义列表转换为JSON字符串
*
* @param executors 执行器定义列表
* @return JSON字符串
*/
String fromExecutorList(List<TaskExecutorDefinition> executors);
}

View File

@ -1,7 +1,7 @@
package com.qqchen.deploy.backend.workflow.converter; package com.qqchen.deploy.backend.workflow.converter;
import com.qqchen.deploy.backend.framework.converter.BaseConverter; 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 com.qqchen.deploy.backend.workflow.entity.NodeInstance;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;

View File

@ -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<NodeType, NodeTypeDTO> {
@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);
}

View File

@ -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<TaskExecutorDefinition> toExecutorList(String json) {
if (json == null || json.isEmpty()) {
return new ArrayList<>();
}
try {
return objectMapper.readValue(json, new TypeReference<List<TaskExecutorDefinition>>() {});
} catch (JsonProcessingException e) {
throw new SystemException("Failed to parse executors JSON: " + e.getMessage(), e);
}
}
@Override
public String fromExecutorList(List<TaskExecutorDefinition> 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);
}
}
}

View File

@ -10,6 +10,19 @@ import lombok.EqualsAndHashCode;
import java.time.LocalDateTime; 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 @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class NodeInstanceDTO extends BaseDTO { public class NodeInstanceDTO extends BaseDTO {
@ -41,6 +54,7 @@ public class NodeInstanceDTO extends BaseDTO {
/** /**
* 节点状态 * 节点状态
*/ */
@NotNull(message = "节点状态不能为空")
private NodeStatusEnum status; private NodeStatusEnum status;
/** /**

View File

@ -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<TaskExecutorDefinition> executors;
/**
* 节点配置模式(JSON)
* 使用JSON Schema格式定义节点的配置结构
* 说明
* 1. 基础配置所有类型节点都需要的配置如节点名称描述等
* 2. 分类配置不同分类节点特有的配置
* - TASK任务节点配置如执行器选择重试策略等
* - GATEWAY网关节点配置如条件表达式分支策略等
* - EVENT事件节点配置如事件类型触发条件等
*/
private String configSchema;
/**
* 默认配置(JSON)
* 符合configSchema定义的默认配置值
*/
private String defaultConfig;
/**
* 是否启用
*/
@NotNull(message = "是否启用不能为空")
private Boolean enabled = true;
}

View File

@ -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.annotation.QueryField;
import com.qqchen.deploy.backend.framework.enums.QueryType; import com.qqchen.deploy.backend.framework.enums.QueryType;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<Long> {
/**
* 节点类型编码
*/
@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;
}

View File

@ -63,6 +63,18 @@ public class WorkflowDefinition extends Entity<Long> {
@Column(name = "transition_config", columnDefinition = "TEXT") @Column(name = "transition_config", columnDefinition = "TEXT")
private String transitionConfig; private String transitionConfig;
/**
* 表单定义(JSON)
*/
@Column(name = "form_definition", columnDefinition = "TEXT")
private String formDefinition;
/**
* 图形信息(JSON)
*/
@Column(name = "graph_definition", columnDefinition = "TEXT")
private String graphDefinition;
/** /**
* 节点定义列表 * 节点定义列表
*/ */

View File

@ -0,0 +1,38 @@
package com.qqchen.deploy.backend.workflow.enums;
import lombok.Getter;
/**
* 节点分类枚举
*/
@Getter
public enum NodeCategory {
/**
* 基础节点如开始结束节点
*/
BASIC("基础节点"),
/**
* 任务节点如ShellJenkins等执行器节点
*/
TASK("任务节点"),
/**
* 网关节点如并行排他包容网关
*/
GATEWAY("网关节点"),
/**
* 事件节点如定时器消息等事件
*/
EVENT("事件节点");
/**
* 分类名称
*/
private final String name;
NodeCategory(String name) {
this.name = name;
}
}

View File

@ -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<NodeType, Long> {
/**
* 根据编码查询未删除的节点类型
*
* @param code 节点类型编码
* @return 节点类型
*/
Optional<NodeType> findByCodeAndDeletedFalse(String code);
/**
* 检查编码是否已存在排除已删除的
*
* @param code 节点类型编码
* @return 是否存在
*/
boolean existsByCodeAndDeletedFalse(String code);
}

View File

@ -1,7 +1,7 @@
package com.qqchen.deploy.backend.workflow.service; package com.qqchen.deploy.backend.workflow.service;
import com.qqchen.deploy.backend.framework.service.IBaseService; 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.entity.NodeInstance;
import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum; import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum;

View File

@ -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<NodeType, NodeTypeDTO, Long> {
/**
* 根据编码查询节点类型
*
* @param code 节点类型编码
* @return 节点类型
*/
NodeTypeDTO findByCode(String code);
/**
* 获取指定节点类型支持的执行器列表
* 说明
* 1. 只有TASK类型的节点才有执行器列表
* 2. 一个任务节点可以支持多种执行器
* 3. 每个执行器都有自己的配置模式
*
* 使用场景
* 1. 流程设计时选择节点类型后需要展示该节点支持的执行器列表
* 2. 根据选择的执行器动态渲染配置表单
* 3. 保存节点配置时验证执行器参数是否符合配置模式
*
* @param code 节点类型编码
* @return 执行器列表
*/
List<TaskExecutorDefinition> getExecutors(String code);
/**
* 启用节点类型
*
* @param id 节点类型ID
*/
void enable(Long id);
/**
* 禁用节点类型
*
* @param id 节点类型ID
*/
void disable(Long id);
}

View File

@ -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.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException; import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; 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.converter.NodeInstanceConverter;
import com.qqchen.deploy.backend.workflow.dto.NodeInstanceDTO;
import com.qqchen.deploy.backend.workflow.entity.NodeInstance; import com.qqchen.deploy.backend.workflow.entity.NodeInstance;
import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum; import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum;
import com.qqchen.deploy.backend.workflow.repository.INodeInstanceRepository; import com.qqchen.deploy.backend.workflow.repository.INodeInstanceRepository;

View File

@ -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<NodeType, NodeTypeDTO, Long> 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<TaskExecutorDefinition> 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);
}
}

View File

@ -77,6 +77,9 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
current.setName(dto.getName()); current.setName(dto.getName());
current.setDescription(dto.getDescription()); current.setDescription(dto.getDescription());
current.setNodeConfig(dto.getNodeConfig()); current.setNodeConfig(dto.getNodeConfig());
current.setTransitionConfig(dto.getTransitionConfig());
current.setFormDefinition(dto.getFormDefinition());
current.setGraphDefinition(dto.getGraphDefinition());
// 保存更新 // 保存更新
current = workflowDefinitionRepository.save(current); current = workflowDefinitionRepository.save(current);
@ -163,9 +166,33 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
@Override @Override
public boolean validate(Long id) { public boolean validate(Long id) {
// TODO: 实现工作流定义验证逻辑 WorkflowDefinition definition = workflowDefinitionRepository.findById(id)
.orElseThrow(() -> new BusinessException(ResponseCode.WORKFLOW_NOT_FOUND));
// 1. 验证节点配置的完整性 // 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; return true;
} }
@ -196,6 +223,8 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
newDefinition.setEnabled(true); newDefinition.setEnabled(true);
newDefinition.setNodeConfig(oldDefinition.getNodeConfig()); newDefinition.setNodeConfig(oldDefinition.getNodeConfig());
newDefinition.setTransitionConfig(oldDefinition.getTransitionConfig()); newDefinition.setTransitionConfig(oldDefinition.getTransitionConfig());
newDefinition.setFormDefinition(oldDefinition.getFormDefinition());
newDefinition.setGraphDefinition(oldDefinition.getGraphDefinition());
// 保存新版本 // 保存新版本
return workflowDefinitionConverter.toDto(workflowDefinitionRepository.save(newDefinition)); return workflowDefinitionConverter.toDto(workflowDefinitionRepository.save(newDefinition));

View File

@ -383,67 +383,73 @@ CREATE TABLE deploy_repo_branch (
-- 工作流定义表 -- 工作流定义表
CREATE TABLE wf_workflow_definition ( CREATE TABLE wf_workflow_definition (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
create_by VARCHAR(255) NULL COMMENT '创建人', create_by VARCHAR(255) NULL COMMENT '创建人',
create_time DATETIME(6) NULL COMMENT '创建时间', create_time DATETIME(6) NULL COMMENT '创建时间',
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除',
update_by VARCHAR(255) NULL COMMENT '更新人', update_by VARCHAR(255) NULL COMMENT '更新人',
update_time DATETIME(6) NULL COMMENT '更新时间', update_time DATETIME(6) NULL COMMENT '更新时间',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
code VARCHAR(100) NOT NULL COMMENT '工作流编码', code VARCHAR(100) NOT NULL COMMENT '工作流编码',
name VARCHAR(100) NOT NULL COMMENT '工作流名称', name VARCHAR(100) NOT NULL COMMENT '工作流名称',
description TEXT NULL COMMENT '工作流描述', description VARCHAR(255) NULL COMMENT '工作流描述',
status VARCHAR(50) NOT NULL DEFAULT 'DRAFT' COMMENT '状态DRAFT草稿PUBLISHED已发布DISABLED已禁用', status VARCHAR(20) NOT NULL COMMENT '工作流状态DRAFT/PUBLISHED/DISABLED',
enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用0禁用1启用', version_no INT NOT NULL DEFAULT 1 COMMENT '版本号',
node_config TEXT NULL COMMENT '节点配置(JSON)', node_config TEXT NULL COMMENT '节点配置(JSON)',
transition_config TEXT NULL COMMENT '流转配置(JSON)',
form_definition TEXT NULL COMMENT '表单定义(JSON)',
graph_definition TEXT NULL COMMENT '图形信息(JSON)',
enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用',
CONSTRAINT UK_workflow_definition_code UNIQUE (code) CONSTRAINT UK_workflow_definition_code_version UNIQUE (code, version_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工作流定义表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工作流定义表';
-- 流转配置 -- 节点定义
CREATE TABLE wf_transition_config ( CREATE TABLE wf_node_definition (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
create_by VARCHAR(255) NULL COMMENT '创建人', create_by VARCHAR(255) NULL COMMENT '创建人',
create_time DATETIME(6) NULL COMMENT '创建时间', create_time DATETIME(6) NULL COMMENT '创建时间',
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除',
update_by VARCHAR(255) NULL COMMENT '更新人', update_by VARCHAR(255) NULL COMMENT '更新人',
update_time DATETIME(6) NULL COMMENT '更新时间', update_time DATETIME(6) NULL COMMENT '更新时间',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
workflow_definition_id BIGINT NOT NULL COMMENT '工作流定义ID', workflow_definition_id BIGINT NOT NULL COMMENT '工作流定义ID',
source_node_id VARCHAR(255) NOT NULL COMMENT '源节点ID', node_id VARCHAR(100) NOT NULL COMMENT '节点ID',
target_node_id VARCHAR(255) NOT NULL COMMENT '目标节点ID', name VARCHAR(100) NOT NULL COMMENT '节点名称',
transition_condition TEXT NULL COMMENT '流转条件', type VARCHAR(20) NOT NULL COMMENT '节点类型START/END/TASK/GATEWAY',
priority INT NOT NULL DEFAULT 0 COMMENT '优先级', config TEXT NULL COMMENT '节点配置(JSON)',
order_num INT NOT NULL DEFAULT 0 COMMENT '排序号',
CONSTRAINT FK_transition_workflow FOREIGN KEY (workflow_definition_id) REFERENCES wf_workflow_definition (id) CONSTRAINT FK_node_definition_workflow FOREIGN KEY (workflow_definition_id) REFERENCES wf_workflow_definition (id),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='流转配置表'; CONSTRAINT UK_node_definition_workflow_node UNIQUE (workflow_definition_id, node_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='节点定义表';
-- 工作流实例表 -- 工作流实例表
CREATE TABLE wf_workflow_instance ( CREATE TABLE wf_workflow_instance (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
create_by VARCHAR(255) NULL COMMENT '创建人', create_by VARCHAR(255) NULL COMMENT '创建人',
create_time DATETIME(6) NULL COMMENT '创建时间', create_time DATETIME(6) NULL COMMENT '创建时间',
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除',
update_by VARCHAR(255) NULL COMMENT '更新人', update_by VARCHAR(255) NULL COMMENT '更新人',
update_time DATETIME(6) NULL COMMENT '更新时间', update_time DATETIME(6) NULL COMMENT '更新时间',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
workflow_definition_id BIGINT NOT NULL COMMENT '工作流定义ID', workflow_definition_id BIGINT NOT NULL COMMENT '工作流定义ID',
project_env_id BIGINT NULL COMMENT '项目环境ID', business_key VARCHAR(100) NOT NULL COMMENT '业务标识',
business_key VARCHAR(100) NULL COMMENT '业务标识', status VARCHAR(20) NOT NULL COMMENT '状态PENDING/RUNNING/COMPLETED/FAILED/CANCELLED',
status VARCHAR(50) NOT NULL DEFAULT 'RUNNING' COMMENT '状态RUNNING运行中COMPLETED已完成TERMINATED已终止FAILED失败',
start_time DATETIME(6) NULL COMMENT '开始时间', start_time DATETIME(6) NULL COMMENT '开始时间',
end_time DATETIME(6) NULL COMMENT '结束时间', end_time DATETIME(6) NULL COMMENT '结束时间',
error TEXT NULL COMMENT '错误信息', error TEXT NULL COMMENT '错误信息',
CONSTRAINT FK_workflow_instance_definition FOREIGN KEY (workflow_definition_id) REFERENCES wf_workflow_definition (id) CONSTRAINT FK_workflow_instance_definition FOREIGN KEY (workflow_definition_id) REFERENCES wf_workflow_definition (id),
CONSTRAINT UK_workflow_instance_business_key UNIQUE (business_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工作流实例表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工作流实例表';
-- 节点定义 -- 节点实例
CREATE TABLE wf_node_definition ( CREATE TABLE wf_node_instance (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
create_by VARCHAR(255) NULL COMMENT '创建人', create_by VARCHAR(255) NULL COMMENT '创建人',
create_time DATETIME(6) NULL COMMENT '创建时间', create_time DATETIME(6) NULL COMMENT '创建时间',
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除',
@ -451,60 +457,39 @@ CREATE TABLE wf_node_definition (
update_time DATETIME(6) NULL COMMENT '更新时间', update_time DATETIME(6) NULL COMMENT '更新时间',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
workflow_definition_id BIGINT NOT NULL COMMENT '工作流定义ID', workflow_instance_id BIGINT NOT NULL COMMENT '工作流实例ID',
node_id VARCHAR(50) NOT NULL COMMENT '节点ID', node_id VARCHAR(100) NOT NULL COMMENT '节点ID',
name VARCHAR(100) NOT NULL COMMENT '节点名称', node_type VARCHAR(20) NOT NULL COMMENT '节点类型',
type VARCHAR(50) NOT NULL COMMENT '节点类型', name VARCHAR(100) NOT NULL COMMENT '节点名称',
config TEXT NULL COMMENT '节点配置(JSON)', status VARCHAR(20) NOT NULL COMMENT '状态PENDING/RUNNING/COMPLETED/FAILED/CANCELLED/SKIPPED',
order_num INT NOT NULL DEFAULT 0 COMMENT '排序号', start_time DATETIME(6) NULL COMMENT '开始时间',
end_time DATETIME(6) NULL COMMENT '结束时间',
CONSTRAINT FK_node_definition_workflow FOREIGN KEY (workflow_definition_id) REFERENCES wf_workflow_definition (id) config TEXT NULL COMMENT '节点配置(JSON)',
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工作流节点定义表'; input TEXT NULL COMMENT '输入参数(JSON)',
output TEXT NULL COMMENT '输出结果(JSON)',
-- 节点实例表 error TEXT NULL COMMENT '错误信息',
CREATE TABLE wf_node_instance ( pre_node_id VARCHAR(100) NULL COMMENT '前置节点ID',
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
create_by VARCHAR(255) NULL COMMENT '创建人',
create_time DATETIME(6) NULL COMMENT '创建时间',
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除',
update_by VARCHAR(255) NULL COMMENT '更新人',
update_time DATETIME(6) NULL COMMENT '更新时间',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
workflow_instance_id BIGINT NOT NULL COMMENT '工作流实例ID',
node_id VARCHAR(100) NOT NULL COMMENT '节点ID',
name VARCHAR(100) NOT NULL COMMENT '节点名称',
type VARCHAR(50) NOT NULL COMMENT '节点类型',
status VARCHAR(50) NOT NULL DEFAULT 'PENDING' COMMENT '状态PENDING待执行RUNNING执行中COMPLETED已完成FAILED失败TERMINATED已终止',
start_time DATETIME(6) NULL COMMENT '开始时间',
end_time DATETIME(6) NULL COMMENT '结束时间',
config TEXT NULL COMMENT '节点配置(JSON)',
input TEXT NULL COMMENT '输入参数(JSON)',
output TEXT NULL COMMENT '输出结果(JSON)',
error TEXT NULL COMMENT '错误信息',
pre_node_id VARCHAR(100) NULL COMMENT '前置节点ID',
CONSTRAINT FK_node_instance_workflow FOREIGN KEY (workflow_instance_id) REFERENCES wf_workflow_instance (id) CONSTRAINT FK_node_instance_workflow FOREIGN KEY (workflow_instance_id) REFERENCES wf_workflow_instance (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='节点实例表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='节点实例表';
-- 工作流变量表 -- 工作流变量表
CREATE TABLE wf_workflow_variable ( CREATE TABLE wf_workflow_variable (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
create_by VARCHAR(255) NULL COMMENT '创建人', create_by VARCHAR(255) NULL COMMENT '创建人',
create_time DATETIME(6) NULL COMMENT '创建时间', create_time DATETIME(6) NULL COMMENT '创建时间',
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除',
update_by VARCHAR(255) NULL COMMENT '更新人', update_by VARCHAR(255) NULL COMMENT '更新人',
update_time DATETIME(6) NULL COMMENT '更新时间', update_time DATETIME(6) NULL COMMENT '更新时间',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
workflow_instance_id BIGINT NOT NULL COMMENT '工作流实例ID', workflow_instance_id BIGINT NOT NULL COMMENT '工作流实例ID',
name VARCHAR(100) NOT NULL COMMENT '变量名', name VARCHAR(100) NOT NULL COMMENT '变量名',
value TEXT NULL COMMENT '变量值', value TEXT NULL COMMENT '变量值',
type VARCHAR(50) NOT NULL COMMENT '变量类型', type VARCHAR(20) NOT NULL COMMENT '变量类型',
scope VARCHAR(50) NOT NULL DEFAULT 'GLOBAL' COMMENT '作用域GLOBAL全局NODE节点',
node_id VARCHAR(100) NULL COMMENT '节点IDscope为NODE时必填',
CONSTRAINT FK_variable_workflow FOREIGN KEY (workflow_instance_id) REFERENCES wf_workflow_instance (id) CONSTRAINT FK_workflow_variable_instance FOREIGN KEY (workflow_instance_id) REFERENCES wf_workflow_instance (id),
CONSTRAINT UK_workflow_variable_instance_name UNIQUE (workflow_instance_id, name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工作流变量表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工作流变量表';
-- 工作流日志表 -- 工作流日志表
@ -547,4 +532,28 @@ CREATE TABLE wf_workflow_permission (
INDEX idx_role_id (role_id), INDEX idx_role_id (role_id),
INDEX idx_department_id (department_id) INDEX idx_department_id (department_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工作流权限'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工作流权限';
-- 节点类型表
CREATE TABLE wf_node_type (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
create_by VARCHAR(255) NULL COMMENT '创建人',
create_time DATETIME(6) NULL COMMENT '创建时间',
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0未删除1已删除',
update_by VARCHAR(255) NULL COMMENT '更新人',
update_time DATETIME(6) NULL COMMENT '更新时间',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
code VARCHAR(100) NOT NULL COMMENT '节点类型编码',
name VARCHAR(100) NOT NULL COMMENT '节点类型名称',
description TEXT NULL COMMENT '节点类型描述',
category VARCHAR(50) NOT NULL COMMENT '节点类型分类',
icon VARCHAR(100) NULL COMMENT '节点图标',
color VARCHAR(20) NULL COMMENT '节点颜色',
executors TEXT NULL COMMENT '执行器列表(JSON)',
config_schema TEXT NULL COMMENT '节点配置模式(JSON)',
default_config TEXT NULL COMMENT '默认配置(JSON)',
enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用',
CONSTRAINT UK_node_type_code UNIQUE (code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='节点类型表';

View File

@ -150,4 +150,101 @@ INSERT INTO sys_external_system (
'链宇GIT', 'GIT', 'http://119.3.203.210:8088/', NULL, 1, 1, '链宇GIT', 'GIT', 'http://119.3.203.210:8088/', NULL, 1, 1,
'TOKEN', NULL, NULL, 'cNSud7D1GmYQKEMco7s5', 'TOKEN', NULL, NULL, 'cNSud7D1GmYQKEMco7s5',
NULL, NULL, NULL, '{}' NULL, NULL, NULL, '{}'
); );
-- --------------------------------------------------------------------------------------
-- 初始化工作流相关数据
-- --------------------------------------------------------------------------------------
-- 初始化工作流定义
INSERT INTO wf_workflow_definition (
id, create_by, create_time, deleted, update_by, update_time, version,
code, name, description, status, version_no, node_config, transition_config, form_definition, graph_definition, enabled
) VALUES (
1, 'admin', NOW(), 0, 'admin', NOW(), 0,
'DEPLOY_WORKFLOW', '标准部署流程', '标准的应用部署流程,包含代码拉取、编译构建、部署等步骤',
'PUBLISHED', 1,
'{"startNode":{"type":"START","name":"开始"},"endNode":{"type":"END","name":"结束"},"taskNodes":[{"id":"build","type":"TASK","name":"构建"},{"id":"deploy","type":"TASK","name":"部署"}]}',
'{"transitions":[{"from":"startNode","to":"build"},{"from":"build","to":"deploy"},{"from":"deploy","to":"endNode"}]}',
'{"fields":[{"name":"appName","label":"应用名称","type":"input","required":true},{"name":"branch","label":"分支","type":"select","required":true}]}',
'{"nodes":[{"id":"startNode","type":"START","x":100,"y":100},{"id":"build","type":"TASK","x":300,"y":100},{"id":"deploy","type":"TASK","x":500,"y":100},{"id":"endNode","type":"END","x":700,"y":100}],"edges":[{"source":"startNode","target":"build"},{"source":"build","target":"deploy"},{"source":"deploy","target":"endNode"}]}',
1
);
-- 初始化节点定义
INSERT INTO wf_node_definition (
id, create_by, create_time, deleted, update_by, update_time, version,
workflow_definition_id, node_id, name, type, config, order_num
) VALUES
-- 开始节点
(1, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'startNode', '开始', 'START',
'{"type":"START","name":"开始"}',
1),
-- 构建节点
(2, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'build', '构建', 'TASK',
'{"type":"TASK","name":"构建","executor":"JENKINS","jenkinsJob":"app-build"}',
2),
-- 部署节点
(3, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'deploy', '部署', 'TASK',
'{"type":"TASK","name":"部署","executor":"SHELL","script":"./deploy.sh"}',
3),
-- 结束节点
(4, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'endNode', '结束', 'END',
'{"type":"END","name":"结束"}',
4);
-- 初始化工作流实例
INSERT INTO wf_workflow_instance (
id, create_by, create_time, deleted, update_by, update_time, version,
workflow_definition_id, business_key, status, start_time, end_time, error
) VALUES (
1, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'TEST-APP-001', 'RUNNING',
NOW(), NULL, NULL
);
-- 初始化节点实例
INSERT INTO wf_node_instance (
id, create_by, create_time, deleted, update_by, update_time, version,
workflow_instance_id, node_id, node_type, name, status, start_time, end_time, config, input, output, error, pre_node_id
) VALUES
-- 开始节点实例
(1, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'startNode', 'START', '开始', 'COMPLETED',
DATE_SUB(NOW(), INTERVAL 5 MINUTE), DATE_SUB(NOW(), INTERVAL 4 MINUTE),
'{"type":"START","name":"开始"}',
'{"appName":"test-app","branch":"master"}', '{}', NULL, NULL),
-- 构建节点实例
(2, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'build', 'TASK', '构建', 'RUNNING',
DATE_SUB(NOW(), INTERVAL 3 MINUTE), NULL,
'{"type":"TASK","name":"构建","executor":"JENKINS","jenkinsJob":"app-build"}',
'{"appName":"test-app","branch":"master"}', NULL, NULL, 'startNode'),
-- 部署节点实例
(3, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'deploy', 'TASK', '部署', 'RUNNING',
DATE_SUB(NOW(), INTERVAL 2 MINUTE), NULL,
'{"type":"TASK","name":"部署","executor":"SHELL","script":"./deploy.sh"}',
'{"appName":"test-app","branch":"master"}', NULL, NULL, 'build'),
-- 结束节点实例
(4, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'endNode', 'END', '结束', 'COMPLETED',
DATE_SUB(NOW(), INTERVAL 1 MINUTE), DATE_SUB(NOW(), INTERVAL 0 MINUTE),
'{"type":"END","name":"结束"}',
'{}', '{}', NULL, 'deploy');
-- 初始化工作流变量
INSERT INTO wf_workflow_variable (
id, create_by, create_time, deleted, update_by, update_time, version,
workflow_instance_id, name, value, type
) VALUES
(1, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'appName', 'test-app', 'STRING'),
(2, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'branch', 'master', 'STRING'),
(3, 'admin', NOW(), 0, 'admin', NOW(), 0,
1, 'buildNumber', '123', 'STRING');

View File

@ -221,4 +221,17 @@ workflow.approval.rejected=审批被拒绝
workflow.dependency.not.satisfied=工作流依赖条件未满足 workflow.dependency.not.satisfied=工作流依赖条件未满足
workflow.circular.dependency=工作流存在循环依赖 workflow.circular.dependency=工作流存在循环依赖
workflow.schedule.invalid=工作流调度配置无效 workflow.schedule.invalid=工作流调度配置无效
workflow.concurrent.limit.exceeded=工作流并发限制超出 workflow.concurrent.limit.exceeded=工作流并发限制超出
# 工作流配置相关错误消息
workflow.node.config.empty=节点配置不能为空
workflow.transition.config.empty=流转配置不能为空
workflow.form.config.empty=表单配置不能为空
workflow.graph.config.empty=图形配置不能为空
# 工作流节点类型错误 (2200-2299)
workflow.node.type.not.found=节点类型不存在或已删除
workflow.node.type.disabled=节点类型已禁用,无法使用
workflow.node.type.code.exists=节点类型编码已存在
workflow.node.type.invalid.category=无效的节点类型分类
workflow.node.type.invalid.executor=无效的执行器配置

View File

@ -41,4 +41,11 @@ workflow.approval.rejected=Approval rejected
workflow.dependency.not.satisfied=Workflow dependency not satisfied workflow.dependency.not.satisfied=Workflow dependency not satisfied
workflow.circular.dependency=Circular dependency detected in workflow workflow.circular.dependency=Circular dependency detected in workflow
workflow.schedule.invalid=Invalid workflow schedule configuration workflow.schedule.invalid=Invalid workflow schedule configuration
workflow.concurrent.limit.exceeded=Workflow concurrent limit exceeded workflow.concurrent.limit.exceeded=Workflow concurrent limit exceeded
# Workflow Node Type Errors (2200-2299)
workflow.node.type.not.found=Node type does not exist or has been deleted
workflow.node.type.disabled=Node type is disabled and cannot be used
workflow.node.type.code.exists=Node type code already exists
workflow.node.type.invalid.category=Invalid node type category
workflow.node.type.invalid.executor=Invalid executor configuration