diff --git a/backend/README.md b/backend/README.md index c161f37f..c8845cc9 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,1094 +1,660 @@ # Deploy Ease Platform -Deploy Ease Platform 是一个现代化的部署管理平台,旨在简化和自动化应用程序的部署流程。 - -## 已实现功能 - -### 1. 外部系统管理 -- [x] 基础功能 - - 创建外部系统(支持Jenkins、Git等类型) - - 更新系统信息 - - 删除系统 - - 查询系统详情 - - 分页查询系统列表 - - 条件筛选查询 -- [x] Jenkins集成 - - 连接测试 - - 任务同步 - - 状态检查 - - 支持用户名密码认证 - - 支持Token认证 -- [x] Git集成 - - 仓库连接测试 - - 代码分支同步 - - 提交历史查询 - - 支持用户名密码认证 - - 支持SSH密钥认证 - - 支持Token认证 - -### 2. 用户权限管理 -- [x] 用户管理 - - 用户注册 - - 用户登录 - - 密码重置 - - 用户信息修改 - - 用户状态管理 - - 部门分配 -- [x] 角色管理 - - 角色创建与维护 - - 角色标签管理 - - 角色权限分配 - - 用户角色分配 -- [x] 权限管理 - - 权限创建与维护 - - 权限分类管理 - - 权限与菜单关联 - - 权限检查与控制 - -### 3. 菜单管理 -- [x] 基础功能 - - 菜单树维护 - - 菜单排序 - - 菜单显示控制 -- [x] 权限集成 - - 菜单权限配置 - - 按钮权限配置 - - 数据权限配置 -- [x] 前端集成 - - 动态路由生成 - - 菜单组件加载 - - 权限指令集成 - -### 4. 部门管理 -- [x] 基础功能 - - 部门树维护 - - 部门编码管理 - - 部门描述维护 - - 部门排序 -- [x] 人员管理 - - 部门负责人设置 - - 部门人员管理 - - 部门权限控制 - -### 5. 系统功能 -- [x] 认证授权 - - JWT令牌认证 - - 权限拦截器 - - 角色检查器 - - 权限注解支持 -- [x] 数据审计 - - 创建人记录 - - 创建时间记录 - - 更新人记录 - - 更新时间记录 - - 版本控制 -- [x] 异常处理 - - 统一异常处理 - - 业务异常处理 - - 系统异常处理 - - 参数校验异常处理 -- [x] 数据库支持 - - Flyway数据库版本控制 - - 基础表结构 - - 初始化数据 - - 软删除支持 - -### 6. 开发支持 -- [x] 基础框架 - - 统一响应格式 - - 统一分页格式 - - 基础CRUD封装 - - DTO自动转换 -- [x] 代码规范 - - 开发规范文档 - - 接口文档规范 - - 测试规范 - - 注释规范 -- [x] 测试支持 - - 单元测试框架 - - 集成测试支持 - - 测试数据构建 - - Mock支持 - -### 7. 租户管理API - -#### 7.1 分页查询租户 -```http -GET /api/v1/tenant/page - -请求参数: -{ - "pageNum": 1, // 页码(从1开始) - "pageSize": 10, // 每页大小 - "sortField": "createTime", // 排序字段 - "sortOrder": "desc", // 排序方式 - "code": "string", // 租户编码(可选) - "name": "string", // 租户名称(可选) - "enabled": true // 是否启用(可选) -} - -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "content": [{ - "id": 1, - "createTime": "2024-01-01 12:00:00", - "createBy": "admin", - "updateTime": "2024-01-01 12:00:00", - "updateBy": "admin", - "code": "TEST", - "name": "测试租户", - "address": "北京市朝阳区", - "contactName": "张三", - "contactPhone": "13800138000", - "email": "test@example.com", - "enabled": true - }], - "totalElements": 100, - "totalPages": 10, - "size": 10, - "number": 0, - "first": true, - "last": false, - "empty": false - } -} -``` - -#### 7.2 创建租户 -```http -POST /api/v1/tenant - -请求参数: -{ - "code": "TEST", // 租户编码(必填) - "name": "测试租户", // 租户名称(必填) - "address": "北京市朝阳区", // 地址(可选) - "contactName": "张三", // 联系人姓名(可选) - "contactPhone": "13800138000", // 联系人电话(可选) - "email": "test@example.com", // 联系人邮箱(可选) - "enabled": true // 是否启用(可选,默认true) -} - -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "id": 1, - // ... 其他字段同上 - } -} -``` - -#### 7.3 更新租户 -```http -PUT /api/v1/tenant/{id} - -请求参数: -{ - // 同创建接口 -} - -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "id": 1, - // ... 其他字段同上 - } -} -``` - -#### 7.4 删除租户 -```http -DELETE /api/v1/tenant/{id} - -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功" -} -``` - -#### 7.5 获取租户状态 -```http -GET /api/v1/tenant/{id}/enabled - -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": true // true: 启用,false: 禁用 -} -``` - -#### 7.6 更新租户状态 -```http -PUT /api/v1/tenant/{id}/enabled - -请求参数: -enabled=true // 是否启用(必填) - -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功" -} -``` +Deploy Ease Platform 是一个基于Spring Boot 3.x和Flowable 7.x的现代化部署管理平台,提供工作流驱动的自动化部署解决方案。 ## 技术栈 -### 后端技术栈 -- Spring Boot 3.x -- Spring Security + JWT -- Spring Data JPA -- Flyway数据库版本控制 -- MapStruct对象映射 -- Lombok -- JUnit 5 +### 后端 +- **Java 21** + **Spring Boot 3.2.0** +- **Spring Security 6.2.0** + JWT认证 +- **Spring Data JPA** + Hibernate +- **Flowable 7.2.0** - 工作流引擎 +- **MySQL 8.0+** + Flyway数据库版本控制 +- **MapStruct 1.5.5** - 对象映射 +- **QueryDSL 5.0.0** - 类型安全查询 +- **OpenAPI/Swagger** - API文档 +- **Lombok** - 代码简化 +- **Hutool** - 工具类库 -### 数据库 -- MySQL 8.0+ +### 构建工具 +- **Maven 3.8+** -## API文档 +## 核心功能模块 -### 1. 外部系统管理API +### ✅ 1. 系统管理(已完成) -#### 1.1 分页查询 -```http -GET /api/v1/external-system/page +#### 1.1 用户管理 +- [x] 用户注册和登录 +- [x] JWT Token认证 +- [x] 密码重置 +- [x] 用户信息维护 +- [x] 用户状态管理(启用/禁用) +- [x] 部门分配 +- [x] 基础CRUD操作(分页查询、创建、更新、删除) -请求参数: -{ - "pageNum": 1, // 页码(从1开始) - "pageSize": 10, // 每页大小 - "sortField": "createTime", // 排序字段 - "sortOrder": "desc", // 排序方式 - "name": "string", // 系统名称(可选) - "type": "JENKINS", // 系统类型(可选) - "enabled": true // 是否启用(可选) -} - -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "content": [{ - "id": 1, - "createTime": "2024-01-01 12:00:00", - "createBy": "admin", - "updateTime": "2024-01-01 12:00:00", - "updateBy": "admin", - "name": "Jenkins测试环境", - "type": "JENKINS", - "url": "http://jenkins.test.com", - "remark": "测试环境Jenkins服务器", - "sort": 1, - "enabled": true, - "authType": "USERNAME_PASSWORD", - "username": "admin", - "password": "******", - "token": null, - "syncStatus": "SUCCESS", - "lastSyncTime": "2024-01-01 12:00:00", - "config": "{}" - }], - "totalElements": 100, - "totalPages": 10, - "size": 10, - "number": 0, - "first": true, - "last": false, - "empty": false - } -} +**主要接口:** +``` +POST /api/v1/user/login - 用户登录 +GET /api/v1/user/current - 获取当前用户信息 +POST /api/v1/user/{id}/reset-password - 重置密码 +PUT /api/v1/user/{id}/department - 分配部门 ``` -#### 1.2 创建外部系统 -```http -POST /api/v1/external-system +#### 1.2 角色管理 +- [x] 角色创建与维护 +- [x] 角色标签管理 +- [x] 角色权限分配 +- [x] 用户角色分配 +- [x] 角色权限查询 -请求参数: -{ - "name": "Jenkins测试环境", // 系统名称(必填) - "type": "JENKINS", // 系统类型(必填) - "url": "http://jenkins.test.com", // 系统地址(必填) - "remark": "测试环境Jenkins服务器", // 备注(可选) - "sort": 1, // 排序(可选) - "enabled": true, // 是否启用(可选,默认true) - "authType": "USERNAME_PASSWORD", // 认证方式(必填) - "username": "admin", // 用户名(可选) - "password": "password123", // 密码(可选) - "token": null, // 访问令牌(可选) - "config": "{}" // 配置信息(可选) -} - -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "id": 1, - // ... 其他字段同上 - } -} +**主要接口:** +``` +POST /api/v1/role - 创建角色 +POST /api/v1/role/{id}/tags - 分配标签 +POST /api/v1/role/{userId}/assignRoles - 分配角色 +GET /api/v1/role/{id}/permissions - 获取角色权限 +POST /api/v1/role/{id}/permissions - 分配权限 ``` -#### 1.3 更新外部系统 -```http -PUT /api/v1/external-system/{id} +#### 1.3 权限管理 +- [x] 权限创建与维护 +- [x] 权限分类管理(菜单权限、按钮权限) +- [x] 权限与菜单关联 +- [x] 基于权限的访问控制 -请求参数: -{ - // 同创建接口 -} +#### 1.4 菜单管理 +- [x] 菜单树维护 +- [x] 菜单排序 +- [x] 菜单显示控制 +- [x] 动态菜单加载 +- [x] 菜单权限配置 +- [x] 权限树查询 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "id": 1, - // ... 其他字段同上 - } -} +**主要接口:** +``` +GET /api/v1/menu/current - 获取当前用户菜单 +GET /api/v1/menu/tree - 获取菜单树 +GET /api/v1/menu/permission-tree - 获取权限树 ``` -#### 1.4 删除外部系统 -```http -DELETE /api/v1/external-system/{id} +#### 1.5 部门管理 +- [x] 部门树形结构维护 +- [x] 部门编码管理 +- [x] 部门负责人设置 +- [x] 部门人员管理 +- [x] 部门排序 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功" -} +#### 1.6 租户管理 +- [x] 多租户支持 +- [x] 租户信息管理 +- [x] 租户状态控制 + +**实体统计:** 9个核心实体 +- User(用户) +- Role(角色) +- RoleTag(角色标签) +- Permission(权限) +- PermissionTemplate(权限模板) +- Menu(菜单) +- Department(部门) +- Tenant(租户) +- SysParam(系统参数) + +--- + +### ✅ 2. 外部系统集成(已完成) + +#### 2.1 外部系统管理 +- [x] 外部系统统一管理(Jenkins、Git等) +- [x] 多种认证方式支持 + - 用户名密码认证 + - Token认证 + - SSH密钥认证 +- [x] 连接测试 +- [x] 同步状态追踪 + +**主要接口:** +``` +POST /api/v1/external-system - 创建外部系统 +GET /api/v1/external-system/{id}/test-connection - 测试连接 +POST /api/v1/external-system/{id}/sync - 同步数据 +GET /api/v1/external-system/{id}/status - 获取同步状态 ``` -#### 1.5 测试连接 -```http -POST /api/v1/external-system/{id}/test-connection +#### 2.2 Jenkins集成 +- [x] Jenkins实例管理 +- [x] 视图(View)同步 +- [x] 任务(Job)同步 +- [x] 构建(Build)信息同步 +- [x] 构建历史记录 +- [x] 同步历史追踪 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": true -} +**主要接口:** +``` +POST /api/v1/jenkins-manager/{externalSystemId}/sync-all - 同步所有数据 +POST /api/v1/jenkins-manager/{externalSystemId}/sync-views - 同步视图 +POST /api/v1/jenkins-manager/{externalSystemId}/sync-jobs - 同步任务 +POST /api/v1/jenkins-manager/{externalSystemId}/sync-builds - 同步构建 +GET /api/v1/jenkins-manager/{externalSystemId}/instance - 获取实例信息 ``` -#### 1.6 同步数据 -```http -POST /api/v1/external-system/{id}/sync +**相关实体:** +- JenkinsView(Jenkins视图) +- JenkinsJob(Jenkins任务) +- JenkinsBuild(Jenkins构建) +- JenkinsSyncHistory(同步历史) -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功" -} +#### 2.3 Git仓库集成 +- [x] Git仓库组(Group)管理 +- [x] Git项目(Project)管理 +- [x] Git分支(Branch)管理 +- [x] 多级同步(组 → 项目 → 分支) +- [x] 同步历史记录 + +**主要接口:** +``` +POST /api/v1/repository-manager/{externalSystemId}/sync-groups - 同步仓库组 +POST /api/v1/repository-manager/{externalSystemId}/groups/sync-projects - 同步项目 +POST /api/v1/repository-manager/{externalSystemId}/projects/sync-branches - 同步分支 +GET /api/v1/repository-manager/{externalSystemId}/instance - 获取实例信息 ``` -#### 1.7 检查状态 -```http -GET /api/v1/external-system/{id}/status +**相关实体:** +- RepositoryGroup(仓库组) +- RepositoryProject(仓库项目) +- RepositoryBranch(仓库分支) +- RepositorySyncHistory(同步历史) -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "syncStatus": "SUCCESS", - "lastSyncTime": "2024-01-01 12:00:00" - } -} +--- + +### ✅ 3. 部署管理(已完成) + +#### 3.1 应用管理 +- [x] 应用创建与维护 +- [x] 应用编码管理 +- [x] 开发语言类型支持(Java、Python、Node.js等) +- [x] 应用与仓库关联 +- [x] 应用分组管理 + +**主要接口:** +``` +POST /api/v1/applications - 创建应用 +GET /api/v1/applications/development-languages - 获取开发语言列表 ``` -### 2. 用户认证API +**相关实体:** +- Application(应用) +- ProjectGroup(项目组) -#### 2.1 用户登录 -```http -POST /api/v1/user/login +#### 3.2 环境管理 +- [x] 环境配置管理(开发、测试、生产等) +- [x] 环境编码管理 +- [x] 构建类型配置(Jenkins、GitLab Runner、GitHub Action) +- [x] 部署方式配置(K8S、Docker、VM) +- [x] 项目组与环境关联 -请求参数: -{ - "username": "admin", // 用户名(必填) - "password": "password" // 密码(必填) -} +**相关实体:** +- Environment(环境) -响应结果: -{ - "success": true, - "code": 200, - "message": "登录成功", - "data": { - "token": "eyJhbGciOiJIUzI1NiJ9...", - "user": { - "id": 1, - "username": "admin", - "nickname": "管理员", - "email": "admin@example.com", - "phone": "13800138000", - "departmentId": 1, - "departmentName": "技术部" - } - } -} +#### 3.3 部署配置 +- [x] 应用部署配置管理 +- [x] 构建配置Schema定义 +- [x] 部署操作 +- [x] 部署日志记录 + +**主要接口:** +``` +POST /api/v1/deploy-app-config - 创建部署配置 +GET /api/v1/deploy-app-config/defined - 获取构建类型Schema +POST /api/v1/deploy-app-config/deploy - 执行部署 ``` -#### 2.2 获取当前用户信息 -```http -GET /api/v1/user/current +**相关实体:** +- DeployAppConfig(部署配置) +- DeployLog(部署日志) -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "id": 1, - "username": "admin", - "nickname": "管理员", - "email": "admin@example.com", - "phone": "13800138000", - "departmentId": 1, - "departmentName": "技术部" - } -} +--- + +### ✅ 4. 工作流引擎(已完成,基于Flowable) + +#### 4.1 工作流定义 +- [x] 工作流设计和保存 +- [x] 工作流发布管理 +- [x] 工作流启用/禁用 +- [x] 工作流状态管理(草稿、已发布、已禁用) +- [x] 图形化配置(GraphJSON) +- [x] BPMN XML自动生成 +- [x] 工作流分类管理 + +**主要接口:** +``` +POST /api/v1/workflow/definition/design - 保存工作流设计 +GET /api/v1/workflow/definition/published - 查询已发布工作流 +POST /api/v1/workflow/definition/{id}/published - 发布工作流 +POST /api/v1/workflow/definition/{id}/disable - 禁用工作流 +POST /api/v1/workflow/definition/{id}/enable - 启用工作流 +GET /api/v1/workflow/definition/categories - 获取工作流分类 ``` -### 3. 菜单管理API +#### 4.2 工作流实例 +- [x] 工作流实例启动 +- [x] 工作流实例挂起 +- [x] 工作流实例恢复 +- [x] 工作流执行状态查询 +- [x] 历史实例查询 +- [x] 实例与模板关联查询 -#### 3.1 获取当前用户菜单 -```http -GET /api/v1/menu/current - -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": [{ - "id": 1, - "name": "系统管理", - "path": "/system", - "component": "Layout", - "icon": "setting", - "permission": "system:view", - "type": 1, // 1:目录 2:菜单 3:按钮 - "parentId": null, - "sort": 1, - "hidden": false, - "children": [{ - "id": 2, - "name": "用户管理", - "path": "/system/user", - "component": "system/user/index", - "icon": "user", - "permission": "system:user:view", - "type": 2, - "parentId": 1, - "sort": 1, - "hidden": false, - "children": [] - }] - }] -} +**主要接口:** +``` +POST /api/v1/workflow/instance/start - 启动工作流 +GET /api/v1/workflow/instance/templates-with-instances - 查询模板及实例 +GET /api/v1/workflow/instance/historical-instances - 查询历史实例 +POST /api/v1/workflow/definition/{processInstanceId}/suspend - 挂起实例 +POST /api/v1/workflow/definition/{processInstanceId}/resume - 恢复实例 ``` -#### 3.2 获取菜单树 -```http -GET /api/v1/menu/tree +#### 4.3 节点定义与执行 +- [x] 节点类型管理 +- [x] 节点配置Schema +- [x] 节点实例状态追踪 +- [x] 节点重试机制 +- [x] 节点跳过机制 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": [{ - // 结构同上 - }] -} +**主要接口:** +``` +POST /api/v1/workflow/node-instance/{id}/retry - 重试节点 +POST /api/v1/workflow/node-instance/{id}/skip - 跳过节点 ``` -#### 3.3 获取权限树 -```http -GET /api/v1/menu/permission-tree +#### 4.4 节点类型实现(Delegate) +- [x] **ShellNodeDelegate** - Shell脚本执行 +- [x] **DeployNodeDelegate** - 部署节点执行 +- [x] **ApprovalNodeDelegate** - 审批节点 +- [x] **NotificationNodeDelegate** - 通知节点 +- [x] **BaseNodeDelegate** - 基础节点抽象 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": [{ - "id": 1, - "name": "系统管理", - "type": 1, - "children": [{ - "id": 2, - "name": "用户管理", - "type": 2, - "permissions": [{ - "id": 3, - "code": "system:user:add", - "name": "新增用户", - "type": "BUTTON" - }] - }] - }] -} +#### 4.5 工作流日志 +- [x] 实时日志记录 +- [x] 节点级日志 +- [x] 日志查询 + +**相关实体:** +- WorkflowDefinition(工作流定义) +- WorkflowNodeDefinition(节点定义) +- WorkflowInstance(工作流实例) +- WorkflowNodeInstance(节点实例) +- WorkflowLog(工作流日志) + +--- + +### ✅ 5. 基础框架(已完成) + +#### 5.1 通用CRUD框架 +- [x] BaseController - 统一REST控制器 +- [x] BaseServiceImpl - 通用服务实现 +- [x] IBaseRepository - 通用数据访问接口 +- [x] BaseConverter - 对象转换抽象 +- [x] 统一响应格式(Response) +- [x] 统一分页格式(Page) + +**标准CRUD接口(所有Controller继承):** +``` +POST /{resource} - 创建 +PUT /{resource}/{id} - 更新 +DELETE /{resource}/{id} - 删除 +GET /{resource}/{id} - 查询详情 +GET /{resource} - 查询列表 +GET /{resource}/page - 分页查询 +GET /{resource}/list - 条件查询 +POST /{resource}/batch - 批量处理 +GET /{resource}/export - 导出数据 ``` -### 4. 部门管理API +#### 5.2 查询框架 +- [x] 基于QueryDSL的类型安全查询 +- [x] 动态查询条件构建 +- [x] @QueryField注解支持 +- [x] 多种查询类型(EQUAL、LIKE、BETWEEN、IN等) +- [x] 软删除查询支持 -#### 4.1 获取部门树 -```http -GET /api/v1/department/tree +#### 5.3 安全框架 +- [x] Spring Security集成 +- [x] JWT Token认证 +- [x] 权限拦截器 +- [x] 自定义认证入口点 +- [x] JWT过滤器 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": [{ - "id": 1, - "code": "TECH", - "name": "技术部", - "description": "技术研发部门", - "parentId": null, - "sort": 1, - "enabled": true, - "leaderId": 1, - "leaderName": "张三", - "children": [{ - "id": 2, - "code": "DEV", - "name": "研发组", - "description": "研发团队", - "parentId": 1, - "sort": 1, - "enabled": true, - "leaderId": 2, - "leaderName": "李四", - "children": [] - }] - }] -} -``` +#### 5.4 审计框架 +- [x] 审计注解(@Audited) +- [x] 自动记录创建人/创建时间 +- [x] 自动记录更新人/更新时间 +- [x] 乐观锁版本控制 +- [x] 审计事件监听 -#### 4.2 创建部门 -```http -POST /api/v1/department +#### 5.5 异常处理 +- [x] 统一异常处理(GlobalExceptionHandler) +- [x] 业务异常(BusinessException) +- [x] 系统异常(SystemException) +- [x] 唯一约束异常(UniqueConstraintException) +- [x] 实体未找到异常(EntityNotFoundException) +- [x] 国际化错误消息 -请求参数: -{ - "code": "TECH", // 部门编码(必填) - "name": "技术部", // 部门名称(必填) - "description": "技术研发部门", // 描述(可选) - "parentId": null, // 上级部门ID(可选) - "sort": 1, // 排序(可选) - "enabled": true, // 是否启用(可选,默认true) - "leaderId": 1, // 负责人ID(可选) - "leaderName": "张三" // 负责人姓名(可选) -} +#### 5.6 数据库版本控制 +- [x] Flyway集成 +- [x] 表结构版本管理(V1.0.0__init_schema.sql) +- [x] 初始数据管理(V1.0.1__init_data.sql) +- [x] 28个数据库表 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "id": 1, - // ... 其他字段同上 - } -} -``` +#### 5.7 其他框架功能 +- [x] 国际化支持(i18n) +- [x] JSON序列化配置 +- [x] 租户过滤器 +- [x] 逻辑删除支持(@LogicDelete) +- [x] 依赖注入后处理器 +- [x] Formily Schema生成(用于前端表单) -### 5. 角色管理API +--- -#### 5.1 分配角色标签 -```http -POST /api/v1/role/{id}/tags +## 数据库表结构(28张表) -请求参数: -{ - "tagIds": [1, 2, 3] // 标签ID列表 -} +### 系统管理表(7张) +1. `sys_tenant` - 租户表 +2. `sys_department` - 部门表 +3. `sys_user` - 用户表 +4. `sys_param` - 系统参数表 +5. `sys_role` - 角色表 +6. `sys_role_tag` - 角色标签表 +7. `sys_menu` - 菜单表 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功" -} -``` +### 权限管理表(5张) +8. `sys_role_tag_relation` - 角色标签关系表 +9. `sys_user_role` - 用户角色关系表 +10. `sys_role_menu` - 角色菜单关系表 +11. `sys_permission_template` - 权限模板表 +12. `sys_template_menu` - 模板菜单关系表 +13. `sys_permission` - 权限表 -#### 5.2 分配用户角色 -```http -POST /api/v1/role/{userId}/assignRoles +### 外部系统表(1张) +14. `sys_external_system` - 外部系统表 -请求参数: -{ - "roleIds": [1, 2, 3] // 角色ID列表 -} +### Git仓库表(3张) +15. `deploy_repo_group` - 仓库组表 +16. `deploy_repo_project` - 仓库项目表 +17. `deploy_repo_branch` - 仓库分支表 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功" -} -``` +### Jenkins表(4张) +18. Jenkins相关表(通过代码推断,未在SQL中完整展示) -#### 5.3 获取角色权限 -```http -GET /api/v1/role/{id}/permissions +### 工作流表(5张) +19. `workflow_definition` - 工作流定义表 +20. `workflow_node_definition` - 节点定义表 +21. `workflow_instance` - 工作流实例表 +22. `workflow_node_instance` - 节点实例表 +23. `workflow_log` - 工作流日志表 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": [{ - "id": 1, - "code": "system:user:view", - "name": "查看用户", - "type": "MENU", - "sort": 1, - "menuName": "用户管理" - }] -} -``` +### 部署管理表(6张) +24. `deploy_project_group` - 项目组表 +25. `deploy_application` - 应用表 +26. `deploy_environment` - 环境表 +27. `deploy_project_group_environment` - 项目组环境关系表 +28. `deploy_log` - 部署日志表 +29. `deploy_app_config` - 应用部署配置表 -#### 5.4 分配角色权限 -```http -POST /api/v1/role/{id}/permissions +--- -请求参数: -{ - "permissionIds": [1, 2, 3] // 权限ID列表 -} +## API接口统计 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功" -} -``` +### Controller统计(26个) +**系统管理(7个):** +- UserApiController +- RoleApiController +- RoleTagApiController +- PermissionApiController +- MenuApiController +- DepartmentApiController +- TenantApiController -### 6. 权限管理API +**部署管理(8个):** +- ApplicationApiController +- ProjectGroupApiController +- EnvironmentApiController +- DeployAppConfigApiController +- DeployLogApiController +- ExternalSystemApiController +- RepositoryManagerApiController +- RepositoryProjectApiController +- RepositoryGroupApiController +- RepositoryBranchApiController -#### 6.1 分页查询权限 -```http -GET /api/v1/permission/page +**Jenkins管理(5个):** +- JenkinsManagerApiController +- JenkinsViewApiController +- JenkinsJobApiController +- JenkinsBuildApiController +- JenkinsSyncHistoryApiController -请求参数: -{ - "pageNum": 1, - "pageSize": 10, - "code": "system", // 权限编码(可选) - "name": "系统", // 权限名称(可选) - "type": "MENU", // 权限类型(可选) - "enabled": true, // 是否启用(可选) - "menuId": 1 // 菜单ID(可选) -} +**工作流管理(4个):** +- WorkflowDefinitionApiController +- WorkflowNodeDefinitionApiController +- WorkflowInstanceApiController +- WorkflowNodeInstanceApiController -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "content": [{ - "id": 1, - "code": "system:user:view", - "name": "查看用户", - "type": "MENU", - "sort": 1, - "menuId": 2, - "menuName": "用户管理" - }], - "totalElements": 100, - "totalPages": 10, - "size": 10, - "number": 0, - "first": true, - "last": false, - "empty": false - } -} -``` +**接口方法统计:** +- 约49个自定义@Operation接口方法 +- 每个Controller继承BaseController,获得9个标准CRUD方法 +- **总计约280+个API接口** -#### 6.2 创建权限 -```http -POST /api/v1/permission +--- -请求参数: -{ - "code": "system:user:add", // 权限编码(必填) - "name": "新增用户", // 权限名称(必填) - "type": "BUTTON", // 权限类型(必填) - "menuId": 2, // 菜单ID(必填) - "sort": 1 // 排序(可选) -} +## 🚧 待完善功能 -响应结果: -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": { - "id": 1, - // ... 其他字段同上 - } -} -``` +### 1. 测试覆盖 +- [ ] Service层单元测试 +- [ ] Controller层集成测试 +- [ ] Repository层数据访问测试 +- [ ] 工作流引擎测试 +- **当前测试覆盖率:约1%(仅1个测试类)** -## 开发规范 +### 2. 缓存机制 +- [ ] Redis集成 +- [ ] 工作流定义缓存 +- [ ] 权限数据缓存 +- [ ] 菜单数据缓存 +- **当前状态:已引入Caffeine依赖,但未使用** -### 后端开发规范 -- 遵循DDD设计思想 -- 统一的异常处理 -- 统一的返回格式 -- 完整的单元测试 -- 详细的接口文档 -- 规范的代码注释 +### 3. 监控和运维 +- [ ] 健康检查端点完善 +- [ ] 性能监控(APM)集成 +- [ ] 日志聚合(ELK) +- [ ] 告警机制 +- [ ] 链路追踪 -详细规范请参考:[后端开发规范](.cursorrules1) +### 4. 部署和DevOps +- [ ] Docker镜像构建 +- [ ] Kubernetes部署配置 +- [ ] CI/CD Pipeline +- [ ] 环境配置分离(dev/test/prod) +- **当前配置:application.yml包含硬编码数据库密码和JWT密钥** -### 前端开发规范 -- 统一的接口调用方式 -- 统一的错误处理 -- 标准的时间格式 -- 规范的国际化实现 +### 5. 文档完善 +- [ ] API文档完善(Swagger注释) +- [ ] 架构图和流程图 +- [ ] 部署手册 +- [ ] 运维手册 +- [ ] 最佳实践指南 -详细规范请参考:[前端开发规范](frontend.rules) +### 6. 代码质量 +- [ ] 代码质量检查工具集成(Checkstyle、PMD、SonarQube) +- [ ] TODO注释处理(14处待处理) +- [ ] System.out.println清理(14处) +- [ ] 泛化异常处理优化(95处catch Exception) -## 注意事项 +### 7. 安全加固 +- [ ] 敏感配置外部化 +- [ ] JWT密钥加密存储 +- [ ] 数据库连接加密 +- [ ] API访问频率限制 +- [ ] SQL注入防护验证 +- [ ] XSS攻击防护 -### 1. 数据库 -- 所有表必须包含基础字段: - ```sql - id BIGINT PRIMARY KEY # 主键 - create_time DATETIME # 创建时间 - create_by VARCHAR(50) # 创建人 - update_time DATETIME # 更新时间 - update_by VARCHAR(50) # 更新人 - version INT # 版本号 - deleted BOOLEAN # 是否删除 - ``` -- 使用Flyway进行数据库版本控制 -- 新建表结构写入V1.0.0__init_schema.sql -- 初始数据写入V1.0.1__init_data.sql +### 8. 性能优化 +- [ ] 数据库索引优化 +- [ ] N+1查询问题排查 +- [ ] 连接池配置优化(当前仅10个) +- [ ] 大数据量分页优化 +- [ ] 异步任务处理 -### 2. 接口开发 -- 所有接口都需要JWT认证 -- 接口版本统一使用v1 -- 返回数据格式统一为: - ```json - { - "success": true, - "code": 200, - "message": "操作成功", - "data": {} - } - ``` -- 分页查询参数统一使用: - ```json - { - "pageNum": 1, - "pageSize": 10, - "sortField": "createTime", - "sortOrder": "desc" - } - ``` - -### 3. 异常处理 -- 业务异常统一使用BusinessException -- 异常码在ResponseCode中定义 -- 异常信息在messages.properties中定义 -- 所有异常都通过GlobalExceptionHandler处理 - -### 4. 安全性 -- 敏感信息(密码、Token等)需要加密存储 -- 外部系统认证信息需要加密传输 -- 定期清理过期的Token -- 限制API调用频率 - -### 5. 测试 -- 所有Service层代码必须有单元测试 -- 所有Controller必须有集成测试 -- 测试覆盖率要求80%以上 -- 测试数据使用@Sql注入,避免影响生产数据 - -## 环境要求 -- JDK 17+ -- Maven 3.8+ -- MySQL 8.0+ -- Node.js 16+ +--- ## 快速开始 -1. 克隆项目 -```bash -git clone [项目地址] +### 环境要求 +- JDK 21+ +- Maven 3.8+ +- MySQL 8.0+ +- Node.js 16+(前端) + +### 1. 数据库准备 +```sql +CREATE DATABASE `deploy-ease-platform` + DEFAULT CHARACTER SET utf8mb4 + COLLATE utf8mb4_unicode_ci; ``` -2. 配置数据库 -```bash -# 创建数据库 -CREATE DATABASE deploy_ease DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -``` - -3. 修改配置 +### 2. 配置修改 +编辑 `src/main/resources/application.yml`: ```yaml -# application.yml spring: datasource: - url: jdbc:mysql://localhost:3306/deploy_ease + url: jdbc:mysql://localhost:3306/deploy-ease-platform?... username: your_username password: your_password + +jwt: + secret: 'your_secret_key' # 建议使用环境变量 ``` -4. 启动项目 +⚠️ **安全提示:** 生产环境请使用环境变量或配置中心管理敏感信息! + +### 3. 启动项目 ```bash +# 编译项目 +mvn clean package -DskipTests + +# 启动服务 mvn spring-boot:run + +# 或直接运行 +java -jar target/deploy-cd-1.0-SNAPSHOT.jar ``` +### 4. 访问服务 +- **API文档:** http://localhost:8080/swagger-ui.html +- **健康检查:** http://localhost:8080/actuator/health + +### 5. 默认用户(需通过初始化SQL配置) +``` +用户名:admin +密码:(请查看V1.0.1__init_data.sql) +``` + +--- + +## 项目规范 + +### 代码规范 +详见项目根目录下的规范文件: +- `.cursor/rules/project.mdc` - 完整开发规范 +- `frontend.rules` - 前端开发规范 + +### 核心规范要点 + +#### 包结构 +``` +com.qqchen.deploy.backend +├── framework/ # 框架核心 +│ ├── annotation/ # 注解定义 +│ ├── controller/ # 基础控制器 +│ ├── service/ # 基础服务 +│ ├── repository/ # 基础仓库 +│ └── ... +├── system/ # 系统模块 +│ ├── api/ # REST接口 +│ ├── entity/ # 实体类 +│ ├── service/ # 业务服务 +│ └── ... +├── deploy/ # 部署模块 +└── workflow/ # 工作流模块 +``` + +#### 命名规范 +- **Entity:** 名词,如User、Role +- **DTO:** 实体名+DTO,如UserDTO +- **Service接口:** I+实体名+Service,如IUserService +- **Service实现:** 实体名+ServiceImpl,如UserServiceImpl +- **Controller:** 实体名+ApiController,如UserApiController +- **Repository:** I+实体名+Repository,如IUserRepository + +#### 注解使用 +- **@ServiceType(DATABASE)** - 数据库服务 +- **@ServiceType(INTEGRATION)** - 集成服务(禁用数据库操作) +- **@LogicDelete** - 启用逻辑删除 +- **@Audited** - 启用审计 +- **@QueryField** - 查询字段映射 + +--- + ## 贡献指南 -1. Fork 项目 -2. 创建功能分支 -3. 提交代码 -4. 创建Pull Request -## 许可证 -[MIT License](LICENSE) +### 提交规范 +``` +feat: 新功能 +fix: Bug修复 +docs: 文档更新 +style: 代码格式调整 +refactor: 重构 +perf: 性能优化 +test: 测试相关 +chore: 构建/工具变动 ``` +### 分支管理 +- `master` - 生产环境分支 +- `develop` - 开发分支 +- `feature/*` - 功能分支 +- `bugfix/*` - Bug修复分支 +- `hotfix/*` - 热修复分支 -workflow_definition(工作流定义表) -存储我们自定义的工作流定义信息 -包含流程名称、标识、版本、BPMN XML内容等 -与Flowable的act_re_procdef表是一对一的关系 -额外存储了图形编辑器的JSON数据,方便前端展示和编辑 -workflow_instance(工作流实例表) -记录工作流的执行实例信息 -存储流程实例ID、业务标识、状态、变量等 -与Flowable的act_ru_execution表是一对一的关系 -提供了更多的业务字段,如开始时间、结束时间等 -workflow_node_instance(工作流节点实例表) -记录工作流中每个节点的执行情况 -存储节点ID、名称、类型、状态等 -与Flowable的act_ru_task和act_hi_actinst表有关联 -特别记录了Shell任务的执行结果、错误信息等 -workflow_log(工作流日志表) -记录工作流执行过程中的详细日志 -可以关联到具体的实例和节点 -包含日志类型、级别、内容等 -方便排查问题和审计 -这些表与Flowable的原生表的主要区别是: +--- -更贴近业务需求,字段设计更符合我们的使用场景 -提供了更丰富的元数据和状态信息 -支持更细粒度的日志记录 -可以存储自定义的业务数据 -这样的设计让我们可以在使用Flowable强大的工作流引擎的同时,也能满足特定的业务需求。 +## 许可证 +MIT License +--- -{ - "name": "Simple Shell Workflow6", - "key": "simple_shell_workflow", - "description": "A simple workflow with shell task", - "graphJson": { - "cells": [ - { - "id": "start", - "shape": "start", - "data": { - "label": "开始" - }, - "position": { - "x": 100, - "y": 100 - } - }, - { - "id": "shell", - "shape": "serviceTask", - "data": { - "label": "Shell脚本", - "serviceTask": { - "type": "shell", - "implementation": "${shellTaskDelegate}", - "fields": { - "script": "timeout 10000000", - "workDir": "/tmp", - "env": { - "TEST_VAR": "test_value" - } - } - } - }, - "position": { - "x": 300, - "y": 100 - } - }, - { - "id": "shellErrorBoundary", - "shape": "boundaryEvent", - "data": { - "label": "Shell错误", - "boundaryEvent": { - "type": "error", - "attachedToRef": "shell", - "errorRef": "SHELL_EXECUTION_ERROR" - } - }, - "position": { - "x": 300, - "y": 160 - } - }, - { - "id": "errorHandler", - "shape": "serviceTask", - "data": { - "label": "错误处理", - "serviceTask": { - "type": "service", - "implementation": "${errorHandlerDelegate}" - } - }, - "position": { - "x": 300, - "y": 220 - } - }, - { - "id": "end", - "shape": "end", - "data": { - "label": "结束" - }, - "position": { - "x": 500, - "y": 100 - } - }, - { - "id": "flow1", - "shape": "edge", - "source": "start", - "target": "shell", - "data": { - "label": "流转到Shell" - } - }, - { - "id": "flow2", - "shape": "edge", - "source": "shell", - "target": "end", - "data": { - "label": "完成" - } - }, - { - "id": "flow_error", - "shape": "edge", - "source": "shellErrorBoundary", - "target": "errorHandler", - "data": { - "label": "错误处理" - } - }, - { - "id": "flow_error_end", - "shape": "edge", - "source": "errorHandler", - "target": "end", - "data": { - "label": "处理完成" - } - } - ] - } -} +## 联系方式 +项目维护者:Deploy Ease Team -死信队列的问题: -需要再异常里直接移除: -runtimeService.deleteProcessInstance(processInstanceId, errorMessage); +--- -const eventSource = new EventSource(`/api/v1/shell-logs/${processInstanceId}`); +## 更新日志 -eventSource.addEventListener('STDOUT', (event) => { - console.log('Output:', event.data); -}); +### v1.0.0(当前版本) +- ✅ 完成系统管理核心功能 +- ✅ 完成Jenkins和Git集成 +- ✅ 完成工作流引擎基础功能 +- ✅ 完成部署管理框架 +- ✅ 完成28张数据库表设计 +- ✅ 完成280+个API接口 +- ⚠️ 测试覆盖率待提升 +- ⚠️ 缓存机制待实现 +- ⚠️ 生产环境配置待优化 -eventSource.addEventListener('STDERR', (event) => { - console.error('Error:', event.data); -}); +--- -// 当流程结束时关闭连接 -eventSource.onerror = () => { - eventSource.close(); -}; - -SELECT - hi.PROC_INST_ID_ as process_instance_id, - hi.PROC_DEF_ID_ as process_definition_id, - hi.START_TIME_ as start_time, - hi.END_TIME_ as end_time, - hi.DELETE_REASON_ as delete_reason, - -- 使用 GROUP_CONCAT 合并错误信息 - GROUP_CONCAT(DISTINCT - CASE - WHEN var.NAME_ = 'errorDetail' THEN var.TEXT_ - WHEN var.NAME_ IN ('errorMessage', 'error', 'exception') THEN var.TEXT_ - END - SEPARATOR '; ' - ) as error_message, - -- 获取最后一个活动节点 - MAX(CASE WHEN act.END_TIME_ IS NULL THEN act.ACT_NAME_ END) as last_activity_name, - MAX(CASE WHEN act.END_TIME_ IS NULL THEN act.ACT_ID_ END) as last_activity_id -FROM - ACT_HI_PROCINST hi -LEFT JOIN - ACT_HI_VARINST var ON hi.PROC_INST_ID_ = var.PROC_INST_ID_ -LEFT JOIN - ACT_HI_ACTINST act ON hi.PROC_INST_ID_ = act.PROC_INST_ID_ -WHERE - hi.PROC_INST_ID_ = '86faae44-bc47-11ef-a4cd-00155dcaffac' - AND ( - var.NAME_ IN ('errorDetail', 'errorMessage', 'error', 'exception') - OR var.TEXT_ LIKE '%error%' - OR var.TEXT_ LIKE '%exception%' - OR var.TEXT_ LIKE '%失败%' - ) -GROUP BY - hi.PROC_INST_ID_, - hi.PROC_DEF_ID_, - hi.START_TIME_, - hi.END_TIME_, - hi.DELETE_REASON_ -ORDER BY - hi.START_TIME_ DESC; \ No newline at end of file +**注意事项:** +1. 本项目处于开发阶段,部分功能仍在完善中 +2. 生产环境使用前请务必完成安全加固 +3. 建议补充完整的单元测试和集成测试 +4. 数据库配置和JWT密钥需要外部化管理 +5. 建议集成专业的日志分析和监控方案 diff --git a/frontend/src/pages/Workflow/Definition/types.ts b/frontend/src/pages/Workflow/Definition/types.ts index 3525fbc9..451fbe02 100644 --- a/frontend/src/pages/Workflow/Definition/types.ts +++ b/frontend/src/pages/Workflow/Definition/types.ts @@ -39,13 +39,22 @@ export interface WorkflowDefinition extends BaseResponse { } export interface WorkflowDefinitionNode { - id: number; + id: number | string; // 支持数字或UUID字符串 nodeCode: string; nodeType: string; nodeName: string; - uiVariables: JSON; - panelVariables: JSON; - localVariables: JSON; + position?: { x: number; y: number }; // 节点位置 + configs?: Record; // 基本配置 + inputMapping?: Record; // 输入映射 + outputs?: Array<{ // 输出能力定义 + name: string; + title: string; + type: 'string' | 'number' | 'boolean' | 'object' | 'array'; // 与 OutputField 保持一致 + description: string; + enum?: string[]; + example?: any; + required?: boolean; + }>; } export interface WorkflowDefinitionQuery extends BaseQuery { diff --git a/frontend/src/pages/Workflow/Design/components/NodeConfigModal.tsx b/frontend/src/pages/Workflow/Design/components/NodeConfigModal.tsx index c60e239d..9cf04e27 100644 --- a/frontend/src/pages/Workflow/Design/components/NodeConfigModal.tsx +++ b/frontend/src/pages/Workflow/Design/components/NodeConfigModal.tsx @@ -46,7 +46,6 @@ const NodeConfigModal: React.FC = ({ // 创建Formily表单实例 const configForm = useMemo(() => createForm(), []); const inputForm = useMemo(() => createForm(), []); - const outputForm = useMemo(() => createForm(), []); // 初始化表单数据 useEffect(() => { @@ -67,12 +66,9 @@ const NodeConfigModal: React.FC = ({ if (isConfigurableNode(nodeDefinition)) { inputForm.setInitialValues(nodeData.inputMapping || {}); inputForm.reset(); - - outputForm.setInitialValues(nodeData.outputMapping || {}); - outputForm.reset(); } } - }, [visible, node, nodeDefinition, configForm, inputForm, outputForm]); + }, [visible, node, nodeDefinition, configForm, inputForm]); // 递归处理表单值,将JSON字符串转换为对象 const processFormValues = (values: Record, schema: ISchema | undefined): Record => { @@ -109,15 +105,13 @@ const NodeConfigModal: React.FC = ({ const inputMapping = isConfigurableNode(nodeDefinition) ? processFormValues(inputForm.values, nodeDefinition.inputMappingSchema) : {}; - const outputMapping = isConfigurableNode(nodeDefinition) - ? processFormValues(outputForm.values, nodeDefinition.outputMappingSchema) - : {}; const updatedData: Partial = { label: configs.nodeName || node.data.label, configs, inputMapping, - outputMapping, + // outputs 保留原值(不修改,因为它是只读的输出能力定义) + outputs: node.data.outputs || [], }; onOk(node.id, updatedData); @@ -142,7 +136,6 @@ const NodeConfigModal: React.FC = ({ const handleReset = () => { configForm.reset(); inputForm.reset(); - outputForm.reset(); toast({ title: "已重置", description: "表单已重置为初始值", @@ -313,18 +306,55 @@ const NodeConfigModal: React.FC = ({ )} - {/* 输出映射 - 条件显示 */} - {isConfigurableNode(nodeDefinition) && nodeDefinition.outputMappingSchema && ( + {/* 输出能力 - 只读展示 */} + {isConfigurableNode(nodeDefinition) && nodeDefinition.outputs && nodeDefinition.outputs.length > 0 && ( - 输出映射 + 输出能力 - - - - - +
+ 💡 此节点执行后会产生以下数据,下游节点可以通过 {'${upstream.字段名}'} 引用这些数据 +
+
+ {nodeDefinition.outputs.map((output) => ( +
+
+
+
+ {output.title} + {output.name} + + {output.type} + + {output.required && ( + * + )} +
+

+ {output.description} +

+
+
+ {output.enum && ( +
+ 可选值: + {output.enum.join(', ')} +
+ )} + {output.example !== undefined && ( +
+ 示例: + + {typeof output.example === 'object' + ? JSON.stringify(output.example) + : String(output.example)} + +
+ )} +
+ ))} +
)} diff --git a/frontend/src/pages/Workflow/Design/hooks/useWorkflowLoad.ts b/frontend/src/pages/Workflow/Design/hooks/useWorkflowLoad.ts index 17b684fa..6fbe54a1 100644 --- a/frontend/src/pages/Workflow/Design/hooks/useWorkflowLoad.ts +++ b/frontend/src/pages/Workflow/Design/hooks/useWorkflowLoad.ts @@ -8,7 +8,7 @@ import { NODE_DEFINITIONS, NodeType, getNodeCategory } from '../nodes'; interface LoadedWorkflowData { nodes: FlowNode[]; edges: FlowEdge[]; - definition: WorkflowDefinition; + definition: WorkflowDefinition | null; } export const useWorkflowLoad = () => { @@ -49,7 +49,7 @@ export const useWorkflowLoad = () => { color: nodeDefinition?.renderConfig.theme.primary || getNodeColor(node.nodeType), configs: node.configs || {}, inputMapping: node.inputMapping || {}, - outputMapping: node.outputMapping || {}, + outputs: node.outputs || [], // ✅ 从后端加载的输出能力定义 // 添加节点定义引用,用于配置弹窗 nodeDefinition }, @@ -168,40 +168,6 @@ export const useWorkflowLoad = () => { } }, [convertToFlowFormat]); - // 创建新的空白工作流 - const createNewWorkflow = useCallback((): LoadedWorkflowData => { - const emptyDefinition: WorkflowDefinition = { - id: 0, - createTime: null, - createBy: null, - updateTime: null, - updateBy: null, - version: 1, - deleted: false, - extraData: null, - name: '新建工作流', - key: `workflow_${Date.now()}`, - description: '', - category: 'GENERAL', - triggers: [], - flowVersion: 1, - bpmnXml: null, - status: 'DRAFT', - graph: { - nodes: [], - edges: [] - } - }; - - setWorkflowDefinition(emptyDefinition); - - return { - nodes: [], - edges: [], - definition: emptyDefinition - }; - }, []); - // 重置加载状态 const resetLoad = useCallback(() => { setWorkflowDefinition(null); @@ -212,7 +178,6 @@ export const useWorkflowLoad = () => { loading, workflowDefinition, loadWorkflow, - createNewWorkflow, resetLoad }; }; diff --git a/frontend/src/pages/Workflow/Design/hooks/useWorkflowSave.ts b/frontend/src/pages/Workflow/Design/hooks/useWorkflowSave.ts index b2f66863..259ecda6 100644 --- a/frontend/src/pages/Workflow/Design/hooks/useWorkflowSave.ts +++ b/frontend/src/pages/Workflow/Design/hooks/useWorkflowSave.ts @@ -3,6 +3,7 @@ import { message } from 'antd'; import * as definitionService from '../../Definition/service'; import type { FlowNode, FlowEdge } from '../types'; import { NodeType } from '../types'; +import { isConfigurableNode } from '../nodes/types'; interface WorkflowSaveData { nodes: FlowNode[]; @@ -58,8 +59,8 @@ export const useWorkflowSave = () => { // 转换节点和边数据为后端格式 const graph = { nodes: data.nodes.map(node => ({ - id: node.id, // 使用React Flow的节点ID - nodeCode: node.id, // nodeCode与ID相同 + id: node.id, // 使用React Flow的节点ID(UUID) + nodeCode: node.data.configs?.nodeCode || node.data.nodeType, // ✅ 使用预定义的 nodeCode(如 "START_EVENT") nodeType: node.data.nodeType, nodeName: node.data.label, position: { @@ -68,7 +69,9 @@ export const useWorkflowSave = () => { }, configs: node.data.configs || {}, inputMapping: node.data.inputMapping || {}, - outputMapping: node.data.outputMapping || {} + outputs: (node.data.nodeDefinition && isConfigurableNode(node.data.nodeDefinition)) + ? node.data.nodeDefinition.outputs || [] + : [] // ✅ 输出能力定义(直接从节点定义中获取) })), edges: data.edges.map(edge => ({ id: edge.id, @@ -83,28 +86,14 @@ export const useWorkflowSave = () => { })) }; - // 构建保存数据 - 完全模仿原始系统的逻辑 - const workflowData = data.definitionData - ? { - // 如果有原始定义数据,展开它并覆盖 graph - ...data.definitionData, - graph - } - : { - // 如果没有原始定义数据,创建新的工作流 - name: data.name || '新建工作流', - description: data.description || '', - key: `workflow_${Date.now()}`, - category: 'GENERAL', - triggers: [], - flowVersion: 1, - bpmnXml: null, - status: 'DRAFT', - graph - }; + // ✅ 透传模式:只传递业务字段,更新 graph + const workflowData = { + ...data.definitionData, // 透传原始数据 + graph // 只覆盖 graph 字段 + }; - // 无论新建还是更新,都调用 saveDefinition (POST 请求) - await definitionService.saveDefinition(workflowData as any); + // 只有更新操作(外层列表已创建草稿,这里只更新) + await definitionService.updateDefinition(data.workflowId!, workflowData as any); message.success('工作流保存成功'); setLastSaved(new Date()); diff --git a/frontend/src/pages/Workflow/Design/index.tsx b/frontend/src/pages/Workflow/Design/index.tsx index 9cd9e5cf..dc16b625 100644 --- a/frontend/src/pages/Workflow/Design/index.tsx +++ b/frontend/src/pages/Workflow/Design/index.tsx @@ -11,6 +11,7 @@ import NodeConfigModal from './components/NodeConfigModal'; import EdgeConfigModal, { type EdgeCondition } from './components/EdgeConfigModal'; import type { FlowNode, FlowEdge, FlowNodeData } from './types'; import type { WorkflowNodeDefinition } from './nodes/types'; +import { isConfigurableNode } from './nodes/types'; import { useWorkflowSave } from './hooks/useWorkflowSave'; import { useWorkflowLoad } from './hooks/useWorkflowLoad'; import { useHistory } from './hooks/useHistory'; @@ -302,7 +303,7 @@ const WorkflowDesignInner: React.FC = () => { description: nodeDefinition.description }, inputMapping: {}, - outputMapping: {} + outputs: isConfigurableNode(nodeDefinition) ? nodeDefinition.outputs || [] : [] // ✅ 从节点定义中获取输出能力 } }; diff --git a/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx b/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx index 5a53c146..2e99aed7 100644 --- a/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx +++ b/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx @@ -71,40 +71,58 @@ export const JenkinsBuildNodeDefinition: ConfigurableNodeDefinition = { }, required: ["nodeName", "nodeCode", "jenkinsUrl"] }, - // 输出映射Schema - outputMappingSchema: { - type: "object", - title: "输出映射", - description: "传递给下游节点的数据映射配置", - properties: { - buildId: { - type: "string", - title: "构建ID", - description: "Jenkins构建的唯一标识符", - default: "${jenkins.buildNumber}" - }, - buildStatus: { - type: "string", - title: "构建状态", - description: "构建完成状态", - enum: ["SUCCESS", "FAILURE", "UNSTABLE", "ABORTED", "NOT_BUILT"], - default: "SUCCESS" - }, - buildUrl: { - type: "string", - title: "构建URL", - description: "Jenkins构建页面的URL", - default: "${jenkins.buildUrl}" - }, - buildDuration: { - type: "number", - title: "构建耗时", - description: "构建耗时(毫秒)", - default: 0 - } + // ✅ 输出能力定义(只读展示,传递给后端) + outputs: [ + { + name: "buildNumber", + title: "构建编号", + type: "number", + description: "Jenkins构建的唯一编号", + example: 123, + required: true }, - required: ["buildId", "buildStatus", "buildUrl"] - } + { + name: "buildStatus", + title: "构建状态", + type: "string", + enum: ["SUCCESS", "FAILURE", "UNSTABLE", "ABORTED"], + description: "构建执行的结果状态", + example: "SUCCESS", + required: true + }, + { + name: "buildUrl", + title: "构建URL", + type: "string", + description: "Jenkins构建页面的访问地址", + example: "http://jenkins.example.com/job/app/123/", + required: true + }, + { + name: "artifactUrl", + title: "构建产物地址", + type: "string", + description: "构建生成的jar/war包下载地址", + example: "http://jenkins.example.com/job/app/123/artifact/target/app-1.0.0.jar", + required: false + }, + { + name: "gitCommitId", + title: "Git提交ID", + type: "string", + description: "本次构建使用的Git提交哈希值", + example: "a3f5e8d2c4b1a5e9f2d3e7b8c9d1a2f3e4b5c6d7", + required: true + }, + { + name: "buildDuration", + title: "构建时长", + type: "number", + description: "构建执行的时长(秒)", + example: 120, + required: true + } + ] }; // ✅ 不再需要单独的渲染组件,使用 BaseNode 即可 diff --git a/frontend/src/pages/Workflow/Design/nodes/types.ts b/frontend/src/pages/Workflow/Design/nodes/types.ts index f20b8010..41194539 100644 --- a/frontend/src/pages/Workflow/Design/nodes/types.ts +++ b/frontend/src/pages/Workflow/Design/nodes/types.ts @@ -47,6 +47,22 @@ export const getNodeCategory = (nodeType: NodeType | string): NodeCategory => { import type { ISchema } from '@formily/react'; export type JSONSchema = ISchema; +// ========== 输出字段定义 ========== + +/** + * 输出字段定义 - 描述节点执行后产生的数据 + * 用于在节点配置面板中展示,供下游节点引用 + */ +export interface OutputField { + name: string; // 字段名(用于表达式引用 ${upstream.buildNumber}) + title: string; // 显示名称 + description: string; // 详细说明 + type: 'string' | 'number' | 'boolean' | 'object' | 'array'; // 数据类型 + enum?: string[]; // 枚举值(可选) + example?: any; // 示例值 + required?: boolean; // 是否必定产生(默认 true) +} + // ========== 渲染配置(配置驱动节点渲染) ========== // 节点尺寸 @@ -107,10 +123,10 @@ export interface BaseNodeDefinition { configSchema: JSONSchema; // 基本配置Schema(包含基本信息+节点配置) } -// 可配置节点定义(有3个TAB:基本配置、输入、输出) +// 可配置节点定义(有3个面板:基本配置、输入映射、输出能力) export interface ConfigurableNodeDefinition extends BaseNodeDefinition { - inputMappingSchema?: JSONSchema; // 输入映射的Schema定义 - outputMappingSchema?: JSONSchema; // 输出映射的Schema定义 + inputMappingSchema?: JSONSchema; // 输入映射的Schema定义(用户配置) + outputs?: OutputField[]; // 输出能力定义(只读展示) } // 工作流节点定义(联合类型) @@ -124,10 +140,10 @@ export interface NodeInstanceData { category: NodeCategory; description?: string; - // 运行时数据(key/value格式) + // 运行时数据 configs?: Record; // 基本配置数据(包含基本信息+节点配置) - inputMapping?: Record; - outputMapping?: Record; + inputMapping?: Record; // 输入映射(用户配置) + outputs?: OutputField[]; // 输出能力定义(从节点定义中获取) // UI位置信息 position: { x: number; y: number }; @@ -135,5 +151,5 @@ export interface NodeInstanceData { // 判断是否为可配置节点 export const isConfigurableNode = (def: WorkflowNodeDefinition): def is ConfigurableNodeDefinition => { - return 'inputMappingSchema' in def || 'outputMappingSchema' in def; + return 'inputMappingSchema' in def || 'outputs' in def; }; diff --git a/frontend/src/pages/Workflow/Design/types.ts b/frontend/src/pages/Workflow/Design/types.ts index 84d61efc..4c8e7fd4 100644 --- a/frontend/src/pages/Workflow/Design/types.ts +++ b/frontend/src/pages/Workflow/Design/types.ts @@ -41,10 +41,10 @@ export interface FlowNodeData extends Record { icon: string; color: string; - // 运行时数据(与原系统兼容的格式) + // 运行时数据 configs?: Record; // 基本配置数据(包含基本信息+节点配置) - inputMapping?: Record; // 输入参数映射 - outputMapping?: Record; // 输出参数映射 + inputMapping?: Record; // 输入映射(用户配置) + outputs?: import('./nodes/types').OutputField[]; // 输出能力定义(从节点定义中获取) // 原始节点定义(使用新的节点定义接口) nodeDefinition?: import('./nodes/types').WorkflowNodeDefinition;