From e4432d49f9d74e69cc71ed1141ebcd30c817e998 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期六, 17 十月 2026 20:34:24 +0800
Subject: [PATCH] feat(hrm): 新增我的考勤状态接口并开放全员打卡
---
docs/project-business/data/roles.json | 2
yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmAttendanceClockTypeEnum.java | 15 ++
docs/project-business/data/modules.json | 2
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/HrmAttendanceRecordController.java | 43 ++++--
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordService.java | 10 +
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceMyStatusRespVO.java | 67 +++++++++++
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java | 166 +++++++++++++++++++++++++++
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRecordRespVO.java | 6 +
8 files changed, 295 insertions(+), 16 deletions(-)
diff --git a/docs/project-business/data/modules.json b/docs/project-business/data/modules.json
index 4c1407b..dc2a3ff 100644
--- a/docs/project-business/data/modules.json
+++ b/docs/project-business/data/modules.json
@@ -83,7 +83,7 @@
{"key": "hrm", "name": "浜哄姏璧勬簮", "color": "#9db85a", "tag": "HRM", "flow": null,
"positioning": "鍛樺伐鍏ヨ浆璋冪涓庤�冨嫟钖叕",
"problem": "浜轰簨娴佺▼瀹℃壒鍖栥�佺鑱屾暟鎹笉涓�(浜ゆ帴)銆佺畻钖嚜鍔ㄥ寲",
- "features": ["鍛樺伐妗f(鍏ヨ亴鑷姩寤虹郴缁熻处鍙�)", "璇峰亣/鍔犵彮/璋冨矖/绂昏亴 BPM 瀹℃壒", "绂昏亴浜ゆ帴鏄犲皠 expandUserIds", "鑰冨嫟(鎵撳崱路瑙勫垯路鎺掔彮路琛ュ崱瀹℃壒路鏈堝害姹囨��)", "钖叕(搴斿彂-绀句繚鍏Н閲�-涓◣-璇峰亣鎵f路1.5/2/3鍊嶅姞鐝垂路鍙戞斁鍙拌处)", "鍩硅璇佷功(SQL鍏堣寰呭疄鐜�)"],
+ "features": ["鍛樺伐妗f(鍏ヨ亴鑷姩寤虹郴缁熻处鍙�)", "璇峰亣/鍔犵彮/璋冨矖/绂昏亴 BPM 瀹℃壒", "绂昏亴浜ゆ帴鏄犲皠 expandUserIds", "鑰冨嫟(绉诲姩绔垜鐨勮�冨嫟鐘舵�伮锋墦鍗÷疯鍒櫬锋帓鐝疯ˉ鍗″鎵孤锋湀搴︽眹鎬�)", "钖叕(搴斿彂-绀句繚鍏Н閲�-涓◣-璇峰亣鎵f路1.5/2/3鍊嶅姞鐝垂路鍙戞斁鍙拌处)", "鍩硅璇佷功(SQL鍏堣寰呭疄鐜�)"],
"objects": ["鍛樺伐", "璇峰亣鍗�", "绂昏亴鐢宠", "浜ゆ帴鏄犲皠", "鑰冨嫟璁板綍", "钖叕鏍哥畻"],
"roles": ["HR", "閮ㄩ棬涓荤", "鍛樺伐鏈汉"],
"upstream": [], "downstream": ["鍚勬ā鍧�(鏁版嵁鍙鎬ф墿灞�)", "system(璐﹀彿)"],
diff --git a/docs/project-business/data/roles.json b/docs/project-business/data/roles.json
index 4980d2b..3a0b7ae 100644
--- a/docs/project-business/data/roles.json
+++ b/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": ["鍛樺伐妗f鍏ヨ浆璋冪", "鑰冨嫟瑙勫垯鎺掔彮", "钖叕鏍哥畻鍙戞斁", "绂昏亴浜ゆ帴"], "data": ["hrm_*"], "scope": "閮ㄩ棬鑼冨洿 dataScope"},
+ {"role": "HR", "modules": ["HRM"], "operations": ["鍛樺伐妗f鍏ヨ浆璋冪", "鑰冨嫟瑙勫垯鎺掔彮(鏈汉鎵撳崱鍏ㄥ憳鍙敤锛屼笉璁炬潈闄愮偣)", "钖叕鏍哥畻鍙戞斁", "绂昏亴浜ゆ帴"], "data": ["hrm_*"], "scope": "閮ㄩ棬鑼冨洿 dataScope"},
{"role": "绠$悊灞�", "modules": ["BI"], "operations": ["鏌ョ湅閲囪喘閿�鍞�/浠撳簱/鐢熶骇璁惧/璐ㄩ噺/浜哄姏浜斿ぇ涓婚澶у睆"], "data": ["bi_dashboard"], "scope": "鍙"}
]
}
diff --git a/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmAttendanceClockTypeEnum.java b/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmAttendanceClockTypeEnum.java
index ee77e9f..99bd961 100644
--- a/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmAttendanceClockTypeEnum.java
+++ b/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;
+ }
+
}
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/HrmAttendanceRecordController.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/HrmAttendanceRecordController.java
index 3d677dc..0528f3e 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/HrmAttendanceRecordController.java
+++ b/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() {
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceMyStatusRespVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceMyStatusRespVO.java
new file mode 100644
index 0000000..f5d1198
--- /dev/null
+++ b/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 = "鍛樺伐妗fID", 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-涓婄彮鎵撳崱锛宱ut-涓嬬彮鎵撳崱锛宯one-鏃犻渶鎵撳崱")
+ private String nextAction;
+
+ @Schema(description = "鎻愮ず鏂囨", example = "宸蹭笂鐝墦鍗★紝鍙笅鐝墦鍗�")
+ private String message;
+
+ }
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRecordRespVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRecordRespVO.java
index 7b91afa..aa44d1e 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRecordRespVO.java
+++ b/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 = "姝e父")
+ 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;
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordService.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordService.java
index 25cfd62..184295a 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordService.java
+++ b/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锛堢郴缁熺敤鎴稩D锛屼笉鏄憳宸D锛�
+ * @param date 鑰冨嫟鏃ユ湡锛屼负绌烘椂鍙栨湇鍔″櫒褰撳ぉ
+ * @return 鎴戠殑鑰冨嫟鐘舵��
+ */
+ HrmAttendanceMyStatusRespVO getMyStatus(Long loginUserId, LocalDate date);
+
/** 鍒涘缓瀵煎叆鐨勮�冨嫟璁板綍 */
void createImportedRecord(HrmAttendanceRecordDO record);
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java
index 60ba60d..92f745d 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java
+++ b/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. 鐧诲綍鐢ㄦ埛 -> 鍛樺伐妗f
+ 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);
--
Gitblit v1.9.3