diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/JenkinsViewQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/JenkinsViewQuery.java index 1f5a552b..3cdc6741 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/JenkinsViewQuery.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/JenkinsViewQuery.java @@ -17,7 +17,7 @@ public class JenkinsViewQuery extends BaseQuery { @QueryField(field = "description", type = QueryType.LIKE) private String description; - @QueryField(field = "externalSystemId") + @QueryField(field = "externalSystemId", type = QueryType.EQUAL) private Long externalSystemId; @QueryField(field = "viewName", type = QueryType.LIKE) diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ApplicationServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ApplicationServiceImpl.java index 80202078..8d02a0c6 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ApplicationServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ApplicationServiceImpl.java @@ -20,11 +20,15 @@ import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository; import com.qqchen.deploy.backend.deploy.repository.IRepositoryProjectRepository; import com.qqchen.deploy.backend.deploy.repository.ITeamApplicationRepository; import com.qqchen.deploy.backend.deploy.service.IApplicationService; +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 jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Arrays; @@ -33,6 +37,7 @@ import java.util.Optional; import static java.util.stream.Collectors.toList; +@Slf4j @Service public class ApplicationServiceImpl extends BaseServiceImpl implements IApplicationService { @@ -151,4 +156,30 @@ public class ApplicationServiceImpl extends BaseServiceImpl new BusinessException(ResponseCode.ERROR)); + + // 2. 校验该应用是否被团队绑定 + Long teamCount = teamApplicationRepository.countDistinctTeamIdByApplicationId(id); + + if (teamCount != null && teamCount > 0) { + log.warn("删除应用失败: 应用 {} ({}) 已被 {} 个团队绑定", + application.getAppName(), id, teamCount); + throw new BusinessException(ResponseCode.APPLICATION_HAS_TEAMS, new Object[]{teamCount}); + } + + // 3. 执行删除(逻辑删除) + super.delete(id); + log.info("成功删除应用: id={}, name={}", id, application.getAppName()); + } + } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/EnvironmentServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/EnvironmentServiceImpl.java index 2cfda7ec..48612494 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/EnvironmentServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/EnvironmentServiceImpl.java @@ -10,8 +10,11 @@ import com.qqchen.deploy.backend.deploy.repository.IEnvironmentRepository; import com.qqchen.deploy.backend.deploy.repository.ITeamApplicationRepository; import com.qqchen.deploy.backend.deploy.repository.ITeamEnvironmentConfigRepository; import com.qqchen.deploy.backend.deploy.service.IEnvironmentService; +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.querydsl.jpa.impl.JPAQueryFactory; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.stereotype.Service; @@ -25,6 +28,7 @@ import java.util.stream.Collectors; /** * 环境服务实现类 */ +@Slf4j @Service public class EnvironmentServiceImpl extends BaseServiceImpl implements IEnvironmentService { @@ -115,4 +119,30 @@ public class EnvironmentServiceImpl extends BaseServiceImpl environmentIds) { // TODO: 实现更新逻辑 } + + /** + * 重写删除方法,删除前校验该环境是否被团队配置 + * + * @param id 环境ID + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Long id) { + // 1. 查询环境是否存在 + Environment environment = environmentRepository.findById(id) + .orElseThrow(() -> new BusinessException(ResponseCode.ENVIRONMENT_NOT_FOUND, new Object[]{id})); + + // 2. 校验该环境是否被团队配置(通过 TeamEnvironmentConfig) + Long teamCount = teamEnvironmentConfigRepository.countByEnvironmentId(id); + + if (teamCount != null && teamCount > 0) { + log.warn("删除环境失败: 环境 {} ({}) 已被 {} 个团队配置", + environment.getEnvName(), id, teamCount); + throw new BusinessException(ResponseCode.ENVIRONMENT_HAS_TEAMS, new Object[]{teamCount}); + } + + // 3. 执行删除(逻辑删除) + super.delete(id); + log.info("成功删除环境: id={}, name={}", id, environment.getEnvName()); + } } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamEnvironmentConfigServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamEnvironmentConfigServiceImpl.java index 44b92c0c..ec2b7c11 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamEnvironmentConfigServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamEnvironmentConfigServiceImpl.java @@ -8,6 +8,8 @@ import com.qqchen.deploy.backend.deploy.repository.IEnvironmentRepository; import com.qqchen.deploy.backend.deploy.repository.ITeamApplicationRepository; import com.qqchen.deploy.backend.deploy.repository.ITeamEnvironmentConfigRepository; import com.qqchen.deploy.backend.deploy.service.ITeamEnvironmentConfigService; +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.notification.entity.NotificationChannel; import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository; @@ -16,6 +18,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.util.stream.Collectors; @@ -148,5 +151,35 @@ public class TeamEnvironmentConfigServiceImpl } }); } + + /** + * 重写删除方法,删除前校验该团队环境下是否有绑定的应用 + * + * @param id 团队环境配置ID + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Long id) { + // 1. 查询团队环境配置 + TeamEnvironmentConfig config = teamEnvironmentConfigRepository.findById(id) + .orElseThrow(() -> new BusinessException(ResponseCode.TEAM_CONFIG_NOT_FOUND, new Object[]{id})); + + // 2. 校验该环境下是否有绑定的应用 + Long appCount = teamApplicationRepository.countByTeamIdAndEnvironmentId( + config.getTeamId(), + config.getEnvironmentId() + ); + + if (appCount != null && appCount > 0) { + log.warn("删除团队环境配置失败: 团队 {} 的环境 {} 下存在 {} 个绑定应用", + config.getTeamId(), config.getEnvironmentId(), appCount); + throw new BusinessException(ResponseCode.TEAM_ENVIRONMENT_HAS_APPLICATIONS, new Object[]{appCount}); + } + + // 3. 执行删除(逻辑删除) + super.delete(id); + log.info("成功删除团队环境配置: id={}, teamId={}, environmentId={}", + id, config.getTeamId(), config.getEnvironmentId()); + } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java index 40c4ad24..5da0fc69 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java @@ -135,6 +135,7 @@ public enum ResponseCode { 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"), + WORKFLOW_FORM_NOT_BOUND(2764, "workflow.form.not.bound"), // 定时任务相关错误码 (2800-2899) SCHEDULE_JOB_NOT_FOUND(2800, "schedule.job.not.found"), @@ -179,27 +180,34 @@ public enum ResponseCode { */ WORKFLOW_VARIABLE_DESERIALIZE_ERROR(50302, "workflow.variable.deserialize.error"), - // 表单管理相关错误码 (2800-2899) + // 表单管理相关错误码 (2800-2819) FORM_DEFINITION_NOT_FOUND(2800, "form.definition.not.found"), FORM_DATA_NOT_FOUND(2801, "form.data.not.found"), FORM_DEFINITION_KEY_EXISTS(2802, "form.definition.key.exists"), FORM_DEFINITION_KEY_VERSION_EXISTS(2803, "form.definition.key.version.exists"), + // 环境管理相关错误码 (2880-2899) + ENVIRONMENT_NOT_FOUND(2880, "environment.not.found"), + ENVIRONMENT_CODE_EXISTS(2881, "environment.code.exists"), + ENVIRONMENT_HAS_TEAMS(2882, "environment.has.teams"), + // 应用分类相关错误码 (2900-2919) APPLICATION_CATEGORY_NOT_FOUND(2900, "application.category.not.found"), APPLICATION_CATEGORY_CODE_EXISTS(2901, "application.category.code.exists"), APPLICATION_CATEGORY_HAS_APPLICATIONS(2902, "application.category.has.applications"), + APPLICATION_HAS_TEAMS(2903, "application.has.teams"), // 团队管理相关错误码 (2920-2949) TEAM_NOT_FOUND(2920, "team.not.found"), TEAM_CODE_EXISTS(2921, "team.code.exists"), TEAM_HAS_MEMBERS(2922, "team.has.members"), TEAM_HAS_APPLICATIONS(2923, "team.has.applications"), - TEAM_MEMBER_NOT_FOUND(2924, "team.member.not.found"), - TEAM_MEMBER_ALREADY_EXISTS(2925, "team.member.already.exists"), - TEAM_APPLICATION_NOT_FOUND(2926, "team.application.not.found"), - TEAM_APPLICATION_ALREADY_EXISTS(2927, "team.application.already.exists"), - TEAM_CONFIG_NOT_FOUND(2928, "team.config.not.found"), + TEAM_ENVIRONMENT_HAS_APPLICATIONS(2924, "team.environment.has.applications"), + TEAM_MEMBER_NOT_FOUND(2925, "team.member.not.found"), + TEAM_MEMBER_ALREADY_EXISTS(2926, "team.member.already.exists"), + TEAM_APPLICATION_NOT_FOUND(2927, "team.application.not.found"), + TEAM_APPLICATION_ALREADY_EXISTS(2928, "team.application.already.exists"), + TEAM_CONFIG_NOT_FOUND(2929, "team.config.not.found"), // 服务器管理相关错误码 (2950-2969) SERVER_NOT_FOUND(2950, "server.not.found"), diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowDefinitionServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowDefinitionServiceImpl.java index bfd71fdd..92ef5d4e 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowDefinitionServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/service/impl/WorkflowDefinitionServiceImpl.java @@ -1,5 +1,7 @@ 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.dto.WorkflowCategoryDTO; import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO; @@ -98,7 +100,7 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl new RuntimeException("Workflow definition not found: " + id)); + .orElseThrow(() -> new BusinessException(ResponseCode.WORKFLOW_NOT_FOUND)); // 2. 查询部署 List deployments = repositoryService.createDeploymentQuery() @@ -311,14 +313,14 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl new RuntimeException("Workflow definition not found: " + id)); + .orElseThrow(() -> new BusinessException(ResponseCode.WORKFLOW_NOT_FOUND)); repositoryService.createDeployment().addString(definition.getKey() + ".bpmn20.xml", definition.getBpmnXml()) .key(definition.getKey()).name(definition.getName()).deploy(); } @@ -327,7 +329,14 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl new RuntimeException("Workflow definition not found: " + workflowDefinitionId)); + .orElseThrow(() -> new BusinessException(ResponseCode.WORKFLOW_NOT_FOUND)); + + // 校验:工作流必须绑定表单才能发布 + if (definition.getFormDefinitionId() == null) { + log.warn("工作流发布失败: 工作流 {} 未绑定表单", workflowDefinitionId); + throw new BusinessException(ResponseCode.WORKFLOW_FORM_NOT_BOUND); + } + WorkflowDefinitionGraph graph = definition.getGraph(); definition.setBpmnXml(bpmnConverter.convertToXml(graph, definition.getKey())); Deployment deployment = this.deployWorkflow(definition); diff --git a/backend/src/main/resources/messages.properties b/backend/src/main/resources/messages.properties index 31f7526e..6fffb19f 100644 --- a/backend/src/main/resources/messages.properties +++ b/backend/src/main/resources/messages.properties @@ -156,6 +156,7 @@ workflow.transition.config.empty=流转配置不能为空 workflow.condition.invalid=工作流条件配置无效 workflow.form.config.empty=表单配置不能为空 workflow.graph.config.empty=图形配置不能为空 +workflow.form.not.bound=工作流未绑定表单,请先绑定表单后再发布 workflow.variable.not.found=工作流变量不存在 workflow.variable.type.invalid=工作流变量类型无效 workflow.variable.serialize.error=工作流变量序列化失败: {0} @@ -169,22 +170,29 @@ workflow.schedule.invalid=工作流调度配置无效 workflow.concurrent.limit.exceeded=工作流并发限制超出 workflow.execution.error=工作流执行错误 -# 表单管理相关 (2800-2899) +# 表单管理相关 (2800-2819) form.definition.not.found=表单定义不存在或已删除 form.data.not.found=表单数据不存在或已删除 form.definition.key.exists=表单标识{0}已存在,请使用不同的标识 form.definition.key.version.exists=表单标识{0}的版本{1}已存在 +# 环境管理相关 (2880-2899) +environment.not.found=环境不存在或已删除 +environment.code.exists=环境编码{0}已存在 +environment.has.teams=该环境已被{0}个团队配置,请先解除团队环境配置后再删除 + # 应用分类相关 (2900-2919) application.category.not.found=应用分类不存在或已删除 application.category.code.exists=分类编码{0}已存在 application.category.has.applications=该分类下存在应用,无法删除 +application.has.teams=该应用已被{0}个团队绑定,请先解除绑定后再删除 # 团队管理相关 (2920-2949) team.not.found=团队不存在或已删除 team.code.exists=团队编码{0}已存在 team.has.members=该团队下存在成员,无法删除 team.has.applications=该团队下存在关联应用,无法删除 +team.environment.has.applications=该团队环境下存在{0}个绑定应用,请先解绑应用后再删除环境配置 team.member.not.found=团队成员不存在或已删除 team.member.already.exists=该用户已是团队成员 team.application.not.found=团队应用关联不存在或已删除