diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/BdTeamRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/BdTeamRestController.java index f53aa366..0e8c309b 100644 --- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/BdTeamRestController.java +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/BdTeamRestController.java @@ -1,7 +1,9 @@ package com.red.circle.other.adapter.app; +import com.red.circle.common.business.dto.cmd.AppExtCommand; import com.red.circle.other.app.dto.clientobject.BdTeamMemberDetailCO; import com.red.circle.other.app.dto.clientobject.BdTeamOverviewCO; +import com.red.circle.other.app.dto.clientobject.BdTeamSummaryCO; import com.red.circle.other.app.dto.cmd.BdTeamMemberDetailQueryCmd; import com.red.circle.other.app.dto.cmd.BdTeamQueryCmd; import com.red.circle.other.app.service.BdTeamService; @@ -49,4 +51,15 @@ public class BdTeamRestController { public BdTeamMemberDetailCO queryMemberDetail(@RequestBody BdTeamMemberDetailQueryCmd cmd) { return bdTeamService.queryMemberDetail(cmd); } + + /** + * 查询BD团队总览 + *

+ * 返回当前用户在BD_LEADER、BD、AGENCY三个角色下的汇总数据 + *

+ */ + @PostMapping("/summary") + public BdTeamSummaryCO queryTeamSummary(AppExtCommand cmd) { + return bdTeamService.queryTeamSummary(cmd.getReqUserId()); + } } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/bd/query/BdTeamSummaryQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/bd/query/BdTeamSummaryQryExe.java new file mode 100644 index 00000000..16e74d82 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/bd/query/BdTeamSummaryQryExe.java @@ -0,0 +1,289 @@ +package com.red.circle.other.app.command.bd.query; + +import com.alibaba.fastjson.JSON; +import com.red.circle.component.redis.service.RedisService; +import com.red.circle.other.app.convertor.user.UserProfileAppConvertor; +import com.red.circle.other.app.dto.clientobject.BdTeamMemberCO; +import com.red.circle.other.app.dto.clientobject.BdTeamSummaryCO; +import com.red.circle.other.domain.gateway.user.UserProfileGateway; +import com.red.circle.other.infra.database.mongo.dto.team.TeamBillMemberTarget; +import com.red.circle.other.infra.database.mongo.entity.team.team.TeamBillCycle; +import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMemberTarget; +import com.red.circle.other.infra.database.mongo.entity.team.team.TeamPolicyManager; +import com.red.circle.other.infra.database.mongo.entity.team.team.TeamProfile; +import com.red.circle.other.infra.database.mongo.service.team.TeamBillCycleUtils; +import com.red.circle.other.infra.database.mongo.service.team.team.TeamBillCycleService; +import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberTargetService; +import com.red.circle.other.infra.database.mongo.service.team.team.TeamPolicyManagerService; +import com.red.circle.other.infra.database.mongo.service.team.team.TeamProfileService; +import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentBaseInfo; +import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentTeam; +import com.red.circle.other.infra.database.rds.entity.team.RoomBdLead; +import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentBaseInfoService; +import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentTeamService; +import com.red.circle.other.infra.database.rds.service.team.RoomBdLeadService; +import com.red.circle.other.inner.enums.team.TeamBillCycleStatus; +import com.red.circle.other.inner.model.dto.user.UserProfileDTO; +import com.red.circle.tool.core.collection.CollectionUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * BD团队总览查询执行器 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class BdTeamSummaryQryExe { + + private final BusinessDevelopmentTeamService businessDevelopmentTeamService; + private final BusinessDevelopmentBaseInfoService businessDevelopmentBaseInfoService; + private final TeamBillCycleService teamBillCycleService; + private final TeamProfileService teamProfileService; + private final TeamMemberTargetService teamMemberTargetService; + private final TeamPolicyManagerService teamPolicyManagerService; + private final UserProfileGateway userProfileGateway; + private final UserProfileAppConvertor userProfileAppConvertor; + private final RoomBdLeadService roomBdLeadService; + private final RedisService redisService; + + /** + * 执行查询 + */ + public BdTeamSummaryCO execute(Long userId) { + // 缓存查询 + String cacheKey = "bdteam:summary:" + userId; + BdTeamSummaryCO cached = redisService.getStringToObject(cacheKey, BdTeamSummaryCO.class); + if (cached != null) { + return cached; + } + + // 查询数据 + BdTeamSummaryCO result = queryTeamSummary(userId); + + // 缓存结果(2分钟) + redisService.setString(cacheKey, JSON.toJSONString(result), 2, TimeUnit.MINUTES); + + return result; + } + + /** + * 查询团队总览 + */ + private BdTeamSummaryCO queryTeamSummary(Long userId) { + BdTeamSummaryCO summary = new BdTeamSummaryCO(); + + // 获取当前账单周期 + Integer currentBillBelong = TeamBillCycleUtils.getCalcBillBelong(); + + // 查询三个角色的数据 + BdTeamSummaryCO.TeamSummaryItem bdLeaderTeams = queryBdLeaderSummary(userId, currentBillBelong); + BdTeamSummaryCO.TeamSummaryItem bdTeams = queryBdSummary(userId, currentBillBelong); + BdTeamSummaryCO.TeamSummaryItem agencyTeams = queryAgencySummary(userId, currentBillBelong); + + summary.setBdLeaderTeams(bdLeaderTeams); + summary.setBdTeams(bdTeams); + summary.setAgencyTeams(agencyTeams); + + // Team earnings this period = BD Teams 的 totalIncome + summary.setTeamEarningsThisPeriod(bdTeams.getTotalIncome()); + + return summary; + } + + /** + * 查询 BD Leader 汇总 + */ + private BdTeamSummaryCO.TeamSummaryItem queryBdLeaderSummary(Long bdLeaderUserId, Integer currentBillBelong) { + BdTeamSummaryCO.TeamSummaryItem item = new BdTeamSummaryCO.TeamSummaryItem(); + + // 查询该 Leader 下的所有 BD + List bdList = + businessDevelopmentBaseInfoService.listBdByLeadUserId(bdLeaderUserId); + + if (CollectionUtils.isEmpty(bdList)) { + item.setCount(0); + item.setTotalIncome(BigDecimal.ZERO); + return item; + } + + // 过滤BD Leader + Set bdIdSet = bdList.stream() + .map(BusinessDevelopmentBaseInfo::getUserId) + .collect(Collectors.toSet()); + List roomBdLeads = roomBdLeadService.listByUserIds(bdIdSet); + + if (CollectionUtils.isEmpty(roomBdLeads)) { + item.setCount(0); + item.setTotalIncome(BigDecimal.ZERO); + return item; + } + + List bdLeaderIdList = roomBdLeads.stream() + .map(RoomBdLead::getUserId) + .toList(); + bdList = bdList.stream() + .filter(e -> !e.getUserId().equals(bdLeaderUserId)) + .filter(e -> bdLeaderIdList.contains(e.getUserId())) + .collect(Collectors.toList()); + + item.setCount(bdList.size()); + + // 汇总所有 BD 的收入 + BigDecimal totalIncome = BigDecimal.ZERO; + for (BusinessDevelopmentBaseInfo bdInfo : bdList) { + List bdTeamList = + businessDevelopmentTeamService.listByUserId(bdInfo.getUserId()); + if (CollectionUtils.isNotEmpty(bdTeamList)) { + BigDecimal bdIncome = calculateBdTotalIncome(bdTeamList, currentBillBelong); + totalIncome = totalIncome.add(bdIncome); + } + } + + item.setTotalIncome(totalIncome); + return item; + } + + /** + * 查询 BD 汇总 + */ + private BdTeamSummaryCO.TeamSummaryItem queryBdSummary(Long bdUserId, Integer currentBillBelong) { + BdTeamSummaryCO.TeamSummaryItem item = new BdTeamSummaryCO.TeamSummaryItem(); + + // 查询该用户下的所有 Agency 团队 + List bdTeamList = businessDevelopmentTeamService.listByUserId(bdUserId); + + if (CollectionUtils.isEmpty(bdTeamList)) { + item.setCount(0); + item.setTotalIncome(BigDecimal.ZERO); + return item; + } + + item.setCount(bdTeamList.size()); + + // 计算总收入 + BigDecimal totalIncome = calculateBdTotalIncome(bdTeamList, currentBillBelong); + item.setTotalIncome(totalIncome); + + return item; + } + + /** + * 查询 Agency 汇总 + */ + private BdTeamSummaryCO.TeamSummaryItem queryAgencySummary(Long agencyUserId, Integer currentBillBelong) { + BdTeamSummaryCO.TeamSummaryItem item = new BdTeamSummaryCO.TeamSummaryItem(); + + // 查询该用户的所有团队 + List bdTeamList = businessDevelopmentTeamService.listByUserId(agencyUserId); + + if (CollectionUtils.isEmpty(bdTeamList)) { + item.setCount(0); + item.setTotalIncome(BigDecimal.ZERO); + return item; + } + + item.setCount(bdTeamList.size()); + + // 获取团队ID集合 + Set teamIdSet = bdTeamList.stream() + .map(BusinessDevelopmentTeam::getTeamId) + .collect(Collectors.toSet()); + + // 查询账单数据 + Map billCycleMap = teamBillCycleService.mapByTeamIds2( + teamIdSet, currentBillBelong, TeamBillCycleStatus.UNPAID); + + Map> memberTargetMap = + teamMemberTargetService.mapMemberBillTarget(teamIdSet, currentBillBelong); + + // 查询区域政策 + Map policyManagerMap = teamPolicyManagerService.mapRegionRelease( + billCycleMap.values().stream() + .map(TeamBillCycle::getRegion) + .collect(Collectors.toSet())); + + // 计算总收入 + BigDecimal totalIncome = BigDecimal.ZERO; + for (BusinessDevelopmentTeam bdTeam : bdTeamList) { + BigDecimal teamIncome = getTeamTotalSalary( + billCycleMap, memberTargetMap, policyManagerMap, bdTeam.getTeamId()); + totalIncome = totalIncome.add(teamIncome); + } + + item.setTotalIncome(totalIncome); + return item; + } + + /** + * 计算 BD 的总收入(汇总其所有 Agency 团队的收入) + */ + private BigDecimal calculateBdTotalIncome(List bdTeamList, Integer currentBillBelong) { + // 1. 获取所有团队ID + Set teamIdSet = bdTeamList.stream() + .map(BusinessDevelopmentTeam::getTeamId) + .collect(Collectors.toSet()); + + // 2. 查询账单周期 + Map billCycleMap = teamBillCycleService.mapByTeamIds2( + teamIdSet, currentBillBelong, TeamBillCycleStatus.UNPAID); + + // 3. 查询成员目标 + Map> memberTargetMap = + teamMemberTargetService.mapMemberBillTarget(teamIdSet, currentBillBelong); + + // 4. 查询区域政策 + Map policyManagerMap = teamPolicyManagerService.mapRegionRelease( + billCycleMap.values().stream() + .map(TeamBillCycle::getRegion) + .collect(Collectors.toSet())); + + // 5. 计算每个团队的收入并汇总 + BigDecimal totalIncome = BigDecimal.ZERO; + for (BusinessDevelopmentTeam bdTeam : bdTeamList) { + Long teamId = bdTeam.getTeamId(); + BigDecimal teamIncome = getTeamTotalSalary(billCycleMap, memberTargetMap, policyManagerMap, teamId); + totalIncome = totalIncome.add(teamIncome); + } + + return totalIncome; + } + + /** + * 计算单个团队的总收入 + */ + private BigDecimal getTeamTotalSalary( + Map billCycleMap, + Map> teamMemberTargetMap, + Map policyManagerMap, + Long teamId) { + + TeamBillCycle billCycle = billCycleMap.get(teamId); + if (billCycle == null) { + return BigDecimal.ZERO; + } + + List targetList = teamMemberTargetMap.get(teamId); + List memberTargets = TeamBillCycleUtils.calculatorPolicyTarget( + targetList, policyManagerMap.get(billCycle.getRegion())); + + return ownTotalSalary(memberTargets); + } + + /** + * 汇总成员工资 + */ + private BigDecimal ownTotalSalary(List teamBillMemberTargets) { + return teamBillMemberTargets.stream() + .map(TeamBillMemberTarget::getTotalSalary) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.DOWN); + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/BdTeamServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/BdTeamServiceImpl.java index 1d0bd78e..a6061035 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/BdTeamServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/BdTeamServiceImpl.java @@ -2,8 +2,10 @@ package com.red.circle.other.app.service; import com.red.circle.other.app.command.bd.query.BdTeamMemberDetailQryExe; import com.red.circle.other.app.command.bd.query.BdTeamQryExe; +import com.red.circle.other.app.command.bd.query.BdTeamSummaryQryExe; import com.red.circle.other.app.dto.clientobject.BdTeamMemberDetailCO; import com.red.circle.other.app.dto.clientobject.BdTeamOverviewCO; +import com.red.circle.other.app.dto.clientobject.BdTeamSummaryCO; import com.red.circle.other.app.dto.cmd.BdTeamMemberDetailQueryCmd; import com.red.circle.other.app.dto.cmd.BdTeamQueryCmd; import lombok.RequiredArgsConstructor; @@ -20,6 +22,7 @@ public class BdTeamServiceImpl implements BdTeamService { private final BdTeamQryExe bdTeamQryExe; private final BdTeamMemberDetailQryExe bdTeamMemberDetailQryExe; + private final BdTeamSummaryQryExe bdTeamSummaryQryExe; @Override public BdTeamOverviewCO queryTeamOverview(BdTeamQueryCmd cmd) { @@ -30,4 +33,9 @@ public class BdTeamServiceImpl implements BdTeamService { public BdTeamMemberDetailCO queryMemberDetail(BdTeamMemberDetailQueryCmd cmd) { return bdTeamMemberDetailQryExe.execute(cmd); } + + @Override + public BdTeamSummaryCO queryTeamSummary(Long userId) { + return bdTeamSummaryQryExe.execute(userId); + } } diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/BdTeamSummaryCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/BdTeamSummaryCO.java new file mode 100644 index 00000000..e73e0fed --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/BdTeamSummaryCO.java @@ -0,0 +1,48 @@ +package com.red.circle.other.app.dto.clientobject; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * BD团队总览 + */ +@Data +public class BdTeamSummaryCO { + + /** + * 本期团队收入(My BD Teams 的 totalIncome) + */ + private BigDecimal teamEarningsThisPeriod; + + /** + * My BD Leader Teams 信息 + */ + private TeamSummaryItem bdLeaderTeams; + + /** + * My BD Teams 信息 + */ + private TeamSummaryItem bdTeams; + + /** + * My Agency Teams 信息 + */ + private TeamSummaryItem agencyTeams; + + /** + * 团队汇总项 + */ + @Data + public static class TeamSummaryItem { + /** + * 团队数量 + */ + private Integer count; + + /** + * 总收入 + */ + private BigDecimal totalIncome; + } +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/BdTeamService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/BdTeamService.java index cabb97df..cd2801e0 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/BdTeamService.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/BdTeamService.java @@ -2,6 +2,7 @@ package com.red.circle.other.app.service; import com.red.circle.other.app.dto.clientobject.BdTeamMemberDetailCO; import com.red.circle.other.app.dto.clientobject.BdTeamOverviewCO; +import com.red.circle.other.app.dto.clientobject.BdTeamSummaryCO; import com.red.circle.other.app.dto.cmd.BdTeamMemberDetailQueryCmd; import com.red.circle.other.app.dto.cmd.BdTeamQueryCmd; @@ -33,4 +34,15 @@ public interface BdTeamService { * @return 成员详情 */ BdTeamMemberDetailCO queryMemberDetail(BdTeamMemberDetailQueryCmd cmd); + + /** + * 查询BD团队总览 + *

+ * 返回当前用户在BD_LEADER、BD、AGENCY三个角色下的汇总数据 + *

+ * + * @param userId 用户ID + * @return 团队总览 + */ + BdTeamSummaryCO queryTeamSummary(Long userId); }