package com.klp.service.impl; import cn.hutool.core.bean.BeanUtil; import com.klp.common.core.page.TableDataInfo; import com.klp.common.core.domain.PageQuery; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.klp.common.utils.StringUtils; import com.klp.domain.vo.WmsAttendanceShiftRuleVo; import com.klp.domain.vo.WmsAttendanceShiftVo; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.klp.domain.bo.WmsAttendanceScheduleBo; import com.klp.domain.bo.GenerateScheduleBo; import com.klp.domain.vo.WmsAttendanceScheduleVo; import com.klp.domain.WmsAttendanceSchedule; import com.klp.domain.WmsAttendanceShiftRule; import com.klp.domain.WmsAttendanceShift; import com.klp.mapper.WmsAttendanceScheduleMapper; import com.klp.service.IWmsAttendanceScheduleService; import com.klp.service.IWmsAttendanceShiftRuleService; import com.klp.service.IWmsAttendanceShiftService; import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Collection; import java.util.Map; /** * 排班(谁在哪天上班)Service业务层处理 * * @author klp * @date 2026-05-08 */ @RequiredArgsConstructor @Service public class WmsAttendanceScheduleServiceImpl implements IWmsAttendanceScheduleService { private final WmsAttendanceScheduleMapper baseMapper; private final IWmsAttendanceShiftRuleService shiftRuleService; private final IWmsAttendanceShiftService shiftService; /** * 查询排班(谁在哪天上班) */ @Override public WmsAttendanceScheduleVo queryById(Long scheduleId){ WmsAttendanceSchedule schedule = baseMapper.selectById(scheduleId); if (schedule == null) { return null; } // 使用关联查询获取详细信息 List list = baseMapper.selectScheduleWithDetails( schedule.getUserId(), schedule.getWorkDate(), schedule.getShiftId()); return list.isEmpty() ? null : list.get(0); } /** * 查询排班(谁在哪天上班)列表 */ @Override public TableDataInfo queryPageList(WmsAttendanceScheduleBo bo, PageQuery pageQuery) { Page page = pageQuery.build(); List list = baseMapper.selectScheduleWithDetailsPage( bo.getUserId(), bo.getWorkDate(), bo.getShiftId(), bo.getShiftName(), bo.getShiftGroup()); // 手动分页处理 int total = list.size(); int startNum = (int) ((page.getCurrent() - 1) * page.getSize()); int endNum = Math.min(startNum + (int) page.getSize(), total); List pageList = new ArrayList<>(); if (startNum < total) { pageList = list.subList(startNum, endNum); } Page result = new Page<>(page.getCurrent(), page.getSize(), total); result.setRecords(pageList); return TableDataInfo.build(result); } /** * 查询排班(谁在哪天上班)列表 */ @Override public List queryList(WmsAttendanceScheduleBo bo) { return baseMapper.selectScheduleWithDetails(bo.getUserId(), bo.getWorkDate(), bo.getShiftId()); } /** * 新增排班(谁在哪天上班) */ @Override public Boolean insertByBo(WmsAttendanceScheduleBo bo) { WmsAttendanceSchedule add = BeanUtil.toBean(bo, WmsAttendanceSchedule.class); validEntityBeforeSave(add); boolean flag = baseMapper.insert(add) > 0; if (flag) { bo.setScheduleId(add.getScheduleId()); } return flag; } /** * 修改排班(谁在哪天上班) */ @Override public Boolean updateByBo(WmsAttendanceScheduleBo bo) { WmsAttendanceSchedule update = BeanUtil.toBean(bo, WmsAttendanceSchedule.class); validEntityBeforeSave(update); return baseMapper.updateById(update) > 0; } /** * 保存前的数据校验 */ private void validEntityBeforeSave(WmsAttendanceSchedule entity){ //TODO 做一些数据校验,如唯一约束 } /** * 批量删除排班(谁在哪天上班) */ @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if(isValid){ //TODO 做一些业务上的校验,判断是否需要校验 } return baseMapper.deleteBatchIds(ids) > 0; } /** * 生成排班 */ @Override @Transactional(rollbackFor = Exception.class) public void generateSchedule(GenerateScheduleBo bo) { LocalDate startDate = bo.getStartDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate(); LocalDate endDate = bo.getEndDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate(); if (startDate.isAfter(endDate)) { throw new RuntimeException("开始时间不能大于结束时间"); } if (bo.getRuleId() == null) { // 正常排班,不倒班 generateNormalSchedule(bo, startDate, endDate); } else { // 倒班排班 generateShiftSchedule(bo, startDate, endDate); } } /** * 生成正常排班 */ private void generateNormalSchedule(GenerateScheduleBo bo, LocalDate startDate, LocalDate endDate) { List schedules = new ArrayList<>(); // 获取班次信息 WmsAttendanceShiftVo shift = shiftService.queryById(bo.getShiftId()); if (shift == null) { throw new RuntimeException("班次不存在"); } LocalDate currentDate = startDate; while (!currentDate.isAfter(endDate)) { // 检查是否已存在排班 if (!isScheduleExists(bo.getUserId(), currentDate)) { WmsAttendanceSchedule schedule = new WmsAttendanceSchedule(); schedule.setUserId(bo.getUserId()); schedule.setWorkDate(java.sql.Date.valueOf(currentDate)); schedule.setShiftId(bo.getShiftId()); schedule.setShiftName(shift.getShiftName()); schedules.add(schedule); } currentDate = currentDate.plusDays(1); } // 批量插入 if (!schedules.isEmpty()) { boolean ok = baseMapper.insertBatch(schedules); if (!ok) { throw new RuntimeException("排班插入失败"); } } } /** * 生成倒班排班 */ private void generateShiftSchedule(GenerateScheduleBo bo, LocalDate startDate, LocalDate endDate) { // 获取倒班规则 WmsAttendanceShiftRuleVo rule = shiftRuleService.queryById(bo.getRuleId()); if (rule == null) { throw new RuntimeException("倒班规则不存在"); } // 验证班次匹配 if (!bo.getShiftId().equals(rule.getShiftA()) && !bo.getShiftId().equals(rule.getShiftB())) { throw new RuntimeException("班次ID与倒班规则不匹配"); } // 获取班次信息 WmsAttendanceShiftVo shiftA = shiftService.queryById(rule.getShiftA()); WmsAttendanceShiftVo shiftB = shiftService.queryById(rule.getShiftB()); WmsAttendanceShiftVo changeShiftB = rule.getChangeShiftBId() != null ? shiftService.queryById(rule.getChangeShiftBId()) : null; WmsAttendanceShiftVo changeShiftA = rule.getChangeShiftAId() != null ? shiftService.queryById(rule.getChangeShiftAId()) : null; if (shiftA == null || shiftB == null) { throw new RuntimeException("倒班规则中的班次不存在"); } List schedules = new ArrayList<>(); LocalDate currentDate = startDate; long daysFromStart = 0; // 确定初始班次 boolean isCurrentShiftA = bo.getShiftId().equals(rule.getShiftA()); while (!currentDate.isAfter(endDate)) { if (!isScheduleExists(bo.getUserId(), currentDate)) { WmsAttendanceSchedule schedule = new WmsAttendanceSchedule(); schedule.setUserId(bo.getUserId()); schedule.setWorkDate(java.sql.Date.valueOf(currentDate)); // 判断是否为倒班日 long cycleDays = rule.getCycleDays() != null ? rule.getCycleDays() : 10; boolean isChangeDay = (daysFromStart + 1) % cycleDays == 0; if (isChangeDay) { // 倒班日 if (isCurrentShiftA) { // 白班转夜班 if (changeShiftB != null) { schedule.setShiftId(rule.getChangeShiftBId()); schedule.setShiftName(changeShiftB.getShiftName()); } else { schedule.setShiftId(rule.getShiftB()); schedule.setShiftName(shiftB.getShiftName()); } // 下一天也使用倒班班次(工作18小时) LocalDate nextDay = currentDate.plusDays(1); if (!nextDay.isAfter(endDate) && !isScheduleExists(bo.getUserId(), nextDay)) { WmsAttendanceSchedule nextSchedule = new WmsAttendanceSchedule(); nextSchedule.setUserId(bo.getUserId()); nextSchedule.setWorkDate(java.sql.Date.valueOf(nextDay)); if (changeShiftB != null) { nextSchedule.setShiftId(rule.getChangeShiftBId()); nextSchedule.setShiftName(changeShiftB.getShiftName()); } else { nextSchedule.setShiftId(rule.getShiftB()); nextSchedule.setShiftName(shiftB.getShiftName()); } schedules.add(nextSchedule); } isCurrentShiftA = false; currentDate = currentDate.plusDays(1); // 跳过下一天,因为已经处理了 daysFromStart++; } else { // 夜班转白班 if (changeShiftA != null) { schedule.setShiftId(rule.getChangeShiftAId()); schedule.setShiftName(changeShiftA.getShiftName()); } else { schedule.setShiftId(rule.getShiftA()); schedule.setShiftName(shiftA.getShiftName()); } isCurrentShiftA = true; } } else { // 普通日 if (isCurrentShiftA) { schedule.setShiftId(rule.getShiftA()); schedule.setShiftName(shiftA.getShiftName()); } else { schedule.setShiftId(rule.getShiftB()); schedule.setShiftName(shiftB.getShiftName()); } } schedules.add(schedule); } currentDate = currentDate.plusDays(1); daysFromStart++; } // 批量插入 if (!schedules.isEmpty()) { for (WmsAttendanceSchedule schedule : schedules) { baseMapper.insert(schedule); } } } /** * 检查排班是否已存在 */ private boolean isScheduleExists(Long userId, LocalDate workDate) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.eq(WmsAttendanceSchedule::getUserId, userId) .eq(WmsAttendanceSchedule::getWorkDate, java.sql.Date.valueOf(workDate)); return baseMapper.selectCount(wrapper) > 0; } }