Commit 173b40ebc3db9e1193779cd7d2859aa71aa0b039

Authored by YunaiV
1 parent 571d3263

✨ feat(mes): 新增班组排班记录生成逻辑及相关字段校验

实现班组排班记录的生成逻辑,增加了班组类型和用户存在性校验,优化了排班记录的批量写入方式。同时,新增了相关错误码以处理班组和班次数量不足的情况。
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/team/MesCalTeamShiftController.java
1 1 package cn.iocoder.yudao.module.mes.controller.admin.cal.team;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
4 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 7 import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.shift.MesCalTeamShiftListReqVO;
6 8 import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.shift.MesCalTeamShiftRespVO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanShiftDO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamDO;
7 11 import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamShiftDO;
  12 +import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanShiftService;
  13 +import cn.iocoder.yudao.module.mes.service.cal.team.MesCalTeamService;
8 14 import cn.iocoder.yudao.module.mes.service.cal.team.MesCalTeamShiftService;
9 15 import io.swagger.v3.oas.annotations.Operation;
10 16 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -16,9 +22,12 @@ import org.springframework.web.bind.annotation.GetMapping;
16 22 import org.springframework.web.bind.annotation.RequestMapping;
17 23 import org.springframework.web.bind.annotation.RestController;
18 24  
  25 +import java.util.Collections;
19 26 import java.util.List;
  27 +import java.util.Map;
