docs/project-business/data/modules.json
@@ -83,7 +83,7 @@ {"key": "hrm", "name": "人åèµæº", "color": "#9db85a", "tag": "HRM", "flow": null, "positioning": "åå·¥å ¥è½¬è°ç¦»ä¸èå¤èªé ¬", "problem": "äººäºæµç¨å®¡æ¹åãç¦»èæ°æ®ä¸ä¸¢(交æ¥)ãç®èªèªå¨å", "features": ["å工档æ¡(å ¥èèªå¨å»ºç³»ç»è´¦å·)", "请å/å ç/è°å²/离è BPM 审æ¹", "离èäº¤æ¥æ å° expandUserIds", "èå¤(æå¡Â·è§å·æç·补å¡å®¡æ¹Â·æåº¦æ±æ»)", "èªé ¬(åºå-社ä¿å ¬ç§¯é-个ç¨-è¯·åæ£æ¬¾Â·1.5/2/3åå çè´¹Â·åæ¾å°è´¦)", "å¹è®è¯ä¹¦(SQLå è¡å¾ å®ç°)"], "features": ["å工档æ¡(å ¥èèªå¨å»ºç³»ç»è´¦å·)", "请å/å ç/è°å²/离è BPM 审æ¹", "离èäº¤æ¥æ å° expandUserIds", "èå¤(ç§»å¨ç«¯æçèå¤ç¶æÂ·æå¡Â·è§å·æç·补å¡å®¡æ¹Â·æåº¦æ±æ»)", "èªé ¬(åºå-社ä¿å ¬ç§¯é-个ç¨-è¯·åæ£æ¬¾Â·1.5/2/3åå çè´¹Â·åæ¾å°è´¦)", "å¹è®è¯ä¹¦(SQLå è¡å¾ å®ç°)"], "objects": ["åå·¥", "请åå", "离èç³è¯·", "äº¤æ¥æ å°", "èå¤è®°å½", "èªé ¬æ ¸ç®"], "roles": ["HR", "é¨é¨ä¸»ç®¡", "åå·¥æ¬äºº"], "upstream": [], "downstream": ["忍¡å(æ°æ®å¯è§æ§æ©å±)", "system(è´¦å·)"], docs/project-business/data/roles.json
@@ -18,7 +18,7 @@ {"role": "设å¤å/维修工", "modules": ["MES-DV"], "operations": ["ç¹æ£ä¿å »", "维修工å", "å·¥è£ é¢ç¨"], "data": ["mes_dv_*", "mes_tm_*"], "scope": "chargeUserId å½å±"}, {"role": "客æ/å®åå·¥ç¨å¸", "modules": ["å®å"], "operations": ["å·¥ååçæ´¾å·¥", "ç»´ä¿®", "éè´§ç³è¯·"], "data": ["after_sale_*"], "scope": "è¡çº§æ°æ®æéåè§å¾ï¼æè´è´£/æåä¸/ä¸å±è´è´£/å ¨é¨(aftersales:view-all)"}, {"role": "è´¢å¡", "modules": ["ERP", "CRM"], "operations": ["æ¶æ¬¾å", "仿¬¾å", "å¼ç¥¨å®¡æ ¸", "ç»ç®è´¦æ·"], "data": ["erp_finance_*", "crm_invoice", "crm_receivable"], "scope": "financeUserId å½å±"}, {"role": "HR", "modules": ["HRM"], "operations": ["å工档æ¡å ¥è½¬è°ç¦»", "èå¤è§åæç", "èªé ¬æ ¸ç®åæ¾", "离è交æ¥"], "data": ["hrm_*"], "scope": "é¨é¨èå´ dataScope"}, {"role": "HR", "modules": ["HRM"], "operations": ["å工档æ¡å ¥è½¬è°ç¦»", "èå¤è§åæç(æ¬äººæå¡å ¨åå¯ç¨ï¼ä¸è®¾æéç¹)", "èªé ¬æ ¸ç®åæ¾", "离è交æ¥"], "data": ["hrm_*"], "scope": "é¨é¨èå´ dataScope"}, {"role": "管çå±", "modules": ["BI"], "operations": ["æ¥çéè´éå®/ä»åº/ç产设å¤/è´¨é/人åäºå¤§ä¸»é¢å¤§å±"], "data": ["bi_dashboard"], "scope": "åªè¯»"} ] } yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmAttendanceClockTypeEnum.java
@@ -28,4 +28,19 @@ return ARRAYS; } /** * æ ¹æ®ç±»åè·ååç§°ï¼æªç¥ç±»åè¿å null */ public static String getNameByType(Integer type) { if (type == null) { return null; } for (HrmAttendanceClockTypeEnum value : values()) { if (value.getType().equals(type)) { return value.getName(); } } return null; } } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/HrmAttendanceRecordController.java
@@ -8,12 +8,14 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.util.OperateLogUtils; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceMyStatusRespVO; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordImportExcelVO; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordImportReqVO; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordPageReqVO; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordRespVO; import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRecordDO; import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO; import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceClockTypeEnum; import cn.iocoder.yudao.module.hrm.service.attendance.HrmAttendanceRecordService; import cn.iocoder.yudao.module.hrm.service.employee.HrmEmployeeService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; @@ -27,11 +29,13 @@ import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.io.IOException; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @@ -39,6 +43,7 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.EMPLOYEE_NOT_EXISTS; import static cn.iocoder.yudao.module.hrm.enums.LogRecordConstants.*; @@ -59,36 +64,46 @@ @PostMapping("/clock-in") @Operation(summary = "ä¸çæå¡") @PreAuthorize("@ss.hasPermission('hrm:attendance-record:clock')") public CommonResult<HrmAttendanceRecordRespVO> clockIn(@RequestParam("location") String location) { Long loginUserId = getLoginUserId(); HrmEmployeeDO employee = employeeService.getEmployeeByUserId(loginUserId); if (employee == null) { throw exception(EMPLOYEE_NOT_EXISTS, "å½åç¨æ·æªå ³èå工信æ¯ï¼æ æ³æå¡"); throw exception(EMPLOYEE_NOT_EXISTS, "å½åç»å½è´¦å·æªå ³èå工档æ¡ï¼æ æ³æå¡ã请è系管çåå¨ãå工管çãä¸å°è¯¥ç»å½è´¦å·ç»å®å°åå·¥ã"); } HrmAttendanceRecordDO record = attendanceRecordService.clockIn(employee.getId(), LocalDateTime.now(), location); HrmAttendanceRecordRespVO respVO = BeanUtils.toBean(record, HrmAttendanceRecordRespVO.class); respVO.setUserName(employee.getName()); if (record.getDeptId() != null) { DeptRespDTO dept = deptApi.getDept(record.getDeptId()); if (dept != null) { respVO.setDeptName(dept.getName()); } } return success(respVO); return success(buildClockRespVO(record, employee)); } @PostMapping("/clock-out") @Operation(summary = "ä¸çæå¡") @PreAuthorize("@ss.hasPermission('hrm:attendance-record:clock')") public CommonResult<HrmAttendanceRecordRespVO> clockOut(@RequestParam("location") String location) { Long loginUserId = getLoginUserId(); HrmEmployeeDO employee = employeeService.getEmployeeByUserId(loginUserId); if (employee == null) { throw exception(EMPLOYEE_NOT_EXISTS, "å½åç¨æ·æªå ³èå工信æ¯ï¼æ æ³æå¡"); throw exception(EMPLOYEE_NOT_EXISTS, "å½åç»å½è´¦å·æªå ³èå工档æ¡ï¼æ æ³æå¡ã请è系管çåå¨ãå工管çãä¸å°è¯¥ç»å½è´¦å·ç»å®å°åå·¥ã"); } HrmAttendanceRecordDO record = attendanceRecordService.clockOut(employee.getId(), LocalDateTime.now(), location); return success(buildClockRespVO(record, employee)); } @GetMapping("/my-status") @Operation(summary = "è·å¾å½åç»å½äººçèå¤ç¶æ") @Parameter(name = "date", description = "è夿¥æï¼æ ¼å¼ yyyy-MM-ddï¼é»è®¤æå¡å¨å½å¤©", example = "2026-10-17") public CommonResult<HrmAttendanceMyStatusRespVO> getMyStatus( @RequestParam(value = "date", required = false) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) LocalDate date) { return success(attendanceRecordService.getMyStatus(getLoginUserId(), date)); } /** * æå»ºæå¡è¿å VOï¼åæ®µä¸ my-status.record ä¿æä¸è´ */ private HrmAttendanceRecordRespVO buildClockRespVO(HrmAttendanceRecordDO record, HrmEmployeeDO employee) { HrmAttendanceRecordRespVO respVO = BeanUtils.toBean(record, HrmAttendanceRecordRespVO.class); respVO.setClockInTypeName(HrmAttendanceClockTypeEnum.getNameByType(record.getClockInType())); respVO.setClockOutTypeName(HrmAttendanceClockTypeEnum.getNameByType(record.getClockOutType())); respVO.setUserName(employee.getName()); if (record.getDeptId() != null) { DeptRespDTO dept = deptApi.getDept(record.getDeptId()); @@ -96,7 +111,7 @@ respVO.setDeptName(dept.getName()); } } return success(respVO); return respVO; } private Long getLoginUserId() { yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceMyStatusRespVO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,67 @@ package cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDate; import java.time.LocalDateTime; @Schema(description = "管çåå° - æçèå¤ç¶æ Response VO") @Data public class HrmAttendanceMyStatusRespVO { @Schema(description = "ç»å½ç¨æ·ID", example = "464") private Long userId; @Schema(description = "å工档æ¡ID", example = "233") private Long employeeId; @Schema(description = "åå·¥å§å", example = "é¿åæå çæ¨Â·å¾æä¾æ¨") private String employeeName; @Schema(description = "é¨é¨ID", example = "131") private Long deptId; @Schema(description = "é¨é¨åç§°", example = "é¢ç»æè½¦é´") private String deptName; @Schema(description = "è夿¥æ", example = "2026-10-17") private LocalDate date; @Schema(description = "æå¡å¨æ¶é´", example = "2026-10-17 18:30:00") private LocalDateTime serverTime; @Schema(description = "æ¯å¦å·¥ä½æ¥") private Boolean workDay; @Schema(description = "伿¯æ¥åå ï¼å¦ï¼å½åºèãå¨å ") private String restDayReason; @Schema(description = "å½åçæçèå¤è§åï¼æªé ç½®æ¶ä¸º null") private HrmAttendanceRuleRespVO rule; @Schema(description = "彿¥èå¤è®°å½ï¼æªæå¡æ¶ä¸º null") private HrmAttendanceRecordRespVO record; @Schema(description = "å½å坿å¡ç¶æ") private Clockable clockable; @Schema(description = "æå¡ç¶æ") @Data public static class Clockable { @Schema(description = "æ¯å¦å¯ä¸çæå¡") private Boolean clockIn; @Schema(description = "æ¯å¦å¯ä¸çæå¡") private Boolean clockOut; @Schema(description = "ä¸ä¸æ¥å¨ä½ï¼in-ä¸çæå¡ï¼out-ä¸çæå¡ï¼none-æ éæå¡") private String nextAction; @Schema(description = "æç¤ºææ¡", example = "å·²ä¸çæå¡ï¼å¯ä¸çæå¡") private String message; } } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRecordRespVO.java
@@ -55,11 +55,17 @@ @DictFormat("hrm_clock_type") private Integer clockInType; @Schema(description = "ä¸çæå¡ç±»ååç§°", example = "æ£å¸¸") private String clockInTypeName; @Schema(description = "ä¸çæå¡ç±»å") @ExcelProperty(value = "ä¸çæå¡ç±»å", converter = DictConvert.class) @DictFormat("hrm_clock_type") private Integer clockOutType; @Schema(description = "ä¸çæå¡ç±»ååç§°", example = "æ©é") private String clockOutTypeName; @Schema(description = "工使¶é¿ï¼å°æ¶ï¼") @ExcelProperty("工使¶é¿") private BigDecimal workHours; yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordService.java
@@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.hrm.service.attendance; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceMyStatusRespVO; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordPageReqVO; import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRecordDO; import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceExceptionDO; @@ -37,6 +38,15 @@ */ HrmAttendanceRecordDO getAttendanceRecordByUserIdAndDate(Long userId, LocalDate date); /** * è·å¾å½åç»å½äººçèå¤ç¶æï¼èå¤è§å + æå®æ¥æçæå¡ç¶æ * * @param loginUserId ç»å½ç¨æ·IDï¼ç³»ç»ç¨æ·IDï¼ä¸æ¯åå·¥IDï¼ * @param date è夿¥æï¼ä¸ºç©ºæ¶åæå¡å¨å½å¤© * @return æçèå¤ç¶æ */ HrmAttendanceMyStatusRespVO getMyStatus(Long loginUserId, LocalDate date); /** åå»ºå¯¼å ¥çèå¤è®°å½ */ void createImportedRecord(HrmAttendanceRecordDO record); yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java
@@ -2,7 +2,11 @@ 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.HrmAttendanceMyStatusRespVO; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordPageReqVO; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordRespVO; import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRuleRespVO; import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceHolidayDO; import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRecordDO; import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRuleDO; import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceExceptionDO; @@ -11,7 +15,10 @@ import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceClockTypeEnum; import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceDataSourceEnum; import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceExceptionTypeEnum; import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceHolidayTypeEnum; import cn.iocoder.yudao.module.hrm.service.employee.HrmEmployeeService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -19,6 +26,7 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.time.DayOfWeek; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; @@ -45,6 +53,8 @@ private HrmAttendanceRuleService attendanceRuleService; @Resource private HrmAttendanceHolidayService attendanceHolidayService; @Resource private DeptApi deptApi; @Override public PageResult<HrmAttendanceRecordDO> getAttendanceRecordPage(HrmAttendanceRecordPageReqVO pageReqVO) { @@ -67,6 +77,162 @@ } @Override public HrmAttendanceMyStatusRespVO getMyStatus(Long loginUserId, LocalDate date) { LocalDate queryDate = date != null ? date : LocalDate.now(); // 1. ç»å½ç¨æ· -> åå·¥æ¡£æ¡ HrmEmployeeDO employee = employeeService.getEmployeeByUserId(loginUserId); if (employee == null) { throw exception(EMPLOYEE_NOT_EXISTS, "å½åç»å½è´¦å·æªå ³èå工档æ¡ï¼æ æ³æå¡ã请è系管çåå¨ãå工管çãä¸å°è¯¥ç»å½è´¦å·ç»å®å°åå·¥ã"); } HrmAttendanceMyStatusRespVO respVO = new HrmAttendanceMyStatusRespVO(); respVO.setUserId(loginUserId); respVO.setEmployeeId(employee.getId()); respVO.setEmployeeName(employee.getName()); respVO.setDeptId(employee.getDeptId()); if (employee.getDeptId() != null) { DeptRespDTO dept = deptApi.getDept(employee.getDeptId()); if (dept != null) { respVO.setDeptName(dept.getName()); } } respVO.setDate(queryDate); respVO.setServerTime(LocalDateTime.now()); // 2. æ¯å¦å·¥ä½æ¥ + 伿¯åå boolean workDay = attendanceHolidayService.isWorkDay(queryDate); respVO.setWorkDay(workDay); if (!workDay) { respVO.setRestDayReason(getRestDayReason(queryDate)); } // 3. å½åçæè§åï¼é¨é¨è§åä¼å ï¼å ¶æ¬¡å ¨å±è§åï¼ HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(employee.getDeptId()); if (rule != null) { HrmAttendanceRuleRespVO ruleRespVO = BeanUtils.toBean(rule, HrmAttendanceRuleRespVO.class); if (rule.getDeptId() != null) { DeptRespDTO ruleDept = deptApi.getDept(rule.getDeptId()); if (ruleDept != null) { ruleRespVO.setDeptName(ruleDept.getName()); } } respVO.setRule(ruleRespVO); } // 4. 彿¥èå¤è®°å½ HrmAttendanceRecordDO record = attendanceRecordMapper.selectByUserIdAndDate(employee.getId(), queryDate); if (record != null) { respVO.setRecord(buildRecordRespVO(record, employee)); } // 5. å½å坿å¡ç¶æ respVO.setClockable(buildClockable(workDay, rule, record, queryDate)); return respVO; } /** * 伿¯æ¥åå ï¼ä¼å åè忥é ç½®åç§°ï¼æªé ç½®æ¶æææç»åºâå¨å /卿¥â */ private String getRestDayReason(LocalDate date) { List<HrmAttendanceHolidayDO> holidays = attendanceHolidayService.getAttendanceHolidayListByDateRange(date, date); for (HrmAttendanceHolidayDO holiday : holidays) { if (HrmAttendanceHolidayTypeEnum.REST_DAY.getType().equals(holiday.getType())) { return holiday.getName(); } } DayOfWeek dayOfWeek = date.getDayOfWeek(); if (dayOfWeek == DayOfWeek.SATURDAY) { return "å¨å "; } if (dayOfWeek == DayOfWeek.SUNDAY) { return "卿¥"; } return null; } /** * æå»ºæå¡è®°å½è¿å VOï¼è¡¥é½æå¡ç±»ååç§°ãåå·¥ä¸é¨é¨ä¿¡æ¯ */ private HrmAttendanceRecordRespVO buildRecordRespVO(HrmAttendanceRecordDO record, HrmEmployeeDO employee) { HrmAttendanceRecordRespVO recordRespVO = BeanUtils.toBean(record, HrmAttendanceRecordRespVO.class); recordRespVO.setClockInTypeName(HrmAttendanceClockTypeEnum.getNameByType(record.getClockInType())); recordRespVO.setClockOutTypeName(HrmAttendanceClockTypeEnum.getNameByType(record.getClockOutType())); if (employee != null) { recordRespVO.setUserName(employee.getName()); recordRespVO.setPhone(employee.getPhone()); } if (record.getDeptId() != null) { DeptRespDTO dept = deptApi.getDept(record.getDeptId()); if (dept != null) { recordRespVO.setDeptName(dept.getName()); } } return recordRespVO; } /** * æ ¹æ®å·¥ä½æ¥ãèå¤è§åä¸å½æ¥è®°å½è®¡ç®å¯æå¡ç¶æ */ private HrmAttendanceMyStatusRespVO.Clockable buildClockable(boolean workDay, HrmAttendanceRuleDO rule, HrmAttendanceRecordDO record, LocalDate date) { HrmAttendanceMyStatusRespVO.Clockable clockable = new HrmAttendanceMyStatusRespVO.Clockable(); if (!workDay) { clockable.setClockIn(false); clockable.setClockOut(false); clockable.setNextAction("none"); clockable.setMessage("仿¥ä¼æ¯ï¼æ éæå¡"); return clockable; } if (rule == null) { clockable.setClockIn(false); clockable.setClockOut(false); clockable.setNextAction("none"); clockable.setMessage("æªé ç½®èå¤è§åï¼è¯·è系管çå"); return clockable; } // åªæä¸çå¡ã没æä¸çå¡ï¼å½æ¥å·²ç»æï¼ä¸åå è®¸ç»§ç»æå¡ if (record != null && record.getClockInTime() == null && record.getClockOutTime() != null) { clockable.setClockIn(false); clockable.setClockOut(false); clockable.setNextAction("none"); clockable.setMessage("仿¥ç¼ºä¸çå¡ï¼å·²å®æä¸çæå¡"); return clockable; } // ä»å¤©è¿æ²¡æä¸çå¡ if (record == null || record.getClockInTime() == null) { clockable.setClockIn(true); clockable.setClockOut(false); clockable.setNextAction("in"); clockable.setMessage("å¯ä¸çæå¡"); // ä» å½å¤©æ¥è¯¢æ¶æç¤ºå·²è¿å°æ¶é¿ LocalDateTime now = LocalDateTime.now(); if (rule.getWorkStartTime() != null && date.equals(now.toLocalDate())) { LocalDateTime workStart = LocalDateTime.of(date, rule.getWorkStartTime()); int lateAllowMinutes = rule.getLateAllowMinutes() != null ? rule.getLateAllowMinutes() : 0; if (now.isAfter(workStart.plusMinutes(lateAllowMinutes))) { long lateMinutes = Duration.between(workStart, now).toMinutes(); clockable.setMessage("å·²è¶ è¿ä¸çæ¶é´ " + lateMinutes + " åé"); } } return clockable; } // å·²æä¸çå¡ãæªæä¸çå¡ if (record.getClockOutTime() == null) { clockable.setClockIn(false); clockable.setClockOut(true); clockable.setNextAction("out"); clockable.setMessage("å·²ä¸çæå¡ï¼å¯ä¸çæå¡"); return clockable; } // ä¸ä¸çå¡é½å·²æ clockable.setClockIn(false); clockable.setClockOut(false); clockable.setNextAction("none"); clockable.setMessage("仿¥å·²å®ææå¡"); return clockable; } @Override public void createImportedRecord(HrmAttendanceRecordDO record) { // æèå¤è§åéç®æå¡ç±»å䏿¶é¿ï¼ä¸ä¿¡ä»» Excel å¡«åçå¼ fillClockTypes(record);