fix(hrm): 考勤异常申请字段匹配与申请人回填;补充 hrm_audit_status 字典脚本
- 新增时按当前登录账号回填申请人与部门,未关联员工档案时给出明确提示
- 分页查询支持异常日期区间,修复前端日期范围筛选不生效
- 补充 hrm_audit_status 字典初始化脚本
Co-Authored-By: Claude Code <noreply@anthropic.com>
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- HRM 审æ¹ç¶æåå
¸ |
| | | -- å½±å页é¢ï¼äººåèµæºæ¨¡å䏿æä½¿ç¨ hrm_audit_status åå
¸çåæ®å表/详æ
ï¼èå¤å¼å¸¸ç³è¯·ã请åã离èãè°å²çï¼ |
| | | -- |
| | | -- èæ¯ï¼ä»£ç ä¸å¤§éä½¿ç¨ @DictFormat("hrm_audit_status") ä¸å端 DICT_TYPE.HRM_AUDIT_STATUSï¼ |
| | | -- ä½ system_dict_type / system_dict_data ä¸ç¼ºå°è¯¥åå
¸ï¼å¯¼è´ç¶æåæ¾ç¤ºä¸ºç©ºãå¯¼åºæ 䏿åã |
| | | -- |
| | | -- æ¬èæ¬å¹çï¼å¯é夿§è¡ãæ§è¡åæ¸
çåå
¸ç¼åï¼éå¯åç«¯ï¼æå é¤ Redis ä¸ç dict_data:* ç¸å
³é®ï¼ï¼ |
| | | -- åç«¯éæ°ç»å½/å·æ°åçæã |
| | | |
| | | -- 1. åå
¸ç±»å |
| | | INSERT INTO system_dict_type (name, type, status, remark, creator, updater) |
| | | SELECT 'HRM 审æ¹ç¶æ', 'hrm_audit_status', 0, 'äººåæ¨¡å忮审æ¹ç¶æ', '1', '1' |
| | | WHERE NOT EXISTS ( |
| | | SELECT 1 FROM system_dict_type WHERE type = 'hrm_audit_status' AND deleted = b'0' |
| | | ); |
| | | |
| | | -- 2. åå
¸æ°æ®ï¼ä¸ HrmAuditStatusEnum ä¿æä¸è´ï¼ |
| | | INSERT INTO system_dict_data (sort, label, value, dict_type, status, color_type, css_class, remark, creator, updater) |
| | | SELECT s.sort, s.label, s.value, 'hrm_audit_status', 0, s.color_type, '', '', '1', '1' |
| | | FROM ( |
| | | SELECT 0 AS sort, 'è稿' AS label, '0' AS value, 'info' AS color_type |
| | | UNION ALL SELECT 10, '审æ¹ä¸', '10', 'default' |
| | | UNION ALL SELECT 20, '审æ¹éè¿', '20', 'success' |
| | | UNION ALL SELECT 30, '审æ¹é©³å', '30', 'danger' |
| | | UNION ALL SELECT 40, 'å·²æ¤é', '40', 'warning' |
| | | ) s |
| | | WHERE NOT EXISTS ( |
| | | SELECT 1 FROM system_dict_data d |
| | | WHERE d.dict_type = 'hrm_audit_status' AND d.value = s.value AND d.deleted = b'0' |
| | | ); |
| | |
| | | ErrorCode ATTENDANCE_EXCEPTION_UPDATE_AUDIT_STATUS_FAIL = new ErrorCode(1_030_004_014, "æ´æ°èå¤å¼å¸¸å®¡æ¹ç¶æå¤±è´¥ï¼åå ï¼ä¸æ¯å®¡æ¹ä¸ç¶æ"); |
| | | ErrorCode ATTENDANCE_EXCEPTION_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_030_004_015, "èå¤å¼å¸¸å®¡æ¹æµç¨ä¸åå¨"); |
| | | ErrorCode ATTENDANCE_CLOCK_ALREADY_CLOCKED = new ErrorCode(1_030_004_016, "å·²æè¿å¡ï¼è¯·å¿é夿å¡"); |
| | | ErrorCode ATTENDANCE_EXCEPTION_EMPLOYEE_NOT_EXISTS = new ErrorCode(1_030_004_018, "æ°å¢èå¤å¼å¸¸ç³è¯·å¤±è´¥ï¼å½åç»å½è´¦å·ï¼{}ï¼æªå
³èå工档æ¡ï¼æ æ³ç¡®å®ç³è¯·äººåé¨é¨ã请使ç¨å·²å
³èå工档æ¡çè´¦å·ç»å½ï¼æå
å¨ãå工档æ¡ãä¸ç»´æ¤å½åè´¦å·ååæäº¤"); |
| | | |
| | | // ========== èªé
¬ç®¡ç 1-030-005-000 ========== |
| | | ErrorCode SALARY_STRUCTURE_NOT_EXISTS = new ErrorCode(1_030_005_000, "èªé
¬ç»æä¸åå¨"); |
| | |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.ToString; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | @Schema(description = "管çåå° - èå¤å¼å¸¸ç³è¯·å页 Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | |
| | | @Schema(description = "ç¶æ", example = "0") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "å¼å¸¸æ¥æåºé´ï¼ä¼ [å¼å§æ¥æ, ç»ææ¥æ]", example = "[\"2026-01-01\", \"2026-12-31\"]") |
| | | private LocalDate[] date; |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceExceptionDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * èå¤å¼å¸¸ç³è¯· Mapper |
| | | * |
| | |
| | | public interface HrmAttendanceExceptionMapper extends BaseMapperX<HrmAttendanceExceptionDO> { |
| | | |
| | | default PageResult<HrmAttendanceExceptionDO> selectPage(HrmAttendanceExceptionPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<HrmAttendanceExceptionDO>() |
| | | LambdaQueryWrapperX<HrmAttendanceExceptionDO> query = new LambdaQueryWrapperX<HrmAttendanceExceptionDO>() |
| | | .likeIfPresent(HrmAttendanceExceptionDO::getNo, reqVO.getNo()) |
| | | .eqIfPresent(HrmAttendanceExceptionDO::getUserId, reqVO.getUserId()) |
| | | .eqIfPresent(HrmAttendanceExceptionDO::getDeptId, reqVO.getDeptId()) |
| | | .eqIfPresent(HrmAttendanceExceptionDO::getType, reqVO.getType()) |
| | | .eqIfPresent(HrmAttendanceExceptionDO::getStatus, reqVO.getStatus()) |
| | | .orderByDesc(HrmAttendanceExceptionDO::getId)); |
| | | .eqIfPresent(HrmAttendanceExceptionDO::getStatus, reqVO.getStatus()); |
| | | // å¼å¸¸æ¥æåºé´çé |
| | | LocalDate[] dateRange = reqVO.getDate(); |
| | | if (dateRange != null && dateRange.length >= 2 && dateRange[0] != null && dateRange[1] != null) { |
| | | query.between(HrmAttendanceExceptionDO::getExceptionDate, dateRange[0], dateRange[1]); |
| | | } |
| | | return selectPage(reqVO, query.orderByDesc(HrmAttendanceExceptionDO::getId)); |
| | | } |
| | | |
| | | default HrmAttendanceExceptionDO selectByNo(String no) { |
| | |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceExceptionPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceExceptionSaveReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceExceptionDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmAttendanceExceptionMapper; |
| | | import cn.iocoder.yudao.module.hrm.service.employee.HrmEmployeeService; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import cn.iocoder.yudao.module.hrm.dal.redis.HrmNoRedisDAO; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import jakarta.annotation.Resource; |
| | |
| | | @Resource |
| | | private HrmAttendanceExceptionMapper attendanceExceptionMapper; |
| | | @Resource |
| | | private HrmEmployeeService employeeService; |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | @Resource |
| | | private HrmNoRedisDAO noRedisDAO; |
| | | @Resource |
| | | private BpmProcessInstanceApi bpmProcessInstanceApi; |
| | |
| | | public Long createAttendanceException(HrmAttendanceExceptionSaveReqVO createReqVO) { |
| | | HrmAttendanceExceptionDO attendanceException = BeanUtils.toBean(createReqVO, HrmAttendanceExceptionDO.class); |
| | | attendanceException.setNo(generateNo()); |
| | | // ç³è¯·äººé»è®¤ä¸ºå½åç»å½ç¨æ·å¯¹åºçåå·¥ï¼å端表åä¸éæ©ç³è¯·äºº |
| | | Long loginUserId = cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId(); |
| | | HrmEmployeeDO employee = employeeService.getEmployeeByUserId(loginUserId); |
| | | if (employee == null) { |
| | | AdminUserRespDTO loginUser = adminUserApi.getUser(loginUserId); |
| | | throw exception(ATTENDANCE_EXCEPTION_EMPLOYEE_NOT_EXISTS, |
| | | loginUser != null ? loginUser.getNickname() : String.valueOf(loginUserId)); |
| | | } |
| | | attendanceException.setUserId(employee.getId()); |
| | | if (attendanceException.getDeptId() == null) { |
| | | attendanceException.setDeptId(employee.getDeptId()); |
| | | } |
| | | attendanceException.setStatus(HrmAuditStatusEnum.DRAFT.getStatus()); |
| | | attendanceExceptionMapper.insert(attendanceException); |
| | | storageAttachmentApi.bindAttachments("file", "hrm_attendance_exception", |