package cn.iocoder.yudao.module.hrm.service.attendance; import cn.hutool.core.util.StrUtil; 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.HrmAttendanceRulePageReqVO; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRuleSaveReqVO; import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRuleDO; import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmAttendanceRuleMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.util.List; 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 HrmAttendanceRuleServiceImpl implements HrmAttendanceRuleService { @Resource private HrmAttendanceRuleMapper attendanceRuleMapper; @Override public Long createAttendanceRule(HrmAttendanceRuleSaveReqVO createReqVO) { validateLocation(createReqVO); // 校验规则名称是否重复 validateAttendanceRuleNameUnique(null, createReqVO.getName()); // 校验部门是否已配置规则(如果指定了部门) if (createReqVO.getDeptId() != null) { validateAttendanceRuleDeptUnique(null, createReqVO.getDeptId()); } HrmAttendanceRuleDO attendanceRule = BeanUtils.toBean(createReqVO, HrmAttendanceRuleDO.class); // 设置默认值 if (attendanceRule.getLateAllowMinutes() == null) { attendanceRule.setLateAllowMinutes(0); } if (attendanceRule.getEarlyAllowMinutes() == null) { attendanceRule.setEarlyAllowMinutes(0); } if (attendanceRule.getOvertimeThreshold() == null) { attendanceRule.setOvertimeThreshold(BigDecimal.ONE); } if (attendanceRule.getStatus() == null) { attendanceRule.setStatus(0); } attendanceRuleMapper.insert(attendanceRule); return attendanceRule.getId(); } @Override public void updateAttendanceRule(HrmAttendanceRuleSaveReqVO updateReqVO) { HrmAttendanceRuleDO currentRule = attendanceRuleMapper.selectById(updateReqVO.getId()); if (currentRule == null) { throw exception(ATTENDANCE_RULE_NOT_EXISTS); } // 兼容旧管理端:没有提交地点字段时,不清空已配置的位置限制。 if (updateReqVO.getLocationRequired() == null) { updateReqVO.setLocationRequired(currentRule.getLocationRequired()); if (updateReqVO.getLocationName() == null) updateReqVO.setLocationName(currentRule.getLocationName()); if (updateReqVO.getLocationAddress() == null) updateReqVO.setLocationAddress(currentRule.getLocationAddress()); if (updateReqVO.getLongitude() == null) updateReqVO.setLongitude(currentRule.getLongitude()); if (updateReqVO.getLatitude() == null) updateReqVO.setLatitude(currentRule.getLatitude()); if (updateReqVO.getRadiusMeters() == null) updateReqVO.setRadiusMeters(currentRule.getRadiusMeters()); if (updateReqVO.getCoordinateSystem() == null) updateReqVO.setCoordinateSystem(currentRule.getCoordinateSystem()); } validateLocation(updateReqVO); // 校验规则名称是否重复 validateAttendanceRuleNameUnique(updateReqVO.getId(), updateReqVO.getName()); // 校验部门是否已配置规则(如果指定了部门) if (updateReqVO.getDeptId() != null) { validateAttendanceRuleDeptUnique(updateReqVO.getId(), updateReqVO.getDeptId()); } HrmAttendanceRuleDO updateObj = BeanUtils.toBean(updateReqVO, HrmAttendanceRuleDO.class); attendanceRuleMapper.updateById(updateObj); } @Override public void deleteAttendanceRule(Long id) { validateAttendanceRuleExists(id); attendanceRuleMapper.deleteById(id); } private void validateAttendanceRuleExists(Long id) { if (attendanceRuleMapper.selectById(id) == null) { throw exception(ATTENDANCE_RULE_NOT_EXISTS); } } private void validateLocation(HrmAttendanceRuleSaveReqVO reqVO) { if (reqVO.getLocationRequired() == null) { reqVO.setLocationRequired(false); } if (reqVO.getRadiusMeters() == null) { reqVO.setRadiusMeters(10); } if (StrUtil.isBlank(reqVO.getCoordinateSystem())) { reqVO.setCoordinateSystem("WGS84"); } else { reqVO.setCoordinateSystem(reqVO.getCoordinateSystem().trim().toUpperCase(java.util.Locale.ROOT)); } if (!"WGS84".equals(reqVO.getCoordinateSystem())) { throw exception(ATTENDANCE_LOCATION_SYSTEM_INVALID); } if (reqVO.getLongitude() != null && (reqVO.getLongitude().compareTo(BigDecimal.valueOf(-180)) < 0 || reqVO.getLongitude().compareTo(BigDecimal.valueOf(180)) > 0)) { throw exception(ATTENDANCE_LOCATION_COORDINATE_INVALID); } if (reqVO.getLatitude() != null && (reqVO.getLatitude().compareTo(BigDecimal.valueOf(-90)) < 0 || reqVO.getLatitude().compareTo(BigDecimal.valueOf(90)) > 0)) { throw exception(ATTENDANCE_LOCATION_COORDINATE_INVALID); } if (reqVO.getRadiusMeters() < 10 || reqVO.getRadiusMeters() > 5000) { throw exception(ATTENDANCE_LOCATION_RULE_INVALID); } if (Boolean.TRUE.equals(reqVO.getLocationRequired()) && (StrUtil.isBlank(reqVO.getLocationName()) || reqVO.getLongitude() == null || reqVO.getLatitude() == null)) { throw exception(ATTENDANCE_LOCATION_RULE_INVALID); } } private void validateAttendanceRuleNameUnique(Long id, String name) { HrmAttendanceRuleDO rule = attendanceRuleMapper.selectOne(HrmAttendanceRuleDO::getName, name); if (rule == null) { return; } if (id == null) { throw exception(ATTENDANCE_RULE_NAME_EXISTS); } if (!rule.getId().equals(id)) { throw exception(ATTENDANCE_RULE_NAME_EXISTS); } } private void validateAttendanceRuleDeptUnique(Long id, Long deptId) { List rules = attendanceRuleMapper.selectListByDeptId(deptId); if (rules.isEmpty()) { return; } for (HrmAttendanceRuleDO rule : rules) { if (id == null || !rule.getId().equals(id)) { throw exception(ATTENDANCE_RULE_DEPT_EXISTS); } } } @Override public HrmAttendanceRuleDO getAttendanceRule(Long id) { return attendanceRuleMapper.selectById(id); } @Override public PageResult getAttendanceRulePage(HrmAttendanceRulePageReqVO pageReqVO) { return attendanceRuleMapper.selectPage(pageReqVO); } @Override public List getAttendanceRuleList() { return attendanceRuleMapper.selectListByStatus(0); } @Override public HrmAttendanceRuleDO getAttendanceRuleByDeptId(Long deptId) { // 1. 先查找部门专属规则 List deptRules = attendanceRuleMapper.selectList(new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX() .eq(HrmAttendanceRuleDO::getDeptId, deptId) .eq(HrmAttendanceRuleDO::getStatus, 0)); if (!deptRules.isEmpty()) { return deptRules.get(0); } // 2. 查找全局规则(deptId 为 null) List globalRules = attendanceRuleMapper.selectList(new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX() .isNull(HrmAttendanceRuleDO::getDeptId) .eq(HrmAttendanceRuleDO::getStatus, 0)); if (!globalRules.isEmpty()) { return globalRules.get(0); } return null; } }