diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/DeployApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/DeployApiController.java index 2f4d0a53..53cc8439 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/DeployApiController.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/DeployApiController.java @@ -1,5 +1,7 @@ package com.qqchen.deploy.backend.deploy.api; +import com.qqchen.deploy.backend.deploy.dto.DeployRequestDTO; +import com.qqchen.deploy.backend.deploy.dto.DeployResultDTO; import com.qqchen.deploy.backend.deploy.dto.UserDeployableDTO; import com.qqchen.deploy.backend.deploy.service.IDeployService; import com.qqchen.deploy.backend.framework.api.Response; @@ -8,9 +10,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + /** * 部署管理API控制器 @@ -36,5 +38,15 @@ public class DeployApiController { public Response getDeployableEnvironments() { return Response.success(deployService.getDeployableEnvironments()); } + + /** + * 执行部署 + */ + @Operation(summary = "执行部署", description = "根据团队应用配置启动部署工作流") + @PostMapping("/execute") + @PreAuthorize("isAuthenticated()") + public Response executeDeploy(@Validated @RequestBody DeployRequestDTO request) { + return Response.success(deployService.executeDeploy(request)); + } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployRequestDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployRequestDTO.java new file mode 100644 index 00000000..e5220f5d --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployRequestDTO.java @@ -0,0 +1,24 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 部署请求DTO + * + * @author qqchen + * @since 2025-11-02 + */ +@Data +@Schema(description = "部署请求") +public class DeployRequestDTO { + + @Schema(description = "团队应用关联ID", required = true) + @NotNull(message = "团队应用关联ID不能为空") + private Long teamApplicationId; + + @Schema(description = "部署备注") + private String remark; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployResultDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployResultDTO.java new file mode 100644 index 00000000..78637e62 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployResultDTO.java @@ -0,0 +1,31 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 部署结果DTO + * + * @author qqchen + * @since 2025-11-02 + */ +@Data +@Schema(description = "部署结果") +public class DeployResultDTO { + + @Schema(description = "工作流实例ID") + private Long workflowInstanceId; + + @Schema(description = "业务标识") + private String businessKey; + + @Schema(description = "流程实例ID") + private String processInstanceId; + + @Schema(description = "部署状态") + private String status; + + @Schema(description = "提示信息") + private String message; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IDeployService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IDeployService.java index a699359d..2ee5f964 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IDeployService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IDeployService.java @@ -1,5 +1,7 @@ package com.qqchen.deploy.backend.deploy.service; +import com.qqchen.deploy.backend.deploy.dto.DeployRequestDTO; +import com.qqchen.deploy.backend.deploy.dto.DeployResultDTO; import com.qqchen.deploy.backend.deploy.dto.UserDeployableDTO; /** @@ -16,5 +18,13 @@ public interface IDeployService { * @return 用户可部署环境信息 */ UserDeployableDTO getDeployableEnvironments(); + + /** + * 执行部署 + * + * @param request 部署请求 + * @return 部署结果 + */ + DeployResultDTO executeDeploy(DeployRequestDTO request); } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployServiceImpl.java index ec41d338..635ed809 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployServiceImpl.java @@ -5,10 +5,17 @@ import com.qqchen.deploy.backend.deploy.entity.*; import com.qqchen.deploy.backend.deploy.repository.*; import com.qqchen.deploy.backend.deploy.service.IDeployService; import com.qqchen.deploy.backend.framework.security.SecurityUtils; +import com.qqchen.deploy.backend.framework.enums.ResponseCode; +import com.qqchen.deploy.backend.framework.exception.BusinessException; import com.qqchen.deploy.backend.system.entity.User; import com.qqchen.deploy.backend.system.repository.IUserRepository; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO; +import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceStartRequest; +import com.qqchen.deploy.backend.workflow.dto.inputmapping.JenkinsBuildInputMapping; import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition; import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository; +import com.qqchen.deploy.backend.workflow.service.IWorkflowInstanceService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -56,6 +63,12 @@ public class DeployServiceImpl implements IDeployService { @Resource private IWorkflowDefinitionRepository workflowDefinitionRepository; + @Resource + private IWorkflowInstanceService workflowInstanceService; + + @Resource + private ObjectMapper objectMapper; + @Override @Transactional(readOnly = true) public UserDeployableDTO getDeployableEnvironments() { @@ -388,5 +401,80 @@ public class DeployServiceImpl implements IDeployService { return dto; } + + @Override + @Transactional + public DeployResultDTO executeDeploy(DeployRequestDTO request) { + // 1. 查询团队应用配置 + TeamApplication teamApp = teamApplicationRepository.findById(request.getTeamApplicationId()) + .orElseThrow(() -> new BusinessException(ResponseCode.NOT_FOUND)); + + // 2. 查询工作流定义(获取 processKey) + WorkflowDefinition workflowDefinition = workflowDefinitionRepository.findById(teamApp.getWorkflowDefinitionId()) + .orElseThrow(() -> new BusinessException(ResponseCode.NOT_FOUND, new Object[]{"工作流定义"})); + + // 3. 查询应用信息 + Application application = applicationRepository.findById(teamApp.getApplicationId()) + .orElseThrow(() -> new BusinessException(ResponseCode.NOT_FOUND, new Object[]{"应用"})); + + // 4. 查询环境信息 + Environment environment = environmentRepository.findById(teamApp.getEnvironmentId()) + .orElseThrow(() -> new BusinessException(ResponseCode.NOT_FOUND, new Object[]{"环境"})); + + // 5. 生成业务标识(UUID) + String businessKey = UUID.randomUUID().toString(); + + // 6. 构造流程变量 + Map variables = new HashMap<>(); + + // 部署上下文 + Map deployContext = new HashMap<>(); + deployContext.put("teamApplicationId", teamApp.getId()); + deployContext.put("teamId", teamApp.getTeamId()); + deployContext.put("applicationId", teamApp.getApplicationId()); + deployContext.put("applicationCode", application.getAppCode()); + deployContext.put("applicationName", application.getAppName()); + deployContext.put("environmentId", teamApp.getEnvironmentId()); + deployContext.put("environmentCode", environment.getEnvCode()); + deployContext.put("environmentName", environment.getEnvName()); + deployContext.put("by", SecurityUtils.getCurrentUsername()); + deployContext.put("remark", request.getRemark()); + variables.put("deploy", deployContext); + + // Jenkins 配置(使用强类型 JenkinsBuildInputMapping) + if (teamApp.getDeploySystemId() != null && teamApp.getDeployJob() != null) { + JenkinsBuildInputMapping jenkinsInput = new JenkinsBuildInputMapping(); + jenkinsInput.setServerId(teamApp.getDeploySystemId()); + jenkinsInput.setJobName(teamApp.getDeployJob()); + if (teamApp.getBranch() != null) { + jenkinsInput.setBranch(teamApp.getBranch()); + } + + // 转换为 Map(Flowable 只支持基本类型) + variables.put("jenkins", objectMapper.convertValue(jenkinsInput, Map.class)); + } + + // 7. 构造工作流启动请求 + WorkflowInstanceStartRequest workflowRequest = new WorkflowInstanceStartRequest(); + workflowRequest.setProcessKey(workflowDefinition.getKey()); + workflowRequest.setBusinessKey(businessKey); + workflowRequest.setVariables(variables); + + // 8. 启动工作流 + WorkflowInstanceDTO workflowInstance = workflowInstanceService.startWorkflow(workflowRequest); + + log.info("部署流程已启动: businessKey={}, workflowInstanceId={}, application={}, environment={}", + businessKey, workflowInstance.getId(), application.getAppCode(), environment.getEnvCode()); + + // 9. 返回结果 + DeployResultDTO result = new DeployResultDTO(); + result.setWorkflowInstanceId(workflowInstance.getId()); + result.setBusinessKey(businessKey); + result.setProcessInstanceId(workflowInstance.getProcessInstanceId()); + result.setStatus(workflowInstance.getStatus().name()); + result.setMessage("部署流程已启动"); + + return result; + } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/BaseNodeDelegate.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/BaseNodeDelegate.java index 12983128..a4253192 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/BaseNodeDelegate.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/BaseNodeDelegate.java @@ -183,6 +183,8 @@ public abstract class BaseNodeDelegate implements JavaDelegate { */ protected Map resolveExpressions(Map inputMap, DelegateExecution execution) { Map resolvedMap = new HashMap<>(); + + log.debug("开始解析 inputMap: {}", inputMap); for (Map.Entry entry : inputMap.entrySet()) { Object value = entry.getValue(); @@ -193,9 +195,10 @@ public abstract class BaseNodeDelegate implements JavaDelegate { try { // 使用简单的变量替换:${sid_xxx.fieldName} -> 从execution中获取 String resolvedValue = resolveVariableExpression(strValue, execution); + log.debug("解析表达式: {} = {} -> {}", entry.getKey(), strValue, resolvedValue); resolvedMap.put(entry.getKey(), resolvedValue); } catch (Exception e) { - log.warn("Failed to resolve expression: {}, using original value", strValue); + log.warn("Failed to resolve expression: {}, using original value", strValue, e); resolvedMap.put(entry.getKey(), value); } } else { @@ -205,7 +208,8 @@ public abstract class BaseNodeDelegate implements JavaDelegate { resolvedMap.put(entry.getKey(), value); } } - + + log.debug("解析后 resolvedMap: {}", resolvedMap); return resolvedMap; } @@ -239,20 +243,28 @@ public abstract class BaseNodeDelegate implements JavaDelegate { */ private Object resolveVariable(String varExpression, DelegateExecution execution) { String[] parts = varExpression.split("\\.", 2); + + log.debug("解析变量表达式: {}, parts: {}", varExpression, java.util.Arrays.toString(parts)); if (parts.length == 1) { // 直接变量:${xxx} - return execution.getVariable(parts[0]); + Object result = execution.getVariable(parts[0]); + log.debug("直接变量 {} = {}", parts[0], result); + return result; } else { - // 对象属性:${sid_xxx.buildNumber} + // 对象属性:${sid_xxx.buildNumber} 或 ${jenkins.systemId} String varName = parts[0]; String fieldName = parts[1]; Object varValue = execution.getVariable(varName); + log.debug("获取变量 {} = {}, 类型: {}", varName, varValue, varValue != null ? varValue.getClass().getName() : "null"); + if (varValue instanceof Map) { @SuppressWarnings("unchecked") Map map = (Map) varValue; - return map.get(fieldName); + Object fieldValue = map.get(fieldName); + log.debug("从 Map 中获取字段 {} = {}", fieldName, fieldValue); + return fieldValue; } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/JenkinsBuildDelegate.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/JenkinsBuildDelegate.java index 0cfcc457..143fd2fe 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/JenkinsBuildDelegate.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/JenkinsBuildDelegate.java @@ -23,7 +23,7 @@ import java.util.Map; /** * Jenkins构建任务委派 - * + * * @author qqchen * @since 2025-10-22 */ @@ -41,36 +41,34 @@ public class JenkinsBuildDelegate extends BaseNodeDelegate configs, - JenkinsBuildInputMapping input - ) { - log.info("Jenkins Build - serverId: {}, jobName: {}", - input.getJenkinsServerId(), input.getProject()); + protected JenkinsBuildOutputs executeInternal(DelegateExecution execution, Map configs, JenkinsBuildInputMapping input) { + log.info("Jenkins Build - serverId: {}, jobName: {}", input.getServerId(), input.getJobName()); // 1. 获取外部系统 - ExternalSystem externalSystem = externalSystemRepository.findById(input.getJenkinsServerId().longValue()) - .orElseThrow(() -> new RuntimeException("Jenkins服务器不存在: " + input.getJenkinsServerId())); - - String jobName = input.getProject(); - + ExternalSystem externalSystem = externalSystemRepository.findById(input.getServerId()) + .orElseThrow(() -> new RuntimeException("Jenkins服务器不存在: " + input.getServerId())); + + String jobName = input.getJobName(); + // 2. 触发构建 Map parameters = new HashMap<>(); // 可以根据需要添加构建参数 // parameters.put("BRANCH", "main"); - + String queueId = jenkinsServiceIntegration.buildWithParameters( externalSystem, jobName, parameters); - + // 3. 等待构建从队列中开始 JenkinsQueueBuildInfoResponse buildInfo = waitForBuildToStart(queueId); - + // 4. 轮询构建状态直到完成 // 注意:如果构建失败或被取消,pollBuildStatus 会抛出 BpmnError,触发错误边界事件 // 只有成功时才会返回到这里 @@ -80,23 +78,23 @@ public class JenkinsBuildDelegate extends BaseNodeDelegate new RuntimeException("Workflow definition not found: " + request.getProcessKey())); // 2. 获取流程变量(如果没有则使用空 Map) - Map variables = request.getVariables() != null ? request.getVariables() : new HashMap<>(); // 3. 启动 Flowable 流程 ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder() .processDefinitionKey(request.getProcessKey()) - .variables(variables) + .variables(request.getVariables()) .businessKey(request.getBusinessKey()) .startAsync(); // 异步启动,会自动执行任务 diff --git a/backend/src/main/resources/db/changelog/changes/v1.0.0-schema.sql b/backend/src/main/resources/db/changelog/changes/v1.0.0-schema.sql index a72c82a3..9460975a 100644 --- a/backend/src/main/resources/db/changelog/changes/v1.0.0-schema.sql +++ b/backend/src/main/resources/db/changelog/changes/v1.0.0-schema.sql @@ -5,23 +5,23 @@ -- 租户表 CREATE TABLE sys_tenant ( - id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', - create_by VARCHAR(255) NULL COMMENT '创建人', - create_time DATETIME(6) NULL COMMENT '创建时间', + 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 '更新时间', + update_by VARCHAR(255) NULL COMMENT '更新人', + update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', code VARCHAR(50) NOT NULL COMMENT '租户编码', - name VARCHAR(100) NOT NULL COMMENT '租户名称', - address VARCHAR(255) NULL COMMENT '租户地址', - contact_name VARCHAR(50) NULL COMMENT '联系人姓名', - contact_phone VARCHAR(20) NULL COMMENT '联系人电话', - email VARCHAR(100) NULL COMMENT '联系人邮箱', + name VARCHAR(100) NOT NULL COMMENT '租户名称', + address VARCHAR(255) NULL COMMENT '租户地址', + contact_name VARCHAR(50) NULL COMMENT '联系人姓名', + contact_phone VARCHAR(20) NULL COMMENT '联系人电话', + email VARCHAR(100) NULL COMMENT '联系人邮箱', enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用(0:禁用,1:启用)', - CONSTRAINT UK_tenant_code UNIQUE (code) + CONSTRAINT UK_tenant_code UNIQUE (code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='租户表'; @@ -64,10 +64,10 @@ CREATE TABLE sys_user nickname VARCHAR(50) NULL COMMENT '昵称', email VARCHAR(100) NULL COMMENT '邮箱', phone VARCHAR(20) NULL COMMENT '手机号', - department_id BIGINT NULL COMMENT '所属部门ID', + department_id BIGINT NULL COMMENT '所属部门ID', enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用(0:禁用,1:启用)', - CONSTRAINT UK_user_username UNIQUE (username), + CONSTRAINT UK_user_username UNIQUE (username), CONSTRAINT FK_user_department FOREIGN KEY (department_id) REFERENCES sys_department (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表'; @@ -249,7 +249,7 @@ CREATE TABLE sys_role_permission ( role_id BIGINT NOT NULL COMMENT '角色ID', permission_id BIGINT NOT NULL COMMENT '权限ID', - + PRIMARY KEY (role_id, permission_id), CONSTRAINT FK_role_permission_role FOREIGN KEY (role_id) REFERENCES sys_role (id), CONSTRAINT FK_role_permission_permission FOREIGN KEY (permission_id) REFERENCES sys_permission (id) @@ -387,23 +387,23 @@ CREATE TABLE deploy_repo_branch -- 工作流分类表 CREATE TABLE workflow_category ( - -- 主键 + -- 主键 id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', - -- 基础信息 + -- 基础信息 name VARCHAR(100) NOT NULL COMMENT '分类名称', code VARCHAR(50) NOT NULL COMMENT '分类编码(唯一,如SCRIPT_EXECUTION)', description VARCHAR(500) NULL COMMENT '分类描述', icon VARCHAR(50) NULL COMMENT '图标', sort INT NOT NULL DEFAULT 0 COMMENT '排序', - - -- 支持的触发方式(JSON数组,如["MANUAL","SCHEDULED"]) + + -- 支持的触发方式(JSON数组,如["MANUAL","SCHEDULED"]) supported_triggers JSON NULL COMMENT '支持的触发方式列表', - - -- 状态 + + -- 状态 enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用', - -- 审计字段 + -- 审计字段 create_by VARCHAR(255) NULL COMMENT '创建人', create_time DATETIME(6) NULL COMMENT '创建时间', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', @@ -411,8 +411,8 @@ CREATE TABLE workflow_category update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', - -- 约束和索引 - UNIQUE KEY uk_code (code), + -- 约束和索引 + UNIQUE KEY uk_code (code), INDEX idx_enabled (enabled), INDEX idx_deleted (deleted), INDEX idx_sort (sort) @@ -421,20 +421,20 @@ CREATE TABLE workflow_category CREATE TABLE form_category ( - -- 主键 + -- 主键 id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', - -- 基础信息 + -- 基础信息 name VARCHAR(100) NOT NULL COMMENT '分类名称', code VARCHAR(50) NOT NULL COMMENT '分类编码(唯一)', description VARCHAR(500) NULL COMMENT '分类描述', icon VARCHAR(50) NULL COMMENT '图标', sort INT NOT NULL DEFAULT 0 COMMENT '排序', - - -- 状态 + + -- 状态 enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用', - -- 审计字段 + -- 审计字段 create_by VARCHAR(255) NULL COMMENT '创建人', create_time DATETIME(6) NULL COMMENT '创建时间', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', @@ -442,8 +442,8 @@ CREATE TABLE form_category update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', - -- 约束和索引 - UNIQUE KEY uk_code (code), + -- 约束和索引 + UNIQUE KEY uk_code (code), INDEX idx_enabled (enabled), INDEX idx_deleted (deleted), INDEX idx_sort (sort) @@ -453,25 +453,25 @@ CREATE TABLE form_category -- 表单定义表 CREATE TABLE form_definition ( - -- 主键 + -- 主键 id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', - -- 基础信息 + -- 基础信息 name VARCHAR(255) NOT NULL COMMENT '表单名称', `key` VARCHAR(255) NOT NULL COMMENT '表单标识(业务唯一)', form_version INT NOT NULL DEFAULT 1 COMMENT '表单版本号', category_id BIGINT NULL COMMENT '表单分类ID(外键关联form_category)', description TEXT NULL COMMENT '表单描述', - -- 表单配置 + -- 表单配置 `schema` JSON NOT NULL COMMENT '表单Schema(前端设计器导出的JSON结构)', tags JSON NULL COMMENT '标签(用于分类和搜索)', - -- 表单属性 + -- 表单属性 status VARCHAR(50) NOT NULL DEFAULT 'DRAFT' COMMENT '状态(DRAFT-草稿、PUBLISHED-已发布、DISABLED-已禁用)', is_template BIT NULL DEFAULT 0 COMMENT '是否为模板', - -- 审计字段 + -- 审计字段 create_by VARCHAR(255) NULL COMMENT '创建人', create_time DATETIME(6) NULL COMMENT '创建时间', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', @@ -479,14 +479,14 @@ CREATE TABLE form_definition update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', - -- 约束和索引 - UNIQUE KEY uk_key_version (`key`, form_version), + -- 约束和索引 + UNIQUE KEY uk_key_version (`key`, form_version), INDEX idx_category_id (category_id), INDEX idx_status (status), INDEX idx_is_template (is_template), INDEX idx_deleted (deleted), - - -- 外键约束 + + -- 外键约束 CONSTRAINT fk_form_definition_category FOREIGN KEY (category_id) REFERENCES form_category (id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '表单定义表'; @@ -563,31 +563,31 @@ CREATE TABLE workflow_node_definition -- 表单数据表 CREATE TABLE form_data ( - -- 主键 + -- 主键 id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', - -- 关联表单定义 + -- 关联表单定义 form_definition_id BIGINT NOT NULL COMMENT '表单定义ID', form_key VARCHAR(255) NOT NULL COMMENT '表单标识(冗余存储,避免JOIN)', form_version INT NOT NULL COMMENT '表单版本(冗余存储,用于历史追溯)', category_id BIGINT NULL COMMENT '表单分类ID(冗余存储,便于统计和查询)', - -- 业务关联(松耦合) + -- 业务关联(松耦合) business_key VARCHAR(255) NULL COMMENT '业务标识(如工作流实例ID、订单号等)', business_type VARCHAR(50) NULL COMMENT '业务类型(WORKFLOW-工作流、ORDER-订单、STANDALONE-独立表单)', - -- 表单数据 + -- 表单数据 data JSON NOT NULL COMMENT '表单填写数据(用户提交的实际数据)', schema_snapshot JSON NOT NULL COMMENT '表单Schema快照(用于历史追溯,确保数据可还原)', - -- 提交信息 + -- 提交信息 submitter VARCHAR(255) NULL COMMENT '提交人', submit_time DATETIME(6) NULL COMMENT '提交时间', - -- 状态 + -- 状态 status VARCHAR(50) NOT NULL DEFAULT 'SUBMITTED' COMMENT '状态(DRAFT-草稿、SUBMITTED-已提交、COMPLETED-已完成、REJECTED-已拒绝)', - -- 审计字段 + -- 审计字段 create_by VARCHAR(255) NULL COMMENT '创建人', create_time DATETIME(6) NULL COMMENT '创建时间', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', @@ -595,7 +595,7 @@ CREATE TABLE form_data update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', - -- 索引 + -- 索引 INDEX idx_form_definition_id (form_definition_id), INDEX idx_form_key (form_key), INDEX idx_category_id (category_id), @@ -703,7 +703,7 @@ CREATE TABLE deploy_application_category icon VARCHAR(50) NULL COMMENT '图标', enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用(0:禁用,1:启用)', sort INT NOT NULL DEFAULT 0 COMMENT '排序号', - + UNIQUE INDEX uk_code (code) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 @@ -745,46 +745,46 @@ CREATE TABLE deploy_application CREATE TABLE deploy_environment ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', - -- 业务字段 - tenant_code VARCHAR(50) DEFAULT NULL COMMENT '租户编码', - env_code VARCHAR(50) NOT NULL COMMENT '环境编码', - env_name VARCHAR(100) NOT NULL COMMENT '环境名称', - env_desc VARCHAR(255) NULL COMMENT '环境描述', + -- 业务字段 + tenant_code VARCHAR(50) DEFAULT NULL COMMENT '租户编码', + env_code VARCHAR(50) NOT NULL COMMENT '环境编码', + env_name VARCHAR(100) NOT NULL COMMENT '环境名称', + env_desc VARCHAR(255) NULL COMMENT '环境描述', enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用(0:禁用,1:启用)', - sort INT NOT NULL DEFAULT 0 COMMENT '排序号', + sort INT NOT NULL DEFAULT 0 COMMENT '排序号', - -- 基础字段 - create_by VARCHAR(100) NULL COMMENT '创建人', + -- 基础字段 + create_by VARCHAR(100) NULL COMMENT '创建人', create_time DATETIME(6) NULL COMMENT '创建时间', - update_by VARCHAR(100) NULL COMMENT '更新人', + update_by VARCHAR(100) NULL COMMENT '更新人', update_time DATETIME(6) NULL COMMENT '更新时间', - version INT NOT NULL DEFAULT 1 COMMENT '版本号', - deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', + version INT NOT NULL DEFAULT 1 COMMENT '版本号', + deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', - -- 索引 - UNIQUE INDEX uk_env_code (env_code) COMMENT '环境编码唯一' + -- 索引 + UNIQUE INDEX uk_env_code (env_code) COMMENT '环境编码唯一' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='环境表'; -- 团队表 CREATE TABLE deploy_team ( - id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', - create_by VARCHAR(100) NULL COMMENT '创建人', + id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', + create_by VARCHAR(100) NULL COMMENT '创建人', create_time DATETIME(6) NULL COMMENT '创建时间', - update_by VARCHAR(100) NULL COMMENT '更新人', + update_by VARCHAR(100) NULL COMMENT '更新人', update_time DATETIME(6) NULL COMMENT '更新时间', - version INT NOT NULL DEFAULT 1 COMMENT '版本号', - deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', - - team_code VARCHAR(50) NOT NULL COMMENT '团队编码', - team_name VARCHAR(100) NOT NULL COMMENT '团队名称', - description VARCHAR(500) NULL COMMENT '团队描述', + version INT NOT NULL DEFAULT 1 COMMENT '版本号', + deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', + + team_code VARCHAR(50) NOT NULL COMMENT '团队编码', + team_name VARCHAR(100) NOT NULL COMMENT '团队名称', + description VARCHAR(500) NULL COMMENT '团队描述', owner_id BIGINT NULL COMMENT '团队负责人用户ID', owner_name VARCHAR(50) NULL COMMENT '团队负责人姓名(冗余)', - enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用', - sort INT NOT NULL DEFAULT 0 COMMENT '排序号', - - UNIQUE INDEX uk_team_code (team_code), + enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用', + sort INT NOT NULL DEFAULT 0 COMMENT '排序号', + + UNIQUE INDEX uk_team_code (team_code), INDEX idx_owner (owner_id), CONSTRAINT fk_team_owner FOREIGN KEY (owner_id) REFERENCES sys_user (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='团队表'; @@ -792,21 +792,21 @@ CREATE TABLE deploy_team -- 团队成员表 CREATE TABLE deploy_team_member ( - id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', - create_by VARCHAR(100) NULL COMMENT '创建人', + id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', + create_by VARCHAR(100) NULL COMMENT '创建人', create_time DATETIME(6) NULL COMMENT '创建时间', - update_by VARCHAR(100) NULL COMMENT '更新人', + update_by VARCHAR(100) NULL COMMENT '更新人', update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 1 COMMENT '版本号', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', - + team_id BIGINT NOT NULL COMMENT '团队ID', user_id BIGINT NOT NULL COMMENT '用户ID', user_name VARCHAR(50) NULL COMMENT '用户名(冗余)', role_in_team VARCHAR(50) NULL COMMENT '团队角色(如:开发、测试、运维、负责人)', join_time DATETIME(6) NULL COMMENT '加入时间', - - UNIQUE INDEX uk_team_user (team_id, user_id), + + UNIQUE INDEX uk_team_user (team_id, user_id), INDEX idx_user (user_id), CONSTRAINT fk_team_member_team FOREIGN KEY (team_id) REFERENCES deploy_team (id), CONSTRAINT fk_team_member_user FOREIGN KEY (user_id) REFERENCES sys_user (id) @@ -815,14 +815,14 @@ CREATE TABLE deploy_team_member -- 团队应用关联表 CREATE TABLE deploy_team_application ( - id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', - create_by VARCHAR(100) NULL COMMENT '创建人', + id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', + create_by VARCHAR(100) NULL COMMENT '创建人', create_time DATETIME(6) NULL COMMENT '创建时间', - update_by VARCHAR(100) NULL COMMENT '更新人', + update_by VARCHAR(100) NULL COMMENT '更新人', update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 1 COMMENT '版本号', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', - + team_id BIGINT NOT NULL COMMENT '团队ID', application_id BIGINT NOT NULL COMMENT '应用ID', environment_id BIGINT NOT NULL COMMENT '环境ID', @@ -830,8 +830,8 @@ CREATE TABLE deploy_team_application deploy_system_id BIGINT NULL COMMENT '部署系统ID(关联sys_external_system,type=JENKINS)', deploy_job VARCHAR(100) NULL COMMENT '部署任务ID(关联deploy_jenkins_job)', workflow_definition_id BIGINT NULL COMMENT '工作流定义ID(关联workflow_definition)', - - UNIQUE INDEX uk_team_app_env (team_id, application_id, environment_id), + + UNIQUE INDEX uk_team_app_env (team_id, application_id, environment_id), INDEX idx_team (team_id), INDEX idx_application (application_id), INDEX idx_environment (environment_id), @@ -852,17 +852,17 @@ CREATE TABLE deploy_team_config update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 1 COMMENT '版本号', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', - + team_id BIGINT NOT NULL COMMENT '团队ID', - - -- 环境权限配置 + + -- 环境权限配置 allowed_environment_ids JSON NULL COMMENT '团队可访问的环境ID列表,如:[1, 2, 3]', - - -- 审批配置(与allowed_environment_ids位置对应) + + -- 审批配置(与allowed_environment_ids位置对应) environment_approval_required JSON NULL COMMENT '各环境是否需要审批(boolean数组),如:[false, false, true]', approver_user_ids JSON NULL COMMENT '各环境的审批人列表(数组,无审批人用null),如:[null, null, [1, 4]]', - - UNIQUE INDEX uk_team (team_id), + + UNIQUE INDEX uk_team (team_id), INDEX idx_deleted (deleted), CONSTRAINT fk_team_config_team FOREIGN KEY (team_id) REFERENCES deploy_team (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='团队配置表'; @@ -874,20 +874,20 @@ CREATE TABLE deploy_team_config -- 通知渠道配置表 CREATE TABLE sys_notification_channel ( - id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', - create_by VARCHAR(100) NULL COMMENT '创建人', - create_time DATETIME(6) NULL COMMENT '创建时间', + id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', + create_by VARCHAR(100) NULL COMMENT '创建人', + create_time DATETIME(6) NULL COMMENT '创建时间', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除(0:未删除,1:已删除)', - update_by VARCHAR(100) NULL COMMENT '更新人', - update_time DATETIME(6) NULL COMMENT '更新时间', + update_by VARCHAR(100) NULL COMMENT '更新人', + update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', - - name VARCHAR(100) NOT NULL COMMENT '渠道名称(如:研发部企业微信群)', + + name VARCHAR(100) NOT NULL COMMENT '渠道名称(如:研发部企业微信群)', channel_type VARCHAR(50) NOT NULL COMMENT '渠道类型(WEWORK, FEISHU, DINGTALK, SMS, EMAIL, SLACK)', config JSON NOT NULL COMMENT '渠道配置(JSON格式,不同渠道存储不同字段)', status VARCHAR(20) NOT NULL DEFAULT 'ENABLED' COMMENT '状态(ENABLED-启用, DISABLED-禁用)', - description VARCHAR(500) NULL COMMENT '描述说明', - + description VARCHAR(500) NULL COMMENT '描述说明', + INDEX idx_channel_type (channel_type), INDEX idx_status (status), INDEX idx_deleted (deleted) @@ -900,23 +900,23 @@ CREATE TABLE sys_notification_channel -- 定时任务分类表 CREATE TABLE schedule_job_category ( - id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', - create_by VARCHAR(100) NULL COMMENT '创建人', + id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', + create_by VARCHAR(100) NULL COMMENT '创建人', create_time DATETIME(6) NULL COMMENT '创建时间', - update_by VARCHAR(100) NULL COMMENT '更新人', + update_by VARCHAR(100) NULL COMMENT '更新人', update_time DATETIME(6) NULL COMMENT '更新时间', - version INT NOT NULL DEFAULT 1 COMMENT '版本号', - deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', - - code VARCHAR(50) NOT NULL COMMENT '分类编码', - name VARCHAR(100) NOT NULL COMMENT '分类名称', - description VARCHAR(500) NULL COMMENT '描述', + version INT NOT NULL DEFAULT 1 COMMENT '版本号', + deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', + + code VARCHAR(50) NOT NULL COMMENT '分类编码', + name VARCHAR(100) NOT NULL COMMENT '分类名称', + description VARCHAR(500) NULL COMMENT '描述', icon VARCHAR(50) NULL COMMENT '图标', color VARCHAR(20) NULL COMMENT '颜色', - enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用', - sort INT NOT NULL DEFAULT 0 COMMENT '排序号', - - UNIQUE INDEX uk_code (code, deleted), + enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用', + sort INT NOT NULL DEFAULT 0 COMMENT '排序号', + + UNIQUE INDEX uk_code (code, deleted), INDEX idx_enabled (enabled) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='定时任务分类表'; @@ -930,35 +930,35 @@ CREATE TABLE schedule_job update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 1 COMMENT '版本号', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', - + job_name VARCHAR(100) NOT NULL COMMENT '任务名称', job_description VARCHAR(500) NULL COMMENT '任务描述', category_id BIGINT NOT NULL COMMENT '任务分类ID', - - -- 执行配置 + + -- 执行配置 bean_name VARCHAR(100) NOT NULL COMMENT 'Spring Bean名称', method_name VARCHAR(100) NOT NULL COMMENT '方法名称', form_definition_id BIGINT NULL COMMENT '参数表单ID', method_params TEXT NULL COMMENT '方法参数JSON', - - -- 调度配置 + + -- 调度配置 cron_expression VARCHAR(100) NOT NULL COMMENT 'Cron表达式', status VARCHAR(20) NOT NULL DEFAULT 'ENABLED' COMMENT '任务状态:ENABLED-启用、DISABLED-禁用、PAUSED-暂停', concurrent BIT NOT NULL DEFAULT 0 COMMENT '是否允许并发执行', - - -- 统计信息 + + -- 统计信息 last_execute_time DATETIME(6) NULL COMMENT '上次执行时间', next_execute_time DATETIME(6) NULL COMMENT '下次执行时间', execute_count INT NOT NULL DEFAULT 0 COMMENT '执行次数', success_count INT NOT NULL DEFAULT 0 COMMENT '成功次数', fail_count INT NOT NULL DEFAULT 0 COMMENT '失败次数', - - -- 高级配置 + + -- 高级配置 timeout_seconds INT NULL COMMENT '超时时间(秒)', retry_count INT NOT NULL DEFAULT 0 COMMENT '失败重试次数', alert_email VARCHAR(500) NULL COMMENT '告警邮箱(多个用逗号分隔)', - - UNIQUE INDEX uk_job_name (job_name, deleted), + + UNIQUE INDEX uk_job_name (job_name, deleted), INDEX idx_category (category_id), INDEX idx_status (status), INDEX idx_next_execute_time (next_execute_time), @@ -976,29 +976,29 @@ CREATE TABLE schedule_job_log update_time DATETIME(6) NULL COMMENT '更新时间', version INT NOT NULL DEFAULT 1 COMMENT '版本号', deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除', - + job_id BIGINT NOT NULL COMMENT '任务ID', job_name VARCHAR(100) NOT NULL COMMENT '任务名称', - - -- 执行信息 + + -- 执行信息 bean_name VARCHAR(100) NOT NULL COMMENT '执行器Bean名称', method_name VARCHAR(100) NOT NULL COMMENT '执行方法名称', method_params TEXT NULL COMMENT '方法参数', - - -- 时间统计 + + -- 时间统计 execute_time DATETIME(6) NOT NULL COMMENT '开始执行时间', finish_time DATETIME(6) NULL COMMENT '完成时间', duration BIGINT NULL COMMENT '执行耗时(毫秒)', - - -- 状态信息 + + -- 状态信息 status VARCHAR(20) NOT NULL COMMENT '执行状态:SUCCESS-成功、FAIL-失败、TIMEOUT-超时', result_message TEXT NULL COMMENT '执行结果消息', exception_info TEXT NULL COMMENT '异常堆栈信息', - - -- 服务器信息 + + -- 服务器信息 server_ip VARCHAR(50) NULL COMMENT '执行服务器IP', server_host VARCHAR(100) NULL COMMENT '执行服务器主机名', - + INDEX idx_job_id (job_id), INDEX idx_execute_time (execute_time), INDEX idx_status (status), @@ -1019,15 +1019,15 @@ CREATE TABLE deploy_server_category description VARCHAR(500) NULL COMMENT '分类描述', sort INT DEFAULT 0 COMMENT '排序', enabled BOOLEAN DEFAULT TRUE COMMENT '是否启用', - - -- 审计字段 + + -- 审计字段 create_by VARCHAR(50) NULL COMMENT '创建人', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', update_by VARCHAR(50) NULL COMMENT '更新人', update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', version INT DEFAULT 1 COMMENT '版本号', deleted BOOLEAN DEFAULT FALSE COMMENT '是否删除', - + INDEX idx_code (code), INDEX idx_enabled (enabled) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='服务器分类表'; @@ -1036,34 +1036,34 @@ CREATE TABLE deploy_server_category CREATE TABLE deploy_server ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', - server_name VARCHAR(100) NOT NULL COMMENT '服务器名称', - host_ip VARCHAR(50) NOT NULL UNIQUE COMMENT 'IP地址', + server_name VARCHAR(100) NOT NULL COMMENT '服务器名称', + host_ip VARCHAR(50) NOT NULL UNIQUE COMMENT 'IP地址', ssh_port INT DEFAULT 22 COMMENT 'SSH端口', ssh_user VARCHAR(50) NULL COMMENT 'SSH用户名', auth_type VARCHAR(20) DEFAULT 'PASSWORD' COMMENT '认证方式:PASSWORD/KEY', - ssh_password VARCHAR(500) NULL COMMENT 'SSH密码(加密存储)', + ssh_password VARCHAR(500) NULL COMMENT 'SSH密码(加密存储)', ssh_private_key TEXT NULL COMMENT 'SSH私钥(加密存储)', - ssh_passphrase VARCHAR(500) NULL COMMENT '私钥密码(加密存储)', + ssh_passphrase VARCHAR(500) NULL COMMENT '私钥密码(加密存储)', category_id BIGINT NULL COMMENT '服务器分类ID', os_type VARCHAR(20) NULL COMMENT '操作系统类型:LINUX/WINDOWS/MACOS/UNIX/OTHER', - os_version VARCHAR(100) NULL COMMENT '操作系统版本:CentOS 7.9', - hostname VARCHAR(100) NULL COMMENT '主机名', + os_version VARCHAR(100) NULL COMMENT '操作系统版本:CentOS 7.9', + hostname VARCHAR(100) NULL COMMENT '主机名', status VARCHAR(20) DEFAULT 'OFFLINE' COMMENT '连接状态:ONLINE/OFFLINE', - description VARCHAR(500) NULL COMMENT '服务器描述', + description VARCHAR(500) NULL COMMENT '服务器描述', cpu_cores INT NULL COMMENT 'CPU核心数', memory_size INT NULL COMMENT '内存大小(GB)', disk_size INT NULL COMMENT '磁盘大小(GB)', tags JSON NULL COMMENT '标签(JSON格式)', last_connect_time DATETIME NULL COMMENT '最后连接时间', - - -- 审计字段 + + -- 审计字段 create_by VARCHAR(50) NULL COMMENT '创建人', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', update_by VARCHAR(50) NULL COMMENT '更新人', update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', version INT DEFAULT 1 COMMENT '版本号', deleted BOOLEAN DEFAULT FALSE COMMENT '是否删除', - + INDEX idx_host_ip (host_ip), INDEX idx_category_id (category_id), INDEX idx_status (status),