Files
klp-oa/klp-wms/src/main/java/com/klp/service/impl/WmsAttendanceScheduleServiceImpl.java
Joshi 1947a5c2d5 fix(wms/attendance-schedule): 调整批量删除接口参数类型与逻辑
1. 接口参数调整:将批量删除接口的路径参数从Long数组改为接收逗号分隔的字符串,并修改为@RequestBody接收
2. 服务层逻辑重构:将deleteWithValidByIds方法参数从Collection<Long>改为String,内部实现字符串解析与转换
3. 新增参数校验:在服务层添加字符串解析逻辑,过滤空值并转换为Long列表,避免空列表操作

调整前,批量删除依赖路径参数数组,存在URL长度限制且类型转换复杂;调整后,通过请求体接收字符串参数,服务层统一解析处理,提升接口健壮性与兼容性。
2026-06-05 16:46:23 +08:00

405 lines
16 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 com.klp.domain.WmsEmployeeInfo;
import com.klp.mapper.WmsEmployeeInfoMapper;
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.bo.BatchUpdateScheduleBo;
import com.klp.domain.bo.BatchUpdateScheduleItemBo;
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.*;
import java.util.stream.Collectors;
/**
* 排班(谁在哪天上班)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;
private final WmsEmployeeInfoMapper employeeInfoMapper;
/**
* 查询排班(谁在哪天上班)
*/
@Override
public WmsAttendanceScheduleVo queryById(Long scheduleId){
WmsAttendanceSchedule schedule = baseMapper.selectById(scheduleId);
if (schedule == null) {
return null;
}
// 使用关联查询获取详细信息
List<WmsAttendanceScheduleVo> list = baseMapper.selectScheduleWithDetails(
schedule.getUserId(), schedule.getWorkDate(), schedule.getShiftId(),null, null, null);
return list.isEmpty() ? null : list.get(0);
}
/**
* 查询排班(谁在哪天上班)列表
*/
@Override
public TableDataInfo<WmsAttendanceScheduleVo> queryPageList(WmsAttendanceScheduleBo bo, PageQuery pageQuery) {
resolveEmployeeNameAndDept(bo);
Page<WmsAttendanceScheduleVo> page = pageQuery.build();
// 2. 调用 Mapper
baseMapper.selectScheduleWithDetailsPage(page, bo);
// 3. 直接返回
return TableDataInfo.build(page);
}
/**
* 查询排班(谁在哪天上班)列表
*/
@Override
public List<WmsAttendanceScheduleVo> queryList(WmsAttendanceScheduleBo bo) {
resolveEmployeeNameAndDept(bo);
return baseMapper.selectScheduleWithDetails(bo.getUserId(), bo.getWorkDate(), bo.getShiftId(),
bo.getStartDate(), bo.getEndDate(), bo.getUserIds());
}
private void resolveEmployeeNameAndDept(WmsAttendanceScheduleBo bo) {
boolean hasName = StringUtils.isNotBlank(bo.getEmployeeName());
boolean hasDept = StringUtils.isNotBlank(bo.getEmployeeDept());
if (!hasName && !hasDept) {
return;
}
LambdaQueryWrapper<WmsEmployeeInfo> qw = Wrappers.lambdaQuery();
qw.select(WmsEmployeeInfo::getInfoId);
if (hasName) {
qw.like(WmsEmployeeInfo::getName, bo.getEmployeeName());
}
if (hasDept) {
qw.like(WmsEmployeeInfo::getDept, bo.getEmployeeDept());
}
List<Long> ids = employeeInfoMapper.selectList(qw).stream()
.map(WmsEmployeeInfo::getInfoId)
.collect(Collectors.toList());
if (ids.isEmpty()) {
bo.setUserIds(java.util.Collections.singletonList(-1L));
} else {
bo.setUserIds(ids);
}
}
/**
* 新增排班(谁在哪天上班)
*/
@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(String ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
// 将逗号分隔的字符串转换为Long列表
List<Long> idList = Arrays.stream(ids.split(","))
.map(String::trim)
.filter(StringUtils::isNotBlank)
.map(Long::parseLong)
.collect(Collectors.toList());
if (idList.isEmpty()) {
return false;
}
return baseMapper.deleteBatchIds(idList) > 0;
}
/**
* 生成排班
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void generateSchedule(List<GenerateScheduleBo> boList) {
for (GenerateScheduleBo bo : boList) {
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);
}
}
}
/**
* 批量修改排班班次(按主键)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void batchUpdateShiftByIds(List<BatchUpdateScheduleItemBo> list) {
if (list == null || list.isEmpty()) {
return;
}
for (BatchUpdateScheduleItemBo item : list) {
baseMapper.update(null, Wrappers.<WmsAttendanceSchedule>lambdaUpdate()
.eq(WmsAttendanceSchedule::getScheduleId, item.getScheduleId())
.set(WmsAttendanceSchedule::getShiftId, item.getShiftId()));
}
}
/**
* 批量修改指定日期多个员工的班次
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void batchUpdateSchedule(BatchUpdateScheduleBo bo) {
Date workDate = bo.getWorkDate();
Long shiftId = bo.getShiftId();
String shiftName = bo.getShiftName();
List<Long> userIds = bo.getUserIds();
baseMapper.update(null, Wrappers.<WmsAttendanceSchedule>lambdaUpdate()
.in(WmsAttendanceSchedule::getUserId, userIds)
.eq(WmsAttendanceSchedule::getWorkDate, workDate)
.set(WmsAttendanceSchedule::getShiftId, shiftId)
.set(WmsAttendanceSchedule::getShiftName, shiftName));
Set<Long> existingUserIds = baseMapper.selectList(Wrappers.<WmsAttendanceSchedule>lambdaQuery()
.in(WmsAttendanceSchedule::getUserId, userIds)
.eq(WmsAttendanceSchedule::getWorkDate, workDate)
.select(WmsAttendanceSchedule::getUserId))
.stream()
.map(WmsAttendanceSchedule::getUserId)
.collect(Collectors.toSet());
List<WmsAttendanceSchedule> insertList = userIds.stream()
.filter(uid -> !existingUserIds.contains(uid))
.map(uid -> {
WmsAttendanceSchedule s = new WmsAttendanceSchedule();
s.setUserId(uid);
s.setWorkDate(workDate);
s.setShiftId(shiftId);
s.setShiftName(shiftName);
return s;
})
.collect(Collectors.toList());
if (!insertList.isEmpty()) {
baseMapper.insertBatch(insertList);
}
}
/**
* 生成正常排班
*/
private void generateNormalSchedule(GenerateScheduleBo bo, LocalDate startDate, LocalDate endDate) {
WmsAttendanceShiftVo shift = shiftService.queryById(bo.getShiftId());
if (shift == null) {
throw new RuntimeException("班次不存在");
}
// 一次查询整个日期范围内已存在的排班
Set<LocalDate> existingDates = getExistingScheduleDates(bo.getUserId(), startDate, endDate);
List<WmsAttendanceSchedule> schedules = new ArrayList<>();
LocalDate currentDate = startDate;
while (!currentDate.isAfter(endDate)) {
if (!existingDates.contains(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("排班插入失败");
}
}
}
/**
* 生成倒班排班
* 根据用户选择的倒班规则和起始日期,生成指定日期范围内的倒班排班表
*
* @param bo 生成排班业务对象包含用户ID、规则ID、起始班次等信息
* @param startDate 排班开始日期
* @param endDate 排班结束日期
*/
private void generateShiftSchedule(GenerateScheduleBo bo, LocalDate startDate, LocalDate endDate) {
// 获取倒班规则
// 通过规则ID查询倒班规则信息
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("倒班规则中的班次不存在");
}
// 一次查询整个日期范围内已存在的排班
// 查询用户在指定日期范围内已有的排班日期,避免重复生成
Set<LocalDate> existingDates = getExistingScheduleDates(bo.getUserId(), startDate, endDate);
List<WmsAttendanceSchedule> schedules = new ArrayList<>();
LocalDate currentDate = startDate;
boolean isCurrentShiftA = bo.getShiftId().equals(rule.getShiftA());
boolean firstDay = true;
while (!currentDate.isAfter(endDate)) {
int dayOfMonth = currentDate.getDayOfMonth();
// 判断是否为交接班日每月1日、11日、21日
boolean isSwapDay = !firstDay
&& (dayOfMonth == 1 || dayOfMonth == 11 || dayOfMonth == 21)
&& dayOfMonth != 31;
if (!existingDates.contains(currentDate)) {
WmsAttendanceSchedule schedule = new WmsAttendanceSchedule();
schedule.setUserId(bo.getUserId());
schedule.setWorkDate(java.sql.Date.valueOf(currentDate));
// 处理交接班日
if (isSwapDay) {
if (isCurrentShiftA) {
// 白班转夜班
if (changeShiftB != null) {
schedule.setShiftId(rule.getChangeShiftBId());
schedule.setShiftName(changeShiftB.getShiftName());
} else {
schedule.setShiftId(rule.getShiftB());
schedule.setShiftName(shiftB.getShiftName());
}
} else {
// 夜班转白班
if (changeShiftA != null) {
schedule.setShiftId(rule.getChangeShiftAId());
schedule.setShiftName(changeShiftA.getShiftName());
} else {
schedule.setShiftId(rule.getShiftA());
schedule.setShiftName(shiftA.getShiftName());
}
}
// 切换班次标识
isCurrentShiftA = !isCurrentShiftA;
} 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);
firstDay = false;
}
if (!schedules.isEmpty()) {
boolean ok = baseMapper.insertBatch(schedules);
if (!ok) {
throw new RuntimeException("批量插入倒班排班失败");
}
}
}
/**
* 批量查询指定用户日期范围内已存在的排班日期
*/
private Set<LocalDate> getExistingScheduleDates(Long userId, LocalDate startDate, LocalDate endDate) {
LambdaQueryWrapper<WmsAttendanceSchedule> wrapper = Wrappers.lambdaQuery();
wrapper.eq(WmsAttendanceSchedule::getUserId, userId)
.between(WmsAttendanceSchedule::getWorkDate, java.sql.Date.valueOf(startDate), java.sql.Date.valueOf(endDate))
.select(WmsAttendanceSchedule::getWorkDate);
List<WmsAttendanceSchedule> list = baseMapper.selectList(wrapper);
return list.stream()
.map(s -> new java.sql.Date(s.getWorkDate().getTime()).toLocalDate())
.collect(Collectors.toSet());
}
}