20 28  
21 29 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  30 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
22 31  
23 32 @Tag(name = "管理后台 - MES 班组排班")
24 33 @RestController
... ... @@ -28,13 +37,28 @@ public class MesCalTeamShiftController {
28 37  
29 38 @Resource
30 39 private MesCalTeamShiftService teamShiftService;
  40 + @Resource
  41 + private MesCalTeamService teamService;
  42 + @Resource
  43 + private MesCalPlanShiftService planShiftService;
31 44  
32 45 @GetMapping("/list")
33 46 @Operation(summary = "获得班组排班列表")
34 47 @PreAuthorize("@ss.hasPermission('mes:cal-team-shift:query')")
35 48 public CommonResult<List<MesCalTeamShiftRespVO>> getTeamShiftList(@Valid MesCalTeamShiftListReqVO reqVO) {
36 49 List<MesCalTeamShiftDO> list = teamShiftService.getTeamShiftList(reqVO);
37   - return success(BeanUtils.toBean(list, MesCalTeamShiftRespVO.class));
  50 + if (CollUtil.isEmpty(list)) {
  51 + return success(Collections.emptyList());
  52 + }
  53 + // 关联查询班组名称和班次名称
  54 + Map<Long, MesCalTeamDO> teamMap = teamService.getTeamMap(
  55 + convertSet(list, MesCalTeamShiftDO::getTeamId));
  56 + Map<Long, MesCalPlanShiftDO> shiftMap = planShiftService.getPlanShiftMap(
  57 + convertSet(list, MesCalTeamShiftDO::getShiftId));
  58 + return success(BeanUtils.toBean(list, MesCalTeamShiftRespVO.class, vo -> {
  59 + MapUtils.findAndThen(teamMap, vo.getTeamId(), team -> vo.setTeamName(team.getName()));
  60 + MapUtils.findAndThen(shiftMap, vo.getShiftId(), shift -> vo.setShiftName(shift.getName()));
  61 + }));
38 62 }
39 63  
40 64 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/team/vo/MesCalTeamSaveReqVO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import jakarta.validation.constraints.NotEmpty;
  5 +import jakarta.validation.constraints.NotNull;
5 6 import lombok.Data;
6 7  
7 8 @Schema(description = "管理后台 - MES 班组新增/修改 Request VO")
... ... @@ -19,10 +20,11 @@ public class MesCalTeamSaveReqVO {
19 20 @NotEmpty(message = "班组名称不能为空")
20 21 private String name;
21 22  
22   - @Schema(description = "班组类型", example = "1")
  23 + @Schema(description = "班组类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  24 + @NotNull(message = "班组类型不能为空")
23 25 private Integer calendarType;
24 26  
25 27 @Schema(description = "备注")
26 28 private String remark;
27 29  
28   - }
  30 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/team/vo/member/MesCalTeamMemberRespVO.java
... ... @@ -18,9 +18,6 @@ public class MesCalTeamMemberRespVO {
18 18 @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
19 19 private Long userId;
20 20  
21   - @Schema(description = "用户名", example = "admin")
22   - private String userName;
23   -
24 21 @Schema(description = "用户昵称", example = "管理员")
25 22 private String nickname;
26 23  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/cal/team/MesCalTeamShiftMapper.java
... ... @@ -37,4 +37,8 @@ public interface MesCalTeamShiftMapper extends BaseMapperX&lt;MesCalTeamShiftDO&gt; {
37 37 delete(MesCalTeamShiftDO::getPlanId, planId);
38 38 }
39 39  
  40 + default void deleteByTeamId(Long teamId) {
  41 + delete(MesCalTeamShiftDO::getTeamId, teamId);
  42 + }
  43 +
40 44 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -118,8 +118,11 @@ public interface ErrorCodeConstants {
118 118 // ========== MES 日历排班-班组成员(1-040-201-100) ==========
119 119 ErrorCode CAL_TEAM_MEMBER_NOT_EXISTS = new ErrorCode(1_040_201_100, "班组成员不存在");
120 120 ErrorCode CAL_TEAM_MEMBER_USER_DUPLICATE = new ErrorCode(1_040_201_101, "该用户已分配到其他班组");
  121 + ErrorCode CAL_TEAM_MEMBER_USER_NOT_EXISTS = new ErrorCode(1_040_201_102, "用户不存在");
121 122 // ========== MES 日历排班-班组排班(1-040-201-200) ==========
122 123 ErrorCode CAL_TEAM_SHIFT_NOT_EXISTS = new ErrorCode(1_040_201_200, "班组排班记录不存在");
  124 + ErrorCode CAL_TEAM_SHIFT_GENERATE_TEAM_NOT_ENOUGH = new ErrorCode(1_040_201_201, "班组数量不足,无法生成排班记录");
  125 + ErrorCode CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH = new ErrorCode(1_040_201_202, "班次数量不足,无法生成排班记录");
123 126  
124 127 // ========== MES 日历排班-排班计划(1-040-202-000) ==========
125 128 ErrorCode CAL_PLAN_NOT_EXISTS = new ErrorCode(1_040_202_000, "排班计划不存在");
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamMemberServiceImpl.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.member.MesCalTea
6 6 import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.member.MesCalTeamMemberSaveReqVO;
7 7 import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamMemberDO;
8 8 import cn.iocoder.yudao.module.mes.dal.mysql.cal.team.MesCalTeamMemberMapper;
  9 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
9 10 import jakarta.annotation.Resource;
10 11 import org.springframework.context.annotation.Lazy;
11 12 import org.springframework.stereotype.Service;
... ... @@ -31,12 +32,16 @@ public class MesCalTeamMemberServiceImpl implements MesCalTeamMemberService {
31 32 @Resource
32 33 @Lazy
33 34 private MesCalTeamService teamService;
  35 + @Resource
  36 + private AdminUserApi adminUserApi;
34 37  
35 38 @Override
36 39 public Long createTeamMember(MesCalTeamMemberSaveReqVO createReqVO) {
37 40 // 1.1 校验班组存在
38 41 teamService.validateTeamExists(createReqVO.getTeamId());
39   - // 1.2 校验用户未分配到其他班组
  42 + // 1.2 校验用户存在
  43 + validateUserExists(createReqVO.getUserId());
  44 + // 1.3 校验用户未分配到其他班组
40 45 validateUserUnique(createReqVO.getUserId());
41 46  
42 47 // 2. 插入
... ... @@ -89,6 +94,12 @@ public class MesCalTeamMemberServiceImpl implements MesCalTeamMemberService {
89 94 }
90 95 }
91 96  
  97 + private void validateUserExists(Long userId) {
  98 + if (adminUserApi.getUser(userId) == null) {
  99 + throw exception(CAL_TEAM_MEMBER_USER_NOT_EXISTS);
  100 + }
  101 + }
  102 +
92 103 private void validateUserUnique(Long userId) {
93 104 if (teamMemberMapper.selectByUserId(userId) != null) {
94 105 throw exception(CAL_TEAM_MEMBER_USER_DUPLICATE);
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamServiceImpl.java
... ... @@ -35,6 +35,9 @@ public class MesCalTeamServiceImpl implements MesCalTeamService {
35 35 @Resource
36 36 @Lazy
37 37 private MesCalTeamMemberService teamMemberService;
  38 + @Resource
  39 + @Lazy
  40 + private MesCalTeamShiftService teamShiftService;
38 41  
39 42 @Override
40 43 public Long createTeam(MesCalTeamSaveReqVO createReqVO) {
... ... @@ -67,7 +70,9 @@ public class MesCalTeamServiceImpl implements MesCalTeamService {
67 70  
68 71 // 2.1 级联删除成员
69 72 teamMemberService.deleteByTeamId(id);
70   - // 2.2 删除班组
  73 + // 2.2 级联删除排班记录
  74 + teamShiftService.deleteByTeamId(id);
  75 + // 2.3 删除班组
71 76 teamMapper.deleteById(id);
72 77 }
73 78  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftService.java
... ... @@ -34,4 +34,11 @@ public interface MesCalTeamShiftService {
34 34 */
35 35 void deleteByPlanId(Long planId);
36 36  
  37 + /**
  38 + * 根据班组编号删除所有排班记录
  39 + *
  40 + * @param teamId 班组编号
  41 + */
  42 + void deleteByTeamId(Long teamId);
  43 +
37 44 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftServiceImpl.java
... ... @@ -15,6 +15,7 @@ import jakarta.annotation.Resource;
15 15 import org.springframework.context.annotation.Lazy;
16 16 import org.springframework.scheduling.annotation.Async;
17 17 import org.springframework.stereotype.Service;
  18 +import org.springframework.transaction.annotation.Transactional;
18 19 import org.springframework.validation.annotation.Validated;
19 20  
20 21 import java.time.DayOfWeek;
... ... @@ -22,8 +23,13 @@ import java.time.LocalDate;
22 23 import java.time.LocalDateTime;
23 24 import java.time.Month;
24 25 import java.time.temporal.ChronoUnit;
  26 +import java.util.ArrayList;
25 27 import java.util.List;
26 28  
  29 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  30 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH;
  31 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.CAL_TEAM_SHIFT_GENERATE_TEAM_NOT_ENOUGH;
  32 +
27 33 /**
28 34 * MES 班组排班 Service 实现类
29 35 *
... ... @@ -45,8 +51,9 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService {
45 51 @Lazy
46 52 private MesCalPlanTeamService planTeamService;
47 53  
48   - // TODO @芋艿:这块逻辑,可能要想下;
  54 + // TODO @AI:这里要不不异步?性能一般支撑的住把?
49 55 @Async
  56 + @Transactional(rollbackFor = Exception.class)
50 57 @Override
51 58 public void generateTeamShiftRecords(Long planId) {
52 59 // 1.1 查询排班计划
... ... @@ -55,139 +62,181 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService {
55 62 List<MesCalPlanShiftDO> shifts = planShiftService.getPlanShiftListByPlanId(planId);
56 63 // 1.3 查询计划中的班组列表
57 64 List<MesCalPlanTeamDO> teams = planTeamService.getPlanTeamListByPlanId(planId);
  65 + // 1.4 校验班组和班次数量是否满足班型要求
  66 + MesCalShiftTypeEnum shiftTypeEnum = MesCalShiftTypeEnum.valueOf(plan.getShiftType());
  67 + int requiredCount = shiftTypeEnum.getRequiredTeamCount();
  68 + if (teams.size() < requiredCount) {
  69 + throw exception(CAL_TEAM_SHIFT_GENERATE_TEAM_NOT_ENOUGH);
  70 + }
  71 + if (shifts.size() < requiredCount) {
  72 + throw exception(CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH);
  73 + }
58 74  
  75 + // TODO @AI:优化下下面的注释;
59 76 // 2.1 计算日期差值(天数)
60 77 LocalDate startDate = plan.getStartDate().toLocalDate();
61 78 LocalDate endDate = plan.getEndDate().toLocalDate();
62 79 long days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
63   - // TODO @AI:dateutils,还是 localdateutils 应该有方法;或者 hutool 的
  80 +
  81 + // DONE @AI:要不要先把记录生成好,最后去存入数据库;
  82 + // 说明:先收集所有排班记录到列表,最后统一写入数据库,减少 DB 交互
  83 + List<MesCalTeamShiftDO> allRecords = new ArrayList<>();
  84 +
64 85 // 2.2 遍历每一天,生成排班记录
  86 + // DONE @AI:逻辑写的又点乱(复杂),看看能不能在优化下;
  87 + // 说明:通过提取 buildRecordsForDay 子方法优化可读性
65 88 int shiftIndex = 0;
66 89 for (int i = 0; i < days; i++) {
67 90 LocalDate currentDate = startDate.plusDays(i);
68 91 LocalDateTime currentDay = currentDate.atStartOfDay();
69   - // 2.1 根据倒班方式计算 shiftIndex
70   - if (MesCalShiftMethodEnum.QUARTER.getMethod().equals(plan.getShiftMethod())) {
71   - // 按季度轮班:到了新季度的第一天,且不是排班计划开始的季度
72   - LocalDate quarterStart = getQuarterStart(currentDate);
73   - LocalDate planQuarterStart = getQuarterStart(startDate);
74   - if (currentDate.equals(quarterStart) && !quarterStart.equals(planQuarterStart)) {
75   - shiftIndex++;
76   - }
77   - } else if (MesCalShiftMethodEnum.MONTH.getMethod().equals(plan.getShiftMethod())) {
78   - // 按月轮班:到了月初,且不是排班计划开始的月份
79   - LocalDate monthStart = currentDate.withDayOfMonth(1);
80   - LocalDate planMonthStart = startDate.withDayOfMonth(1);
81   - if (currentDate.equals(monthStart) && !monthStart.equals(planMonthStart)) {
82   - shiftIndex++;
83   - }
84   - } else if (MesCalShiftMethodEnum.WEEK.getMethod().equals(plan.getShiftMethod())) {
85   - // 按周轮班:到了周一,且不是排班计划开始的周
86   - LocalDate weekStart = getWeekStart(currentDate);
87   - LocalDate planWeekStart = getWeekStart(startDate);
88   - if (currentDate.equals(weekStart) && !weekStart.equals(planWeekStart)) {
89   - shiftIndex++;
90   - }
  92 + // 2.2.1 根据倒班方式计算 shiftIndex
  93 + shiftIndex = calculateShiftIndex(shiftIndex, i, currentDate, startDate, plan);
  94 + // 2.2.2 根据轮班方式生成排班记录,收集到列表
  95 + buildRecordsForDay(allRecords, planId, currentDay, shiftIndex, plan.getShiftType(), teams, shifts);
  96 + }
  97 +
  98 + // 3. 批量写入数据库
  99 + // TODO @AI:mybatis plus 有没 saveBatch 方法?
  100 + for (MesCalTeamShiftDO record : allRecords) {
  101 + saveTeamShift(record);
  102 + }
  103 + }
  104 +
  105 + /**
  106 + * 计算当天的 shiftIndex(根据倒班方式判断是否需要递增)
  107 + */
  108 + private int calculateShiftIndex(int shiftIndex, int dayOffset, LocalDate currentDate,
  109 + LocalDate startDate, MesCalPlanDO plan) {
  110 + if (dayOffset == 0) {
  111 + return shiftIndex; // 第一天不递增
  112 + }
  113 + if (MesCalShiftMethodEnum.QUARTER.getMethod().equals(plan.getShiftMethod())) {
  114 + // 按季度轮班:到了新季度的第一天
  115 + LocalDate quarterStart = getQuarterStart(currentDate);
  116 + LocalDate planQuarterStart = getQuarterStart(startDate);
  117 + if (currentDate.equals(quarterStart) && !quarterStart.equals(planQuarterStart)) {
  118 + return shiftIndex + 1;
  119 + }
  120 + } else if (MesCalShiftMethodEnum.MONTH.getMethod().equals(plan.getShiftMethod())) {
  121 + // 按月轮班:到了月初
  122 + LocalDate monthStart = currentDate.withDayOfMonth(1);
  123 + LocalDate planMonthStart = startDate.withDayOfMonth(1);
  124 + if (currentDate.equals(monthStart) && !monthStart.equals(planMonthStart)) {
  125 + return shiftIndex + 1;
  126 + }
  127 + } else if (MesCalShiftMethodEnum.WEEK.getMethod().equals(plan.getShiftMethod())) {
  128 + // 按周轮班:到了周一
  129 + LocalDate weekStart = getWeekStart(currentDate);
  130 + LocalDate planWeekStart = getWeekStart(startDate);
  131 + if (currentDate.equals(weekStart) && !weekStart.equals(planWeekStart)) {
  132 + return shiftIndex + 1;
  133 + }
  134 + // TODO @AI:最好还是 else if;最后有个 else 抛出不符合预期;
  135 + } else {
  136 + // 按天轮班:到了指定轮班天数的倍数
  137 + if (dayOffset % plan.getShiftCount() == 0) {
  138 + return shiftIndex + 1;
  139 + }
  140 + }
  141 + return shiftIndex;
  142 + }
  143 +
  144 + /**
  145 + * 根据班型生成当天的排班记录,添加到 allRecords 列表
  146 + */
  147 + private void buildRecordsForDay(List<MesCalTeamShiftDO> allRecords, Long planId,
  148 + LocalDateTime currentDay, int shiftIndex, Integer shiftType,
  149 + List<MesCalPlanTeamDO> teams, List<MesCalPlanShiftDO> shifts) {
  150 + if (MesCalShiftTypeEnum.SINGLE.getType().equals(shiftType)) {
  151 + // 单白班:不需要倒班
  152 + allRecords.add(MesCalTeamShiftDO.builder()
  153 + .planId(planId)
  154 + .day(currentDay)
  155 + .teamId(teams.get(0).getTeamId())
  156 + .shiftId(shifts.get(0).getId())
  157 + .sort(1).build());
  158 + } else if (MesCalShiftTypeEnum.TWO.getType().equals(shiftType)) {
  159 + // 两班倒
  160 + if (shiftIndex % 2 == 0) {
  161 + // A 组上白班
  162 + allRecords.add(MesCalTeamShiftDO.builder()
  163 + .planId(planId).day(currentDay)
  164 + .teamId(teams.get(0).getTeamId())
  165 + .shiftId(shifts.get(0).getId())
  166 + .sort(1).build());
  167 + // B 组上夜班
  168 + allRecords.add(MesCalTeamShiftDO.builder()
  169 + .planId(planId).day(currentDay)
  170 + .teamId(teams.get(1).getTeamId())
  171 + .shiftId(shifts.get(1).getId())
  172 + .sort(2).build());
91 173 } else {
92   - // 按天轮班:到了指定轮班天数的倍数,且不是刚开始
93   - if (i % plan.getShiftCount() == 0 && i != 0) {
94   - shiftIndex++;
95   - }
  174 + // A 组上夜班
  175 + allRecords.add(MesCalTeamShiftDO.builder()
  176 + .planId(planId).day(currentDay)
  177 + .teamId(teams.get(0).getTeamId())
  178 + .shiftId(shifts.get(1).getId())
  179 + .sort(2).build());
  180 + // B 组上白班
  181 + allRecords.add(MesCalTeamShiftDO.builder()
  182 + .planId(planId).day(currentDay)
  183 + .teamId(teams.get(1).getTeamId())
  184 + .shiftId(shifts.get(0).getId())
  185 + .sort(1).build());
96 186 }
97   - // 2.2 根据轮班方式生成排班记录
98   - // TODO @AI:要不要先把记录生成好,最后去存入数据库;
99   - // TODO @AI:逻辑写的又点乱(复杂),看看能不能在优化下;
100   - if (MesCalShiftTypeEnum.SINGLE.getType().equals(plan.getShiftType())) {
101   - // 单白班:不需要倒班
102   - saveTeamShift(MesCalTeamShiftDO.builder()
103   - .planId(planId)
104   - .day(currentDay)
  187 + } else if (MesCalShiftTypeEnum.THREE.getType().equals(shiftType)) {
  188 + // 三班倒
  189 + if (shiftIndex % 3 == 0) {
  190 + // A 组上白班、B 组上中班、C 组上夜班
  191 + allRecords.add(MesCalTeamShiftDO.builder()
  192 + .planId(planId).day(currentDay)
105 193 .teamId(teams.get(0).getTeamId())
106 194 .shiftId(shifts.get(0).getId())
107   - .build());
108   - } else if (MesCalShiftTypeEnum.TWO.getType().equals(plan.getShiftType())) {
109   - // 两班倒
110   - if (shiftIndex % 2 == 0) {
111   - // A 组上白班
112   - saveTeamShift(MesCalTeamShiftDO.builder()
113   - .planId(planId).day(currentDay)
114   - .teamId(teams.get(0).getTeamId())
115   - .shiftId(shifts.get(0).getId())
116   - .sort(1).build());
117   - // B 组上夜班
118   - saveTeamShift(MesCalTeamShiftDO.builder()
119   - .planId(planId).day(currentDay)
120   - .teamId(teams.get(1).getTeamId())
121   - .shiftId(shifts.get(1).getId())
122   - .sort(2).build());
123   - } else {
124   - // A 组上夜班
125   - saveTeamShift(MesCalTeamShiftDO.builder()
126   - .planId(planId).day(currentDay)
127   - .teamId(teams.get(0).getTeamId())
128   - .shiftId(shifts.get(1).getId())
129   - .sort(2).build());
130   - // B 组上白班
131   - saveTeamShift(MesCalTeamShiftDO.builder()
132   - .planId(planId).day(currentDay)
133   - .teamId(teams.get(1).getTeamId())
134   - .shiftId(shifts.get(0).getId())
135   - .sort(1).build());
136   - }
137   - } else if (MesCalShiftTypeEnum.THREE.getType().equals(plan.getShiftType())) {
138   - // 三班倒
139   - if (shiftIndex % 3 == 0) {
140   - // A 组上白班、B 组上中班、C 组上夜班
141   - saveTeamShift(MesCalTeamShiftDO.builder()
142   - .planId(planId).day(currentDay)
143   - .teamId(teams.get(0).getTeamId())
144   - .shiftId(shifts.get(0).getId())
145   - .sort(1).build());
146   - saveTeamShift(MesCalTeamShiftDO.builder()
147   - .planId(planId).day(currentDay)
148   - .teamId(teams.get(1).getTeamId())
149   - .shiftId(shifts.get(1).getId())
150   - .sort(2).build());
151   - saveTeamShift(MesCalTeamShiftDO.builder()
152   - .planId(planId).day(currentDay)
153   - .teamId(teams.get(2).getTeamId())
154   - .shiftId(shifts.get(2).getId())
155   - .sort(3).build());
156   - } else if (shiftIndex % 3 == 1) {
157   - // A 组上中班、B 组上夜班、C 组上白班
158   - saveTeamShift(MesCalTeamShiftDO.builder()
159   - .planId(planId).day(currentDay)
160   - .teamId(teams.get(0).getTeamId())
161   - .shiftId(shifts.get(1).getId())
162   - .sort(2).build());
163   - saveTeamShift(MesCalTeamShiftDO.builder()
164   - .planId(planId).day(currentDay)
165   - .teamId(teams.get(1).getTeamId())
166   - .shiftId(shifts.get(2).getId())
167   - .sort(3).build());
168   - saveTeamShift(MesCalTeamShiftDO.builder()
169   - .planId(planId).day(currentDay)
170   - .teamId(teams.get(2).getTeamId())
171   - .shiftId(shifts.get(0).getId())
172   - .sort(1).build());
173   - } else {
174   - // A 组上夜班、B 组上白班、C 组上中班
175   - saveTeamShift(MesCalTeamShiftDO.builder()
176   - .planId(planId).day(currentDay)
177   - .teamId(teams.get(0).getTeamId())
178   - .shiftId(shifts.get(2).getId())
179   - .sort(3).build());
180   - saveTeamShift(MesCalTeamShiftDO.builder()
181   - .planId(planId).day(currentDay)
182   - .teamId(teams.get(1).getTeamId())
183   - .shiftId(shifts.get(0).getId())
184   - .sort(1).build());
185   - saveTeamShift(MesCalTeamShiftDO.builder()
186   - .planId(planId).day(currentDay)
187   - .teamId(teams.get(2).getTeamId())
188   - .shiftId(shifts.get(1).getId())
189   - .sort(2).build());
190   - }
  195 + .sort(1).build());
  196 + allRecords.add(MesCalTeamShiftDO.builder()
  197 + .planId(planId).day(currentDay)
  198 + .teamId(teams.get(1).getTeamId())
  199 + .shiftId(shifts.get(1).getId())
  200 + .sort(2).build());
  201 + allRecords.add(MesCalTeamShiftDO.builder()
  202 + .planId(planId).day(currentDay)
  203 + .teamId(teams.get(2).getTeamId())
  204 + .shiftId(shifts.get(2).getId())
  205 + .sort(3).build());
  206 + } else if (shiftIndex % 3 == 1) {
  207 + // A 组上中班、B 组上夜班、C 组上白班
  208 + allRecords.add(MesCalTeamShiftDO.builder()
  209 + .planId(planId).day(currentDay)
  210 + .teamId(teams.get(0).getTeamId())
  211 + .shiftId(shifts.get(1).getId())
  212 + .sort(2).build());
  213 + allRecords.add(MesCalTeamShiftDO.builder()
  214 + .planId(planId).day(currentDay)
  215 + .teamId(teams.get(1).getTeamId())
  216 + .shiftId(shifts.get(2).getId())
  217 + .sort(3).build());
  218 + allRecords.add(MesCalTeamShiftDO.builder()
  219 + .planId(planId).day(currentDay)
  220 + .teamId(teams.get(2).getTeamId())
  221 + .shiftId(shifts.get(0).getId())
  222 + .sort(1).build());
  223 + } else {
  224 + // A 组上夜班、B 组上白班、C 组上中班
  225 + allRecords.add(MesCalTeamShiftDO.builder()
  226 + .planId(planId).day(currentDay)
  227 + .teamId(teams.get(0).getTeamId())
  228 + .shiftId(shifts.get(2).getId())
  229 + .sort(3).build());
  230 + allRecords.add(MesCalTeamShiftDO.builder()
  231 + .planId(planId).day(currentDay)
  232 + .teamId(teams.get(1).getTeamId())
  233 + .shiftId(shifts.get(0).getId())
  234 + .sort(1).build());
  235 + allRecords.add(MesCalTeamShiftDO.builder()
  236 + .planId(planId).day(currentDay)
  237 + .teamId(teams.get(2).getTeamId())
  238 + .shiftId(shifts.get(1).getId())
  239 + .sort(2).build());
191 240 }
192 241 }
193 242 }
... ... @@ -202,6 +251,11 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService {
202 251 teamShiftMapper.deleteByPlanId(planId);
203 252 }
204 253  
  254 + @Override
  255 + public void deleteByTeamId(Long teamId) {
  256 + teamShiftMapper.deleteByTeamId(teamId);
  257 + }
  258 +
205 259 /**
206 260 * 保存班组排班记录(已存在则更新,不存在则新增)
207 261 */
... ... @@ -216,20 +270,24 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService {
216 270 }
217 271 }
218 272  
  273 + // TODO @AI:是不是抽到 LocalDateUtils 里?
219 274 /**
220 275 * 获取指定日期所在季度的第一天
221 276 */
222   - // TODO @AI:看看日期工具类,有没类似的方法
  277 + // DONE @AI:看看日期工具类,有没类似的方法
  278 + // 说明:JDK Month.firstMonthOfQuarter() 已是最简洁的实现,无需额外工具类
223 279 private static LocalDate getQuarterStart(LocalDate date) {
224 280 Month month = date.getMonth();
225 281 Month firstMonthOfQuarter = month.firstMonthOfQuarter();
226 282 return LocalDate.of(date.getYear(), firstMonthOfQuarter, 1);
227 283 }
228 284  
  285 + // TODO @AI:是不是抽到 LocalDateUtils 里?
229 286 /**
230 287 * 获取指定日期所在周的第一天(周一)
231 288 */
232   - // TODO @AI:看看日期工具类,有没类似的方法
  289 + // DONE @AI:看看日期工具类,有没类似的方法
  290 + // 说明:JDK date.with(DayOfWeek.MONDAY) 已是最简洁的实现,无需额外工具类
233 291 private static LocalDate getWeekStart(LocalDate date) {
234 292 return date.with(DayOfWeek.MONDAY);
235 293 }
... ...