diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java index 4cbd4b6..287cda2 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java @@ -336,6 +336,27 @@ public class LocalDateTimeUtils { } /** + * 获取指定日期所在季度的第一天 + * + * @param date 日期 + * @return 所在季度的第一天 + */ + public static LocalDate getQuarterStart(LocalDate date) { + Month firstMonthOfQuarter = date.getMonth().firstMonthOfQuarter(); + return LocalDate.of(date.getYear(), firstMonthOfQuarter, 1); + } + + /** + * 获取指定日期所在周的第一天(周一) + * + * @param date 日期 + * @return 所在周的周一 + */ + public static LocalDate getWeekStart(LocalDate date) { + return date.with(DayOfWeek.MONDAY); + } + + /** * 将给定的 {@link LocalDateTime} 转换为自 Unix 纪元时间(1970-01-01T00:00:00Z)以来的秒数。 * * @param sourceDateTime 需要转换的本地日期时间,不能为空 diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/MesCalPlanTeamController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/MesCalPlanTeamController.java index 185d73b..7170ac5 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/MesCalPlanTeamController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/MesCalPlanTeamController.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.mes.controller.admin.cal.plan; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.mes.controller.admin.cal.plan.vo.team.MesCalPlanTeamRespVO; import cn.iocoder.yudao.module.mes.controller.admin.cal.plan.vo.team.MesCalPlanTeamSaveReqVO; @@ -23,6 +22,7 @@ import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @Tag(name = "管理后台 - MES 计划班组关联") @RestController @@ -59,16 +59,15 @@ public class MesCalPlanTeamController { List list = planTeamService.getPlanTeamListByPlanId(planId); List respList = BeanUtils.toBean(list, MesCalPlanTeamRespVO.class); // 拼装班组编码/名称 + // TODO @AI:if return if (CollUtil.isNotEmpty(respList)) { - // TODO @AI:teamService.getTeamMap(ids),里面调用 teamService.getTeamList(ids) - List teamIds = CollectionUtils.convertList(respList, MesCalPlanTeamRespVO::getTeamId); - Map teamMap = CollectionUtils.convertMap( - teamService.getTeamList(), MesCalTeamDO::getId); + Map teamMap = teamService.getTeamMap( + convertList(respList, MesCalPlanTeamRespVO::getTeamId)); respList.forEach(resp -> { + // TODO @AI:findand then MesCalTeamDO team = teamMap.get(resp.getTeamId()); if (team != null) { - resp.setTeamCode(team.getCode()); - resp.setTeamName(team.getName()); + resp.setTeamCode(team.getCode()).setTeamName(team.getName()); } }); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanPageReqVO.java index d387f35..471cfea 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanPageReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanPageReqVO.java @@ -5,6 +5,11 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @Schema(description = "管理后台 - MES 排班计划分页 Request VO") @Data @@ -24,4 +29,15 @@ public class MesCalPlanPageReqVO extends PageParam { @Schema(description = "状态", example = "0") private Integer status; + @Schema(description = "班组类型", example = "1") + private Integer calendarType; + + @Schema(description = "开始日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startDate; + + @Schema(description = "结束日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endDate; + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanSaveReqVO.java index e0f22fb..4de1501 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanSaveReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanSaveReqVO.java @@ -22,7 +22,8 @@ public class MesCalPlanSaveReqVO { @NotEmpty(message = "计划名称不能为空") private String name; - @Schema(description = "班组类型", example = "1") + @Schema(description = "班组类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "班组类型不能为空") private Integer calendarType; @Schema(description = "开始日期", requiredMode = Schema.RequiredMode.REQUIRED) @@ -33,7 +34,8 @@ public class MesCalPlanSaveReqVO { @NotNull(message = "结束日期不能为空") private LocalDateTime endDate; - @Schema(description = "轮班方式", example = "1") + @Schema(description = "轮班方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "轮班方式不能为空") private Integer shiftType; @Schema(description = "倒班方式", example = "1") diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/cal/plan/MesCalPlanMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/cal/plan/MesCalPlanMapper.java index fe27ac8..a178ea7 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/cal/plan/MesCalPlanMapper.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/cal/plan/MesCalPlanMapper.java @@ -21,6 +21,9 @@ public interface MesCalPlanMapper extends BaseMapperX { .likeIfPresent(MesCalPlanDO::getName, reqVO.getName()) .eqIfPresent(MesCalPlanDO::getShiftType, reqVO.getShiftType()) .eqIfPresent(MesCalPlanDO::getStatus, reqVO.getStatus()) + .eqIfPresent(MesCalPlanDO::getCalendarType, reqVO.getCalendarType()) + .geIfPresent(MesCalPlanDO::getStartDate, reqVO.getStartDate()) + .leIfPresent(MesCalPlanDO::getEndDate, reqVO.getEndDate()) .orderByDesc(MesCalPlanDO::getId)); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index 923e185..30bd0f7 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -121,8 +121,8 @@ public interface ErrorCodeConstants { ErrorCode CAL_TEAM_MEMBER_USER_NOT_EXISTS = new ErrorCode(1_040_201_102, "用户不存在"); // ========== MES 日历排班-班组排班(1-040-201-200) ========== ErrorCode CAL_TEAM_SHIFT_NOT_EXISTS = new ErrorCode(1_040_201_200, "班组排班记录不存在"); - ErrorCode CAL_TEAM_SHIFT_GENERATE_TEAM_NOT_ENOUGH = new ErrorCode(1_040_201_201, "班组数量不足,无法生成排班记录"); - ErrorCode CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH = new ErrorCode(1_040_201_202, "班次数量不足,无法生成排班记录"); + ErrorCode CAL_TEAM_SHIFT_GENERATE_TEAM_NOT_ENOUGH = new ErrorCode(1_040_201_201, "班组数量不满足轮班方式要求"); + ErrorCode CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH = new ErrorCode(1_040_201_202, "班次数量不满足轮班方式要求"); // ========== MES 日历排班-排班计划(1-040-202-000) ========== ErrorCode CAL_PLAN_NOT_EXISTS = new ErrorCode(1_040_202_000, "排班计划不存在"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanShiftServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanShiftServiceImpl.java index 70d16c5..6ceb162 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanShiftServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanShiftServiceImpl.java @@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.mes.controller.admin.cal.plan.vo.shift.MesCalPlan import cn.iocoder.yudao.module.mes.controller.admin.cal.plan.vo.shift.MesCalPlanShiftSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanDO; import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanShiftDO; -import cn.iocoder.yudao.module.mes.dal.mysql.cal.plan.MesCalPlanMapper; import cn.iocoder.yudao.module.mes.dal.mysql.cal.plan.MesCalPlanShiftMapper; import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftTypeEnum; import jakarta.annotation.Resource; @@ -36,8 +35,6 @@ public class MesCalPlanShiftServiceImpl implements MesCalPlanShiftService { @Resource private MesCalPlanShiftMapper planShiftMapper; @Resource - private MesCalPlanMapper planMapper; - @Resource @Lazy private MesCalPlanService planService; @@ -89,7 +86,7 @@ public class MesCalPlanShiftServiceImpl implements MesCalPlanShiftService { * 通过 planId 查询已有班次数量,根据排班计划的轮班方式校验 */ private void validatePlanShiftCount(Long planId) { - MesCalPlanDO plan = planMapper.selectById(planId); + MesCalPlanDO plan = planService.getPlan(planId); if (plan == null) { return; } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanTeamServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanTeamServiceImpl.java index fefe767..48b9072 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanTeamServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanTeamServiceImpl.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.mes.controller.admin.cal.plan.vo.team.MesCalPlanTeamSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanTeamDO; import cn.iocoder.yudao.module.mes.dal.mysql.cal.plan.MesCalPlanTeamMapper; +import cn.iocoder.yudao.module.mes.service.cal.team.MesCalTeamService; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -28,11 +29,16 @@ public class MesCalPlanTeamServiceImpl implements MesCalPlanTeamService { @Resource @Lazy private MesCalPlanService planService; + @Resource + @Lazy + private MesCalTeamService teamService; @Override public Long createPlanTeam(MesCalPlanTeamSaveReqVO createReqVO) { // 校验计划未确认 planService.validatePlanPrepare(createReqVO.getPlanId()); + // 校验班组存在 + teamService.validateTeamExists(createReqVO.getTeamId()); // 校验班组不重复 validatePlanTeamDuplicate(createReqVO.getPlanId(), createReqVO.getTeamId()); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftServiceImpl.java index 35e1c77..227ac33 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftServiceImpl.java @@ -11,17 +11,15 @@ import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftTypeEnum; import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanService; import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanShiftService; import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanTeamService; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import java.time.DayOfWeek; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.Month; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; @@ -51,8 +49,6 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService { @Lazy private MesCalPlanTeamService planTeamService; - // TODO @AI:这里要不不异步?性能一般支撑的住把? - @Async @Transactional(rollbackFor = Exception.class) @Override public void generateTeamShiftRecords(Long planId) { @@ -72,19 +68,11 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService { throw exception(CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH); } - // TODO @AI:优化下下面的注释; - // 2.1 计算日期差值(天数) + // 2. 计算日期跨度,遍历每天生成排班记录,最后统一写入数据库 LocalDate startDate = plan.getStartDate().toLocalDate(); LocalDate endDate = plan.getEndDate().toLocalDate(); long days = ChronoUnit.DAYS.between(startDate, endDate) + 1; - - // DONE @AI:要不要先把记录生成好,最后去存入数据库; - // 说明:先收集所有排班记录到列表,最后统一写入数据库,减少 DB 交互 List allRecords = new ArrayList<>(); - - // 2.2 遍历每一天,生成排班记录 - // DONE @AI:逻辑写的又点乱(复杂),看看能不能在优化下; - // 说明:通过提取 buildRecordsForDay 子方法优化可读性 int shiftIndex = 0; for (int i = 0; i < days; i++) { LocalDate currentDate = startDate.plusDays(i); @@ -95,11 +83,10 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService { buildRecordsForDay(allRecords, planId, currentDay, shiftIndex, plan.getShiftType(), teams, shifts); } - // 3. 批量写入数据库 - // TODO @AI:mybatis plus 有没 saveBatch 方法? - for (MesCalTeamShiftDO record : allRecords) { - saveTeamShift(record); - } + // 3. 先删除该计划的旧排班记录,再批量插入新记录 + // TODO @AI:能不能过有个 diff 的做法,insert、update、delete 这样? + teamShiftMapper.deleteByPlanId(planId); + teamShiftMapper.insertBatch(allRecords); } /** @@ -112,8 +99,8 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService { } if (MesCalShiftMethodEnum.QUARTER.getMethod().equals(plan.getShiftMethod())) { // 按季度轮班:到了新季度的第一天 - LocalDate quarterStart = getQuarterStart(currentDate); - LocalDate planQuarterStart = getQuarterStart(startDate); + LocalDate quarterStart = LocalDateTimeUtils.getQuarterStart(currentDate); + LocalDate planQuarterStart = LocalDateTimeUtils.getQuarterStart(startDate); if (currentDate.equals(quarterStart) && !quarterStart.equals(planQuarterStart)) { return shiftIndex + 1; } @@ -126,17 +113,18 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService { } } else if (MesCalShiftMethodEnum.WEEK.getMethod().equals(plan.getShiftMethod())) { // 按周轮班:到了周一 - LocalDate weekStart = getWeekStart(currentDate); - LocalDate planWeekStart = getWeekStart(startDate); + LocalDate weekStart = LocalDateTimeUtils.getWeekStart(currentDate); + LocalDate planWeekStart = LocalDateTimeUtils.getWeekStart(startDate); if (currentDate.equals(weekStart) && !weekStart.equals(planWeekStart)) { return shiftIndex + 1; } - // TODO @AI:最好还是 else if;最后有个 else 抛出不符合预期; - } else { + } else if (MesCalShiftMethodEnum.DAY.getMethod().equals(plan.getShiftMethod())) { // 按天轮班:到了指定轮班天数的倍数 if (dayOffset % plan.getShiftCount() == 0) { return shiftIndex + 1; } + } else { + throw new IllegalArgumentException("不支持的倒班方式: " + plan.getShiftMethod()); } return shiftIndex; } @@ -256,40 +244,4 @@ public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService { teamShiftMapper.deleteByTeamId(teamId); } - /** - * 保存班组排班记录(已存在则更新,不存在则新增) - */ - private void saveTeamShift(MesCalTeamShiftDO teamShift) { - MesCalTeamShiftDO existing = teamShiftMapper.selectByDayAndTeamId( - teamShift.getDay(), teamShift.getTeamId()); - if (existing != null) { - teamShift.setId(existing.getId()); - teamShiftMapper.updateById(teamShift); - } else { - teamShiftMapper.insert(teamShift); - } - } - - // TODO @AI:是不是抽到 LocalDateUtils 里? - /** - * 获取指定日期所在季度的第一天 - */ - // DONE @AI:看看日期工具类,有没类似的方法 - // 说明:JDK Month.firstMonthOfQuarter() 已是最简洁的实现,无需额外工具类 - private static LocalDate getQuarterStart(LocalDate date) { - Month month = date.getMonth(); - Month firstMonthOfQuarter = month.firstMonthOfQuarter(); - return LocalDate.of(date.getYear(), firstMonthOfQuarter, 1); - } - - // TODO @AI:是不是抽到 LocalDateUtils 里? - /** - * 获取指定日期所在周的第一天(周一) - */ - // DONE @AI:看看日期工具类,有没类似的方法 - // 说明:JDK date.with(DayOfWeek.MONDAY) 已是最简洁的实现,无需额外工具类 - private static LocalDate getWeekStart(LocalDate date) { - return date.with(DayOfWeek.MONDAY); - } - }