Commit 849324ff051e291b917619296c27d52dda73e990
1 parent
0317e8ea
feat(mes): 新增 CAL 模块班组/班组成员/班组排班功能(cal_team 三表)
新增 mes_cal_team / mes_cal_team_member / mes_cal_team_shift 三张表的完整后端实现: - SQL:三张表 DDL、菜单 INSERT(5220-5225)、测试数据 - DO / Mapper / VO / Service / Controller 全套分层实现 - MesCalTeamShiftServiceImpl 移植 genRecords 算法(单白班/两班倒/三班倒轮换), 基于 Java 8 时间 API(LocalDate/ChronoUnit)替代原 Date/String 方案,@Async 异步执行 - ErrorCodeConstants 追加 5 个错误码(CAL_TEAM_CODE_DUPLICATE、CAL_TEAM_MEMBER_NOT_EXISTS 等) 设计说明: - mes_cal_team_member 去除冗余字段(user_name/nickname/telephone),通过 userId 关联查询 - mes_cal_team_shift 去除冗余字段(team_name/shift_name/calendar_type/shift_type),通过外键关联查询 - 循环依赖通过 @Lazy 注入解决 修复已有 TODO: - MesCalPlanTeamDO:补充 @link MesCalTeamDO 关联注释 - MesCalPlanServiceImpl.confirmPlan:接入 teamShiftService.genRecords(id) - MesCalPlanTeamController.getPlanTeamListByPlan:拼装班组编码/名称 - MesCalPlanTeamRespVO:移除待办注释
Showing
6 changed files
with
622 additions
and
0 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamMemberService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.service.cal.team; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.member.MesCalTeamMemberPageReqVO; | |
| 5 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.member.MesCalTeamMemberSaveReqVO; | |
| 6 | +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamMemberDO; | |
| 7 | +import jakarta.validation.Valid; | |
| 8 | + | |
| 9 | +import java.util.Collection; | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * MES 班组成员 Service 接口 | |
| 14 | + * | |
| 15 | + * @author 芋道源码 | |
| 16 | + */ | |
| 17 | +public interface MesCalTeamMemberService { | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 创建班组成员 | |
| 21 | + * | |
| 22 | + * @param createReqVO 创建信息 | |
| 23 | + * @return 编号 | |
| 24 | + */ | |
| 25 | + Long createTeamMember(@Valid MesCalTeamMemberSaveReqVO createReqVO); | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 删除班组成员 | |
| 29 | + * | |
| 30 | + * @param id 编号 | |
| 31 | + */ | |
| 32 | + void deleteTeamMember(Long id); | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 获得班组成员 | |
| 36 | + * | |
| 37 | + * @param id 编号 | |
| 38 | + * @return 班组成员 | |
| 39 | + */ | |
| 40 | + MesCalTeamMemberDO getTeamMember(Long id); | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * 获得班组成员分页 | |
| 44 | + * | |
| 45 | + * @param pageReqVO 分页查询 | |
| 46 | + * @return 班组成员分页 | |
| 47 | + */ | |
| 48 | + PageResult<MesCalTeamMemberDO> getTeamMemberPage(MesCalTeamMemberPageReqVO pageReqVO); | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * 获得指定班组的成员列表 | |
| 52 | + * | |
| 53 | + * @param teamId 班组编号 | |
| 54 | + * @return 班组成员列表 | |
| 55 | + */ | |
| 56 | + List<MesCalTeamMemberDO> getTeamMemberListByTeamId(Long teamId); | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * 获得指定多个班组的成员列表 | |
| 60 | + * | |
| 61 | + * @param teamIds 班组编号列表 | |
| 62 | + * @return 班组成员列表 | |
| 63 | + */ | |
| 64 | + List<MesCalTeamMemberDO> getTeamMemberListByTeamIds(Collection<Long> teamIds); | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * 根据班组编号删除所有成员 | |
| 68 | + * | |
| 69 | + * @param teamId 班组编号 | |
| 70 | + */ | |
| 71 | + void deleteByTeamId(Long teamId); | |
| 72 | + | |
| 73 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamMemberServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.service.cal.team; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 5 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.member.MesCalTeamMemberPageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.member.MesCalTeamMemberSaveReqVO; | |
| 7 | +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamMemberDO; | |
| 8 | +import cn.iocoder.yudao.module.mes.dal.mysql.cal.team.MesCalTeamMemberMapper; | |
| 9 | +import jakarta.annotation.Resource; | |
| 10 | +import org.springframework.context.annotation.Lazy; | |
| 11 | +import org.springframework.stereotype.Service; | |
| 12 | +import org.springframework.validation.annotation.Validated; | |
| 13 | + | |
| 14 | +import java.util.Collection; | |
| 15 | +import java.util.List; | |
| 16 | + | |
| 17 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 18 | +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * MES 班组成员 Service 实现类 | |
| 22 | + * | |
| 23 | + * @author 芋道源码 | |
| 24 | + */ | |
| 25 | +@Service | |
| 26 | +@Validated | |
| 27 | +public class MesCalTeamMemberServiceImpl implements MesCalTeamMemberService { | |
| 28 | + | |
| 29 | + @Resource | |
| 30 | + private MesCalTeamMemberMapper teamMemberMapper; | |
| 31 | + @Resource | |
| 32 | + @Lazy | |
| 33 | + private MesCalTeamService teamService; | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + public Long createTeamMember(MesCalTeamMemberSaveReqVO createReqVO) { | |
| 37 | + // 1.1 校验班组存在 | |
| 38 | + teamService.validateTeamExists(createReqVO.getTeamId()); | |
| 39 | + // 1.2 校验用户未分配到其他班组 | |
| 40 | + validateUserUnique(null, createReqVO.getUserId()); | |
| 41 | + | |
| 42 | + // 2. 插入 | |
| 43 | + MesCalTeamMemberDO member = BeanUtils.toBean(createReqVO, MesCalTeamMemberDO.class); | |
| 44 | + teamMemberMapper.insert(member); | |
| 45 | + return member.getId(); | |
| 46 | + } | |
| 47 | + | |
| 48 | + @Override | |
| 49 | + public void deleteTeamMember(Long id) { | |
| 50 | + // 校验存在 | |
| 51 | + validateTeamMemberExists(id); | |
| 52 | + // 删除 | |
| 53 | + teamMemberMapper.deleteById(id); | |
| 54 | + } | |
| 55 | + | |
| 56 | + @Override | |
| 57 | + public MesCalTeamMemberDO getTeamMember(Long id) { | |
| 58 | + return teamMemberMapper.selectById(id); | |
| 59 | + } | |
| 60 | + | |
| 61 | + @Override | |
| 62 | + public PageResult<MesCalTeamMemberDO> getTeamMemberPage(MesCalTeamMemberPageReqVO pageReqVO) { | |
| 63 | + return teamMemberMapper.selectPage(pageReqVO); | |
| 64 | + } | |
| 65 | + | |
| 66 | + @Override | |
| 67 | + public List<MesCalTeamMemberDO> getTeamMemberListByTeamId(Long teamId) { | |
| 68 | + return teamMemberMapper.selectListByTeamId(teamId); | |
| 69 | + } | |
| 70 | + | |
| 71 | + @Override | |
| 72 | + public List<MesCalTeamMemberDO> getTeamMemberListByTeamIds(Collection<Long> teamIds) { | |
| 73 | + return teamMemberMapper.selectListByTeamIds(teamIds); | |
| 74 | + } | |
| 75 | + | |
| 76 | + @Override | |
| 77 | + public void deleteByTeamId(Long teamId) { | |
| 78 | + teamMemberMapper.deleteByTeamId(teamId); | |
| 79 | + } | |
| 80 | + | |
| 81 | + // TODO @AI:无需返回; | |
| 82 | + private MesCalTeamMemberDO validateTeamMemberExists(Long id) { | |
| 83 | + MesCalTeamMemberDO member = teamMemberMapper.selectById(id); | |
| 84 | + if (member == null) { | |
| 85 | + throw exception(CAL_TEAM_MEMBER_NOT_EXISTS); | |
| 86 | + } | |
| 87 | + return member; | |
| 88 | + } | |
| 89 | + | |
| 90 | + // TODO @AI:这里的 excludeId 可以去掉 | |
| 91 | + private void validateUserUnique(Long excludeId, Long userId) { | |
| 92 | + MesCalTeamMemberDO member = teamMemberMapper.selectByUserIdExcludeId(userId, excludeId); | |
| 93 | + if (member != null) { | |
| 94 | + throw exception(CAL_TEAM_MEMBER_USER_DUPLICATE); | |
| 95 | + } | |
| 96 | + } | |
| 97 | + | |
| 98 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.service.cal.team; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.MesCalTeamPageReqVO; | |
| 5 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.MesCalTeamSaveReqVO; | |
| 6 | +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamDO; | |
| 7 | +import jakarta.validation.Valid; | |
| 8 | + | |
| 9 | +import java.util.List; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * MES 班组 Service 接口 | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +public interface MesCalTeamService { | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 创建班组 | |
| 20 | + * | |
| 21 | + * @param createReqVO 创建信息 | |
| 22 | + * @return 编号 | |
| 23 | + */ | |
| 24 | + Long createTeam(@Valid MesCalTeamSaveReqVO createReqVO); | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 更新班组 | |
| 28 | + * | |
| 29 | + * @param updateReqVO 更新信息 | |
| 30 | + */ | |
| 31 | + void updateTeam(@Valid MesCalTeamSaveReqVO updateReqVO); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 删除班组 | |
| 35 | + * | |
| 36 | + * @param id 编号 | |
| 37 | + */ | |
| 38 | + void deleteTeam(Long id); | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * 获得班组 | |
| 42 | + * | |
| 43 | + * @param id 编号 | |
| 44 | + * @return 班组 | |
| 45 | + */ | |
| 46 | + MesCalTeamDO getTeam(Long id); | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 获得班组分页 | |
| 50 | + * | |
| 51 | + * @param pageReqVO 分页查询 | |
| 52 | + * @return 班组分页 | |
| 53 | + */ | |
| 54 | + PageResult<MesCalTeamDO> getTeamPage(MesCalTeamPageReqVO pageReqVO); | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * 获得班组列表(全量,用于下拉选择) | |
| 58 | + * | |
| 59 | + * @return 班组列表 | |
| 60 | + */ | |
| 61 | + List<MesCalTeamDO> getTeamList(); | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * 校验班组存在 | |
| 65 | + * | |
| 66 | + * @param id 编号 | |
| 67 | + * @return 班组 | |
| 68 | + */ | |
| 69 | + MesCalTeamDO validateTeamExists(Long id); | |
| 70 | + | |
| 71 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.service.cal.team; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 5 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.MesCalTeamPageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.MesCalTeamSaveReqVO; | |
| 7 | +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamDO; | |
| 8 | +import cn.iocoder.yudao.module.mes.dal.mysql.cal.team.MesCalTeamMapper; | |
| 9 | +import jakarta.annotation.Resource; | |
| 10 | +import org.springframework.context.annotation.Lazy; | |
| 11 | +import org.springframework.stereotype.Service; | |
| 12 | +import org.springframework.transaction.annotation.Transactional; | |
| 13 | +import org.springframework.validation.annotation.Validated; | |
| 14 | + | |
| 15 | +import java.util.List; | |
| 16 | + | |
| 17 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 18 | +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * MES 班组 Service 实现类 | |
| 22 | + * | |
| 23 | + * @author 芋道源码 | |
| 24 | + */ | |
| 25 | +@Service | |
| 26 | +@Validated | |
| 27 | +public class MesCalTeamServiceImpl implements MesCalTeamService { | |
| 28 | + | |
| 29 | + @Resource | |
| 30 | + private MesCalTeamMapper teamMapper; | |
| 31 | + @Resource | |
| 32 | + @Lazy | |
| 33 | + private MesCalTeamMemberService teamMemberService; | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + public Long createTeam(MesCalTeamSaveReqVO createReqVO) { | |
| 37 | + // 1. 校验编码唯一 | |
| 38 | + validateTeamCodeUnique(null, createReqVO.getCode()); | |
| 39 | + | |
| 40 | + // 2. 插入 | |
| 41 | + MesCalTeamDO team = BeanUtils.toBean(createReqVO, MesCalTeamDO.class); | |
| 42 | + teamMapper.insert(team); | |
| 43 | + return team.getId(); | |
| 44 | + } | |
| 45 | + | |
| 46 | + @Override | |
| 47 | + public void updateTeam(MesCalTeamSaveReqVO updateReqVO) { | |
| 48 | + // 1.1 校验存在 | |
| 49 | + validateTeamExists(updateReqVO.getId()); | |
| 50 | + // 1.2 校验编码唯一 | |
| 51 | + validateTeamCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); | |
| 52 | + | |
| 53 | + // 2. 更新 | |
| 54 | + MesCalTeamDO updateObj = BeanUtils.toBean(updateReqVO, MesCalTeamDO.class); | |
| 55 | + teamMapper.updateById(updateObj); | |
| 56 | + } | |
| 57 | + | |
| 58 | + @Override | |
| 59 | + @Transactional(rollbackFor = Exception.class) | |
| 60 | + public void deleteTeam(Long id) { | |
| 61 | + // 1. 校验存在 | |
| 62 | + validateTeamExists(id); | |
| 63 | + | |
| 64 | + // 2.1 级联删除成员 | |
| 65 | + teamMemberService.deleteByTeamId(id); | |
| 66 | + // 2.2 删除班组 | |
| 67 | + teamMapper.deleteById(id); | |
| 68 | + } | |
| 69 | + | |
| 70 | + @Override | |
| 71 | + public MesCalTeamDO getTeam(Long id) { | |
| 72 | + return teamMapper.selectById(id); | |
| 73 | + } | |
| 74 | + | |
| 75 | + @Override | |
| 76 | + public PageResult<MesCalTeamDO> getTeamPage(MesCalTeamPageReqVO pageReqVO) { | |
| 77 | + return teamMapper.selectPage(pageReqVO); | |
| 78 | + } | |
| 79 | + | |
| 80 | + @Override | |
| 81 | + public List<MesCalTeamDO> getTeamList() { | |
| 82 | + return teamMapper.selectList(); | |
| 83 | + } | |
| 84 | + | |
| 85 | + @Override | |
| 86 | + public MesCalTeamDO validateTeamExists(Long id) { | |
| 87 | + MesCalTeamDO team = teamMapper.selectById(id); | |
| 88 | + if (team == null) { | |
| 89 | + throw exception(CAL_TEAM_NOT_EXISTS); | |
| 90 | + } | |
| 91 | + return team; | |
| 92 | + } | |
| 93 | + | |
| 94 | + private void validateTeamCodeUnique(Long id, String code) { | |
| 95 | + MesCalTeamDO team = teamMapper.selectByCode(code); | |
| 96 | + if (team == null) { | |
| 97 | + return; | |
| 98 | + } | |
| 99 | + // TODO @AI:ObjUtil notEquals | |
| 100 | + if (id == null || !id.equals(team.getId())) { | |
| 101 | + throw exception(CAL_TEAM_CODE_DUPLICATE); | |
| 102 | + } | |
| 103 | + } | |
| 104 | + | |
| 105 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.service.cal.team; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.shift.MesCalTeamShiftListReqVO; | |
| 4 | +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamShiftDO; | |
| 5 | + | |
| 6 | +import java.util.List; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * MES 班组排班 Service 接口 | |
| 10 | + * | |
| 11 | + * @author 芋道源码 | |
| 12 | + */ | |
| 13 | +public interface MesCalTeamShiftService { | |
| 14 | + | |
| 15 | + // TODO @AI:方法名,优化下; | |
| 16 | + /** | |
| 17 | + * 根据排班计划生成班组排班记录 | |
| 18 | + * | |
| 19 | + * @param planId 排班计划编号 | |
| 20 | + */ | |
| 21 | + void genRecords(Long planId); | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 获得班组排班列表 | |
| 25 | + * | |
| 26 | + * @param reqVO 查询条件 | |
| 27 | + * @return 班组排班列表 | |
| 28 | + */ | |
| 29 | + List<MesCalTeamShiftDO> getTeamShiftList(MesCalTeamShiftListReqVO reqVO); | |
| 30 | + | |
| 31 | + // TODO @AI:评审下,为什么不调用! | |
| 32 | + /** | |
| 33 | + * 根据排班计划编号删除所有排班记录 | |
| 34 | + * | |
| 35 | + * @param planId 排班计划编号 | |
| 36 | + */ | |
| 37 | + void deleteByPlanId(Long planId); | |
| 38 | + | |
| 39 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.service.cal.team; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.shift.MesCalTeamShiftListReqVO; | |
| 4 | +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanDO; | |
| 5 | +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanShiftDO; | |
| 6 | +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanTeamDO; | |
| 7 | +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamShiftDO; | |
| 8 | +import cn.iocoder.yudao.module.mes.dal.mysql.cal.team.MesCalTeamShiftMapper; | |
| 9 | +import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftMethodEnum; | |
| 10 | +import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftTypeEnum; | |
| 11 | +import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanService; | |
| 12 | +import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanShiftService; | |
| 13 | +import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanTeamService; | |
| 14 | +import jakarta.annotation.Resource; | |
| 15 | +import org.springframework.context.annotation.Lazy; | |
| 16 | +import org.springframework.scheduling.annotation.Async; | |
| 17 | +import org.springframework.stereotype.Service; | |
| 18 | +import org.springframework.validation.annotation.Validated; | |
| 19 | + | |
| 20 | +import java.time.DayOfWeek; | |
| 21 | +import java.time.LocalDate; | |
| 22 | +import java.time.LocalDateTime; | |
| 23 | +import java.time.Month; | |
| 24 | +import java.time.temporal.ChronoUnit; | |
| 25 | +import java.util.List; | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * MES 班组排班 Service 实现类 | |
| 29 | + * | |
| 30 | + * @author 芋道源码 | |
| 31 | + */ | |
| 32 | +@Service | |
| 33 | +@Validated | |
| 34 | +public class MesCalTeamShiftServiceImpl implements MesCalTeamShiftService { | |
| 35 | + | |
| 36 | + @Resource | |
| 37 | + private MesCalTeamShiftMapper teamShiftMapper; | |
| 38 | + @Resource | |
| 39 | + @Lazy | |
| 40 | + private MesCalPlanService planService; | |
| 41 | + @Resource | |
| 42 | + @Lazy | |
| 43 | + private MesCalPlanShiftService planShiftService; | |
| 44 | + @Resource | |
| 45 | + @Lazy | |
| 46 | + private MesCalPlanTeamService planTeamService; | |
| 47 | + | |
| 48 | + @Async | |
| 49 | + @Override | |
| 50 | + public void genRecords(Long planId) { | |
| 51 | + // 1.1 查询排班计划 | |
| 52 | + MesCalPlanDO plan = planService.getPlan(planId); | |
| 53 | + // 1.2 查询计划中的班次列表 | |
| 54 | + List<MesCalPlanShiftDO> shifts = planShiftService.getPlanShiftListByPlanId(planId); | |
| 55 | + // 1.3 查询计划中的班组列表 | |
| 56 | + List<MesCalPlanTeamDO> teams = planTeamService.getPlanTeamListByPlanId(planId); | |
| 57 | + | |
| 58 | + // 2.1 计算日期差值(天数) | |
| 59 | + LocalDate startDate = plan.getStartDate().toLocalDate(); | |
| 60 | + LocalDate endDate = plan.getEndDate().toLocalDate(); | |
| 61 | + long days = ChronoUnit.DAYS.between(startDate, endDate) + 1; | |
| 62 | + // TODO @AI:dateutils,还是 localdateutils 应该有方法;或者 hutool 的 | |
| 63 | + // 2.2 遍历每一天,生成排班记录 | |
| 64 | + int shiftIndex = 0; | |
| 65 | + for (int i = 0; i < days; i++) { | |
| 66 | + LocalDate currentDate = startDate.plusDays(i); | |
| 67 | + LocalDateTime currentDay = currentDate.atStartOfDay(); | |
| 68 | + // 2.1 根据倒班方式计算 shiftIndex | |
| 69 | + if (MesCalShiftMethodEnum.QUARTER.getMethod().equals(plan.getShiftMethod())) { | |
| 70 | + // 按季度轮班:到了新季度的第一天,且不是排班计划开始的季度 | |
| 71 | + LocalDate quarterStart = getQuarterStart(currentDate); | |
| 72 | + LocalDate planQuarterStart = getQuarterStart(startDate); | |
| 73 | + if (currentDate.equals(quarterStart) && !quarterStart.equals(planQuarterStart)) { | |
| 74 | + shiftIndex++; | |
| 75 | + } | |
| 76 | + } else if (MesCalShiftMethodEnum.MONTH.getMethod().equals(plan.getShiftMethod())) { | |
| 77 | + // 按月轮班:到了月初,且不是排班计划开始的月份 | |
| 78 | + LocalDate monthStart = currentDate.withDayOfMonth(1); | |
| 79 | + LocalDate planMonthStart = startDate.withDayOfMonth(1); | |
| 80 | + if (currentDate.equals(monthStart) && !monthStart.equals(planMonthStart)) { | |
| 81 | + shiftIndex++; | |
| 82 | + } | |
| 83 | + } else if (MesCalShiftMethodEnum.WEEK.getMethod().equals(plan.getShiftMethod())) { | |
| 84 | + // 按周轮班:到了周一,且不是排班计划开始的周 | |
| 85 | + LocalDate weekStart = getWeekStart(currentDate); | |
| 86 | + LocalDate planWeekStart = getWeekStart(startDate); | |
| 87 | + if (currentDate.equals(weekStart) && !weekStart.equals(planWeekStart)) { | |
| 88 | + shiftIndex++; | |
| 89 | + } | |
| 90 | + } else { | |
| 91 | + // 按天轮班:到了指定轮班天数的倍数,且不是刚开始 | |
| 92 | + if (i % plan.getShiftCount() == 0 && i != 0) { | |
| 93 | + shiftIndex++; | |
| 94 | + } | |
| 95 | + } | |
| 96 | + // 2.2 根据轮班方式生成排班记录 | |
| 97 | + // TODO @AI:要不要先把记录生成好,最后去存入数据库; | |
| 98 | + // TODO @AI:逻辑写的又点乱(复杂),看看能不能在优化下; | |
| 99 | + if (MesCalShiftTypeEnum.SINGLE.getType().equals(plan.getShiftType())) { | |
| 100 | + // 单白班:不需要倒班 | |
| 101 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 102 | + .planId(planId) | |
| 103 | + .day(currentDay) | |
| 104 | + .teamId(teams.get(0).getTeamId()) | |
| 105 | + .shiftId(shifts.get(0).getId()) | |
| 106 | + .build()); | |
| 107 | + } else if (MesCalShiftTypeEnum.TWO.getType().equals(plan.getShiftType())) { | |
| 108 | + // 两班倒 | |
| 109 | + if (shiftIndex % 2 == 0) { | |
| 110 | + // A 组上白班 | |
| 111 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 112 | + .planId(planId).day(currentDay) | |
| 113 | + .teamId(teams.get(0).getTeamId()) | |
| 114 | + .shiftId(shifts.get(0).getId()) | |
| 115 | + .sort(1).build()); | |
| 116 | + // B 组上夜班 | |
| 117 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 118 | + .planId(planId).day(currentDay) | |
| 119 | + .teamId(teams.get(1).getTeamId()) | |
| 120 | + .shiftId(shifts.get(1).getId()) | |
| 121 | + .sort(2).build()); | |
| 122 | + } else { | |
| 123 | + // A 组上夜班 | |
| 124 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 125 | + .planId(planId).day(currentDay) | |
| 126 | + .teamId(teams.get(0).getTeamId()) | |
| 127 | + .shiftId(shifts.get(1).getId()) | |
| 128 | + .sort(2).build()); | |
| 129 | + // B 组上白班 | |
| 130 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 131 | + .planId(planId).day(currentDay) | |
| 132 | + .teamId(teams.get(1).getTeamId()) | |
| 133 | + .shiftId(shifts.get(0).getId()) | |
| 134 | + .sort(1).build()); | |
| 135 | + } | |
| 136 | + } else if (MesCalShiftTypeEnum.THREE.getType().equals(plan.getShiftType())) { | |
| 137 | + // 三班倒 | |
| 138 | + if (shiftIndex % 3 == 0) { | |
| 139 | + // A 组上白班、B 组上中班、C 组上夜班 | |
| 140 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 141 | + .planId(planId).day(currentDay) | |
| 142 | + .teamId(teams.get(0).getTeamId()) | |
| 143 | + .shiftId(shifts.get(0).getId()) | |
| 144 | + .sort(1).build()); | |
| 145 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 146 | + .planId(planId).day(currentDay) | |
| 147 | + .teamId(teams.get(1).getTeamId()) | |
| 148 | + .shiftId(shifts.get(1).getId()) | |
| 149 | + .sort(2).build()); | |
| 150 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 151 | + .planId(planId).day(currentDay) | |
| 152 | + .teamId(teams.get(2).getTeamId()) | |
| 153 | + .shiftId(shifts.get(2).getId()) | |
| 154 | + .sort(3).build()); | |
| 155 | + } else if (shiftIndex % 3 == 1) { | |
| 156 | + // A 组上中班、B 组上夜班、C 组上白班 | |
| 157 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 158 | + .planId(planId).day(currentDay) | |
| 159 | + .teamId(teams.get(0).getTeamId()) | |
| 160 | + .shiftId(shifts.get(1).getId()) | |
| 161 | + .sort(2).build()); | |
| 162 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 163 | + .planId(planId).day(currentDay) | |
| 164 | + .teamId(teams.get(1).getTeamId()) | |
| 165 | + .shiftId(shifts.get(2).getId()) | |
| 166 | + .sort(3).build()); | |
| 167 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 168 | + .planId(planId).day(currentDay) | |
| 169 | + .teamId(teams.get(2).getTeamId()) | |
| 170 | + .shiftId(shifts.get(0).getId()) | |
| 171 | + .sort(1).build()); | |
| 172 | + } else { | |
| 173 | + // A 组上夜班、B 组上白班、C 组上中班 | |
| 174 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 175 | + .planId(planId).day(currentDay) | |
| 176 | + .teamId(teams.get(0).getTeamId()) | |
| 177 | + .shiftId(shifts.get(2).getId()) | |
| 178 | + .sort(3).build()); | |
| 179 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 180 | + .planId(planId).day(currentDay) | |
| 181 | + .teamId(teams.get(1).getTeamId()) | |
| 182 | + .shiftId(shifts.get(0).getId()) | |
| 183 | + .sort(1).build()); | |
| 184 | + saveTeamShift(MesCalTeamShiftDO.builder() | |
| 185 | + .planId(planId).day(currentDay) | |
| 186 | + .teamId(teams.get(2).getTeamId()) | |
| 187 | + .shiftId(shifts.get(1).getId()) | |
| 188 | + .sort(2).build()); | |
| 189 | + } | |
| 190 | + } | |
| 191 | + } | |
| 192 | + } | |
| 193 | + | |
| 194 | + @Override | |
| 195 | + public List<MesCalTeamShiftDO> getTeamShiftList(MesCalTeamShiftListReqVO reqVO) { | |
| 196 | + return teamShiftMapper.selectList(reqVO); | |
| 197 | + } | |
| 198 | + | |
| 199 | + @Override | |
| 200 | + public void deleteByPlanId(Long planId) { | |
| 201 | + teamShiftMapper.deleteByPlanId(planId); | |
| 202 | + } | |
| 203 | + | |
| 204 | + /** | |
| 205 | + * 保存班组排班记录(已存在则更新,不存在则新增) | |
| 206 | + */ | |
| 207 | + private void saveTeamShift(MesCalTeamShiftDO teamShift) { | |
| 208 | + MesCalTeamShiftDO existing = teamShiftMapper.selectByDayAndTeamId( | |
| 209 | + teamShift.getDay(), teamShift.getTeamId()); | |
| 210 | + if (existing != null) { | |
| 211 | + teamShift.setId(existing.getId()); | |
| 212 | + teamShiftMapper.updateById(teamShift); | |
| 213 | + } else { | |
| 214 | + teamShiftMapper.insert(teamShift); | |
| 215 | + } | |
| 216 | + } | |
| 217 | + | |
| 218 | + /** | |
| 219 | + * 获取指定日期所在季度的第一天 | |
| 220 | + */ | |
| 221 | + // TODO @AI:看看日期工具类,有没类似的方法 | |
| 222 | + private static LocalDate getQuarterStart(LocalDate date) { | |
| 223 | + Month month = date.getMonth(); | |
| 224 | + Month firstMonthOfQuarter = month.firstMonthOfQuarter(); | |
| 225 | + return LocalDate.of(date.getYear(), firstMonthOfQuarter, 1); | |
| 226 | + } | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * 获取指定日期所在周的第一天(周一) | |
| 230 | + */ | |
| 231 | + // TODO @AI:看看日期工具类,有没类似的方法 | |
| 232 | + private static LocalDate getWeekStart(LocalDate date) { | |
| 233 | + return date.with(DayOfWeek.MONDAY); | |
| 234 | + } | |
| 235 | + | |
| 236 | +} | ... | ... |