diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/TeamApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/TeamApiController.java new file mode 100644 index 00000000..f96c608b --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/TeamApiController.java @@ -0,0 +1,34 @@ +package com.qqchen.deploy.backend.deploy.api; + +import com.qqchen.deploy.backend.deploy.dto.TeamDTO; +import com.qqchen.deploy.backend.deploy.entity.Team; +import com.qqchen.deploy.backend.deploy.query.TeamQuery; +import com.qqchen.deploy.backend.deploy.service.ITeamService; +import com.qqchen.deploy.backend.framework.controller.BaseController; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 团队API控制器 + */ +@Slf4j +@RestController +@RequestMapping("/api/v1/teams") +@Tag(name = "团队管理", description = "团队的增删改查接口") +public class TeamApiController extends BaseController { + + @Resource + private ITeamService teamService; + + @Override + protected void exportData(HttpServletResponse response, List data) { + // TODO: 实现导出功能 + } +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/TeamApplicationApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/TeamApplicationApiController.java new file mode 100644 index 00000000..e4d4ab9f --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/TeamApplicationApiController.java @@ -0,0 +1,34 @@ +package com.qqchen.deploy.backend.deploy.api; + +import com.qqchen.deploy.backend.deploy.dto.TeamApplicationDTO; +import com.qqchen.deploy.backend.deploy.entity.TeamApplication; +import com.qqchen.deploy.backend.deploy.query.TeamApplicationQuery; +import com.qqchen.deploy.backend.deploy.service.ITeamApplicationService; +import com.qqchen.deploy.backend.framework.controller.BaseController; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 团队应用关联API控制器 + */ +@Slf4j +@RestController +@RequestMapping("/api/v1/team-applications") +@Tag(name = "团队应用关联管理", description = "团队应用关联的增删改查接口") +public class TeamApplicationApiController extends BaseController { + + @Resource + private ITeamApplicationService teamApplicationService; + + @Override + protected void exportData(HttpServletResponse response, List data) { + // TODO: 实现导出功能 + } +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/TeamMemberApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/TeamMemberApiController.java new file mode 100644 index 00000000..51a71985 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/TeamMemberApiController.java @@ -0,0 +1,34 @@ +package com.qqchen.deploy.backend.deploy.api; + +import com.qqchen.deploy.backend.deploy.dto.TeamMemberDTO; +import com.qqchen.deploy.backend.deploy.entity.TeamMember; +import com.qqchen.deploy.backend.deploy.query.TeamMemberQuery; +import com.qqchen.deploy.backend.deploy.service.ITeamMemberService; +import com.qqchen.deploy.backend.framework.controller.BaseController; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 团队成员API控制器 + */ +@Slf4j +@RestController +@RequestMapping("/api/v1/team-members") +@Tag(name = "团队成员管理", description = "团队成员的增删改查接口") +public class TeamMemberApiController extends BaseController { + + @Resource + private ITeamMemberService teamMemberService; + + @Override + protected void exportData(HttpServletResponse response, List data) { + // TODO: 实现导出功能 + } +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamApplicationConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamApplicationConverter.java new file mode 100644 index 00000000..cc2c77df --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamApplicationConverter.java @@ -0,0 +1,11 @@ +package com.qqchen.deploy.backend.deploy.converter; + +import com.qqchen.deploy.backend.deploy.dto.TeamApplicationDTO; +import com.qqchen.deploy.backend.deploy.entity.TeamApplication; +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import org.mapstruct.Mapper; + +@Mapper(config = BaseConverter.class) +public interface TeamApplicationConverter extends BaseConverter { +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamConverter.java new file mode 100644 index 00000000..0f4561c0 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamConverter.java @@ -0,0 +1,11 @@ +package com.qqchen.deploy.backend.deploy.converter; + +import com.qqchen.deploy.backend.deploy.dto.TeamDTO; +import com.qqchen.deploy.backend.deploy.entity.Team; +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import org.mapstruct.Mapper; + +@Mapper(config = BaseConverter.class) +public interface TeamConverter extends BaseConverter { +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamMemberConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamMemberConverter.java new file mode 100644 index 00000000..1f727c9f --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamMemberConverter.java @@ -0,0 +1,11 @@ +package com.qqchen.deploy.backend.deploy.converter; + +import com.qqchen.deploy.backend.deploy.dto.TeamMemberDTO; +import com.qqchen.deploy.backend.deploy.entity.TeamMember; +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import org.mapstruct.Mapper; + +@Mapper(config = BaseConverter.class) +public interface TeamMemberConverter extends BaseConverter { +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/TeamApplicationDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/TeamApplicationDTO.java new file mode 100644 index 00000000..3ae45bc7 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/TeamApplicationDTO.java @@ -0,0 +1,31 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "团队应用关联信息") +public class TeamApplicationDTO extends BaseDTO { + + @Schema(description = "团队ID", required = true) + @NotNull(message = "团队ID不能为空") + private Long teamId; + + @Schema(description = "应用ID", required = true) + @NotNull(message = "应用ID不能为空") + private Long applicationId; + + @Schema(description = "团队名称") + private String teamName; + + @Schema(description = "应用名称") + private String applicationName; + + @Schema(description = "应用编码") + private String applicationCode; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/TeamDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/TeamDTO.java new file mode 100644 index 00000000..28e20e5a --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/TeamDTO.java @@ -0,0 +1,46 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "团队信息") +public class TeamDTO extends BaseDTO { + + @Schema(description = "团队编码", example = "PLATFORM_TEAM") + @NotBlank(message = "团队编码不能为空") + private String teamCode; + + @Schema(description = "团队名称", example = "平台研发团队") + @NotBlank(message = "团队名称不能为空") + private String teamName; + + @Schema(description = "团队描述") + private String description; + + @Schema(description = "团队负责人ID") + private Long ownerId; + + @Schema(description = "团队负责人姓名") + private String ownerName; + + @Schema(description = "是否启用") + @NotNull(message = "启用状态不能为空") + private Boolean enabled; + + @Schema(description = "排序号") + @NotNull(message = "排序号不能为空") + private Integer sort; + + @Schema(description = "成员数量") + private Long memberCount; + + @Schema(description = "应用数量") + private Long applicationCount; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/TeamMemberDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/TeamMemberDTO.java new file mode 100644 index 00000000..881f65d2 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/TeamMemberDTO.java @@ -0,0 +1,38 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "团队成员信息") +public class TeamMemberDTO extends BaseDTO { + + @Schema(description = "团队ID", required = true) + @NotNull(message = "团队ID不能为空") + private Long teamId; + + @Schema(description = "用户ID", required = true) + @NotNull(message = "用户ID不能为空") + private Long userId; + + @Schema(description = "用户名") + private String userName; + + @Schema(description = "团队角色", example = "开发") + private String roleInTeam; + + @Schema(description = "加入时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime joinTime; + + @Schema(description = "团队名称") + private String teamName; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/Team.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/Team.java new file mode 100644 index 00000000..67aab2a1 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/Team.java @@ -0,0 +1,39 @@ +package com.qqchen.deploy.backend.deploy.entity; + +import com.qqchen.deploy.backend.framework.domain.Entity; +import jakarta.persistence.Column; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 团队实体 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@jakarta.persistence.Entity +@Table(name = "deploy_team") +public class Team extends Entity { + + @Column(name = "team_code", nullable = false, length = 50) + private String teamCode; + + @Column(name = "team_name", nullable = false, length = 100) + private String teamName; + + @Column(name = "description", length = 500) + private String description; + + @Column(name = "owner_id") + private Long ownerId; + + @Column(name = "owner_name", length = 50) + private String ownerName; + + @Column(name = "enabled", nullable = false) + private Boolean enabled = true; + + @Column(name = "sort", nullable = false) + private Integer sort = 0; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/TeamApplication.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/TeamApplication.java new file mode 100644 index 00000000..40c05cbe --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/TeamApplication.java @@ -0,0 +1,24 @@ +package com.qqchen.deploy.backend.deploy.entity; + +import com.qqchen.deploy.backend.framework.domain.Entity; +import jakarta.persistence.Column; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 团队应用关联实体 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@jakarta.persistence.Entity +@Table(name = "deploy_team_application") +public class TeamApplication extends Entity { + + @Column(name = "team_id", nullable = false) + private Long teamId; + + @Column(name = "application_id", nullable = false) + private Long applicationId; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/TeamMember.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/TeamMember.java new file mode 100644 index 00000000..68ae082a --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/TeamMember.java @@ -0,0 +1,35 @@ +package com.qqchen.deploy.backend.deploy.entity; + +import com.qqchen.deploy.backend.framework.domain.Entity; +import jakarta.persistence.Column; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 团队成员实体 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@jakarta.persistence.Entity +@Table(name = "deploy_team_member") +public class TeamMember extends Entity { + + @Column(name = "team_id", nullable = false) + private Long teamId; + + @Column(name = "user_id", nullable = false) + private Long userId; + + @Column(name = "user_name", length = 50) + private String userName; + + @Column(name = "role_in_team", length = 50) + private String roleInTeam; + + @Column(name = "join_time") + private LocalDateTime joinTime; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/TeamApplicationQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/TeamApplicationQuery.java new file mode 100644 index 00000000..85de5ff0 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/TeamApplicationQuery.java @@ -0,0 +1,25 @@ +package com.qqchen.deploy.backend.deploy.query; + +import com.qqchen.deploy.backend.framework.annotation.QueryField; +import com.qqchen.deploy.backend.framework.query.BaseQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 团队应用关联查询条件 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "团队应用关联查询条件") +public class TeamApplicationQuery extends BaseQuery { + + @QueryField(field = "teamId") + @Schema(description = "团队ID") + private Long teamId; + + @QueryField(field = "applicationId") + @Schema(description = "应用ID") + private Long applicationId; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/TeamMemberQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/TeamMemberQuery.java new file mode 100644 index 00000000..fa7971df --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/TeamMemberQuery.java @@ -0,0 +1,34 @@ +package com.qqchen.deploy.backend.deploy.query; + +import com.qqchen.deploy.backend.framework.annotation.QueryField; +import com.qqchen.deploy.backend.framework.enums.QueryType; +import com.qqchen.deploy.backend.framework.query.BaseQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 团队成员查询条件 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "团队成员查询条件") +public class TeamMemberQuery extends BaseQuery { + + @QueryField(field = "teamId") + @Schema(description = "团队ID") + private Long teamId; + + @QueryField(field = "userId") + @Schema(description = "用户ID") + private Long userId; + + @QueryField(field = "userName", type = QueryType.LIKE) + @Schema(description = "用户名(模糊查询)") + private String userName; + + @QueryField(field = "roleInTeam", type = QueryType.LIKE) + @Schema(description = "团队角色(模糊查询)") + private String roleInTeam; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/TeamQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/TeamQuery.java new file mode 100644 index 00000000..da43e608 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/TeamQuery.java @@ -0,0 +1,34 @@ +package com.qqchen.deploy.backend.deploy.query; + +import com.qqchen.deploy.backend.framework.annotation.QueryField; +import com.qqchen.deploy.backend.framework.enums.QueryType; +import com.qqchen.deploy.backend.framework.query.BaseQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 团队查询条件 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "团队查询条件") +public class TeamQuery extends BaseQuery { + + @QueryField(field = "teamName", type = QueryType.LIKE) + @Schema(description = "团队名称(模糊查询)") + private String teamName; + + @QueryField(field = "teamCode", type = QueryType.LIKE) + @Schema(description = "团队编码(模糊查询)") + private String teamCode; + + @QueryField(field = "enabled") + @Schema(description = "是否启用") + private Boolean enabled; + + @QueryField(field = "ownerId") + @Schema(description = "负责人ID") + private Long ownerId; +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/ITeamApplicationRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/ITeamApplicationRepository.java new file mode 100644 index 00000000..858c083f --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/ITeamApplicationRepository.java @@ -0,0 +1,32 @@ +package com.qqchen.deploy.backend.deploy.repository; + +import com.qqchen.deploy.backend.deploy.entity.TeamApplication; +import com.qqchen.deploy.backend.framework.repository.IBaseRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface ITeamApplicationRepository extends IBaseRepository { + + /** + * 统计团队关联的应用数量 + */ + Long countByTeamIdAndDeletedFalse(Long teamId); + + /** + * 统计应用被哪些团队关联 + */ + Long countByApplicationIdAndDeletedFalse(Long applicationId); + + /** + * 检查团队是否已关联该应用 + */ + boolean existsByTeamIdAndApplicationIdAndDeletedFalse(Long teamId, Long applicationId); + + /** + * 根据团队ID和应用ID查询 + */ + Optional findByTeamIdAndApplicationIdAndDeletedFalse(Long teamId, Long applicationId); +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/ITeamMemberRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/ITeamMemberRepository.java new file mode 100644 index 00000000..91d513b3 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/ITeamMemberRepository.java @@ -0,0 +1,27 @@ +package com.qqchen.deploy.backend.deploy.repository; + +import com.qqchen.deploy.backend.deploy.entity.TeamMember; +import com.qqchen.deploy.backend.framework.repository.IBaseRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface ITeamMemberRepository extends IBaseRepository { + + /** + * 统计团队成员数量 + */ + Long countByTeamIdAndDeletedFalse(Long teamId); + + /** + * 检查成员是否已加入团队 + */ + boolean existsByTeamIdAndUserIdAndDeletedFalse(Long teamId, Long userId); + + /** + * 根据团队ID和用户ID查询 + */ + Optional findByTeamIdAndUserIdAndDeletedFalse(Long teamId, Long userId); +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/ITeamRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/ITeamRepository.java new file mode 100644 index 00000000..bb0a7ae0 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/ITeamRepository.java @@ -0,0 +1,22 @@ +package com.qqchen.deploy.backend.deploy.repository; + +import com.qqchen.deploy.backend.deploy.entity.Team; +import com.qqchen.deploy.backend.framework.repository.IBaseRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface ITeamRepository extends IBaseRepository { + + /** + * 根据团队编码查询(忽略已删除) + */ + Optional findByTeamCodeAndDeletedFalse(String teamCode); + + /** + * 检查团队编码是否存在 + */ + boolean existsByTeamCodeAndDeletedFalse(String teamCode); +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/ITeamApplicationService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/ITeamApplicationService.java new file mode 100644 index 00000000..93350c73 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/ITeamApplicationService.java @@ -0,0 +1,10 @@ +package com.qqchen.deploy.backend.deploy.service; + +import com.qqchen.deploy.backend.deploy.dto.TeamApplicationDTO; +import com.qqchen.deploy.backend.deploy.entity.TeamApplication; +import com.qqchen.deploy.backend.deploy.query.TeamApplicationQuery; +import com.qqchen.deploy.backend.framework.service.IBaseService; + +public interface ITeamApplicationService extends IBaseService { +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/ITeamMemberService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/ITeamMemberService.java new file mode 100644 index 00000000..e499a793 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/ITeamMemberService.java @@ -0,0 +1,10 @@ +package com.qqchen.deploy.backend.deploy.service; + +import com.qqchen.deploy.backend.deploy.dto.TeamMemberDTO; +import com.qqchen.deploy.backend.deploy.entity.TeamMember; +import com.qqchen.deploy.backend.deploy.query.TeamMemberQuery; +import com.qqchen.deploy.backend.framework.service.IBaseService; + +public interface ITeamMemberService extends IBaseService { +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/ITeamService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/ITeamService.java new file mode 100644 index 00000000..ddecf80e --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/ITeamService.java @@ -0,0 +1,10 @@ +package com.qqchen.deploy.backend.deploy.service; + +import com.qqchen.deploy.backend.deploy.dto.TeamDTO; +import com.qqchen.deploy.backend.deploy.entity.Team; +import com.qqchen.deploy.backend.deploy.query.TeamQuery; +import com.qqchen.deploy.backend.framework.service.IBaseService; + +public interface ITeamService extends IBaseService { +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamApplicationServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamApplicationServiceImpl.java new file mode 100644 index 00000000..8e046468 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamApplicationServiceImpl.java @@ -0,0 +1,74 @@ +package com.qqchen.deploy.backend.deploy.service.impl; + +import com.qqchen.deploy.backend.deploy.converter.TeamApplicationConverter; +import com.qqchen.deploy.backend.deploy.dto.TeamApplicationDTO; +import com.qqchen.deploy.backend.deploy.entity.Application; +import com.qqchen.deploy.backend.deploy.entity.Team; +import com.qqchen.deploy.backend.deploy.entity.TeamApplication; +import com.qqchen.deploy.backend.deploy.query.TeamApplicationQuery; +import com.qqchen.deploy.backend.deploy.repository.IApplicationRepository; +import com.qqchen.deploy.backend.deploy.repository.ITeamApplicationRepository; +import com.qqchen.deploy.backend.deploy.repository.ITeamRepository; +import com.qqchen.deploy.backend.deploy.service.ITeamApplicationService; +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.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class TeamApplicationServiceImpl extends BaseServiceImpl + implements ITeamApplicationService { + + @Resource + private ITeamApplicationRepository teamApplicationRepository; + + @Resource + private ITeamRepository teamRepository; + + @Resource + private IApplicationRepository applicationRepository; + + @Resource + private TeamApplicationConverter teamApplicationConverter; + + @Override + @Transactional + public TeamApplicationDTO create(TeamApplicationDTO dto) { + // 检查是否已关联 + if (teamApplicationRepository.existsByTeamIdAndApplicationIdAndDeletedFalse(dto.getTeamId(), dto.getApplicationId())) { + throw new RuntimeException("该应用已关联到此团队"); + } + + return super.create(dto); + } + + @Override + public Page page(TeamApplicationQuery query) { + Page page = super.page(query); + + // 填充团队名称和应用信息 + List content = page.getContent().stream() + .peek(teamApp -> { + Optional teamOptional = teamRepository.findById(teamApp.getTeamId()); + teamOptional.ifPresent(team -> teamApp.setTeamName(team.getTeamName())); + + Optional appOptional = applicationRepository.findById(teamApp.getApplicationId()); + appOptional.ifPresent(app -> { + teamApp.setApplicationName(app.getAppName()); + teamApp.setApplicationCode(app.getAppCode()); + }); + }) + .collect(Collectors.toList()); + + return new PageImpl<>(content, page.getPageable(), page.getTotalElements()); + } +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamMemberServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamMemberServiceImpl.java new file mode 100644 index 00000000..041f517e --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamMemberServiceImpl.java @@ -0,0 +1,79 @@ +package com.qqchen.deploy.backend.deploy.service.impl; + +import com.qqchen.deploy.backend.deploy.converter.TeamMemberConverter; +import com.qqchen.deploy.backend.deploy.dto.TeamMemberDTO; +import com.qqchen.deploy.backend.deploy.entity.Team; +import com.qqchen.deploy.backend.deploy.entity.TeamMember; +import com.qqchen.deploy.backend.deploy.query.TeamMemberQuery; +import com.qqchen.deploy.backend.deploy.repository.ITeamMemberRepository; +import com.qqchen.deploy.backend.deploy.repository.ITeamRepository; +import com.qqchen.deploy.backend.deploy.service.ITeamMemberService; +import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; +import com.qqchen.deploy.backend.system.entity.User; +import com.qqchen.deploy.backend.system.repository.IUserRepository; +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.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class TeamMemberServiceImpl extends BaseServiceImpl + implements ITeamMemberService { + + @Resource + private ITeamMemberRepository teamMemberRepository; + + @Resource + private ITeamRepository teamRepository; + + @Resource + private IUserRepository userRepository; + + @Resource + private TeamMemberConverter teamMemberConverter; + + @Override + @Transactional + public TeamMemberDTO create(TeamMemberDTO dto) { + // 检查成员是否已加入团队 + if (teamMemberRepository.existsByTeamIdAndUserIdAndDeletedFalse(dto.getTeamId(), dto.getUserId())) { + throw new RuntimeException("该用户已是团队成员"); + } + + // 自动填充用户名和加入时间 + if (dto.getUserName() == null && dto.getUserId() != null) { + Optional userOptional = userRepository.findById(dto.getUserId()); + userOptional.ifPresent(user -> dto.setUserName(user.getUsername())); + } + + if (dto.getJoinTime() == null) { + dto.setJoinTime(LocalDateTime.now()); + } + + return super.create(dto); + } + + @Override + public Page page(TeamMemberQuery query) { + Page page = super.page(query); + + // 填充团队名称 + List content = page.getContent().stream() + .peek(member -> { + Optional teamOptional = teamRepository.findById(member.getTeamId()); + teamOptional.ifPresent(team -> member.setTeamName(team.getTeamName())); + }) + .collect(Collectors.toList()); + + return new PageImpl<>(content, page.getPageable(), page.getTotalElements()); + } +} + diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamServiceImpl.java new file mode 100644 index 00000000..7eca288c --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/TeamServiceImpl.java @@ -0,0 +1,85 @@ +package com.qqchen.deploy.backend.deploy.service.impl; + +import com.qqchen.deploy.backend.deploy.converter.TeamConverter; +import com.qqchen.deploy.backend.deploy.dto.TeamDTO; +import com.qqchen.deploy.backend.deploy.entity.Team; +import com.qqchen.deploy.backend.deploy.query.TeamQuery; +import com.qqchen.deploy.backend.deploy.repository.ITeamApplicationRepository; +import com.qqchen.deploy.backend.deploy.repository.ITeamMemberRepository; +import com.qqchen.deploy.backend.deploy.repository.ITeamRepository; +import com.qqchen.deploy.backend.deploy.service.ITeamService; +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.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class TeamServiceImpl extends BaseServiceImpl + implements ITeamService { + + @Resource + private ITeamRepository teamRepository; + + @Resource + private ITeamMemberRepository teamMemberRepository; + + @Resource + private ITeamApplicationRepository teamApplicationRepository; + + @Resource + private TeamConverter teamConverter; + + @Override + @Transactional + public TeamDTO create(TeamDTO dto) { + // 检查编码唯一性 + if (teamRepository.existsByTeamCodeAndDeletedFalse(dto.getTeamCode())) { + throw new RuntimeException("团队编码已存在: " + dto.getTeamCode()); + } + return super.create(dto); + } + + @Override + @Transactional + public void delete(Long id) { + // 检查是否有成员 + Long memberCount = teamMemberRepository.countByTeamIdAndDeletedFalse(id); + if (memberCount > 0) { + throw new RuntimeException("该团队下存在成员,无法删除"); + } + + // 检查是否有关联应用 + Long applicationCount = teamApplicationRepository.countByTeamIdAndDeletedFalse(id); + if (applicationCount > 0) { + throw new RuntimeException("该团队下存在关联应用,无法删除"); + } + + super.delete(id); + } + + @Override + public Page page(TeamQuery query) { + Page page = super.page(query); + + // 统计每个团队的成员数量和应用数量 + List content = page.getContent().stream() + .peek(team -> { + Long memberCount = teamMemberRepository.countByTeamIdAndDeletedFalse(team.getId()); + Long applicationCount = teamApplicationRepository.countByTeamIdAndDeletedFalse(team.getId()); + team.setMemberCount(memberCount); + team.setApplicationCount(applicationCount); + }) + .collect(Collectors.toList()); + + return new PageImpl<>(content, page.getPageable(), page.getTotalElements()); + } +} + diff --git a/backend/src/main/resources/db/changelog/changes/v1.0.0-data.sql b/backend/src/main/resources/db/changelog/changes/v1.0.0-data.sql index 085c2e20..c553e8cd 100644 --- a/backend/src/main/resources/db/changelog/changes/v1.0.0-data.sql +++ b/backend/src/main/resources/db/changelog/changes/v1.0.0-data.sql @@ -64,8 +64,8 @@ VALUES -- 运维管理 (200, '运维管理', '/deploy', 'Layout', 'DeploymentUnitOutlined', 1, NULL, 2, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), --- 项目组管理 -(201, '项目组管理', '/deploy/project-group', '/src/pages/Deploy/ProjectGroup/List/index', 'ProjectOutlined', 2, 200, 1, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), +-- 团队管理 +(201, '团队管理', '/deploy/teams', '/src/pages/Deploy/Team/List/index', 'TeamOutlined', 2, 200, 1, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), -- 应用管理 (202, '应用管理', '/deploy/applications', '/src/pages/Deploy/Application/List/index', 'AppstoreOutlined', 2, 200, 2, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), @@ -853,3 +853,23 @@ VALUES ('数据采集', 'DATA_COLLECTION', '用于数据采集的表单', 'DatabaseOutlined', 2, 1, 'system', NOW(), 'system', NOW(), 0, 0), ('问卷调查', 'SURVEY', '用于问卷调查的表单', 'FormOutlined', 3, 1, 'system', NOW(), 'system', NOW(), 0, 0), ('其他', 'OTHER', '其他类型的表单', 'FileOutlined', 99, 1, 'system', NOW(), 'system', NOW(), 0, 0); + +-- -------------------------------------------------------------------------------------- +-- 初始化团队管理数据 +-- -------------------------------------------------------------------------------------- + +-- 初始化团队数据 +INSERT INTO deploy_team (id, team_code, team_name, description, owner_id, owner_name, enabled, sort, create_by, create_time, update_by, update_time, version, deleted) +VALUES +(1, 'PLATFORM_TEAM', '平台研发团队', '负责基础平台和框架的开发维护', 1, '超级管理员', 1, 1, 'admin', NOW(), 'admin', NOW(), 1, 0), +(2, 'DEVOPS_TEAM', 'DevOps团队', '负责CI/CD和运维自动化', 4, '运维经理', 1, 2, 'admin', NOW(), 'admin', NOW(), 1, 0); + +-- 初始化团队成员数据 +INSERT INTO deploy_team_member (team_id, user_id, user_name, role_in_team, join_time, create_by, create_time, update_by, update_time, version, deleted) +VALUES +-- 平台研发团队成员 +(1, 1, 'admin', '负责人', NOW(), 'admin', NOW(), 'admin', NOW(), 1, 0), +(1, 3, 'dev_manager', '开发', NOW(), 'admin', NOW(), 'admin', NOW(), 1, 0), +-- DevOps团队成员 +(2, 4, 'ops_manager', '负责人', NOW(), 'admin', NOW(), 'admin', NOW(), 1, 0), +(2, 2, 'it_manager', '运维', NOW(), 'admin', NOW(), 'admin', NOW(), 1, 0); 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 a68aaf04..b939779c 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 @@ -755,6 +755,73 @@ CREATE TABLE deploy_environment -- 索引 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 '创建人', + create_time DATETIME(6) 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 '团队描述', + 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), + 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='团队表'; + +-- 团队成员表 +CREATE TABLE deploy_team_member +( + 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_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), + 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) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='团队成员表'; + +-- 团队应用关联表 +CREATE TABLE deploy_team_application +( + 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_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', + + UNIQUE INDEX uk_team_app (team_id, application_id), + INDEX idx_application (application_id), + CONSTRAINT fk_team_app_team FOREIGN KEY (team_id) REFERENCES deploy_team(id), + CONSTRAINT fk_team_app_application FOREIGN KEY (application_id) REFERENCES deploy_application(id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='团队应用关联表'; CREATE TABLE deploy_log ( -- 基础字段