package cn.iocoder.yudao.module.hrm.service.attendance;
|
|
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceHolidayGroupRespVO;
|
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceHolidayPageReqVO;
|
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceHolidayRangeCreateReqVO;
|
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceHolidayRangeUpdateReqVO;
|
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceHolidaySaveReqVO;
|
import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceHolidayDO;
|
import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmAttendanceHolidayMapper;
|
import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceHolidayTypeEnum;
|
import jakarta.annotation.Resource;
|
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.util.ArrayList;
|
import java.util.Collections;
|
import java.util.Comparator;
|
import java.util.List;
|
import java.util.Objects;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.*;
|
|
/**
|
* 考勤节假日配置 Service 实现类
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class HrmAttendanceHolidayServiceImpl implements HrmAttendanceHolidayService {
|
|
@Resource
|
private HrmAttendanceHolidayMapper attendanceHolidayMapper;
|
|
@Override
|
public Long createAttendanceHoliday(HrmAttendanceHolidaySaveReqVO createReqVO) {
|
// 校验日期是否已存在配置
|
validateAttendanceHolidayDateExists(createReqVO.getDate());
|
HrmAttendanceHolidayDO attendanceHoliday = BeanUtils.toBean(createReqVO, HrmAttendanceHolidayDO.class);
|
// VO 侧用 Boolean 兼容前端勾选框的 true/false,落库统一为 0/1
|
attendanceHoliday.setIsLegal(Boolean.TRUE.equals(createReqVO.getIsLegal()) ? 1 : 0);
|
attendanceHolidayMapper.insert(attendanceHoliday);
|
return attendanceHoliday.getId();
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Integer createAttendanceHolidayRange(HrmAttendanceHolidayRangeCreateReqVO createReqVO) {
|
if (createReqVO.getEndDate().isBefore(createReqVO.getStartDate())) {
|
throw exception(ATTENDANCE_HOLIDAY_DATE_RANGE_INVALID);
|
}
|
return insertDays(createReqVO.getName(), createReqVO.getStartDate(), createReqVO.getEndDate(),
|
createReqVO.getType(), createReqVO.getIsLegal(), createReqVO.getRemark());
|
}
|
|
/**
|
* 按天写入节假日;写入前整体查重,任一日期已存在则整体不写入
|
*/
|
private int insertDays(String name, LocalDate startDate, LocalDate endDate,
|
Integer type, Boolean isLegal, String remark) {
|
// 先整体校验,区间内已存在任一日期时不做部分写入
|
List<HrmAttendanceHolidayDO> existingList = attendanceHolidayMapper.selectListByDateBetween(startDate, endDate);
|
if (!existingList.isEmpty()) {
|
HrmAttendanceHolidayDO existing = existingList.get(0);
|
throw exception(ATTENDANCE_HOLIDAY_RANGE_DATE_EXISTS, existing.getDate(), existing.getName());
|
}
|
int count = 0;
|
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
|
HrmAttendanceHolidayDO attendanceHoliday = HrmAttendanceHolidayDO.builder()
|
.name(name)
|
.date(date)
|
.type(type)
|
.isLegal(Boolean.TRUE.equals(isLegal) ? 1 : 0)
|
.remark(remark)
|
.build();
|
attendanceHolidayMapper.insert(attendanceHoliday);
|
count++;
|
}
|
return count;
|
}
|
|
@Override
|
public void updateAttendanceHoliday(HrmAttendanceHolidaySaveReqVO updateReqVO) {
|
validateAttendanceHolidayExists(updateReqVO.getId());
|
// 如果日期变更,校验新日期是否已存在配置
|
HrmAttendanceHolidayDO oldHoliday = attendanceHolidayMapper.selectById(updateReqVO.getId());
|
if (!oldHoliday.getDate().equals(updateReqVO.getDate())) {
|
validateAttendanceHolidayDateExists(updateReqVO.getDate());
|
}
|
HrmAttendanceHolidayDO updateObj = BeanUtils.toBean(updateReqVO, HrmAttendanceHolidayDO.class);
|
updateObj.setIsLegal(Boolean.TRUE.equals(updateReqVO.getIsLegal()) ? 1 : 0);
|
attendanceHolidayMapper.updateById(updateObj);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void updateAttendanceHolidayRange(HrmAttendanceHolidayRangeUpdateReqVO updateReqVO) {
|
// 1. 校验时间范围与区间记录
|
if (updateReqVO.getEndDate().isBefore(updateReqVO.getStartDate())) {
|
throw exception(ATTENDANCE_HOLIDAY_DATE_RANGE_INVALID);
|
}
|
List<Long> ids = updateReqVO.getIds().stream().filter(Objects::nonNull).distinct().toList();
|
if (ids.isEmpty()) {
|
throw exception(ATTENDANCE_HOLIDAY_RANGE_IDS_EMPTY);
|
}
|
List<HrmAttendanceHolidayDO> oldList = attendanceHolidayMapper.selectBatchIds(ids);
|
if (oldList.size() != ids.size()) {
|
throw exception(ATTENDANCE_HOLIDAY_RANGE_NOT_EXISTS);
|
}
|
// 2. 删除区间内原记录,再按新的起止日期整体重写(同一事务,异常会回滚)
|
attendanceHolidayMapper.physicalDeleteByIds(ids);
|
insertDays(updateReqVO.getName(), updateReqVO.getStartDate(), updateReqVO.getEndDate(),
|
updateReqVO.getType(), updateReqVO.getIsLegal(), updateReqVO.getRemark());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteAttendanceHolidayRange(List<Long> ids) {
|
List<Long> cleanIds = ids == null ? Collections.emptyList()
|
: ids.stream().filter(Objects::nonNull).distinct().toList();
|
if (cleanIds.isEmpty()) {
|
throw exception(ATTENDANCE_HOLIDAY_RANGE_IDS_EMPTY);
|
}
|
attendanceHolidayMapper.physicalDeleteByIds(cleanIds);
|
}
|
|
@Override
|
public void deleteAttendanceHoliday(Long id) {
|
validateAttendanceHolidayExists(id);
|
attendanceHolidayMapper.physicalDeleteByIds(Collections.singletonList(id));
|
}
|
|
private void validateAttendanceHolidayExists(Long id) {
|
if (attendanceHolidayMapper.selectById(id) == null) {
|
throw exception(ATTENDANCE_HOLIDAY_NOT_EXISTS);
|
}
|
}
|
|
private void validateAttendanceHolidayDateExists(LocalDate date) {
|
if (attendanceHolidayMapper.selectByDate(date) != null) {
|
throw exception(ATTENDANCE_HOLIDAY_DATE_EXISTS);
|
}
|
}
|
|
@Override
|
public HrmAttendanceHolidayDO getAttendanceHoliday(Long id) {
|
return attendanceHolidayMapper.selectById(id);
|
}
|
|
@Override
|
public PageResult<HrmAttendanceHolidayDO> getAttendanceHolidayPage(HrmAttendanceHolidayPageReqVO pageReqVO) {
|
return attendanceHolidayMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public PageResult<HrmAttendanceHolidayGroupRespVO> getAttendanceHolidayGroupPage(
|
HrmAttendanceHolidayPageReqVO pageReqVO) {
|
List<HrmAttendanceHolidayDO> list = attendanceHolidayMapper.selectListByCondition(pageReqVO);
|
if (list.isEmpty()) {
|
return new PageResult<>(Collections.emptyList(), 0L);
|
}
|
// 1. 连续日期 + 名称/类型/是否法定/备注一致的记录合并为一行
|
List<HrmAttendanceHolidayGroupRespVO> groups = new ArrayList<>();
|
HrmAttendanceHolidayDO previous = null;
|
for (HrmAttendanceHolidayDO current : list) {
|
HrmAttendanceHolidayGroupRespVO last = groups.isEmpty() ? null : groups.get(groups.size() - 1);
|
boolean sameGroup = last != null && previous != null
|
&& previous.getDate().plusDays(1).equals(current.getDate())
|
&& sameHoliday(previous, current);
|
if (sameGroup) {
|
last.setEndDate(current.getDate());
|
last.getIds().add(current.getId());
|
last.setDayCount(last.getDayCount() + 1);
|
} else {
|
HrmAttendanceHolidayGroupRespVO group = new HrmAttendanceHolidayGroupRespVO();
|
group.setId(current.getId());
|
List<Long> ids = new ArrayList<>();
|
ids.add(current.getId());
|
group.setIds(ids);
|
group.setName(current.getName());
|
group.setDate(current.getDate());
|
group.setEndDate(current.getDate());
|
group.setDayCount(1);
|
group.setType(current.getType());
|
group.setIsLegal(current.getIsLegal());
|
group.setRemark(current.getRemark());
|
group.setCreateTime(current.getCreateTime());
|
groups.add(group);
|
}
|
previous = current;
|
}
|
// 2. 按日期倒序,与逐日列表保持一致
|
groups.sort(Comparator.comparing(HrmAttendanceHolidayGroupRespVO::getDate).reversed());
|
// 3. 分组后内存分页
|
return pageGroups(groups, pageReqVO);
|
}
|
|
private boolean sameHoliday(HrmAttendanceHolidayDO a, HrmAttendanceHolidayDO b) {
|
return StrUtil.equals(a.getName(), b.getName())
|
&& Objects.equals(a.getType(), b.getType())
|
&& Objects.equals(a.getIsLegal(), b.getIsLegal())
|
&& StrUtil.equals(a.getRemark(), b.getRemark());
|
}
|
|
private PageResult<HrmAttendanceHolidayGroupRespVO> pageGroups(
|
List<HrmAttendanceHolidayGroupRespVO> groups, HrmAttendanceHolidayPageReqVO pageReqVO) {
|
long total = groups.size();
|
if (Objects.equals(PageParam.PAGE_SIZE_NONE, pageReqVO.getPageSize())) {
|
return new PageResult<>(groups, total);
|
}
|
int pageNo = pageReqVO.getPageNo() == null ? 1 : pageReqVO.getPageNo();
|
int pageSize = pageReqVO.getPageSize() == null ? 10 : pageReqVO.getPageSize();
|
int from = Math.max(0, (pageNo - 1) * pageSize);
|
if (from >= groups.size()) {
|
return new PageResult<>(Collections.emptyList(), total);
|
}
|
int to = Math.min(groups.size(), from + pageSize);
|
return new PageResult<>(new ArrayList<>(groups.subList(from, to)), total);
|
}
|
|
@Override
|
public List<HrmAttendanceHolidayDO> getAttendanceHolidayListByDateRange(LocalDate startDate, LocalDate endDate) {
|
return attendanceHolidayMapper.selectListByDateBetween(startDate, endDate);
|
}
|
|
@Override
|
public boolean isWorkDay(LocalDate date) {
|
// 1. 查询节假日配置
|
HrmAttendanceHolidayDO holiday = attendanceHolidayMapper.selectByDate(date);
|
if (holiday != null) {
|
// 有配置时,按配置判断
|
return HrmAttendanceHolidayTypeEnum.WORK_DAY.getType().equals(holiday.getType());
|
}
|
// 2. 无配置时,按周末判断
|
DayOfWeek dayOfWeek = date.getDayOfWeek();
|
return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
|
}
|
|
}
|