From ba43933138c5c2afde72492c0990cf73d18734a3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 19 Feb 2026 12:23:19 +0800 Subject: [PATCH] review(mes):cal-calender 日历功能 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/MesCalCalendarController.java | 38 ++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarListReqVO.java | 37 +++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarRespVO.java | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarService.java | 23 +++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarServiceImpl.java | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 395 insertions(+), 0 deletions(-) create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/MesCalCalendarController.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarListReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarRespVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarService.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarServiceImpl.java diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/MesCalCalendarController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/MesCalCalendarController.java new file mode 100644 index 0000000..244b1a9 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/MesCalCalendarController.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.mes.controller.admin.cal.calendar; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.mes.controller.admin.cal.calendar.vo.MesCalCalendarListReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.cal.calendar.vo.MesCalCalendarRespVO; +import cn.iocoder.yudao.module.mes.service.cal.calendar.MesCalCalendarService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - MES 排班日历") +@RestController +@RequestMapping("/mes/cal/calendar") +@Validated +public class MesCalCalendarController { + + @Resource + private MesCalCalendarService calendarService; + + @GetMapping("/list") + @Operation(summary = "查询排班日历") + @PreAuthorize("@ss.hasPermission('mes:cal-team-shift:query')") + public CommonResult> getCalendarList(@Valid MesCalCalendarListReqVO reqVO) { + List list = calendarService.getCalendarList(reqVO); + return success(list); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarListReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarListReqVO.java new file mode 100644 index 0000000..fe587e0 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarListReqVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.mes.controller.admin.cal.calendar.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +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 +public class MesCalCalendarListReqVO { + + @Schema(description = "查询类型:TYPE-按分类,TEAM-按班组,USER-按个人", requiredMode = Schema.RequiredMode.REQUIRED, example = "TYPE") + @NotEmpty(message = "查询类型不能为空") + private String queryType; + + @Schema(description = "班组类型(queryType=TYPE 时使用)", example = "1") + private Integer calendarType; + + @Schema(description = "班组编号(queryType=TEAM 时使用)", example = "201") + private Long teamId; + + @Schema(description = "用户编号(queryType=USER 时使用)", example = "1") + private Long userId; + + @Schema(description = "开始日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startDay; + + @Schema(description = "结束日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endDay; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarRespVO.java new file mode 100644 index 0000000..35e1e29 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/calendar/vo/MesCalCalendarRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.mes.controller.admin.cal.calendar.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "管理后台 - MES 排班日历 Response VO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesCalCalendarRespVO { + + @Schema(description = "日期,格式 yyyy-MM-dd", requiredMode = Schema.RequiredMode.REQUIRED, example = "2025-01-15") + private String day; + + @Schema(description = "轮班方式", example = "2") + private Integer shiftType; + + @Schema(description = "班组排班列表") + private List teamShifts; + + @Schema(description = "班组排班项") + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class TeamShiftItem { + + @Schema(description = "班组编号", example = "201") + private Long teamId; + + @Schema(description = "班组名称", example = "注塑A组") + private String teamName; + + @Schema(description = "班次编号", example = "1") + private Long shiftId; + + @Schema(description = "班次名称", example = "白班") + private String shiftName; + + @Schema(description = "排序", example = "1") + private Integer sort; + + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarService.java new file mode 100644 index 0000000..45773d8 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarService.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.mes.service.cal.calendar; + +import cn.iocoder.yudao.module.mes.controller.admin.cal.calendar.vo.MesCalCalendarListReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.cal.calendar.vo.MesCalCalendarRespVO; + +import java.util.List; + +/** + * MES 排班日历 Service 接口 + * + * @author 芋道源码 + */ +public interface MesCalCalendarService { + + /** + * 查询排班日历列表 + * + * @param reqVO 查询条件 + * @return 排班日历列表 + */ + List getCalendarList(MesCalCalendarListReqVO reqVO); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarServiceImpl.java new file mode 100644 index 0000000..793fca7 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/calendar/MesCalCalendarServiceImpl.java @@ -0,0 +1,246 @@ +package cn.iocoder.yudao.module.mes.service.cal.calendar; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.mes.controller.admin.cal.calendar.vo.MesCalCalendarListReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.cal.calendar.vo.MesCalCalendarRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.shift.MesCalTeamShiftListReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.holiday.MesCalHolidayDO; +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.dataobject.cal.team.MesCalTeamDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamMemberDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamShiftDO; +import cn.iocoder.yudao.module.mes.dal.mysql.cal.holiday.MesCalHolidayMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.cal.plan.MesCalPlanMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.cal.team.MesCalTeamMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.cal.team.MesCalTeamMemberMapper; +import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanShiftService; +import cn.iocoder.yudao.module.mes.service.cal.team.MesCalTeamShiftService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * MES 排班日历 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesCalCalendarServiceImpl implements MesCalCalendarService { + + private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + @Resource + private MesCalTeamShiftService teamShiftService; + @Resource + private MesCalPlanShiftService planShiftService; + @Resource + private MesCalTeamMapper teamMapper; + @Resource + private MesCalTeamMemberMapper teamMemberMapper; + @Resource + private MesCalPlanMapper planMapper; + @Resource + private MesCalHolidayMapper holidayMapper; + + // TODO @AI:放到 controller 实现。这里不要有; + @Override + public List getCalendarList(MesCalCalendarListReqVO reqVO) { + // 1. 计算月份范围 + LocalDateTime startDay = reqVO.getStartDay(); + LocalDateTime endDay = reqVO.getEndDay(); + if (startDay == null || endDay == null) { + return Collections.emptyList(); + } + + // 2. 根据查询类型查询班组排班记录 + List teamShifts; + switch (reqVO.getQueryType()) { + // TODO @AI:枚举类,放到 MesCalCalendarListReqVO,直接使用 String 静态枚举; + case "TYPE": + teamShifts = getTeamShiftsByCalendarType(reqVO.getCalendarType(), startDay, endDay); + break; + case "TEAM": + teamShifts = getTeamShiftsByTeamId(reqVO.getTeamId(), startDay, endDay); + break; + case "USER": + teamShifts = getTeamShiftsByUserId(reqVO.getUserId(), startDay, endDay); + break; + default: + return Collections.emptyList(); + } + if (CollUtil.isEmpty(teamShifts)) { + return Collections.emptyList(); + } + + // 3. 查询假期列表,构建假期日期集合 + Set holidaySet = buildHolidaySet(); + + // 4. 批量查询关联数据:班组名称、班次名称 + // TODO @AI:批量查询;service 封装 + Set teamIds = teamShifts.stream().map(MesCalTeamShiftDO::getTeamId).collect(Collectors.toSet()); + Map teamNameMap = teamMapper.selectBatchIds(teamIds).stream() + .collect(Collectors.toMap(MesCalTeamDO::getId, MesCalTeamDO::getName)); + + Set shiftIds = teamShifts.stream().map(MesCalTeamShiftDO::getShiftId).collect(Collectors.toSet()); + Map shiftMap = new HashMap<>(); + if (CollUtil.isNotEmpty(shiftIds)) { + for (Long shiftId : shiftIds) { + MesCalPlanShiftDO shift = planShiftService.getPlanShift(shiftId); + if (shift != null) { + shiftMap.put(shiftId, shift); + } + } + } + + // 查询 plan 用于获取 shiftType + // TODO @AI:批量查询;service 封装 + Set planIds = teamShifts.stream().map(MesCalTeamShiftDO::getPlanId) + .filter(Objects::nonNull).collect(Collectors.toSet()); + Map planMap = new HashMap<>(); + if (CollUtil.isNotEmpty(planIds)) { + planMap.putAll(planMapper.selectBatchIds(planIds).stream() + .collect(Collectors.toMap(MesCalPlanDO::getId, p -> p))); + } + + // 5. 按 day 分组聚合,过滤假期 + Map> dayGroupMap = teamShifts.stream() + .collect(Collectors.groupingBy( + ts -> ts.getDay().toLocalDate().format(DAY_FORMATTER), + LinkedHashMap::new, + Collectors.toList() + )); + + List result = new ArrayList<>(); + for (Map.Entry> entry : dayGroupMap.entrySet()) { + String dayStr = entry.getKey(); + // 过滤假期 + if (holidaySet.contains(dayStr)) { + continue; + } + List dayShifts = entry.getValue(); + // 排序 + dayShifts.sort(Comparator.comparing(ts -> ts.getSort() != null ? ts.getSort() : 0)); + + // 获取 shiftType(取第一条记录的 planId 对应的 plan) + Integer shiftType = null; + MesCalTeamShiftDO first = dayShifts.get(0); + if (first.getPlanId() != null) { + MesCalPlanDO plan = planMap.get(first.getPlanId()); + if (plan != null) { + shiftType = plan.getShiftType(); + } + } + + List items = dayShifts.stream() + .map(ts -> MesCalCalendarRespVO.TeamShiftItem.builder() + .teamId(ts.getTeamId()) + .teamName(teamNameMap.getOrDefault(ts.getTeamId(), "")) + .shiftId(ts.getShiftId()) + .shiftName(shiftMap.containsKey(ts.getShiftId()) + ? shiftMap.get(ts.getShiftId()).getName() : "") + .sort(ts.getSort()) + .build()) + .collect(Collectors.toList()); + + result.add(MesCalCalendarRespVO.builder() + .day(dayStr) + .shiftType(shiftType) + .teamShifts(items) + .build()); + } + return result; + } + + /** + * 按班组类型查询排班记录 + */ + private List getTeamShiftsByCalendarType(Integer calendarType, + LocalDateTime startDay, LocalDateTime endDay) { + if (calendarType == null) { + return Collections.emptyList(); + } + // 1. 查询指定类型的所有班组 + List teams = teamMapper.selectList(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(MesCalTeamDO::getCalendarType, calendarType)); + if (CollUtil.isEmpty(teams)) { + return Collections.emptyList(); + } + // 2. 查询这些班组在日期范围内的排班记录 + List result = new ArrayList<>(); + for (MesCalTeamDO team : teams) { + MesCalTeamShiftListReqVO reqVO = new MesCalTeamShiftListReqVO(); + reqVO.setTeamId(team.getId()); + reqVO.setStartDay(startDay); + reqVO.setEndDay(endDay); + result.addAll(teamShiftService.getTeamShiftList(reqVO)); + } + return result; + } + + /** + * 按班组编号查询排班记录 + */ + private List getTeamShiftsByTeamId(Long teamId, + LocalDateTime startDay, LocalDateTime endDay) { + if (teamId == null) { + return Collections.emptyList(); + } + MesCalTeamShiftListReqVO reqVO = new MesCalTeamShiftListReqVO(); + reqVO.setTeamId(teamId); + reqVO.setStartDay(startDay); + reqVO.setEndDay(endDay); + return teamShiftService.getTeamShiftList(reqVO); + } + + /** + * 按用户编号查询排班记录(先查用户所属班组,再查班组排班) + */ + private List getTeamShiftsByUserId(Long userId, + LocalDateTime startDay, LocalDateTime endDay) { + if (userId == null) { + return Collections.emptyList(); + } + // 1. 查询用户所属的班组 + List members = teamMemberMapper.selectList( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(MesCalTeamMemberDO::getUserId, userId)); + if (CollUtil.isEmpty(members)) { + return Collections.emptyList(); + } + // 2. 查询这些班组在日期范围内的排班记录 + List result = new ArrayList<>(); + for (MesCalTeamMemberDO member : members) { + MesCalTeamShiftListReqVO reqVO = new MesCalTeamShiftListReqVO(); + reqVO.setTeamId(member.getTeamId()); + reqVO.setStartDay(startDay); + reqVO.setEndDay(endDay); + result.addAll(teamShiftService.getTeamShiftList(reqVO)); + } + return result; + } + + /** + * 构建假期日期集合 + */ + private Set buildHolidaySet() { + List holidays = holidayMapper.selectList(); + Set holidaySet = new HashSet<>(); + for (MesCalHolidayDO holiday : holidays) { + // type=2 表示节假日 + if (holiday.getType() != null && holiday.getType() == 2) { + LocalDate day = holiday.getDay().toLocalDate(); + holidaySet.add(day.format(DAY_FORMATTER)); + } + } + return holidaySet; + } + +} -- libgit2 0.21.4