From 52feee3e55403d2858da59605173ec055f601bfa Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期六, 24 十月 2026 19:47:25 +0800
Subject: [PATCH] feat(hrm): 同步新疆中亿装配的人力资源模块到北方科技

---
 sql/mysql/hrm_menu_sync_from_zyjc_20261024.sql                                                                               |   29 
 yudao-module-hrm/src/main/resources/template/contract/original/service.doc                                                   |    0 
 yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmAttendanceClockTypeEnum.java                         |   12 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java                      |  194 ++++
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/HrmAttendanceRecordController.java    |   92 -
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/employee/HrmEmployeeDO.java                        |    7 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordService.java                |   20 
 yudao-module-hrm/src/main/resources/template/contract/original/labor_simple.docx                                             |    0 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceRuleMapper.java                 |   12 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ContractDocumentServiceImpl.java        |  204 ++++
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleSaveReqVO.java    |    7 
 yudao-module-hrm/src/main/resources/template/contract/original/labor_standard.docx                                           |    0 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmTransferApplicationServiceImpl.java           |   44 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/salary/HrmOvertimeWageConfigMapper.java                 |   39 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmResignationApplicationServiceImpl.java        |   11 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java            |  371 ++++----
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayService.java               |    2 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ByteArrayMultipartFile.java             |   71 +
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleRespVO.java       |    9 
 yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmEmployeeCategoryEnum.java                            |   40 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleService.java                  |   21 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmOvertimeWageConfigRespVO.java       |   37 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSocialSecuritySchemeDO.java              |   20 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeSaveReqVO.java  |   14 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceHolidayDO.java             |   12 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationService.java                   |    7 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSimpleRespVO.java         |   11 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSocialSecurityConfigController.java    |   12 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmLeaveApplicationServiceImpl.java              |   11 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmOvertimeWageConfigController.java      |  112 ++
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeContractController.java      |   88 ++
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmOvertimeWageConfigServiceImpl.java              |   83 ++
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayServiceImpl.java           |   41 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRecordRespVO.java     |    8 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeController.java              |   22 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayPageReqVO.java |    8 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmOvertimeWageConfigSaveReqVO.java    |   39 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceHolidayMapper.java              |   30 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeRespVO.java     |   14 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmOvertimeWageConfigService.java                  |   24 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeImportExcelVO.java        |   21 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeService.java                          |   15 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ContractDocumentService.java            |   26 
 yudao-module-hrm/src/main/resources/template/contract/contract_labor_standard.docx                                           |    0 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSalaryCalculationController.java       |   11 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeContractServiceImpl.java              |    8 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayRespVO.java    |   10 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceExceptionServiceImpl.java         |   11 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleServiceImpl.java              |  136 +--
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmOvertimeApplicationServiceImpl.java           |    8 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java               |  199 ++++
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeRespVO.java               |   15 
 yudao-module-hrm/src/main/resources/template/contract/contract_service.docx                                                  |    0 
 yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/ErrorCodeConstants.java                                 |   13 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidaySaveReqVO.java |   10 
 yudao-module-hrm/src/main/resources/template/contract/contract_labor_simple.docx                                             |    0 
 yudao-module-hrm/src/main/resources/template/contract/original/retire.docx                                                   |    0 
 yudao-module-hrm/pom.xml                                                                                                     |    7 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSaveReqVO.java            |    6 
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmOvertimeWageConfigDO.java                |   64 +
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceRuleDO.java                |   10 
 sql/mysql/hrm_sync_from_zyjc_20261024.sql                                                                                    |   70 +
 62 files changed, 1,835 insertions(+), 583 deletions(-)

diff --git a/sql/mysql/hrm_menu_sync_from_zyjc_20261024.sql b/sql/mysql/hrm_menu_sync_from_zyjc_20261024.sql
new file mode 100644
index 0000000..63fa424
--- /dev/null
+++ b/sql/mysql/hrm_menu_sync_from_zyjc_20261024.sql
@@ -0,0 +1,29 @@
+-- ============================================================
+-- 浠庛�屾柊鐤嗕腑浜胯閰嶃�嶅悓姝� HRM 鑳藉姏鍒般�屾柊鐤嗗寳鏂圭鎶�銆嶁�斺�� 鑿滃崟鏁版嵁
+-- 鐢熸垚鏃ユ湡锛�2026-10-24
+--
+-- 璇存槑锛�
+--   1. 鍏� 1 涓彍鍗曢〉锛堝姞鐝伐璧勭鐞嗭級+ 34 涓寜閽潈闄愮偣锛屽叏閮ㄤ负 HRM 妯″潡
+--   2. 鑿滃崟 ID 涓庝腑浜胯閰嶄繚鎸佷竴鑷达紙宸茬‘璁ゅ寳鏂圭鎶�搴撲腑杩欎簺 ID 鍧囨湭琚崰鐢級锛�
+--      渚夸簬鍚庣画涓ょ瀵圭収涓庡悓姝�
+--   3. 浣跨敤 INSERT IGNORE锛氶噸澶嶆墽琛屼笉浼氭姤涓婚敭鍐茬獊
+--   4. 銆愰粯璁や笉鑷姩鎺堟潈缁欎换浣曡鑹层��
+--      - 瓒呯骇绠$悊鍛橈紙super_admin锛夋湰鏉ュ氨涓嶅彈瑙掕壊鑿滃崟闄愬埗锛屽彲鐩存帴鐪嬪埌
+--      - 鍏朵綑瑙掕壊璇峰湪銆愮郴缁熺鐞� 鈫� 瑙掕壊绠$悊銆戜腑鎸夐渶鍕鹃�夛紝閬垮厤鎶婅柂閰�/鑰冨嫟
+--        绠$悊鏉冮檺涓�娆℃�у紑鏀剧粰鍏ㄩ儴鏅�氬憳宸�
+--   5. 鑻ョ‘闇�鐢� SQL 鎵归噺鎺堟潈锛屽弬鑰冩枃浠舵湯灏剧殑娉ㄩ噴妯℃澘
+-- ============================================================
+
+INSERT IGNORE INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6026,'鍔犵彮宸ヨ祫绠$悊','',2,4,6020,'overtime-wage','ep:clock','hrm/salary/overtime-wage/index','HrmOvertimeWage',0,0x01,0x01,0x01,'1','2026-10-13 17:13:58','1','2026-10-14 10:52:27',0x00),(60261,'鍔犵彮宸ヨ祫鏌ヨ','hrm:overtime-wage:query',3,1,6026,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-13 17:13:58','1','2026-10-14 10:52:27',0x00),(60262,'鍔犵彮宸ヨ祫鏂板','hrm:overtime-wage:create',3,2,6026,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-13 17:13:58','1','2026-10-14 10:52:28',0x00),(60263,'鍔犵彮宸ヨ祫淇敼','hrm:overtime-wage:update',3,3,6026,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-13 17:13:58','1','2026-10-14 10:52:29',0x00),(60264,'鍔犵彮宸ヨ祫鍒犻櫎','hrm:overtime-wage:delete',3,4,6026,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-13 17:13:58','1','2026-10-14 10:52:31',0x00),(602800,'鑰冨嫟瑙勫垯鏌ヨ','hrm:attendance-rule:query',3,10,6013,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602801,'鑰冨嫟璁板綍鏌ヨ','hrm:attendance-record:query',3,10,6011,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602802,'鑰冨嫟寮傚父鏌ヨ','hrm:attendance-exception:query',3,10,6012,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602803,'鑰冨嫟寮傚父淇敼','hrm:attendance-exception:update',3,11,6012,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602804,'鑰冨嫟寮傚父鍒犻櫎','hrm:attendance-exception:delete',3,12,6012,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602805,'鑺傚亣鏃ラ厤缃煡璇�','hrm:attendance-holiday:query',3,10,6014,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602806,'鑰冨嫟缁熻鏌ヨ','hrm:attendance-summary:query',3,10,6015,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602807,'璇峰亣鐢宠瀵煎嚭','hrm:leave:export',3,10,6003,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602808,'璋冨矖鐢宠鏌ヨ','hrm:transfer:query',3,10,6004,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602809,'璋冨矖鐢宠瀵煎嚭','hrm:transfer:export',3,11,6004,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602810,'绂昏亴鐢宠鏌ヨ','hrm:resignation:query',3,10,6005,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602811,'绂昏亴鐢宠瀵煎嚭','hrm:resignation:export',3,11,6005,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602812,'鍔犵彮鐢宠鏌ヨ','hrm:overtime:query',3,10,1065211,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602813,'鍚堝悓瀵煎叆','hrm:employee-contract:import',3,10,1063105,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602814,'钖叕鏍哥畻鏌ヨ','hrm:salary-calculation:query',3,10,6021,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602815,'钖叕鏍哥畻鍒犻櫎','hrm:salary-calculation:delete',3,11,6021,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602816,'钖祫鍙戞斁鏌ヨ','hrm:salary-payment:query',3,10,6022,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602817,'钖祫鍙戞斁鐢熸垚','hrm:salary-payment:generate',3,11,6022,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602818,'钖祫鍙戞斁鍒犻櫎','hrm:salary-payment:delete',3,12,6022,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602819,'绀句繚妗f鏌ヨ','hrm:employee-social-security:query',3,10,6023,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602820,'绀句繚鏂规鏌ヨ','hrm:social-security-scheme:query',3,10,602445,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602821,'绀句繚閰嶇疆鏌ヨ','hrm:social-security-config:query',3,30,6020,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602822,'绀句繚閰嶇疆鏂板','hrm:social-security-config:create',3,31,6020,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602823,'绀句繚閰嶇疆淇敼','hrm:social-security-config:update',3,32,6020,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602824,'绀句繚閰嶇疆鍒犻櫎','hrm:social-security-config:delete',3,33,6020,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602825,'涓◣绋庣巼鏌ヨ','hrm:tax-rate-config:query',3,10,6024,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602826,'钖叕缁撴瀯鏌ヨ','hrm:salary-structure:query',3,40,6020,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602827,'钖叕缁撴瀯鏂板','hrm:salary-structure:create',3,41,6020,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602828,'钖叕缁撴瀯淇敼','hrm:salary-structure:update',3,42,6020,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00),(602829,'钖叕缁撴瀯鍒犻櫎','hrm:salary-structure:delete',3,43,6020,'','','',NULL,0,0x01,0x01,0x01,'1','2026-10-22 18:41:02','1','2026-10-22 18:41:02',0x00);
+-- ------------------------------------------------------------
+-- 鍙�夛細鎵归噺鎺堟潈缁欐寚瀹氳鑹诧紙榛樿娉ㄩ噴锛屾寜闇�鍚敤锛�
+-- 娉ㄦ剰 system_role_menu 鏈� tenant_id 瀛楁锛屽繀椤绘樉寮忓啓 1锛�
+-- 鍚﹀垯璇ヨ鑹插湪绉熸埛 1 涓嬩粛鐒舵煡涓嶅埌杩欎簺鑿滃崟銆�
+-- ------------------------------------------------------------
+-- INSERT IGNORE INTO `system_role_menu` (`role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`)
+-- SELECT 2, m.`id`, '1', NOW(), '1', NOW(), b'0', 1
+-- FROM `system_menu` m
+-- WHERE m.`id` IN (6026,60261,60262,60263,60264,602800,602801,602802,602803,602804,
+--                  602805,602806,602807,602808,602809,602810,602811,602812,602813,
+--                  602814,602815,602816,602817,602818,602819,602820,602821,602822,
+--                  602823,602824,602825,602826,602827,602828,602829);
diff --git a/sql/mysql/hrm_sync_from_zyjc_20261024.sql b/sql/mysql/hrm_sync_from_zyjc_20261024.sql
new file mode 100644
index 0000000..2978f75
--- /dev/null
+++ b/sql/mysql/hrm_sync_from_zyjc_20261024.sql
@@ -0,0 +1,70 @@
+-- ============================================================
+-- 浠庛�屾柊鐤嗕腑浜胯閰嶃�嶅悓姝� HRM 鑳藉姏鍒般�屾柊鐤嗗寳鏂圭鎶�銆嶁�斺�� 琛ㄧ粨鏋勫彉鏇�
+-- 鐢熸垚鏃ユ湡锛�2026-10-24
+--
+-- 璇存槑锛�
+--   1. 鏈剼鏈�愬彧鍋氳〃缁撴瀯鍙樻洿銆戯紝涓嶅惈浠讳綍涓氬姟鏁版嵁
+--   2. 涓氬姟鏁版嵁锛堝憳宸ャ�侀儴闂ㄣ�佸矖浣嶃�佽�冨嫟瑙勫垯銆佽柂璧勩�佺ぞ淇濇柟妗堢瓑锛�
+--      淇濈暀鍖楁柟绉戞妧鑷繁鐨勶紝涓嶄粠鍏朵粬浼佷笟杩佺Щ
+--   3. 閰嶅浠g爜锛歽udao-module-hrm / yudao-module-hrm-api 鐢变腑浜胯閰嶅垎鏀悓姝�
+--   4. 銆愭墽琛屼竴娆″嵆鍙�慉LTER TABLE ADD COLUMN 涓嶅箓绛夛紝閲嶅鎵ц浼氭姤
+--      Duplicate column name锛屽睘姝e父鐜拌薄锛汣REATE TABLE 宸茬敤 IF NOT EXISTS
+--   5. 瀛橀噺鏁版嵁鑷姩鍏煎锛�
+--      - employee_category 榛樿 1锛堟櫘閫氬憳宸ワ級
+--      - 鑰冨嫟瑙勫垯 effective_*_date 涓虹┖琛ㄧず涓嶉檺锛屽師瑙勫垯缁х画鐢熸晥
+--      - 绀句繚鏂版瘮渚嬪瓧娈典负绌猴紝涓嶅奖鍝嶅師鏈夎绠�
+-- ============================================================
+
+-- ------------------------------------------------------------
+-- 1. 鍔犵彮宸ヨ祫閰嶇疆琛紙鏂板鍔熻兘锛氳柂閰� 鈫� 鍔犵彮宸ヨ祫锛�
+-- ------------------------------------------------------------
+CREATE TABLE IF NOT EXISTS `hrm_overtime_wage_config` (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '閰嶇疆ID',
+  `post_id` bigint NOT NULL COMMENT '宀椾綅ID锛屽叧鑱� system_post.id',
+  `hourly_rate` decimal(10,2) NOT NULL DEFAULT '20.00' COMMENT '鍔犵彮鏃惰柂锛堝厓/灏忔椂锛夛紝榛樿 20',
+  `max_overtime_hours` decimal(6,1) DEFAULT NULL COMMENT '姣忔湀鏈�澶у姞鐝椂闀夸笂闄愶紙灏忔椂锛夛紝涓虹┖琛ㄧず涓嶉檺',
+  `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鍚敤锛�1-绂佺敤',
+  `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
+  `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+  `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `uk_post_id` (`post_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='HRM宀椾綅鍔犵彮宸ヨ祫閰嶇疆琛�';
+
+-- ------------------------------------------------------------
+-- 2. 鍛樺伐绫诲埆锛堥粯璁� 1-鏅�氬憳宸ワ紝瀛橀噺 168 鏉¤嚜鍔ㄥ~鍏呬负鏅�氬憳宸ワ級
+-- ------------------------------------------------------------
+ALTER TABLE `hrm_employee`
+  ADD COLUMN `employee_category` tinyint NOT NULL DEFAULT 1 COMMENT '鍛樺伐绫诲埆锛�1-鏅�氬憳宸ワ紝2-鎶�宸ワ紝3-绠$悊' AFTER `employee_status`;
+
+-- ------------------------------------------------------------
+-- 3. 鑰冨嫟瑙勫垯鐢熸晥鏃ユ湡鍖洪棿锛堢┖琛ㄧず涓嶉檺锛屽瓨閲忚鍒欐寜鍘熼�昏緫缁х画鐢熸晥锛�
+-- ------------------------------------------------------------
+ALTER TABLE `hrm_attendance_rule`
+  ADD COLUMN `effective_start_date` date DEFAULT NULL COMMENT '鐢熸晥寮�濮嬫棩鏈燂紙绌鸿〃绀轰笉闄愶級' AFTER `overtime_threshold`,
+  ADD COLUMN `effective_end_date` date DEFAULT NULL COMMENT '鐢熸晥缁撴潫鏃ユ湡锛堢┖琛ㄧず涓嶉檺锛�' AFTER `effective_start_date`;
+
+-- ------------------------------------------------------------
+-- 4. 绀句繚鍏Н閲戞柟妗堬細鏂板澶х梾鍖荤枟銆侀暱鏈熸姢鐞嗕袱椤逛繚闄╂瘮渚�
+-- ------------------------------------------------------------
+ALTER TABLE `hrm_social_security_scheme`
+  ADD COLUMN `serious_illness_company_ratio` decimal(10,4) DEFAULT NULL COMMENT '澶х梾鍖荤枟浼佷笟缂寸撼姣斾緥' AFTER `maternity_ratio`,
+  ADD COLUMN `serious_illness_personal_ratio` decimal(10,4) DEFAULT NULL COMMENT '澶х梾鍖荤枟涓汉缂寸撼姣斾緥' AFTER `serious_illness_company_ratio`,
+  ADD COLUMN `long_term_care_company_ratio` decimal(10,4) DEFAULT NULL COMMENT '闀挎湡鎶ょ悊浼佷笟缂寸撼姣斾緥' AFTER `serious_illness_personal_ratio`,
+  ADD COLUMN `long_term_care_personal_ratio` decimal(10,4) DEFAULT NULL COMMENT '闀挎湡鎶ょ悊涓汉缂寸撼姣斾緥' AFTER `long_term_care_company_ratio`;
+
+-- ------------------------------------------------------------
+-- 5. 銆愬繀椤汇�戣妭鍋囨棩琛ㄦ斁寮� start_date / end_date 闈炵┖绾︽潫
+--
+-- 鑳屾櫙锛氬寳鏂圭鎶�鍘熷厛鏀寔銆岃妭鍋囨棩鏃堕棿娈点�嶏紙start_date/end_date锛孨OT NULL锛夛紝
+--       涓嚎瑁呴厤鐨� HrmAttendanceHolidayDO 鍙湁鍗曟棩 date 瀛楁锛屼笉鍐欒繖涓や釜鍒椼��
+--       鑻ヤ繚鐣� NOT NULL锛屾柊澧�/瀵煎叆鑺傚亣鏃ヤ細鐩存帴鎶�
+--         Field 'start_date' doesn't have a default value  鈫� 鍓嶇鏄剧ず銆岀郴缁熷紓甯搞��
+-- 鐜版湁鏁版嵁锛氫袱杈� hrm_attendance_holiday 鍧囦负 0 鏉★紝鏀惧紑绾︽潫涓嶆秹鍙婃暟鎹縼绉�
+-- ------------------------------------------------------------
+ALTER TABLE `hrm_attendance_holiday`
+  MODIFY COLUMN `start_date` date DEFAULT NULL COMMENT '寮�濮嬫棩鏈燂紙涓嚎鐗堜唬鐮佷笉鍐欐鍒楋紝淇濈暀鍏煎鍖楁柟鍘熷尯闂寸粨鏋勶級',
+  MODIFY COLUMN `end_date` date DEFAULT NULL COMMENT '缁撴潫鏃ユ湡锛堜腑浜跨増浠g爜涓嶅啓姝ゅ垪锛屼繚鐣欏吋瀹瑰寳鏂瑰師鍖洪棿缁撴瀯锛�';
diff --git a/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/ErrorCodeConstants.java b/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/ErrorCodeConstants.java
index 11e1ef3..3af9511 100644
--- a/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/ErrorCodeConstants.java
+++ b/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/ErrorCodeConstants.java
@@ -83,10 +83,9 @@
     ErrorCode ATTENDANCE_EXCEPTION_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_030_004_004, "鑰冨嫟寮傚父鐢宠鎻愪氦澶辫触锛屽師鍥狅細涓嶆槸鑽夌鐘舵��");
     ErrorCode ATTENDANCE_RULE_NOT_EXISTS = new ErrorCode(1_030_004_005, "鑰冨嫟瑙勫垯涓嶅瓨鍦�");
     ErrorCode ATTENDANCE_RULE_NAME_EXISTS = new ErrorCode(1_030_004_006, "鑰冨嫟瑙勫垯鍚嶇О宸插瓨鍦�");
-    // 宸插簾寮冿紙2026-10-16锛夛細鍚屼竴涓儴闂ㄥ厑璁搁厤缃鏉¤�冨嫟瑙勫垯锛堝鐝锛夛紝涓嶅啀鏍¢獙閮ㄩ棬鍞竴锛屼繚鐣欒閿欒鐮佷粎涓哄吋瀹瑰巻鍙插紩鐢�
     ErrorCode ATTENDANCE_RULE_DEPT_EXISTS = new ErrorCode(1_030_004_007, "璇ラ儴闂ㄥ凡閰嶇疆鑰冨嫟瑙勫垯");
-    ErrorCode ATTENDANCE_HOLIDAY_NOT_EXISTS = new ErrorCode(1_030_004_008, "鑺傚亣鏃ラ厤缃笉瀛樺湪锛圛D={}锛夛紝鍙兘宸茶浠栦汉鍒犻櫎銆傝鍒锋柊鍒楄〃鍚庨噸璇�");
-    ErrorCode ATTENDANCE_HOLIDAY_RANGE_OVERLAP = new ErrorCode(1_030_004_009, "鏃ユ湡鍖洪棿銆恵} ~ {}銆戜笌宸叉湁閰嶇疆銆寋}銆嶏紙{} ~ {}锛夐噸鍙狅紝鏃犳硶淇濆瓨銆傝璋冩暣鏈鏃ユ湡鍖洪棿閬垮紑璇ラ厤缃紝鎴栫洿鎺ョ紪杈�/鍒犻櫎宸叉湁閰嶇疆鍚庡啀淇濆瓨");
+    ErrorCode ATTENDANCE_HOLIDAY_NOT_EXISTS = new ErrorCode(1_030_004_008, "鑺傚亣鏃ラ厤缃笉瀛樺湪");
+    ErrorCode ATTENDANCE_HOLIDAY_DATE_EXISTS = new ErrorCode(1_030_004_009, "璇ユ棩鏈熻妭鍋囨棩閰嶇疆宸插瓨鍦�");
     ErrorCode ATTENDANCE_CLOCK_FAIL_NO_RULE = new ErrorCode(1_030_004_010, "鎵撳崱澶辫触锛屾湭鎵惧埌鑰冨嫟瑙勫垯");
     ErrorCode ATTENDANCE_CLOCK_FAIL_HOLIDAY = new ErrorCode(1_030_004_011, "鎵撳崱澶辫触锛屽綋鏃ヤ负浼戞伅鏃�");
     ErrorCode ATTENDANCE_CLOCK_FAIL_NOT_WORKDAY = new ErrorCode(1_030_004_012, "鎵撳崱澶辫触锛屽綋鏃ヤ笉鏄伐浣滄棩");
@@ -94,7 +93,7 @@
     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_HOLIDAY_DATE_RANGE_INVALID = new ErrorCode(1_030_004_017, "缁撴潫鏃ユ湡銆恵}銆戜笉鑳芥棭浜庡紑濮嬫棩鏈熴�恵}銆戯紝鏃犳硶淇濆瓨銆傝閲嶆柊閫夋嫨姝g‘鐨勬棩鏈熷尯闂�");
+    ErrorCode ATTENDANCE_RULE_EFFECTIVE_DATE_INVALID = new ErrorCode(1_030_004_017, "鐢熸晥寮�濮嬫棩鏈熶笉鑳芥櫄浜庣敓鏁堢粨鏉熸棩鏈�");
 
     // ========== 钖叕绠$悊 1-030-005-000 ==========
     ErrorCode SALARY_STRUCTURE_NOT_EXISTS = new ErrorCode(1_030_005_000, "钖叕缁撴瀯涓嶅瓨鍦�");
@@ -125,6 +124,12 @@
     ErrorCode SALARY_PAYMENT_HAS_PAID_DETAIL = new ErrorCode(1_030_005_024, "鍒犻櫎澶辫触锛屽師鍥狅細瀛樺湪宸插彂鏀炬槑缁嗭紝璇峰厛鎾ら攢");
     ErrorCode SALARY_STRUCTURE_NAME_EXISTS = new ErrorCode(1_030_005_025, "钖叕缁撴瀯鍚嶇О宸插瓨鍦�");
     ErrorCode SALARY_STRUCTURE_IN_USE = new ErrorCode(1_030_005_026, "钖叕缁撴瀯姝e湪琚憳宸ヤ娇鐢紝鏃犳硶鍒犻櫎");
+    ErrorCode OVERTIME_WAGE_CONFIG_NOT_EXISTS = new ErrorCode(1_030_005_027, "宀椾綅鍔犵彮宸ヨ祫閰嶇疆涓嶅瓨鍦�");
+    ErrorCode OVERTIME_WAGE_CONFIG_POST_EXISTS = new ErrorCode(1_030_005_028, "璇ュ矖浣嶅凡閰嶇疆鍔犵彮宸ヨ祫锛岃鍕块噸澶嶆坊鍔�");
+    ErrorCode CONTRACT_TEMPLATE_TYPE_NOT_SUPPORT = new ErrorCode(1_030_005_029, "涓嶆敮鎸佺殑鍚堝悓妯℃澘绫诲瀷");
+    ErrorCode CONTRACT_TEMPLATE_LOAD_FAILED = new ErrorCode(1_030_005_030, "鍚堝悓妯℃澘鍔犺浇澶辫触");
+    ErrorCode EMPLOYEE_REGULARIZE_NEED_LABOR_CONTRACT = new ErrorCode(1_030_005_031, "璇ュ憳宸ュ綋鍓嶅悎鍚屼笉鏄姵鍔ㄥ悎鍚岋紝鏃犳硶杞");
+    ErrorCode SALARY_CALCULATION_UPDATE_FAIL = new ErrorCode(1_030_005_032, "淇敼澶辫触锛屽師鍥狅細浠呭緟纭鐘舵�佸彲淇敼锛岃鍏堟挙閿�纭");
 
     // ========== 鐝绠$悊 1-030-009-000 ==========
     ErrorCode SHIFT_NOT_EXISTS = new ErrorCode(1_030_009_000, "鐝涓嶅瓨鍦�");
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 99bd961..7fdb4a7 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
@@ -23,13 +23,8 @@
 
     public static final Integer[] ARRAYS = Arrays.stream(values()).map(HrmAttendanceClockTypeEnum::getType).toArray(Integer[]::new);
 
-    @Override
-    public Integer[] array() {
-        return ARRAYS;
-    }
-
     /**
-     * 鏍规嵁绫诲瀷鑾峰彇鍚嶇О锛屾湭鐭ョ被鍨嬭繑鍥� null
+     * 鏍规嵁绫诲瀷鑾峰緱鍚嶇О锛堢敤浜庣晫闈㈠睍绀猴紝濡� my-status 杩斿洖锛�
      */
     public static String getNameByType(Integer type) {
         if (type == null) {
@@ -43,4 +38,9 @@
         return null;
     }
 
+    @Override
+    public Integer[] array() {
+        return ARRAYS;
+    }
+
 }
\ No newline at end of file
diff --git a/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmEmployeeCategoryEnum.java b/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmEmployeeCategoryEnum.java
new file mode 100644
index 0000000..1265b0a
--- /dev/null
+++ b/yudao-module-hrm-api/src/main/java/cn/iocoder/yudao/module/hrm/enums/HrmEmployeeCategoryEnum.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.hrm.enums;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 鍛樺伐绫诲埆鏋氫妇锛氱敤浜庡姞鐝伐璧勭殑宸紓鍖栨牳绠椼��
+ *
+ * <ul>
+ *     <li>鏅�氬憳宸ワ細鍔犵彮宸ヨ祫鎸夊矖浣嶉厤缃殑鍥哄畾鏃惰柂锛堥粯璁� 20 鍏�/灏忔椂锛夋牳绠�</li>
+ *     <li>鎶�宸ワ細鍔犵彮钖祫鎸� 1:1 鏍哥畻锛屼笌骞虫椂鏃惰柂涓�鑷达紙鍩烘湰宸ヨ祫 / 21.75 / 8锛�</li>
+ *     <li>绠$悊锛氫笉璁″姞鐝伐璧�</li>
+ * </ul>
+ */
+@Getter
+@RequiredArgsConstructor
+public enum HrmEmployeeCategoryEnum {
+
+    NORMAL(1, "鏅�氬憳宸�"),
+    TECHNICIAN(2, "鎶�宸�"),
+    MANAGER(3, "绠$悊");
+
+    private final Integer category;
+    private final String name;
+
+    public static HrmEmployeeCategoryEnum valueOfCategory(Integer category) {
+        if (category == null) {
+            return null;
+        }
+        return Arrays.stream(values()).filter(item -> item.category.equals(category)).findFirst().orElse(null);
+    }
+
+    public static String getName(Integer category) {
+        HrmEmployeeCategoryEnum value = valueOfCategory(category);
+        return value == null ? "" : value.name;
+    }
+
+}
diff --git a/yudao-module-hrm/pom.xml b/yudao-module-hrm/pom.xml
index df07d9c..0f56438 100644
--- a/yudao-module-hrm/pom.xml
+++ b/yudao-module-hrm/pom.xml
@@ -70,6 +70,13 @@
             <artifactId>yudao-spring-boot-starter-excel</artifactId>
         </dependency>
 
+        <!-- Word 鍚堝悓妯℃澘娓叉煋锛坧oi-tl锛� -->
+        <dependency>
+            <groupId>com.deepoove</groupId>
+            <artifactId>poi-tl</artifactId>
+            <version>1.12.2</version>
+        </dependency>
+
         <!-- Test 娴嬭瘯鐩稿叧 -->
         <dependency>
             <groupId>cn.iocoder.boot</groupId>
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 0528f3e..8bbe2ef 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
@@ -2,34 +2,31 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 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.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.controller.admin.attendance.vo.HrmAttendanceMyStatusRespVO;
 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;
 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
-import com.mzt.logapi.starter.annotation.LogRecord;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
 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.*;
@@ -43,9 +40,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.*;
 
 @Tag(name = "绠$悊鍚庡彴 - HRM 鑰冨嫟璁板綍")
 @RestController
@@ -64,46 +59,16 @@
 
     @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 new ServiceException(EMPLOYEE_NOT_EXISTS.getCode(),
+                    "褰撳墠鐧诲綍璐﹀彿鏈叧鑱斿憳宸ヤ俊鎭紝鏃犳硶鎵撳崱銆傝鑱旂郴绠$悊鍛樺湪銆愬憳宸ョ鐞嗐�戜腑灏嗚鐧诲綍璐﹀彿缁戝畾鍒板憳宸ャ��");
         }
         HrmAttendanceRecordDO record = attendanceRecordService.clockIn(employee.getId(), LocalDateTime.now(), location);
-        return success(buildClockRespVO(record, employee));
-    }
-
-    @PostMapping("/clock-out")
-    @Operation(summary = "涓嬬彮鎵撳崱")
-    public CommonResult<HrmAttendanceRecordRespVO> clockOut(@RequestParam("location") String location) {
-        Long loginUserId = getLoginUserId();
-        HrmEmployeeDO employee = employeeService.getEmployeeByUserId(loginUserId);
-        if (employee == null) {
-            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());
@@ -111,12 +76,42 @@
                 respVO.setDeptName(dept.getName());
             }
         }
-        return respVO;
+        return success(respVO);
+    }
+
+    @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 new ServiceException(EMPLOYEE_NOT_EXISTS.getCode(),
+                    "褰撳墠鐧诲綍璐﹀彿鏈叧鑱斿憳宸ヤ俊鎭紝鏃犳硶鎵撳崱銆傝鑱旂郴绠$悊鍛樺湪銆愬憳宸ョ鐞嗐�戜腑灏嗚鐧诲綍璐﹀彿缁戝畾鍒板憳宸ャ��");
+        }
+        HrmAttendanceRecordDO record = attendanceRecordService.clockOut(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);
+    }
+
+    @GetMapping("/my-status")
+    @Operation(summary = "鑾峰緱褰撳墠鐧诲綍浜虹殑鑰冨嫟鐘舵��", description = "App 鎵撳崱椤典娇鐢細杩斿洖褰撴棩鑰冨嫟瑙勫垯銆佹墦鍗¤褰曚笌鍙墦鍗$姸鎬�")
+    @Parameter(name = "date", description = "鑰冨嫟鏃ユ湡锛屾牸寮� yyyy-MM-dd锛岄粯璁ゆ湇鍔″櫒褰撳ぉ", example = "2026-10-17")
+    public CommonResult<HrmAttendanceMyStatusRespVO> getMyStatus(
+            @RequestParam(value = "date", required = false)
+            @org.springframework.format.annotation.DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
+        return success(attendanceRecordService.getMyStatus(getLoginUserId(), date));
     }
 
     private Long getLoginUserId() {
-        return cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId();
-    }
+        return cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId();    }
 
     @GetMapping("/page")
     @Operation(summary = "鑾峰緱鑰冨嫟璁板綍鍒嗛〉")
@@ -222,18 +217,12 @@
     @PostMapping("/import")
     @Operation(summary = "瀵煎叆鑰冨嫟璁板綍")
     @PreAuthorize("@ss.hasPermission('hrm:attendance-record:import')")
-    @LogRecord(type = HRM_ATTENDANCE_RECORD_TYPE, subType = HRM_ATTENDANCE_RECORD_IMPORT_SUB_TYPE, bizNo = "0",
-            success = HRM_ATTENDANCE_RECORD_IMPORT_SUCCESS)
     public CommonResult<String> importExcel(@Valid HrmAttendanceRecordImportReqVO importReqVO) throws IOException {
         List<HrmAttendanceRecordImportExcelVO> list = ExcelUtils.read(importReqVO.getFile(), HrmAttendanceRecordImportExcelVO.class);
         if (CollUtil.isEmpty(list)) {
-            // 璁板綍瀵煎叆缁撴灉姹囨�伙紝渚� @LogRecord 鐨� success 鏂囨寮曠敤
-            OperateLogUtils.putImportSummary(0, null, null);
             return success("娌℃湁鍙鍏ョ殑鏁版嵁");
         }
         int successCount = 0;
-        int createCount = 0; // 鏂板鐨勮褰曟暟
-        int updateCount = 0; // 鏇存柊鐨勮褰曟暟锛堜粎鍕鹃�夈�屾敮鎸佹洿鏂般�嶆椂鎵嶄細璧版洿鏂帮級
         Set<String> missingNames = new LinkedHashSet<>();
         Set<String> duplicateNames = new LinkedHashSet<>();
         Set<String> invalidRows = new LinkedHashSet<>();
@@ -279,7 +268,6 @@
                         .location(item.getLocation()).remark(item.getRemark())
                         .dataSource(2).build();
                 attendanceRecordService.createImportedRecord(record);
-                createCount++;
             } else if (Boolean.TRUE.equals(importReqVO.getUpdateSupport())) {
                 record.setClockInTime(item.getClockInTime());
                 record.setClockOutTime(item.getClockOutTime());
@@ -288,7 +276,6 @@
                 record.setLocation(item.getLocation());
                 record.setRemark(item.getRemark());
                 attendanceRecordService.updateImportedRecord(record);
-                updateCount++;
             }
             successCount++;
         }
@@ -302,9 +289,6 @@
         if (!invalidRows.isEmpty()) {
             msg.append("锛涗互涓嬭褰曟暟鎹笉瀹屾暣锛屾湭鑳藉鍏ワ細").append(String.join("銆�", invalidRows));
         }
-        // 璁板綍瀵煎叆缁撴灉姹囨�伙紝渚� @LogRecord 鐨� success 鏂囨寮曠敤
-        OperateLogUtils.putImportSummary(createCount, updateCount,
-                missingNames.size() + duplicateNames.size() + invalidRows.size());
         return success(msg.toString());
     }
 
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayPageReqVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayPageReqVO.java
index 893bac3..c4a43f3 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayPageReqVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayPageReqVO.java
@@ -20,10 +20,10 @@
     @Schema(description = "绫诲瀷锛�1-浼戞伅鏃ワ紝2-宸ヤ綔鏃�", example = "1")
     private Integer type;
 
-    @Schema(description = "鏄惁娉曞畾鑺傚亣鏃ワ細0-鍚︼紝1-鏄�", example = "1")
-    private Integer isLegal;
+    @Schema(description = "寮�濮嬫棩鏈�", example = "2024-01-01")
+    private LocalDate startDate;
 
-    @Schema(description = "鏃ユ湡鍖洪棿锛屼紶 [寮�濮嬫棩鏈�, 缁撴潫鏃ユ湡]锛岃繑鍥炰笌閰嶇疆鏃堕棿娈垫湁浜ら泦鐨勬暟鎹�", example = "[\"2026-01-01\", \"2026-12-31\"]")
-    private LocalDate[] date;
+    @Schema(description = "缁撴潫鏃ユ湡", example = "2024-12-31")
+    private LocalDate endDate;
 
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayRespVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayRespVO.java
index 133ab30..9a53176 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayRespVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidayRespVO.java
@@ -23,13 +23,9 @@
     @ExcelProperty("鑺傚亣鏃ュ悕绉�")
     private String name;
 
-    @Schema(description = "寮�濮嬫棩鏈�")
-    @ExcelProperty("寮�濮嬫棩鏈�")
-    private LocalDate startDate;
-
-    @Schema(description = "缁撴潫鏃ユ湡")
-    @ExcelProperty("缁撴潫鏃ユ湡")
-    private LocalDate endDate;
+    @Schema(description = "鏃ユ湡")
+    @ExcelProperty("鏃ユ湡")
+    private LocalDate date;
 
     @Schema(description = "绫诲瀷锛�1-浼戞伅鏃ワ紝2-宸ヤ綔鏃�")
     @ExcelProperty(value = "绫诲瀷", converter = DictConvert.class)
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidaySaveReqVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidaySaveReqVO.java
index f11563c..8f2fcb6 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidaySaveReqVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceHolidaySaveReqVO.java
@@ -18,13 +18,9 @@
     @NotBlank(message = "鑺傚亣鏃ュ悕绉颁笉鑳戒负绌�")
     private String name;
 
-    @Schema(description = "寮�濮嬫棩鏈�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-10")
-    @NotNull(message = "寮�濮嬫棩鏈熶笉鑳戒负绌�")
-    private LocalDate startDate;
-
-    @Schema(description = "缁撴潫鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-17")
-    @NotNull(message = "缁撴潫鏃ユ湡涓嶈兘涓虹┖")
-    private LocalDate endDate;
+    @Schema(description = "鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-10")
+    @NotNull(message = "鏃ユ湡涓嶈兘涓虹┖")
+    private LocalDate date;
 
     @Schema(description = "绫诲瀷锛�1-浼戞伅鏃ワ紝2-宸ヤ綔鏃�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(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 aa44d1e..d2bba94 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,15 +55,15 @@
     @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 = "鏃╅��")
+    @Schema(description = "涓婄彮鎵撳崱绫诲瀷鍚嶇О锛堟甯�/杩熷埌/缂哄崱锛�")
+    private String clockInTypeName;
+
+    @Schema(description = "涓嬬彮鎵撳崱绫诲瀷鍚嶇О锛堟甯�/鏃╅��/缂哄崱锛�")
     private String clockOutTypeName;
 
     @Schema(description = "宸ヤ綔鏃堕暱锛堝皬鏃讹級")
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleRespVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleRespVO.java
index 360c315..f28e95d 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleRespVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleRespVO.java
@@ -8,6 +8,7 @@
 import lombok.Data;
 
 import java.math.BigDecimal;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 
@@ -51,6 +52,14 @@
     @ExcelProperty("鍔犵彮璧风畻鏃堕暱")
     private BigDecimal overtimeThreshold;
 
+    @Schema(description = "鐢熸晥寮�濮嬫棩鏈燂紙绌鸿〃绀轰笉闄愶級")
+    @ExcelProperty("鐢熸晥寮�濮嬫棩鏈�")
+    private LocalDate effectiveStartDate;
+
+    @Schema(description = "鐢熸晥缁撴潫鏃ユ湡锛堢┖琛ㄧず涓嶉檺锛�")
+    @ExcelProperty("鐢熸晥缁撴潫鏃ユ湡")
+    private LocalDate effectiveEndDate;
+
     @Schema(description = "鐘舵�侊細0-鍚敤锛�1-绂佺敤")
     @ExcelProperty(value = "鐘舵��", converter = DictConvert.class)
     @DictFormat("hrm_rule_status")
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleSaveReqVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleSaveReqVO.java
index 8c244a8..ba2737e 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleSaveReqVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceRuleSaveReqVO.java
@@ -6,6 +6,7 @@
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
 import java.math.BigDecimal;
+import java.time.LocalDate;
 import java.time.LocalTime;
 
 @Schema(description = "绠$悊鍚庡彴 - 鑰冨嫟瑙勫垯鏂板/淇敼 Request VO")
@@ -39,6 +40,12 @@
     @Schema(description = "鍔犵彮璧风畻鏃堕暱锛堝皬鏃讹級", example = "1")
     private BigDecimal overtimeThreshold;
 
+    @Schema(description = "鐢熸晥寮�濮嬫棩鏈燂紙绌鸿〃绀轰笉闄愶級", example = "2026-01-01")
+    private LocalDate effectiveStartDate;
+
+    @Schema(description = "鐢熸晥缁撴潫鏃ユ湡锛堢┖琛ㄧず涓嶉檺锛�", example = "2026-12-31")
+    private LocalDate effectiveEndDate;
+
     @Schema(description = "鐘舵�侊細0-鍚敤锛�1-绂佺敤", example = "0")
     private Integer status;
 
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeContractController.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeContractController.java
index 0530349..1aef685 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeContractController.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeContractController.java
@@ -11,6 +11,11 @@
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractSaveReqVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractTerminateReqVO;
 import cn.iocoder.yudao.module.hrm.service.employee.HrmEmployeeContractService;
+import cn.iocoder.yudao.module.hrm.service.employee.contract.ContractDocumentService;
+import cn.iocoder.yudao.module.hrm.service.employee.contract.ByteArrayMultipartFile;
+import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi;
+import cn.iocoder.yudao.module.system.service.storage.SystemStorageBlobService;
+import org.springframework.web.multipart.MultipartFile;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -22,12 +27,19 @@
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.time.LocalDate;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.CONTRACT_TEMPLATE_LOAD_FAILED;
+import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.CONTRACT_TEMPLATE_TYPE_NOT_SUPPORT;
 
 @Tag(name = "绠$悊鍚庡彴 - HRM 鍛樺伐鍚堝悓")
 @RestController
@@ -37,6 +49,12 @@
 
     @Resource
     private HrmEmployeeContractService contractService;
+    @Resource
+    private ContractDocumentService contractDocumentService;
+    @Resource
+    private SystemStorageBlobService storageBlobService;
+    @Resource
+    private StorageAttachmentApi storageAttachmentApi;
 
     @PostMapping("/create")
     @Operation(summary = "鍒涘缓鍛樺伐鍚堝悓")
@@ -92,6 +110,76 @@
         return success(contractService.getExpiringCount());
     }
 
+    @PostMapping("/generate")
+    @Operation(summary = "鐢熸垚鍚堝悓骞跺洖瀛樹负鍚堝悓闄勪欢")
+    @Parameter(name = "id", description = "鍚堝悓ID", required = true)
+    @Parameter(name = "templateType", description = "妯℃澘绫诲瀷锛�1-鍔冲姩鍚堝悓(绠�鐗�) 2-鍔冲姩鍚堝悓(鏍囧噯) 3-鍔冲姟鍚堝悓", required = true)
+    @PreAuthorize("@ss.hasPermission('hrm:employee-contract:query')")
+    public CommonResult<Long> generateContract(@RequestParam("id") Long id,
+                                               @RequestParam("templateType") Integer templateType) {
+        byte[] bytes = contractDocumentService.generateDocx(id, templateType);
+        String fileName = contractDocumentService.buildFileName(id, templateType);
+        MultipartFile file = new ByteArrayMultipartFile("file", fileName,
+                "application/vnd.openxmlformats-officedocument.wordprocessingml.document", bytes);
+        Long blobId = storageBlobService.upload(Collections.singletonList(file), false).get(0).getId();
+        storageAttachmentApi.bindAttachments("file", "hrm_employee_contract", id, Collections.singletonList(blobId));
+        return success(blobId);
+    }
+
+    @GetMapping("/generate-docx")
+    @Operation(summary = "鐢熸垚骞朵笅杞藉悎鍚屾枃妗o紙docx锛�")
+    @Parameter(name = "id", description = "鍚堝悓ID", required = true)
+    @Parameter(name = "templateType", description = "妯℃澘绫诲瀷锛�1-鍔冲姩鍚堝悓(绠�鐗�) 2-鍔冲姩鍚堝悓(鏍囧噯) 3-鍔冲姟鍚堝悓", required = true)
+    @PreAuthorize("@ss.hasPermission('hrm:employee-contract:query')")
+    public void generateDocx(@RequestParam("id") Long id,
+                             @RequestParam("templateType") Integer templateType,
+                             HttpServletResponse response) throws IOException {
+        byte[] bytes = contractDocumentService.generateDocx(id, templateType);
+        String fileName = URLEncoder.encode(contractDocumentService.buildFileName(id, templateType), StandardCharsets.UTF_8);
+        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+        response.setHeader("Content-Disposition", "attachment; filename=" + fileName + "; filename*=UTF-8''" + fileName);
+        response.getOutputStream().write(bytes);
+    }
+
+    @GetMapping("/download-template")
+    @Operation(summary = "涓嬭浇鍚堝悓绌虹櫧妯℃澘", description = "1-鍔冲姩鍚堝悓(绠�鐗�) 2-鍔冲姩鍚堝悓(鏍囧噯) 3-鍔冲姟鍚堝悓 4-閫�浼戣繑鑱樺悎鍚�")
+    @Parameter(name = "type", description = "妯℃澘绫诲瀷锛�1-鍔冲姩鍚堝悓(绠�鐗�) 2-鍔冲姩鍚堝悓(鏍囧噯) 3-鍔冲姟鍚堝悓 4-閫�浼戣繑鑱樺悎鍚�", required = true)
+    @PreAuthorize("@ss.hasPermission('hrm:employee-contract:query')")
+    public void downloadTemplate(@RequestParam("type") Integer type, HttpServletResponse response) throws IOException {
+        String path;
+        String fileName;
+        String contentType;
+        if (type == 1) {
+            path = "template/contract/original/labor_simple.docx";
+            fileName = "鍔冲姩鍚堝悓(绠�鐗�).docx";
+            contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
+        } else if (type == 2) {
+            path = "template/contract/original/labor_standard.docx";
+            fileName = "鍔冲姩鍚堝悓(鏍囧噯).docx";
+            contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
+        } else if (type == 3) {
+            path = "template/contract/original/service.doc";
+            fileName = "鍔冲姟鍚堝悓.doc";
+            contentType = "application/msword";
+        } else if (type == 4) {
+            path = "template/contract/original/retire.docx";
+            fileName = "閫�浼戣繑鑱樺悎鍚�.docx";
+            contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
+        } else {
+            throw exception(CONTRACT_TEMPLATE_TYPE_NOT_SUPPORT);
+        }
+        try (InputStream in = getClass().getClassLoader().getResourceAsStream(path)) {
+            if (in == null) {
+                throw exception(CONTRACT_TEMPLATE_LOAD_FAILED);
+            }
+            byte[] bytes = in.readAllBytes();
+            String enc = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
+            response.setContentType(contentType);
+            response.setHeader("Content-Disposition", "attachment; filename=" + enc + "; filename*=UTF-8''" + enc);
+            response.getOutputStream().write(bytes);
+        }
+    }
+
     @GetMapping("/import-template")
     @Operation(summary = "涓嬭浇鍛樺伐鍚堝悓瀵煎叆妯℃澘")
     @PreAuthorize("@ss.hasPermission('hrm:employee-contract:import')")
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeController.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeController.java
index 4d4829a..e1c4c6a 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeController.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/HrmEmployeeController.java
@@ -205,8 +205,8 @@
         List<HrmEmployeeImportExcelVO> list = Arrays.asList(
                 HrmEmployeeImportExcelVO.builder().name("寮犱笁").gender(1).phone("13800138000")
                         .deptName("鐮斿彂閮�").postName("閮ㄩ棬缁忕悊,椤圭洰缁忕悊").roleNames("鏅�氱鐞嗗憳")
-                        .hireDate(LocalDate.of(2020, 3, 1)).employeeStatus(1)
-                        .idCard("320102199001150011").birthday(LocalDate.of(1990, 1, 15))
+                        .hireDate("2020-03-01").employeeStatus(1)
+                        .idCard("320102199001150011").birthday("1990-01-15")
                         .nation("姹夋棌").marriageStatus("宸插").age(36).education("鏈").politicalStatus("涓叡鍏氬憳")
                         .email("zhangsan@example.com").build()
         );
@@ -222,4 +222,22 @@
         return success(employeeService.importEmployeeList(list, importReqVO));
     }
 
+    @PutMapping("/regular")
+    @Operation(summary = "鍛樺伐杞", description = "浠呫�庡姵鍔ㄥ悎鍚屻�忓憳宸ュ彲杞锛涘姵鍔″悎鍚屼笉杞銆傝浆姝e彧鏀圭姸鎬�+杞鏃ユ湡锛屼笉鍚皟宀�")
+    @Parameter(name = "id", description = "鍛樺伐ID", required = true)
+    @PreAuthorize("@ss.hasPermission('hrm:employee:update')")
+    public CommonResult<Boolean> regularizeEmployee(@RequestParam("id") Long id) {
+        employeeService.regularizeEmployee(id);
+        return success(true);
+    }
+
+    @GetMapping("/regularize-reminders")
+    @Operation(summary = "鑾峰緱寰呰浆姝f彁閱掑垪琛�", description = "璇曠敤涓�佷笖褰撳墠涓哄姵鍔ㄥ悎鍚屻�佽瘯鐢ㄦ湡鍦� days 澶╁唴鍒版湡鐨勫憳宸�")
+    @PreAuthorize("@ss.hasPermission('hrm:employee:query')")
+    public CommonResult<List<HrmEmployeeRespVO>> getRegularizeReminders(
+            @RequestParam(value = "days", required = false, defaultValue = "7") Integer days) {
+        List<HrmEmployeeDO> list = employeeService.getRegularizeReminderList(days);
+        return success(BeanUtils.toBean(list, HrmEmployeeRespVO.class));
+    }
+
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeImportExcelVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeImportExcelVO.java
index 977f0c1..c276c95 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeImportExcelVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeImportExcelVO.java
@@ -8,6 +8,7 @@
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.math.BigDecimal;
 import java.time.LocalDate;
 
 /**
@@ -39,17 +40,21 @@
     private String roleNames;
 
     @ExcelProperty("鍏ヨ亴鏃ユ湡")
-    private LocalDate hireDate;
+    private String hireDate;
 
     @ExcelProperty(value = "鍛樺伐鐘舵��", converter = DictConvert.class)
     @DictFormat("hrm_employee_status")
     private Integer employeeStatus;
 
+    @ExcelProperty(value = "鍛樺伐绫诲埆", converter = DictConvert.class)
+    @DictFormat("hrm_employee_category")
+    private Integer employeeCategory;
+
     @ExcelProperty("韬唤璇佸彿")
     private String idCard;
 
     @ExcelProperty("鍑虹敓鏃ユ湡")
-    private LocalDate birthday;
+    private String birthday;
 
     @ExcelProperty("姘戞棌")
     private String nation;
@@ -72,4 +77,16 @@
     @ExcelProperty("澶囨敞")
     private String remark;
 
+    @ExcelProperty("鍩烘湰宸ヨ祫")
+    private BigDecimal baseSalary;
+
+    @ExcelProperty("寮�鎴烽摱琛�")
+    private String bankName;
+
+    @ExcelProperty("閾惰璐﹀彿")
+    private String bankAccount;
+
+    @ExcelProperty("灞呬綇鍦板潃")
+    private String address;
+
 }
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeRespVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeRespVO.java
index 8706fc4..687c923 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeRespVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeRespVO.java
@@ -4,6 +4,7 @@
 import cn.idev.excel.annotation.ExcelProperty;
 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -45,7 +46,7 @@
 
     @Schema(description = "鎬у埆")
     @ExcelProperty(value = "鎬у埆", converter = DictConvert.class)
-    @DictFormat("system_user_sex")
+    @DictFormat("hrm_gender")
     private Integer gender;
 
     @Schema(description = "鍑虹敓鏃ユ湡")
@@ -53,7 +54,7 @@
     private LocalDate birthday;
 
     @Schema(description = "鎵嬫満鍙风爜")
-    @ExcelProperty("鎵嬫満鍙风爜")
+    @ExcelProperty("鎵嬫満鍙�")
     private String phone;
 
     @Schema(description = "閭")
@@ -101,6 +102,11 @@
     @DictFormat("hrm_employee_status")
     private Integer employeeStatus;
 
+    @Schema(description = "鍛樺伐绫诲埆")
+    @ExcelProperty(value = "鍛樺伐绫诲埆", converter = DictConvert.class)
+    @DictFormat("hrm_employee_category")
+    private Integer employeeCategory;
+
     @Schema(description = "骞村亣浣欓锛堝ぉ锛�")
     @ExcelProperty("骞村亣浣欓")
     private BigDecimal annualLeaveBalance;
@@ -120,7 +126,7 @@
     private List<Long> roleIds;
 
     @Schema(description = "瑙掕壊鍚嶇О鍒楄〃")
-    @ExcelProperty("瑙掕壊")
+    @ExcelProperty("鐢ㄦ埛瑙掕壊")
     private String roleNames;
 
     @Schema(description = "寮�鎴烽摱琛�")
@@ -143,4 +149,7 @@
     @ExcelProperty("鍒涘缓鏃堕棿")
     private LocalDateTime createTime;
 
+    @Schema(description = "闄勪欢鍒楄〃")
+    private List<StorageBlobRespDTO> attachmentList;
+
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSaveReqVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSaveReqVO.java
index f0f0231..f642f86 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSaveReqVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSaveReqVO.java
@@ -78,6 +78,9 @@
     @NotNull(message = "鍛樺伐鐘舵�佷笉鑳戒负绌�")
     private Integer employeeStatus;
 
+    @Schema(description = "鍛樺伐绫诲埆锛�1-鏅�氬憳宸ワ紝2-鎶�宸ワ紝3-绠$悊", example = "1")
+    private Integer employeeCategory;
+
     @Schema(description = "骞村亣浣欓锛堝ぉ锛�", example = "5")
     private BigDecimal annualLeaveBalance;
 
@@ -119,4 +122,7 @@
     @Valid
     private List<HrmEmployeeEmergencyContactSaveReqVO> emergencyContacts;
 
+    @Schema(description = "闄勪欢 blobId 鍒楄〃", example = "[1, 2, 3]")
+    private List<Long> blobIds;
+
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSimpleRespVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSimpleRespVO.java
index 2bf625f..0859adb 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSimpleRespVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSimpleRespVO.java
@@ -3,6 +3,8 @@
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import java.util.List;
+
 @Schema(description = "绠$悊鍚庡彴 - 鍛樺伐绠�鍗曚俊鎭� Response VO")
 @Data
 public class HrmEmployeeSimpleRespVO {
@@ -16,9 +18,18 @@
     @Schema(description = "鍛樺伐濮撳悕")
     private String name;
 
+    @Schema(description = "閮ㄩ棬ID")
+    private Long deptId;
+
     @Schema(description = "閮ㄩ棬鍚嶇О")
     private String deptName;
 
+    @Schema(description = "宀椾綅ID鍒楄〃")
+    private List<Long> postIds;
+
+    @Schema(description = "宀椾綅鍚嶇О锛堝涓敤閫楀彿鍒嗛殧锛�")
+    private String postName;
+
     @Schema(description = "鍛樺伐鐘舵��")
     private Integer employeeStatus;
 
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmOvertimeWageConfigController.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmOvertimeWageConfigController.java
new file mode 100644
index 0000000..6b77184
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmOvertimeWageConfigController.java
@@ -0,0 +1,112 @@
+package cn.iocoder.yudao.module.hrm.controller.admin.salary;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmOvertimeWageConfigRespVO;
+import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmOvertimeWageConfigSaveReqVO;
+import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmOvertimeWageConfigDO;
+import cn.iocoder.yudao.module.hrm.service.salary.HrmOvertimeWageConfigService;
+import cn.iocoder.yudao.module.system.api.dept.PostApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "绠$悊鍚庡彴 - HRM 鍔犵彮宸ヨ祫绠$悊")
+@RestController
+@RequestMapping("/hrm/salary/overtime-wage")
+@Validated
+public class HrmOvertimeWageConfigController {
+
+    @Resource
+    private HrmOvertimeWageConfigService overtimeWageConfigService;
+    @Resource
+    private PostApi postApi;
+
+    @PostMapping("/create")
+    @Operation(summary = "鍒涘缓宀椾綅鍔犵彮宸ヨ祫閰嶇疆")
+    @PreAuthorize("@ss.hasPermission('hrm:overtime-wage:create')")
+    public CommonResult<Long> createOvertimeWageConfig(@Valid @RequestBody HrmOvertimeWageConfigSaveReqVO reqVO) {
+        return success(overtimeWageConfigService.createOvertimeWageConfig(
+                BeanUtils.toBean(reqVO, HrmOvertimeWageConfigDO.class)));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "鏇存柊宀椾綅鍔犵彮宸ヨ祫閰嶇疆")
+    @PreAuthorize("@ss.hasPermission('hrm:overtime-wage:update')")
+    public CommonResult<Boolean> updateOvertimeWageConfig(@Valid @RequestBody HrmOvertimeWageConfigSaveReqVO reqVO) {
+        overtimeWageConfigService.updateOvertimeWageConfig(BeanUtils.toBean(reqVO, HrmOvertimeWageConfigDO.class));
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "鍒犻櫎宀椾綅鍔犵彮宸ヨ祫閰嶇疆")
+    @Parameter(name = "id", description = "閰嶇疆缂栧彿", required = true)
+    @PreAuthorize("@ss.hasPermission('hrm:overtime-wage:delete')")
+    public CommonResult<Boolean> deleteOvertimeWageConfig(@RequestParam("id") Long id) {
+        overtimeWageConfigService.deleteOvertimeWageConfig(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "鑾峰緱宀椾綅鍔犵彮宸ヨ祫閰嶇疆")
+    @Parameter(name = "id", description = "閰嶇疆缂栧彿", required = true)
+    @PreAuthorize("@ss.hasPermission('hrm:overtime-wage:query')")
+    public CommonResult<HrmOvertimeWageConfigRespVO> getOvertimeWageConfig(@RequestParam("id") Long id) {
+        return success(convert(overtimeWageConfigService.getOvertimeWageConfig(id)));
+    }
+
+    @GetMapping("/list")
+    @Operation(summary = "鑾峰緱宀椾綅鍔犵彮宸ヨ祫閰嶇疆鍒楄〃")
+    @PreAuthorize("@ss.hasPermission('hrm:overtime-wage:query')")
+    public CommonResult<List<HrmOvertimeWageConfigRespVO>> getOvertimeWageConfigList(
+            @RequestParam(value = "postId", required = false) Long postId,
+            @RequestParam(value = "status", required = false) Integer status) {
+        return success(convertList(overtimeWageConfigService.getOvertimeWageConfigList(postId, status)));
+    }
+
+    private HrmOvertimeWageConfigRespVO convert(HrmOvertimeWageConfigDO config) {
+        if (config == null) {
+            return null;
+        }
+        return convertList(Collections.singletonList(config)).get(0);
+    }
+
+    private List<HrmOvertimeWageConfigRespVO> convertList(List<HrmOvertimeWageConfigDO> list) {
+        List<HrmOvertimeWageConfigRespVO> voList = BeanUtils.toBean(list, HrmOvertimeWageConfigRespVO.class);
+        List<Long> postIds = voList.stream().map(HrmOvertimeWageConfigRespVO::getPostId)
+                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        if (CollUtil.isNotEmpty(postIds)) {
+            Map<Long, PostRespDTO> postMap = postApi.getPostMap(postIds);
+            voList.forEach(vo -> {
+                PostRespDTO post = postMap.get(vo.getPostId());
+                if (post != null) {
+                    vo.setPostName(post.getName());
+                }
+            });
+        }
+        return voList;
+    }
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSalaryCalculationController.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSalaryCalculationController.java
index 10de4fd..d32cdd2 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSalaryCalculationController.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSalaryCalculationController.java
@@ -200,7 +200,7 @@
 
     @PostMapping("/save")
     @Operation(summary = "鎵归噺淇濆瓨钖叕鏍哥畻璁板綍")
-    @PreAuthorize("@ss.hasPermission('hrm:salary-calculation:save')")
+    @PreAuthorize("@ss.hasPermission('hrm:salary-calculation:calculate')")
     public CommonResult<Boolean> saveSalaryCalculation(@Valid @RequestBody HrmSalaryCalculationSaveReqVO saveReqVO) {
         // 杞崲涓� DO 鍒楄〃
         List<HrmSalaryCalculationDO> calculationList = saveReqVO.getList().stream()
@@ -215,4 +215,13 @@
         return success(true);
     }
 
+    @PutMapping("/update")
+    @Operation(summary = "淇敼钖叕鏍哥畻璁板綍", description = "浠呭緟纭鐘舵�佸彲淇敼锛涘疄鍙戝伐璧勭敱鍚庣鎸夋敹鍏�/鎵i櫎椤归噸绠�")
+    @PreAuthorize("@ss.hasPermission('hrm:salary-calculation:calculate')")
+    public CommonResult<Boolean> updateSalaryCalculation(@Valid @RequestBody HrmSalaryCalculationRespVO updateReqVO) {
+        HrmSalaryCalculationDO calculation = BeanUtils.toBean(updateReqVO, HrmSalaryCalculationDO.class);
+        salaryCalculationService.updateSalaryCalculation(calculation);
+        return success(true);
+    }
+
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSocialSecurityConfigController.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSocialSecurityConfigController.java
index a01acf0..5915785 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSocialSecurityConfigController.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/HrmSocialSecurityConfigController.java
@@ -31,7 +31,7 @@
 
     @PostMapping("/create")
     @Operation(summary = "鍒涘缓绀句繚鍏Н閲戦厤缃�")
-    @PreAuthorize("@ss.hasPermission('hrm:social-security:create')")
+    @PreAuthorize("@ss.hasPermission('hrm:social-security-config:create')")
     public CommonResult<Long> createSocialSecurityConfig(@Valid @RequestBody HrmSocialSecurityConfigSaveReqVO createReqVO) {
         HrmSocialSecurityConfigDO config = BeanUtils.toBean(createReqVO, HrmSocialSecurityConfigDO.class);
         return success(socialSecurityConfigService.createSocialSecurityConfig(config));
@@ -39,7 +39,7 @@
 
     @PutMapping("/update")
     @Operation(summary = "鏇存柊绀句繚鍏Н閲戦厤缃�")
-    @PreAuthorize("@ss.hasPermission('hrm:social-security:update')")
+    @PreAuthorize("@ss.hasPermission('hrm:social-security-config:update')")
     public CommonResult<Boolean> updateSocialSecurityConfig(@Valid @RequestBody HrmSocialSecurityConfigSaveReqVO updateReqVO) {
         HrmSocialSecurityConfigDO config = BeanUtils.toBean(updateReqVO, HrmSocialSecurityConfigDO.class);
         socialSecurityConfigService.updateSocialSecurityConfig(config);
@@ -49,7 +49,7 @@
     @DeleteMapping("/delete")
     @Operation(summary = "鍒犻櫎绀句繚鍏Н閲戦厤缃�")
     @Parameter(name = "id", description = "閰嶇疆ID", required = true)
-    @PreAuthorize("@ss.hasPermission('hrm:social-security:delete')")
+    @PreAuthorize("@ss.hasPermission('hrm:social-security-config:delete')")
     public CommonResult<Boolean> deleteSocialSecurityConfig(@RequestParam("id") Long id) {
         socialSecurityConfigService.deleteSocialSecurityConfig(id);
         return success(true);
@@ -58,7 +58,7 @@
     @GetMapping("/get")
     @Operation(summary = "鑾峰彇绀句繚鍏Н閲戦厤缃�")
     @Parameter(name = "id", description = "閰嶇疆ID", required = true)
-    @PreAuthorize("@ss.hasPermission('hrm:social-security:query')")
+    @PreAuthorize("@ss.hasPermission('hrm:social-security-config:query')")
     public CommonResult<HrmSocialSecurityConfigRespVO> getSocialSecurityConfig(@RequestParam("id") Long id) {
         HrmSocialSecurityConfigDO config = socialSecurityConfigService.getSocialSecurityConfig(id);
         return success(BeanUtils.toBean(config, HrmSocialSecurityConfigRespVO.class));
@@ -66,7 +66,7 @@
 
     @GetMapping("/list")
     @Operation(summary = "鑾峰彇绀句繚鍏Н閲戦厤缃垪琛�")
-    @PreAuthorize("@ss.hasPermission('hrm:social-security:query')")
+    @PreAuthorize("@ss.hasPermission('hrm:social-security-config:query')")
     public CommonResult<List<HrmSocialSecurityConfigRespVO>> getSocialSecurityConfigList() {
         List<HrmSocialSecurityConfigDO> list = socialSecurityConfigService.getSocialSecurityConfigList();
         return success(BeanUtils.toBean(list, HrmSocialSecurityConfigRespVO.class));
@@ -75,7 +75,7 @@
     @GetMapping("/get-effective")
     @Operation(summary = "鑾峰彇鐢熸晥鐨勭ぞ淇濆叕绉噾閰嶇疆")
     @Parameter(name = "effectiveDate", description = "鐢熸晥鏃ユ湡", required = true)
-    @PreAuthorize("@ss.hasPermission('hrm:social-security:query')")
+    @PreAuthorize("@ss.hasPermission('hrm:social-security-config:query')")
     public CommonResult<HrmSocialSecurityConfigRespVO> getEffectiveSocialSecurityConfig(
             @RequestParam("effectiveDate") LocalDate effectiveDate) {
         HrmSocialSecurityConfigDO config = socialSecurityConfigService.getEffectiveSocialSecurityConfig(effectiveDate);
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmOvertimeWageConfigRespVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmOvertimeWageConfigRespVO.java
new file mode 100644
index 0000000..3acba1b
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmOvertimeWageConfigRespVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.hrm.controller.admin.salary.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - 宀椾綅鍔犵彮宸ヨ祫閰嶇疆 Response VO")
+@Data
+public class HrmOvertimeWageConfigRespVO {
+
+    @Schema(description = "閰嶇疆缂栧彿")
+    private Long id;
+
+    @Schema(description = "宀椾綅ID")
+    private Long postId;
+
+    @Schema(description = "宀椾綅鍚嶇О")
+    private String postName;
+
+    @Schema(description = "鍔犵彮鏃惰柂锛堝厓/灏忔椂锛�")
+    private BigDecimal hourlyRate;
+
+    @Schema(description = "姣忔湀鏈�澶у姞鐝椂闀夸笂闄愶紙灏忔椂锛夛紝涓虹┖琛ㄧず涓嶉檺")
+    private BigDecimal maxOvertimeHours;
+
+    @Schema(description = "鐘舵�侊細0-鍚敤锛�1-绂佺敤")
+    private Integer status;
+
+    @Schema(description = "澶囨敞")
+    private String remark;
+
+    @Schema(description = "鍒涘缓鏃堕棿")
+    private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmOvertimeWageConfigSaveReqVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmOvertimeWageConfigSaveReqVO.java
new file mode 100644
index 0000000..fc22c73
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmOvertimeWageConfigSaveReqVO.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.hrm.controller.admin.salary.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Schema(description = "绠$悊鍚庡彴 - 宀椾綅鍔犵彮宸ヨ祫閰嶇疆鏂板/淇敼 Request VO")
+@Data
+public class HrmOvertimeWageConfigSaveReqVO {
+
+    @Schema(description = "閰嶇疆缂栧彿", example = "1")
+    private Long id;
+
+    @Schema(description = "宀椾綅ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "宀椾綅涓嶈兘涓虹┖")
+    private Long postId;
+
+    @Schema(description = "鍔犵彮鏃惰柂锛堝厓/灏忔椂锛夛紝榛樿 20", requiredMode = Schema.RequiredMode.REQUIRED, example = "20.00")
+    @NotNull(message = "鍔犵彮鏃惰柂涓嶈兘涓虹┖")
+    @DecimalMin(value = "0", message = "鍔犵彮鏃惰柂涓嶈兘灏忎簬 0")
+    private BigDecimal hourlyRate;
+
+    @Schema(description = "姣忔湀鏈�澶у姞鐝椂闀夸笂闄愶紙灏忔椂锛夛紝涓虹┖琛ㄧず涓嶉檺", example = "36.0")
+    @DecimalMin(value = "0", message = "鏈�澶у姞鐝椂闀夸笉鑳藉皬浜� 0")
+    private BigDecimal maxOvertimeHours;
+
+    @Schema(description = "鐘舵�侊細0-鍚敤锛�1-绂佺敤", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    @NotNull(message = "鐘舵�佷笉鑳戒负绌�")
+    private Integer status;
+
+    @Schema(description = "澶囨敞")
+    @Size(max = 500, message = "澶囨敞涓嶈兘瓒呰繃 500 涓瓧绗�")
+    private String remark;
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeRespVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeRespVO.java
index 9c2462d..ffa2ecd 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeRespVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeRespVO.java
@@ -49,6 +49,20 @@
     @Schema(description = "鐢熻偛淇濋櫓浼佷笟缂寸撼姣斾緥", example = "0.005")
     private BigDecimal maternityRatio;
 
+    // ========== 澶х梾鍖荤枟姣斾緥 ==========
+    @Schema(description = "澶х梾鍖荤枟浼佷笟缂寸撼姣斾緥", example = "0.005")
+    private BigDecimal seriousIllnessCompanyRatio;
+
+    @Schema(description = "澶х梾鍖荤枟涓汉缂寸撼姣斾緥", example = "0.005")
+    private BigDecimal seriousIllnessPersonalRatio;
+
+    // ========== 闀挎湡鎶ょ悊姣斾緥 ==========
+    @Schema(description = "闀挎湡鎶ょ悊浼佷笟缂寸撼姣斾緥", example = "0.003")
+    private BigDecimal longTermCareCompanyRatio;
+
+    @Schema(description = "闀挎湡鎶ょ悊涓汉缂寸撼姣斾緥", example = "0.003")
+    private BigDecimal longTermCarePersonalRatio;
+
     // ========== 鍏Н閲戞瘮渚� ==========
     @Schema(description = "鍏Н閲戜紒涓氱即绾虫瘮渚�", example = "0.12")
     private BigDecimal housingFundCompanyRatio;
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeSaveReqVO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeSaveReqVO.java
index 08099ab..6a13aef 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeSaveReqVO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/salary/vo/HrmSocialSecuritySchemeSaveReqVO.java
@@ -52,6 +52,20 @@
     @Schema(description = "鐢熻偛淇濋櫓浼佷笟缂寸撼姣斾緥", example = "0.005")
     private BigDecimal maternityRatio;
 
+    // ========== 澶х梾鍖荤枟姣斾緥 ==========
+    @Schema(description = "澶х梾鍖荤枟浼佷笟缂寸撼姣斾緥", example = "0.005")
+    private BigDecimal seriousIllnessCompanyRatio;
+
+    @Schema(description = "澶х梾鍖荤枟涓汉缂寸撼姣斾緥", example = "0.005")
+    private BigDecimal seriousIllnessPersonalRatio;
+
+    // ========== 闀挎湡鎶ょ悊姣斾緥 ==========
+    @Schema(description = "闀挎湡鎶ょ悊浼佷笟缂寸撼姣斾緥", example = "0.003")
+    private BigDecimal longTermCareCompanyRatio;
+
+    @Schema(description = "闀挎湡鎶ょ悊涓汉缂寸撼姣斾緥", example = "0.003")
+    private BigDecimal longTermCarePersonalRatio;
+
     // ========== 鍏Н閲戞瘮渚� ==========
     @Schema(description = "鍏Н閲戜紒涓氱即绾虫瘮渚�", example = "0.12")
     private BigDecimal housingFundCompanyRatio;
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceHolidayDO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceHolidayDO.java
index 4ea1136..3b79774 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceHolidayDO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceHolidayDO.java
@@ -35,19 +35,9 @@
     private String name;
 
     /**
-     * 鏃ユ湡锛堝吋瀹瑰瓨閲� NOT NULL 鍒楃殑鍐椾綑瀛楁锛屽缁堝啓鍏� startDate锛�
+     * 鏃ユ湡
      */
     private LocalDate date;
-
-    /**
-     * 寮�濮嬫棩鏈�
-     */
-    private LocalDate startDate;
-
-    /**
-     * 缁撴潫鏃ユ湡
-     */
-    private LocalDate endDate;
 
     /**
      * 绫诲瀷锛�1-浼戞伅鏃ワ紝2-宸ヤ綔鏃�
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceRuleDO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceRuleDO.java
index 71bdfdc..d49ce30 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceRuleDO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceRuleDO.java
@@ -68,6 +68,16 @@
     private BigDecimal overtimeThreshold;
 
     /**
+     * 鐢熸晥寮�濮嬫棩鏈燂紙绌鸿〃绀轰笉闄愶級
+     */
+    private LocalDate effectiveStartDate;
+
+    /**
+     * 鐢熸晥缁撴潫鏃ユ湡锛堢┖琛ㄧず涓嶉檺锛�
+     */
+    private LocalDate effectiveEndDate;
+
+    /**
      * 鐘舵�侊細0-鍚敤锛�1-绂佺敤
      */
     private Integer status;
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/employee/HrmEmployeeDO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/employee/HrmEmployeeDO.java
index b784f3d..dd4b92c 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/employee/HrmEmployeeDO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/employee/HrmEmployeeDO.java
@@ -136,6 +136,13 @@
     private Integer employeeStatus;
 
     /**
+     * 鍛樺伐绫诲埆
+     *
+     * 1-鏅�氬憳宸ワ紝2-鎶�宸ワ紝3-绠$悊锛涚敤浜庡姞鐝伐璧勫樊寮傚寲鏍哥畻
+     */
+    private Integer employeeCategory;
+
+    /**
      * 骞村亣浣欓锛堝ぉ锛�
      */
     private BigDecimal annualLeaveBalance;
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmOvertimeWageConfigDO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmOvertimeWageConfigDO.java
new file mode 100644
index 0000000..b414564
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmOvertimeWageConfigDO.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.hrm.dal.dataobject.salary;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+
+/**
+ * 宀椾綅鍔犵彮宸ヨ祫閰嶇疆 DO
+ *
+ * <p>鐢ㄤ簬銆屽姞鐝伐璧勭鐞嗐�嶏細涓嶅悓宀椾綅锛堝伐绉嶏級閰嶇疆涓嶅悓鐨勫姞鐝椂钖笌鏈�澶у姞鐝椂闀夸笂闄愩��
+ * 鏍哥畻鏃舵櫘閫氬憳宸ユ寜姝ら厤缃殑鍥哄畾鏃惰柂璁″姞鐝伐璧勩��
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@TableName("hrm_overtime_wage_config")
+@KeySequence("hrm_overtime_wage_config_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class HrmOvertimeWageConfigDO extends BaseDO {
+
+    /**
+     * 閰嶇疆ID
+     */
+    @TableId
+    private Long id;
+
+    /**
+     * 宀椾綅ID
+     *
+     * 鍏宠仈 PostDO#getId()
+     */
+    private Long postId;
+
+    /**
+     * 鍔犵彮鏃惰柂锛堝厓/灏忔椂锛夛紝榛樿 20
+     */
+    private BigDecimal hourlyRate;
+
+    /**
+     * 姣忔湀鏈�澶у姞鐝椂闀夸笂闄愶紙灏忔椂锛�
+     *
+     * 涓虹┖琛ㄧず涓嶉檺鍒�
+     */
+    private BigDecimal maxOvertimeHours;
+
+    /**
+     * 鐘舵�侊細0-鍚敤锛�1-绂佺敤
+     */
+    private Integer status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSocialSecuritySchemeDO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSocialSecuritySchemeDO.java
index 1962eeb..d453ea7 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSocialSecuritySchemeDO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/salary/HrmSocialSecuritySchemeDO.java
@@ -84,6 +84,26 @@
      */
     private BigDecimal maternityRatio;
 
+    // ========== 澶х梾鍖荤枟姣斾緥 ==========
+    /**
+     * 澶х梾鍖荤枟浼佷笟缂寸撼姣斾緥
+     */
+    private BigDecimal seriousIllnessCompanyRatio;
+    /**
+     * 澶х梾鍖荤枟涓汉缂寸撼姣斾緥
+     */
+    private BigDecimal seriousIllnessPersonalRatio;
+
+    // ========== 闀挎湡鎶ょ悊姣斾緥 ==========
+    /**
+     * 闀挎湡鎶ょ悊浼佷笟缂寸撼姣斾緥
+     */
+    private BigDecimal longTermCareCompanyRatio;
+    /**
+     * 闀挎湡鎶ょ悊涓汉缂寸撼姣斾緥
+     */
+    private BigDecimal longTermCarePersonalRatio;
+
     // ========== 鍏Н閲戞瘮渚� ==========
     /**
      * 鍏Н閲戜紒涓氱即绾虫瘮渚�
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceHolidayMapper.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceHolidayMapper.java
index 2ebdc80..d38a149 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceHolidayMapper.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceHolidayMapper.java
@@ -19,30 +19,22 @@
 public interface HrmAttendanceHolidayMapper extends BaseMapperX<HrmAttendanceHolidayDO> {
 
     default PageResult<HrmAttendanceHolidayDO> selectPage(HrmAttendanceHolidayPageReqVO reqVO) {
-        LambdaQueryWrapperX<HrmAttendanceHolidayDO> query = new LambdaQueryWrapperX<HrmAttendanceHolidayDO>()
+        return selectPage(reqVO, new LambdaQueryWrapperX<HrmAttendanceHolidayDO>()
                 .likeIfPresent(HrmAttendanceHolidayDO::getName, reqVO.getName())
                 .eqIfPresent(HrmAttendanceHolidayDO::getType, reqVO.getType())
-                .eqIfPresent(HrmAttendanceHolidayDO::getIsLegal, reqVO.getIsLegal());
-        // 鏃ユ湡绛涢�夛細閰嶇疆鏃堕棿娈典笌鏌ヨ鍖洪棿鏈変氦闆嗗嵆鍛戒腑
-        LocalDate[] dateRange = reqVO.getDate();
-        if (dateRange != null && dateRange.length >= 2 && dateRange[0] != null && dateRange[1] != null) {
-            query.le(HrmAttendanceHolidayDO::getStartDate, dateRange[1])
-                    .ge(HrmAttendanceHolidayDO::getEndDate, dateRange[0]);
-        }
-        return selectPage(reqVO, query.orderByDesc(HrmAttendanceHolidayDO::getStartDate)
-                .orderByDesc(HrmAttendanceHolidayDO::getId));
+                .betweenIfPresent(HrmAttendanceHolidayDO::getDate, reqVO.getStartDate(), reqVO.getEndDate())
+                .orderByDesc(HrmAttendanceHolidayDO::getDate));
     }
 
-    /**
-     * 鏌ヨ鏃堕棿娈典笌 [startDate, endDate] 鏈変氦闆嗙殑閰嶇疆
-     * 浼犲叆鍚屼竴澶╋紙date, date锛夋椂锛屽嵆鏌ヨ瑕嗙洊璇ユ棩鐨勯厤缃�
-     */
-    default List<HrmAttendanceHolidayDO> selectListByDateRange(LocalDate startDate, LocalDate endDate) {
+    default HrmAttendanceHolidayDO selectByDate(LocalDate date) {
+        return selectOne(HrmAttendanceHolidayDO::getDate, date);
+    }
+
+    default List<HrmAttendanceHolidayDO> selectListByDateBetween(LocalDate startDate, LocalDate endDate) {
         return selectList(new LambdaQueryWrapperX<HrmAttendanceHolidayDO>()
-                .le(HrmAttendanceHolidayDO::getStartDate, endDate)
-                .ge(HrmAttendanceHolidayDO::getEndDate, startDate)
-                .orderByAsc(HrmAttendanceHolidayDO::getStartDate)
-                .orderByAsc(HrmAttendanceHolidayDO::getId));
+                .ge(HrmAttendanceHolidayDO::getDate, startDate)
+                .le(HrmAttendanceHolidayDO::getDate, endDate)
+                .orderByAsc(HrmAttendanceHolidayDO::getDate));
     }
 
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceRuleMapper.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceRuleMapper.java
index ab6a06a..a22c23b 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceRuleMapper.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/attendance/HrmAttendanceRuleMapper.java
@@ -37,16 +37,4 @@
                 .orderByAsc(HrmAttendanceRuleDO::getName));
     }
 
-    /**
-     * 鏌ヨ閮ㄩ棬涓嬪凡鍚敤鐨勮鍒欙紝鏈�鏂板垱寤虹殑鎺掑湪鍓嶉潰
-     *
-     * 鍚屼竴閮ㄩ棬鍙厤缃鏉″惎鐢ㄨ鍒欙紙澶氱彮娆★級锛岀敱璋冪敤鏂规寜鎵撳崱鏃堕棿鍖归厤鐝
-     */
-    default List<HrmAttendanceRuleDO> selectEnabledListByDeptId(Long deptId) {
-        return selectList(new LambdaQueryWrapperX<HrmAttendanceRuleDO>()
-                .eq(HrmAttendanceRuleDO::getDeptId, deptId)
-                .eq(HrmAttendanceRuleDO::getStatus, 0)
-                .orderByDesc(HrmAttendanceRuleDO::getId));
-    }
-
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/salary/HrmOvertimeWageConfigMapper.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/salary/HrmOvertimeWageConfigMapper.java
new file mode 100644
index 0000000..5bc49c8
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/salary/HrmOvertimeWageConfigMapper.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.hrm.dal.mysql.salary;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmOvertimeWageConfigDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 宀椾綅鍔犵彮宸ヨ祫閰嶇疆 Mapper
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Mapper
+public interface HrmOvertimeWageConfigMapper extends BaseMapperX<HrmOvertimeWageConfigDO> {
+
+    default List<HrmOvertimeWageConfigDO> selectListByCondition(Long postId, Integer status) {
+        return selectList(new LambdaQueryWrapperX<HrmOvertimeWageConfigDO>()
+                .eqIfPresent(HrmOvertimeWageConfigDO::getPostId, postId)
+                .eqIfPresent(HrmOvertimeWageConfigDO::getStatus, status)
+                .orderByDesc(HrmOvertimeWageConfigDO::getId));
+    }
+
+    default HrmOvertimeWageConfigDO selectByPostId(Long postId) {
+        return selectOne(HrmOvertimeWageConfigDO::getPostId, postId);
+    }
+
+    /**
+     * 鏌ヨ澶氫釜宀椾綅涓嬨�屽惎鐢ㄣ�嶇殑鍔犵彮宸ヨ祫閰嶇疆锛岀敤浜庤柂閰牳绠楁椂鎸夊憳宸ュ矖浣嶅尮閰嶃��
+     */
+    default List<HrmOvertimeWageConfigDO> selectEnabledListByPostIds(Collection<Long> postIds) {
+        return selectList(new LambdaQueryWrapperX<HrmOvertimeWageConfigDO>()
+                .inIfPresent(HrmOvertimeWageConfigDO::getPostId, postIds)
+                .eq(HrmOvertimeWageConfigDO::getStatus, 0));
+    }
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmLeaveApplicationServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmLeaveApplicationServiceImpl.java
index cec35b5..0ee5726 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmLeaveApplicationServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmLeaveApplicationServiceImpl.java
@@ -223,17 +223,6 @@
         }
 
         // 2. 鏍¢獙鍒嗙被鍜屾祦绋嬪畾涔夋槸鍚﹀瓨鍦�
-        // 鍏ㄥ眬鍏嶅鎵癸細涓氬姟鏍¢獙閫氳繃鍚庣洿鎺ユ墽琛屽鎵归�氳繃閫昏緫锛屾棤闇�娴佺▼妯″瀷銆�
-        if (bpmProcessInstanceApi.isGlobalAutoApprove()) {
-            leaveApplicationMapper.updateById(HrmLeaveApplicationDO.builder()
-                    .id(id)
-                    .processInstanceId("")
-                    .status(HrmAuditStatusEnum.PROCESS.getStatus())
-                    .build());
-            updateLeaveApplicationAuditStatus(id, HrmAuditStatusEnum.APPROVE.getStatus());
-            return;
-        }
-
         validateApproveCategoryAndProcessDefinition();
 
         // 3. 鏍¢獙浼犲叆鐨勬祦绋嬪畾涔� Key 鏄惁灞炰簬璇ュ垎绫讳笖澶勪簬婵�娲荤姸鎬�
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmOvertimeApplicationServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmOvertimeApplicationServiceImpl.java
index 21eb335..a044fba 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmOvertimeApplicationServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmOvertimeApplicationServiceImpl.java
@@ -117,14 +117,6 @@
     @Transactional(rollbackFor = Exception.class)
     public void submit(Long id, String processDefinitionKey, Long loginUserId) {
         HrmOvertimeApplicationDO application = requireOwnedDraft(id, loginUserId);
-        // 鍏ㄥ眬鍏嶅鎵癸細涓氬姟鏍¢獙閫氳繃鍚庣洿鎺ユ墽琛屽鎵归�氳繃閫昏緫锛屾棤闇�娴佺▼妯″瀷銆�
-        if (bpmProcessInstanceApi.isGlobalAutoApprove()) {
-            mapper.updateById(HrmOvertimeApplicationDO.builder().id(id).processInstanceId("")
-                    .status(HrmAuditStatusEnum.PROCESS.getStatus()).build());
-            updateAuditStatus(id, HrmAuditStatusEnum.APPROVE.getStatus());
-            return;
-        }
-
         validateProcessDefinitions();
         ProcessDefinition definition = bpmProcessDefinitionService.getActiveProcessDefinition(processDefinitionKey);
         if (definition == null || !BPM_PROCESS_DEFINITION_KEY.equals(definition.getKey())) {
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmResignationApplicationServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmResignationApplicationServiceImpl.java
index df408d2..54dfc6d 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmResignationApplicationServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmResignationApplicationServiceImpl.java
@@ -244,17 +244,6 @@
         if (ObjUtil.notEqual(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus())) {
             throw exception(RESIGNATION_APPLICATION_SUBMIT_FAIL_NOT_DRAFT);
         }
-        // 鍏ㄥ眬鍏嶅鎵癸細涓氬姟鏍¢獙閫氳繃鍚庣洿鎺ユ墽琛屽鎵归�氳繃閫昏緫锛屾棤闇�娴佺▼妯″瀷銆�
-        if (bpmProcessInstanceApi.isGlobalAutoApprove()) {
-            resignationApplicationMapper.updateById(HrmResignationApplicationDO.builder()
-                    .id(id)
-                    .processInstanceId("")
-                    .status(HrmAuditStatusEnum.PROCESS.getStatus())
-                    .build());
-            updateResignationApplicationAuditStatus(id, HrmAuditStatusEnum.APPROVE.getStatus());
-            return;
-        }
-
         validateApproveCategoryAndProcessDefinition();
         ProcessDefinition processDefinition = bpmProcessDefinitionService.getActiveProcessDefinition(processDefinitionKey);
         if (processDefinition == null) {
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmTransferApplicationServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmTransferApplicationServiceImpl.java
index fb14bad..3d02148 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmTransferApplicationServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/approval/HrmTransferApplicationServiceImpl.java
@@ -13,7 +13,9 @@
 import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmTransferApplicationRespVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmTransferApplicationSaveReqVO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmTransferApplicationDO;
+import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO;
 import cn.iocoder.yudao.module.hrm.dal.mysql.approval.HrmTransferApplicationMapper;
+import cn.iocoder.yudao.module.hrm.service.employee.HrmEmployeeService;
 import cn.iocoder.yudao.module.hrm.dal.redis.HrmNoRedisDAO;
 import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum;
 import cn.iocoder.yudao.module.hrm.enums.HrmTransferTypeEnum;
@@ -66,6 +68,8 @@
     @Resource
     private AdminUserApi adminUserApi;
     @Resource
+    private HrmEmployeeService employeeService;
+    @Resource
     private BpmProcessInstanceApi bpmProcessInstanceApi;
     @Resource
     private BpmCategoryService bpmCategoryService;
@@ -87,14 +91,14 @@
         }
         // 3. 鐢熸垚鐢宠鍗曞彿
         String no = generateUniqueNo();
-        // 4. 璁剧疆鐢宠浜轰俊鎭�
+        // 4. 璁剧疆璋冨矖浜猴紙鍛樺伐ID锛夛細涓虹┖鏃跺彇褰撳墠鐧诲綍鐢ㄦ埛瀵瑰簲鐨勫憳宸�
         Long userId = createReqVO.getUserId();
         if (userId == null) {
-            userId = getCurrentUserId();
+            HrmEmployeeDO currentEmployee = employeeService.getEmployeeByUserId(getCurrentUserId());
+            userId = currentEmployee != null ? currentEmployee.getId() : null;
         }
-        AdminUserRespDTO user = adminUserApi.getUser(userId);
-        if (user == null) {
-            userId = getCurrentUserId();
+        if (userId != null && employeeService.getEmployee(userId) == null) {
+            throw exception(EMPLOYEE_NOT_EXISTS);
         }
         // 5. 鎻掑叆
         HrmTransferApplicationDO application = BeanUtils.toBean(createReqVO, HrmTransferApplicationDO.class);
@@ -168,9 +172,9 @@
         }
         HrmTransferApplicationRespVO respVO = BeanUtils.toBean(application, HrmTransferApplicationRespVO.class);
         if (application.getUserId() != null) {
-            AdminUserRespDTO user = adminUserApi.getUser(application.getUserId());
-            if (user != null) {
-                respVO.setUserName(user.getNickname());
+            HrmEmployeeDO employee = employeeService.getEmployee(application.getUserId());
+            if (employee != null) {
+                respVO.setUserName(employee.getName());
             }
         }
         fillDeptNames(respVO, application);
@@ -215,7 +219,14 @@
                 .map(HrmTransferApplicationDO::getUserId)
                 .filter(Objects::nonNull)
                 .collect(Collectors.toSet());
-        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
+        // userId 瀛樼殑鏄憳宸D锛屾寜鍛樺伐琛ㄦ煡璇㈠鍚�
+        Map<Long, String> employeeNameMap = new HashMap<>();
+        for (Long userId : userIds) {
+            HrmEmployeeDO employee = employeeService.getEmployee(userId);
+            if (employee != null) {
+                employeeNameMap.put(userId, employee.getName());
+            }
+        }
         Set<Long> deptIds = pageResult.getList().stream()
                 .flatMap(app -> Stream.of(app.getCurrentDeptId(), app.getTargetDeptId()))
                 .filter(Objects::nonNull)
@@ -228,8 +239,8 @@
         Map<Long, PostRespDTO> postMap = postApi.getPostMap(postIds);
         List<HrmTransferApplicationRespVO> list = pageResult.getList().stream().map(app -> {
             HrmTransferApplicationRespVO vo = BeanUtils.toBean(app, HrmTransferApplicationRespVO.class);
-            if (app.getUserId() != null && userMap.containsKey(app.getUserId())) {
-                vo.setUserName(userMap.get(app.getUserId()).getNickname());
+            if (app.getUserId() != null && employeeNameMap.containsKey(app.getUserId())) {
+                vo.setUserName(employeeNameMap.get(app.getUserId()));
             }
             if (app.getCurrentDeptId() != null && deptMap.containsKey(app.getCurrentDeptId())) {
                 vo.setCurrentDeptName(deptMap.get(app.getCurrentDeptId()).getName());
@@ -257,17 +268,6 @@
         if (ObjUtil.notEqual(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus())) {
             throw exception(TRANSFER_APPLICATION_SUBMIT_FAIL_NOT_DRAFT);
         }
-        // 鍏ㄥ眬鍏嶅鎵癸細涓氬姟鏍¢獙閫氳繃鍚庣洿鎺ユ墽琛屽鎵归�氳繃閫昏緫锛屾棤闇�娴佺▼妯″瀷銆�
-        if (bpmProcessInstanceApi.isGlobalAutoApprove()) {
-            transferApplicationMapper.updateById(HrmTransferApplicationDO.builder()
-                    .id(id)
-                    .processInstanceId("")
-                    .status(HrmAuditStatusEnum.PROCESS.getStatus())
-                    .build());
-            updateTransferApplicationAuditStatus(id, HrmAuditStatusEnum.APPROVE.getStatus());
-            return;
-        }
-
         validateApproveCategoryAndProcessDefinition();
         ProcessDefinition processDefinition = bpmProcessDefinitionService.getActiveProcessDefinition(processDefinitionKey);
         if (processDefinition == null) {
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceExceptionServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceExceptionServiceImpl.java
index 17613bc..625be8e 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceExceptionServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceExceptionServiceImpl.java
@@ -102,17 +102,6 @@
         }
 
         // 2. 鏍¢獙娴佺▼瀹氫箟瀛樺湪涓斾负婵�娲荤姸鎬�
-        // 鍏ㄥ眬鍏嶅鎵癸細涓氬姟鏍¢獙閫氳繃鍚庣洿鎺ユ墽琛屽鎵归�氳繃閫昏緫锛屾棤闇�娴佺▼妯″瀷銆�
-        if (bpmProcessInstanceApi.isGlobalAutoApprove()) {
-            attendanceExceptionMapper.updateById(HrmAttendanceExceptionDO.builder()
-                    .id(id)
-                    .processInstanceId("")
-                    .status(HrmAuditStatusEnum.PROCESS.getStatus())
-                    .build());
-            updateAttendanceExceptionAuditStatus(id, HrmAuditStatusEnum.APPROVE.getStatus());
-            return;
-        }
-
         if (processDefinitionKey != null) {
             bpmProcessDefinitionService.getActiveProcessDefinition(processDefinitionKey);
         }
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayService.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayService.java
index a3af424..7127029 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayService.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayService.java
@@ -55,7 +55,7 @@
     PageResult<HrmAttendanceHolidayDO> getAttendanceHolidayPage(HrmAttendanceHolidayPageReqVO pageReqVO);
 
     /**
-     * 鑾峰緱鏃堕棿娈典笌鎸囧畾鏃ユ湡鑼冨洿鏈変氦闆嗙殑鑺傚亣鏃ュ垪琛�
+     * 鑾峰緱鎸囧畾鏃ユ湡鑼冨洿鐨勮妭鍋囨棩鍒楄〃
      *
      * @param startDate 寮�濮嬫棩鏈�
      * @param endDate 缁撴潫鏃ユ湡
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayServiceImpl.java
index d894d4c..0981a6a 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceHolidayServiceImpl.java
@@ -32,10 +32,9 @@
 
     @Override
     public Long createAttendanceHoliday(HrmAttendanceHolidaySaveReqVO createReqVO) {
-        validateDateRange(createReqVO);
-        validateDateRangeNoOverlap(createReqVO.getStartDate(), createReqVO.getEndDate(), null);
+        // 鏍¢獙鏃ユ湡鏄惁宸插瓨鍦ㄩ厤缃�
+        validateAttendanceHolidayDateExists(createReqVO.getDate());
         HrmAttendanceHolidayDO attendanceHoliday = BeanUtils.toBean(createReqVO, HrmAttendanceHolidayDO.class);
-        attendanceHoliday.setDate(createReqVO.getStartDate());
         if (attendanceHoliday.getIsLegal() == null) {
             attendanceHoliday.setIsLegal(0);
         }
@@ -46,10 +45,12 @@
     @Override
     public void updateAttendanceHoliday(HrmAttendanceHolidaySaveReqVO updateReqVO) {
         validateAttendanceHolidayExists(updateReqVO.getId());
-        validateDateRange(updateReqVO);
-        validateDateRangeNoOverlap(updateReqVO.getStartDate(), updateReqVO.getEndDate(), 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.setDate(updateReqVO.getStartDate());
         attendanceHolidayMapper.updateById(updateObj);
     }
 
@@ -61,23 +62,13 @@
 
     private void validateAttendanceHolidayExists(Long id) {
         if (attendanceHolidayMapper.selectById(id) == null) {
-            throw exception(ATTENDANCE_HOLIDAY_NOT_EXISTS, id);
+            throw exception(ATTENDANCE_HOLIDAY_NOT_EXISTS);
         }
     }
 
-    private void validateDateRange(HrmAttendanceHolidaySaveReqVO reqVO) {
-        if (reqVO.getEndDate().isBefore(reqVO.getStartDate())) {
-            throw exception(ATTENDANCE_HOLIDAY_DATE_RANGE_INVALID, reqVO.getEndDate(), reqVO.getStartDate());
-        }
-    }
-
-    private void validateDateRangeNoOverlap(LocalDate startDate, LocalDate endDate, Long excludeId) {
-        for (HrmAttendanceHolidayDO exist : attendanceHolidayMapper.selectListByDateRange(startDate, endDate)) {
-            if (excludeId != null && excludeId.equals(exist.getId())) {
-                continue;
-            }
-            throw exception(ATTENDANCE_HOLIDAY_RANGE_OVERLAP, startDate, endDate,
-                    exist.getName(), exist.getStartDate(), exist.getEndDate());
+    private void validateAttendanceHolidayDateExists(LocalDate date) {
+        if (attendanceHolidayMapper.selectByDate(date) != null) {
+            throw exception(ATTENDANCE_HOLIDAY_DATE_EXISTS);
         }
     }
 
@@ -93,16 +84,16 @@
 
     @Override
     public List<HrmAttendanceHolidayDO> getAttendanceHolidayListByDateRange(LocalDate startDate, LocalDate endDate) {
-        return attendanceHolidayMapper.selectListByDateRange(startDate, endDate);
+        return attendanceHolidayMapper.selectListByDateBetween(startDate, endDate);
     }
 
     @Override
     public boolean isWorkDay(LocalDate date) {
-        // 1. 鏌ヨ瑕嗙洊璇ユ棩鏈熺殑鑺傚亣鏃ラ厤缃紙閰嶇疆鏃堕棿娈典笉鍏佽閲嶅彔锛岃嚦澶氬懡涓竴鏉★級
-        List<HrmAttendanceHolidayDO> holidays = attendanceHolidayMapper.selectListByDateRange(date, date);
-        if (!holidays.isEmpty()) {
+        // 1. 鏌ヨ鑺傚亣鏃ラ厤缃�
+        HrmAttendanceHolidayDO holiday = attendanceHolidayMapper.selectByDate(date);
+        if (holiday != null) {
             // 鏈夐厤缃椂锛屾寜閰嶇疆鍒ゆ柇
-            return HrmAttendanceHolidayTypeEnum.WORK_DAY.getType().equals(holidays.get(0).getType());
+            return HrmAttendanceHolidayTypeEnum.WORK_DAY.getType().equals(holiday.getType());
         }
         // 2. 鏃犻厤缃椂锛屾寜鍛ㄦ湯鍒ゆ柇
         DayOfWeek dayOfWeek = date.getDayOfWeek();
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 184295a..73e8dd9 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,7 +1,6 @@
 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;
@@ -38,15 +37,6 @@
      */
     HrmAttendanceRecordDO getAttendanceRecordByUserIdAndDate(Long userId, LocalDate date);
 
-    /**
-     * 鑾峰緱褰撳墠鐧诲綍浜虹殑鑰冨嫟鐘舵�侊細鑰冨嫟瑙勫垯 + 鎸囧畾鏃ユ湡鐨勬墦鍗$姸鎬�
-     *
-     * @param loginUserId 鐧诲綍鐢ㄦ埛ID锛堢郴缁熺敤鎴稩D锛屼笉鏄憳宸D锛�
-     * @param date        鑰冨嫟鏃ユ湡锛屼负绌烘椂鍙栨湇鍔″櫒褰撳ぉ
-     * @return 鎴戠殑鑰冨嫟鐘舵��
-     */
-    HrmAttendanceMyStatusRespVO getMyStatus(Long loginUserId, LocalDate date);
-
     /** 鍒涘缓瀵煎叆鐨勮�冨嫟璁板綍 */
     void createImportedRecord(HrmAttendanceRecordDO record);
 
@@ -80,4 +70,14 @@
      */
     void supplementClockIn(HrmAttendanceExceptionDO exception);
 
+    /**
+     * 鑾峰緱褰撳墠鐧诲綍浜虹殑鑰冨嫟鐘舵�侊紙App 鎵撳崱椤典娇鐢級
+     *
+     * @param loginUserId 鐧诲綍鐢ㄦ埛ID锛堢郴缁熺敤鎴凤紝闈炲憳宸D锛�
+     * @param date        鑰冨嫟鏃ユ湡锛屼负绌烘椂鍙栨湇鍔″櫒褰撳ぉ
+     * @return 鎴戠殑鑰冨嫟鐘舵��
+     */
+    cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceMyStatusRespVO
+    getMyStatus(Long loginUserId, LocalDate date);
+
 }
\ No newline at end of file
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 95a4a13..c41e56a 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
@@ -1,12 +1,16 @@
 package cn.iocoder.yudao.module.hrm.service.attendance;
 
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
 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.HrmAttendanceMyStatusRespVO;
 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.enums.HrmAttendanceHolidayTypeEnum;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 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;
@@ -15,10 +19,7 @@
 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;
@@ -77,162 +78,6 @@
     }
 
     @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);
@@ -254,31 +99,27 @@
         if (record.getDeptId() == null) {
             return;
         }
-        // 涓婄彮鎵撳崱绫诲瀷锛氭櫄浜� 涓婄彮鏃堕棿+杩熷埌鍏佽 璁颁负杩熷埌锛堟寜涓婄彮鎵撳崱鏃堕棿鍖归厤鐝锛�
-        if (record.getClockInTime() != null) {
-            HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(
-                    record.getDeptId(), record.getClockInTime());
-            if (rule != null && rule.getWorkStartTime() != null) {
-                int lateAllowMinutes = rule.getLateAllowMinutes() != null ? rule.getLateAllowMinutes() : 0;
-                LocalTime lateThreshold = rule.getWorkStartTime().plusMinutes(lateAllowMinutes);
-                LocalTime clockInOnly = record.getClockInTime().toLocalTime();
-                record.setClockInType(clockInOnly.isAfter(lateThreshold)
-                        ? HrmAttendanceClockTypeEnum.LATE.getType()
-                        : HrmAttendanceClockTypeEnum.NORMAL.getType());
-            }
+        HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(record.getDeptId(), record.getDate());
+        if (rule == null) {
+            return;
         }
-        // 涓嬬彮鎵撳崱绫诲瀷锛氭棭浜� 涓嬬彮鏃堕棿-鏃╅��鍏佽 璁颁负鏃╅��锛堟寜涓嬬彮鎵撳崱鏃堕棿鍖归厤鐝锛�
-        if (record.getClockOutTime() != null) {
-            HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(
-                    record.getDeptId(), record.getClockOutTime());
-            if (rule != null && rule.getWorkEndTime() != null) {
-                int earlyAllowMinutes = rule.getEarlyAllowMinutes() != null ? rule.getEarlyAllowMinutes() : 0;
-                LocalTime earlyThreshold = rule.getWorkEndTime().minusMinutes(earlyAllowMinutes);
-                LocalTime clockOutOnly = record.getClockOutTime().toLocalTime();
-                record.setClockOutType(clockOutOnly.isBefore(earlyThreshold)
-                        ? HrmAttendanceClockTypeEnum.EARLY.getType()
-                        : HrmAttendanceClockTypeEnum.NORMAL.getType());
-            }
+        // 涓婄彮鎵撳崱绫诲瀷锛氭櫄浜� 涓婄彮鏃堕棿+杩熷埌鍏佽 璁颁负杩熷埌
+        if (record.getClockInTime() != null && rule.getWorkStartTime() != null) {
+            int lateAllowMinutes = rule.getLateAllowMinutes() != null ? rule.getLateAllowMinutes() : 0;
+            LocalTime lateThreshold = rule.getWorkStartTime().plusMinutes(lateAllowMinutes);
+            LocalTime clockInOnly = record.getClockInTime().toLocalTime();
+            record.setClockInType(clockInOnly.isAfter(lateThreshold)
+                    ? HrmAttendanceClockTypeEnum.LATE.getType()
+                    : HrmAttendanceClockTypeEnum.NORMAL.getType());
+        }
+        // 涓嬬彮鎵撳崱绫诲瀷锛氭棭浜� 涓嬬彮鏃堕棿-鏃╅��鍏佽 璁颁负鏃╅��
+        if (record.getClockOutTime() != null && rule.getWorkEndTime() != null) {
+            int earlyAllowMinutes = rule.getEarlyAllowMinutes() != null ? rule.getEarlyAllowMinutes() : 0;
+            LocalTime earlyThreshold = rule.getWorkEndTime().minusMinutes(earlyAllowMinutes);
+            LocalTime clockOutOnly = record.getClockOutTime().toLocalTime();
+            record.setClockOutType(clockOutOnly.isBefore(earlyThreshold)
+                    ? HrmAttendanceClockTypeEnum.EARLY.getType()
+                    : HrmAttendanceClockTypeEnum.NORMAL.getType());
         }
     }
 
@@ -293,10 +134,9 @@
                     .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
             record.setWorkHours(workHours);
         }
-        // 鍔犵彮鏃堕暱锛氭寜鑰冨嫟瑙勫垯鐨勬爣鍑嗕笅鐝椂闂磋绠楄秴棰濋儴鍒嗭紙鎸変笅鐝墦鍗℃椂闂村尮閰嶇彮娆★級
+        // 鍔犵彮鏃堕暱锛氭寜鑰冨嫟瑙勫垯鐨勬爣鍑嗕笅鐝椂闂磋绠楄秴棰濋儴鍒�
         if (record.getClockOutTime() != null && record.getDeptId() != null) {
-            HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(
-                    record.getDeptId(), record.getClockOutTime());
+            HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(record.getDeptId(), record.getDate());
             if (rule != null && rule.getWorkEndTime() != null) {
                 LocalTime workEnd = rule.getWorkEndTime();
                 LocalDate outDate = record.getClockOutTime().toLocalDate();
@@ -330,8 +170,7 @@
         if (employee == null) {
             throw exception(EMPLOYEE_NOT_EXISTS);
         }
-        // 鎸夋湰娆℃墦鍗℃椂闂村尮閰嶇彮娆★紙鍚屼竴涓儴闂ㄥ彲鑳介厤缃簡澶氭潯瑙勫垯锛�
-        HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(employee.getDeptId(), clockTime);
+        HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(employee.getDeptId(), clockDate);
         if (rule == null) {
             throw exception(ATTENDANCE_CLOCK_FAIL_NO_RULE);
         }
@@ -384,8 +223,7 @@
         if (employee == null) {
             throw exception(EMPLOYEE_NOT_EXISTS);
         }
-        // 鎸夋湰娆℃墦鍗℃椂闂村尮閰嶇彮娆★紙鍚屼竴涓儴闂ㄥ彲鑳介厤缃簡澶氭潯瑙勫垯锛�
-        HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(employee.getDeptId(), clockTime);
+        HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(employee.getDeptId(), clockDate);
         if (rule == null) {
             throw exception(ATTENDANCE_CLOCK_FAIL_NO_RULE);
         }
@@ -476,4 +314,155 @@
         attendanceRecordMapper.updateById(record);
     }
 
+    // ==================== 鎴戠殑鑰冨嫟鐘舵�侊紙App 鎵撳崱椤碉級 ====================
+
+    @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 new ServiceException(EMPLOYEE_NOT_EXISTS.getCode(),
+                    "褰撳墠鐧诲綍璐﹀彿鏈叧鑱斿憳宸ユ。妗堬紝鏃犳硶鎵撳崱銆傝鑱旂郴绠$悊鍛樺湪銆愬憳宸ョ鐞嗐�戜腑灏嗚鐧诲綍璐﹀彿缁戝畾鍒板憳宸ャ��");
+        }
+        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(), queryDate);
+        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());
+        }
+        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;
+    }
+
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleService.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleService.java
index 30b3ccf..96eaf1b 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleService.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleService.java
@@ -6,7 +6,6 @@
 import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRuleDO;
 import jakarta.validation.Valid;
 
-import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -62,24 +61,14 @@
     List<HrmAttendanceRuleDO> getAttendanceRuleList();
 
     /**
-     * 鏍规嵁閮ㄩ棬ID鑾峰彇鑰冨嫟瑙勫垯
-     * 浼樺厛鍖归厤閮ㄩ棬瑙勫垯锛屽叾娆℃煡鎵惧叏灞�瑙勫垯锛坉eptId=null锛�
+     * 鏍规嵁閮ㄩ棬ID + 鑰冨嫟鏃ユ湡鑾峰彇鐢熸晥鐨勮�冨嫟瑙勫垯
+     * 浼樺厛鍖归厤閮ㄩ棬瑙勫垯锛屽叾娆℃煡鎵惧叏灞�瑙勫垯锛坉eptId=null锛夛紱
+     * 鍚岄儴闂ㄥ瓨鍦ㄥ鏉¤鍒欐椂锛屽彇銆岀敓鏁堝紑濮嬫棩鏈熴�嶆渶鏅氫笖瑕嗙洊璇ユ棩鏈熺殑閭f潯銆�
      *
      * @param deptId 閮ㄩ棬ID
+     * @param date   鑰冨嫟鏃ユ湡锛堜负绌烘椂鎸夊綋澶╋級
      * @return 鑰冨嫟瑙勫垯
      */
-    HrmAttendanceRuleDO getAttendanceRuleByDeptId(Long deptId);
-
-    /**
-     * 鏍规嵁閮ㄩ棬ID + 鎵撳崱鏃堕棿鑾峰彇鑰冨嫟瑙勫垯
-     *
-     * 鍚屼竴涓儴闂ㄥ厑璁搁厤缃鏉¤�冨嫟瑙勫垯锛堝鐝锛夛紝姝ゆ椂鎸夋墦鍗℃椂闂村尮閰嶇彮娆★細
-     * 浼樺厛鍙栫彮娆℃椂闂寸獥鍙e寘鍚鎵撳崱鏃堕棿鐨勮鍒欙紝閮戒笉鍖呭惈鏃跺彇鏃堕棿绐楀彛鏈�鎺ヨ繎鐨勪竴鏉°��
-     *
-     * @param deptId    閮ㄩ棬ID
-     * @param clockTime 鎵撳崱鏃堕棿锛涗负绌烘椂鍙栬閮ㄩ棬涓婄彮鏃堕棿鏈�鏃╃殑涓�鏉¤鍒�
-     * @return 鑰冨嫟瑙勫垯
-     */
-    HrmAttendanceRuleDO getAttendanceRuleByDeptId(Long deptId, LocalDateTime clockTime);
+    HrmAttendanceRuleDO getAttendanceRuleByDeptId(Long deptId, java.time.LocalDate date);
 
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleServiceImpl.java
index 373c401..3421f76 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRuleServiceImpl.java
@@ -3,25 +3,17 @@
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import com.google.common.annotations.VisibleForTesting;
 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 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.validation.annotation.Validated;
 
 import java.math.BigDecimal;
-import java.time.Duration;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.Comparator;
-import java.util.HashSet;
+import java.time.LocalDate;
 import java.util.List;
-import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.*;
@@ -29,25 +21,23 @@
 /**
  * 鑰冨嫟瑙勫垯閰嶇疆 Service 瀹炵幇绫�
  *
+ * 璇存槑锛氬悓涓�閮ㄩ棬鍏佽閰嶇疆澶氭潯瑙勫垯锛屾寜銆岀敓鏁堝紑濮嬫棩鏈� / 鐢熸晥缁撴潫鏃ユ湡銆嶅尯闂村尯鍒嗭紱
+ * 鍖归厤鏃跺彇瑕嗙洊鐩爣鏃ユ湡銆佷笖鐢熸晥寮�濮嬫棩鏈熸渶鏅氱殑閭f潯锛堟棤鏃ユ湡鐨勮涓洪暱鏈熸湁鏁堬紝浼樺厛绾ф渶浣庯級銆�
+ *
  * @author 瓒呯骇绠$悊鍛�
  */
 @Service
 @Validated
 public class HrmAttendanceRuleServiceImpl implements HrmAttendanceRuleService {
 
-    /** 瑙勫垯鐘舵�侊細0-鍚敤 */
-    private static final Integer ENABLED_STATUS = 0;
-
     @Resource
     private HrmAttendanceRuleMapper attendanceRuleMapper;
-    @Resource
-    private DeptApi deptApi;
 
     @Override
     public Long createAttendanceRule(HrmAttendanceRuleSaveReqVO createReqVO) {
-        // 鏍¢獙瑙勫垯鍚嶇О鏄惁閲嶅
+        // 鏍¢獙瑙勫垯鍚嶇О鏄惁閲嶅锛堝悓涓�閮ㄩ棬鍏佽澶氭潯瑙勫垯锛屼笉鍐嶉檺鍒堕儴闂ㄥ敮涓�锛�
         validateAttendanceRuleNameUnique(null, createReqVO.getName());
-        // 娉細鍚屼竴涓儴闂ㄥ厑璁搁厤缃鏉¤鍒欙紙澶氱彮娆★級锛岃繖閲屼笉鍐嶆牎楠岄儴闂ㄥ敮涓�
+        validateEffectiveDateRange(createReqVO.getEffectiveStartDate(), createReqVO.getEffectiveEndDate());
         HrmAttendanceRuleDO attendanceRule = BeanUtils.toBean(createReqVO, HrmAttendanceRuleDO.class);
         // 璁剧疆榛樿鍊�
         if (attendanceRule.getLateAllowMinutes() == null) {
@@ -71,7 +61,7 @@
         validateAttendanceRuleExists(updateReqVO.getId());
         // 鏍¢獙瑙勫垯鍚嶇О鏄惁閲嶅
         validateAttendanceRuleNameUnique(updateReqVO.getId(), updateReqVO.getName());
-        // 娉細鍚屼竴涓儴闂ㄥ厑璁搁厤缃鏉¤鍒欙紙澶氱彮娆★級锛岃繖閲屼笉鍐嶆牎楠岄儴闂ㄥ敮涓�
+        validateEffectiveDateRange(updateReqVO.getEffectiveStartDate(), updateReqVO.getEffectiveEndDate());
         HrmAttendanceRuleDO updateObj = BeanUtils.toBean(updateReqVO, HrmAttendanceRuleDO.class);
         attendanceRuleMapper.updateById(updateObj);
     }
@@ -101,6 +91,15 @@
         }
     }
 
+    /**
+     * 鏍¢獙鐢熸晥鏃ユ湡鍖洪棿锛氬紑濮嬫棩鏈熶笉鑳芥櫄浜庣粨鏉熸棩鏈�
+     */
+    private void validateEffectiveDateRange(LocalDate startDate, LocalDate endDate) {
+        if (startDate != null && endDate != null && startDate.isAfter(endDate)) {
+            throw exception(ATTENDANCE_RULE_EFFECTIVE_DATE_INVALID);
+        }
+    }
+
     @Override
     public HrmAttendanceRuleDO getAttendanceRule(Long id) {
         return attendanceRuleMapper.selectById(id);
@@ -117,90 +116,47 @@
     }
 
     @Override
-    public HrmAttendanceRuleDO getAttendanceRuleByDeptId(Long deptId) {
-        return getAttendanceRuleByDeptId(deptId, null);
-    }
-
-    @Override
-    public HrmAttendanceRuleDO getAttendanceRuleByDeptId(Long deptId, LocalDateTime clockTime) {
-        // 1. 浠庡憳宸ユ墍鍦ㄩ儴闂ㄥ紑濮嬮�愮骇鍚戜笂鏌ユ壘锛氶厤缃湪涓婄骇閮ㄩ棬鐨勮鍒欏鍏跺瓙閮ㄩ棬鐢熸晥
-        Set<Long> visitedDeptIds = new HashSet<>();
-        Long currentDeptId = deptId;
-        while (currentDeptId != null && currentDeptId != 0 && visitedDeptIds.add(currentDeptId)) {
-            List<HrmAttendanceRuleDO> deptRules = attendanceRuleMapper.selectEnabledListByDeptId(currentDeptId);
+    public HrmAttendanceRuleDO getAttendanceRuleByDeptId(Long deptId, LocalDate date) {
+        LocalDate targetDate = date != null ? date : LocalDate.now();
+        // 1. 鍏堟煡鎵鹃儴闂ㄤ笓灞炶鍒欙紙瑕嗙洊鐩爣鏃ユ湡鐨勶紝鐢熸晥寮�濮嬫棩鏈熸渶鏅氱殑浼樺厛锛�
+        if (deptId != null) {
+            List<HrmAttendanceRuleDO> deptRules = selectEffectiveRules(deptId, targetDate);
             if (!deptRules.isEmpty()) {
-                // 鍚屼竴閮ㄩ棬鍙厤缃鏉¤鍒欙紙澶氱彮娆★級锛屾寜鎵撳崱鏃堕棿鍖归厤鐝
-                return matchRuleByClockTime(deptRules, clockTime);
+                return deptRules.get(0);
             }
-            DeptRespDTO dept = deptApi.getDept(currentDeptId);
-            if (dept == null) {
-                break;
-            }
-            currentDeptId = dept.getParentId();
         }
         // 2. 鏌ユ壘鍏ㄥ眬瑙勫垯锛坉eptId 涓� null锛�
-        List<HrmAttendanceRuleDO> globalRules = attendanceRuleMapper.selectList(new LambdaQueryWrapperX<HrmAttendanceRuleDO>()
-                .isNull(HrmAttendanceRuleDO::getDeptId)
-                .eq(HrmAttendanceRuleDO::getStatus, ENABLED_STATUS)
-                .orderByDesc(HrmAttendanceRuleDO::getId));
+        List<HrmAttendanceRuleDO> globalRules = selectEffectiveRules(null, targetDate);
         if (!globalRules.isEmpty()) {
-            return matchRuleByClockTime(globalRules, clockTime);
+            return globalRules.get(0);
         }
         return null;
     }
 
     /**
-     * 澶氭潯瑙勫垯锛堝悓涓�涓儴闂ㄥ鐝锛夋椂锛屾寜鎵撳崱鏃堕棿閫夌彮娆★細
-     * 1. 鎵撳崱鏃堕棿钀藉湪鏌愪釜鐝鐨� [涓婄彮鏃堕棿, 涓嬬彮鏃堕棿] 鍐咃紝灏卞彇杩欎竴鏉�
-     * 2. 閮戒笉鍦ㄧ獥鍙e唴鏃讹紝鍙栫彮娆℃椂闂寸獥鍙g鎵撳崱鏃堕棿鏈�杩戠殑涓�鏉�
-     * 3. 浠嶇劧骞跺垪鏃讹紝鎸変笂鐝椂闂淬�佺紪鍙锋帓搴忥紝淇濊瘉缁撴灉绋冲畾锛堜笉浼氶殢鏁版嵁搴撹繑鍥為『搴忔紓绉伙級
-     * 鎵撳崱鏃堕棿涓虹┖锛堜笉鍏冲績鐝锛夋椂锛屽彇涓婄彮鏃堕棿鏈�鏃╃殑涓�鏉°��
+     * 鏌ヨ鍦ㄦ寚瀹氭棩鏈熺敓鏁堢殑瑙勫垯
+     *
+     * @param deptId 閮ㄩ棬ID锛宯ull 琛ㄧず鍏ㄥ眬瑙勫垯
+     * @param date   鐩爣鏃ユ湡
      */
-    @VisibleForTesting
-    static HrmAttendanceRuleDO matchRuleByClockTime(List<HrmAttendanceRuleDO> rules, LocalDateTime clockTime) {
-        if (rules.size() == 1) {
-            return rules.get(0);
+    private List<HrmAttendanceRuleDO> selectEffectiveRules(Long deptId, LocalDate date) {
+        LambdaQueryWrapperX<HrmAttendanceRuleDO> wrapper = new LambdaQueryWrapperX<>();
+        if (deptId == null) {
+            wrapper.isNull(HrmAttendanceRuleDO::getDeptId);
+        } else {
+            wrapper.eq(HrmAttendanceRuleDO::getDeptId, deptId);
         }
-        if (clockTime == null) {
-            return rules.stream().min(Comparator
-                            .comparing(HrmAttendanceRuleDO::getWorkStartTime,
-                                    Comparator.nullsLast(Comparator.<LocalTime>naturalOrder()))
-                            .thenComparing(HrmAttendanceRuleDO::getId))
-                    .orElse(rules.get(0));
-        }
-        LocalTime time = clockTime.toLocalTime();
-        return rules.stream().min(Comparator
-                        .comparingLong((HrmAttendanceRuleDO rule) -> minutesToRuleWindow(rule, time))
-                        .thenComparing(HrmAttendanceRuleDO::getWorkStartTime,
-                                Comparator.nullsLast(Comparator.<LocalTime>naturalOrder()))
-                        .thenComparing(HrmAttendanceRuleDO::getId))
-                .orElse(rules.get(0));
+        wrapper.eq(HrmAttendanceRuleDO::getStatus, 0);
+        // 鐢熸晥寮�濮嬫棩鏈熶负绌猴紙涓嶉檺锛夋垨 <= 鐩爣鏃ユ湡
+        wrapper.and(w -> w.isNull(HrmAttendanceRuleDO::getEffectiveStartDate)
+                .or().le(HrmAttendanceRuleDO::getEffectiveStartDate, date));
+        // 鐢熸晥缁撴潫鏃ユ湡涓虹┖锛堜笉闄愶級鎴� >= 鐩爣鏃ユ湡
+        wrapper.and(w -> w.isNull(HrmAttendanceRuleDO::getEffectiveEndDate)
+                .or().ge(HrmAttendanceRuleDO::getEffectiveEndDate, date));
+        // 鐢熸晥寮�濮嬫棩鏈熻秺鏅氫紭鍏堢骇瓒婇珮锛涘悓寮�濮嬫棩鏈熸椂鍙栧厛鍒涘缓鐨�
+        wrapper.orderByDesc(HrmAttendanceRuleDO::getEffectiveStartDate);
+        wrapper.orderByAsc(HrmAttendanceRuleDO::getId);
+        return attendanceRuleMapper.selectList(wrapper);
     }
 
-    /**
-     * 鎵撳崱鏃堕棿鍒拌鍒欑彮娆$獥鍙g殑璺濈锛堝垎閽燂級锛氳惤鍦ㄧ獥鍙e唴涓� 0锛岀彮娆℃椂闂存湭閰嶇疆鏃惰涓烘渶澶с��
-     * 鏀寔璺ㄥぉ鐝锛堝 22:00-06:00锛屽彧瑕� end <= start 灏辨寜璺ㄥぉ澶勭悊锛夈��
-     */
-    private static long minutesToRuleWindow(HrmAttendanceRuleDO rule, LocalTime time) {
-        LocalTime start = rule.getWorkStartTime();
-        LocalTime end = rule.getWorkEndTime();
-        if (start == null || end == null) {
-            return Long.MAX_VALUE;
-        }
-        boolean crossDay = !end.isAfter(start);
-        boolean inWindow = crossDay
-                ? !time.isBefore(start) || !time.isAfter(end)
-                : !time.isBefore(start) && !time.isAfter(end);
-        if (inWindow) {
-            return 0;
-        }
-        return Math.min(minutesBetween(time, start), minutesBetween(time, end));
-    }
-
-    /** 涓や釜鏃跺埢鐨勫垎閽熷樊锛屾寜涓�澶� 24 灏忔椂鍙栨渶杩戠殑鐜洖璺濈锛�23:50 涓� 00:10 鍙樊 20 鍒嗛挓锛� */
-    private static long minutesBetween(LocalTime one, LocalTime other) {
-        long minutes = Math.abs(Duration.between(one, other).toMinutes());
-        return Math.min(minutes, 24 * 60 - minutes);
-    }
-
-}
\ No newline at end of file
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeContractServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeContractServiceImpl.java
index 2e95548..80cb347 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeContractServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeContractServiceImpl.java
@@ -5,7 +5,6 @@
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.framework.operatelog.core.util.OperateLogUtils;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractPageReqVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractRespVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeContractSaveReqVO;
@@ -21,7 +20,6 @@
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi;
-import com.mzt.logapi.starter.annotation.LogRecord;
 import jakarta.annotation.Resource;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -40,7 +38,6 @@
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.*;
-import static cn.iocoder.yudao.module.hrm.enums.LogRecordConstants.*;
 
 /**
  * 鍛樺伐鍚堝悓 Service 瀹炵幇绫�
@@ -335,8 +332,6 @@
     }
 
     @Override
-    @LogRecord(type = HRM_EMPLOYEE_CONTRACT_TYPE, subType = HRM_EMPLOYEE_CONTRACT_IMPORT_SUB_TYPE, bizNo = "0",
-            success = HRM_EMPLOYEE_CONTRACT_IMPORT_SUCCESS)
     public HrmEmployeeContractImportRespVO importContractList(List<HrmEmployeeContractImportExcelVO> importContracts,
                                                               HrmEmployeeContractImportReqVO importReqVO) {
         // 1. 杩囨护鍛樺伐濮撳悕涓虹┖鐨勮
@@ -386,9 +381,6 @@
                 respVO.getFailureNames().put(name, ex.getMessage());
             }
         }
-        // 璁板綍瀵煎叆缁撴灉姹囨�伙紝渚� @LogRecord 鐨� success 鏂囨寮曠敤
-        OperateLogUtils.putImportSummary(respVO.getCreateNames(), respVO.getUpdateNames(),
-                respVO.getFailureNames());
         return respVO;
     }
 
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeService.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeService.java
index 90424ba..9fff42d 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeService.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeService.java
@@ -115,4 +115,19 @@
     HrmEmployeeImportRespVO importEmployeeList(List<HrmEmployeeImportExcelVO> importEmployees,
                                                HrmEmployeeImportReqVO importReqVO);
 
+    /**
+     * 鍛樺伐杞锛氫粎銆屽姵鍔ㄥ悎鍚屻�嶅彲杞锛堝姵鍔″悎鍚屼笉鍙級锛岀姸鎬� 璇曠敤 -> 鍦ㄨ亴锛岃褰曡浆姝f棩鏈�
+     *
+     * @param id 鍛樺伐ID
+     */
+    void regularizeEmployee(Long id);
+
+    /**
+     * 鑾峰緱寰呰浆姝f彁閱掑垪琛細璇曠敤涓�佷笖褰撳墠涓哄姵鍔ㄥ悎鍚屻�佽瘯鐢ㄦ湡鍦� days 澶╁唴鍒版湡鐨勫憳宸�
+     *
+     * @param days 鎻愬墠澶╂暟
+     * @return 鍛樺伐鍒楄〃
+     */
+    List<HrmEmployeeDO> getRegularizeReminderList(Integer days);
+
 }
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
index f03a1c0..d32b4c5 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
@@ -6,7 +6,7 @@
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.framework.operatelog.core.util.OperateLogUtils;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeEducationSaveReqVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeEmergencyContactSaveReqVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeImportExcelVO;
@@ -17,10 +17,12 @@
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSaveReqVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSimpleRespVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeWorkHistorySaveReqVO;
+import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeContractDO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeEducationDO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeEmergencyContactDO;
 import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeWorkHistoryDO;
+import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeContractMapper;
 import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeEducationMapper;
 import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeEmergencyContactMapper;
 import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper;
@@ -32,18 +34,21 @@
 import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO;
 import cn.iocoder.yudao.module.system.api.permission.RoleApi;
 import cn.iocoder.yudao.module.system.api.permission.dto.RoleRespDTO;
+import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi;
+import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserCreateReqDTO;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserUpdateReqDTO;
-import com.mzt.logapi.starter.annotation.LogRecord;
 import jakarta.annotation.Resource;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
+import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
@@ -56,7 +61,6 @@
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
 import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.*;
-import static cn.iocoder.yudao.module.hrm.enums.LogRecordConstants.*;
 
 /**
  * 鍛樺伐淇℃伅 Service 瀹炵幇绫�
@@ -69,6 +73,8 @@
 
     @Resource
     private HrmEmployeeMapper employeeMapper;
+    @Resource
+    private HrmEmployeeContractMapper contractMapper;
     @Resource
     private HrmEmployeeEducationMapper educationMapper;
     @Resource
@@ -85,6 +91,8 @@
     private AdminUserApi adminUserApi;
     @Resource
     private RoleApi roleApi;
+    @Resource
+    private StorageAttachmentApi storageAttachmentApi;
     @Resource
     @Lazy // 鑷敞鍏ラ渶寤惰繜鍔犺浇锛屽惁鍒� bean 琚唬鐞嗗寘瑁呭悗娉ㄥ叆鍘熷鐗堟湰瀵艰嚧鍚姩澶辫触
     private HrmEmployeeService self;
@@ -132,6 +140,8 @@
         }
         employeeMapper.insert(employee);
         Long employeeId = employee.getId();
+        // 缁戝畾闄勪欢
+        storageAttachmentApi.bindAttachments("file", "hrm_employee", employeeId, createReqVO.getBlobIds());
         // 7. 鍚屾娣诲姞鏁欒偛缁忓巻
         if (CollUtil.isNotEmpty(createReqVO.getEducations())) {
             createReqVO.getEducations().forEach(educationVO -> {
@@ -213,6 +223,8 @@
         syncWorkHistoryList(employeeId, updateReqVO.getWorkHistories());
         // 鍚屾绱ф�ヨ仈绯讳汉
         syncEmergencyContactList(employeeId, updateReqVO.getEmergencyContacts());
+        // 鏇存柊闄勪欢
+        storageAttachmentApi.updateAttachments("file", "hrm_employee", employeeId, updateReqVO.getBlobIds());
     }
 
     private void syncEducationList(Long employeeId, List<HrmEmployeeEducationSaveReqVO> newList) {
@@ -260,6 +272,8 @@
         educationMapper.deleteByEmployeeId(id);
         workHistoryMapper.deleteByEmployeeId(id);
         emergencyContactMapper.deleteByEmployeeId(id);
+        // 鍒犻櫎闄勪欢
+        storageAttachmentApi.deleteAttachmentsByRecord("hrm_employee", id);
         // 鍒犻櫎鍛樺伐
         employeeMapper.deleteById(id);
     }
@@ -314,6 +328,8 @@
                 respVO.setRoleNames(roles.stream().map(RoleRespDTO::getName).collect(Collectors.joining(",")));
             }
         }
+        // 濉厖闄勪欢
+        respVO.setAttachmentList(storageAttachmentApi.listAttachments("hrm_employee", id));
         return respVO;
     }
 
@@ -355,18 +371,67 @@
                 .filter(Objects::nonNull)
                 .collect(Collectors.toSet());
         Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(deptIds);
+        // 瑙f瀽宀椾綅ID锛坧ost_ids 瀛樼殑鏄� JSON 鏁扮粍瀛楃涓诧紝濡� [38]锛夛紝骞舵壒閲忓姞杞藉矖浣嶅悕绉�
+        Map<Long, List<Long>> empPostIdsMap = new LinkedHashMap<>();
+        Set<Long> allPostIds = new LinkedHashSet<>();
+        for (HrmEmployeeDO emp : list) {
+            List<Long> postIdList = parseEmployeePostIds(emp.getPostIds());
+            empPostIdsMap.put(emp.getId(), postIdList);
+            allPostIds.addAll(postIdList);
+        }
+        Map<Long, PostRespDTO> postMap = CollUtil.isEmpty(allPostIds)
+                ? Collections.emptyMap() : postApi.getPostMap(allPostIds);
         return list.stream().map(emp -> {
             HrmEmployeeSimpleRespVO vo = new HrmEmployeeSimpleRespVO();
             vo.setId(emp.getId());
             vo.setEmployeeNo(emp.getEmployeeNo());
             vo.setName(emp.getName());
             vo.setEmployeeStatus(emp.getEmployeeStatus());
+            vo.setDeptId(emp.getDeptId());
             if (emp.getDeptId() != null && deptMap.containsKey(emp.getDeptId())) {
                 vo.setDeptName(deptMap.get(emp.getDeptId()).getName());
+            }
+            // 宀椾綅淇℃伅锛堢敤浜庤皟宀楃瓑鍦烘櫙鑷姩甯﹀嚭鍘熷矖浣嶏級
+            List<Long> postIdList = empPostIdsMap.getOrDefault(emp.getId(), Collections.emptyList());
+            vo.setPostIds(postIdList);
+            if (CollUtil.isNotEmpty(postIdList)) {
+                vo.setPostName(postIdList.stream()
+                        .map(postMap::get)
+                        .filter(Objects::nonNull)
+                        .map(PostRespDTO::getName)
+                        .collect(Collectors.joining(",")));
             }
             return vo;
         }).collect(Collectors.toList());
     }
+
+    /**
+     * 瑙f瀽鍛樺伐鐨勫矖浣岻D瀛楃涓诧紙JSON 鏁扮粍鏍煎紡锛屽 [38] 鎴� [1,2]锛�
+     */
+
+    /**
+     * 瑙f瀽鍛樺伐宀椾綅ID瀛楃涓诧紙post_ids 瀛� JSON 鏁扮粍锛屽 [38] 鎴� [1,2]锛�
+     */
+    private java.util.List<Long> parseEmployeePostIds(String postIds) {
+        if (StrUtil.isBlank(postIds)) {
+            return Collections.emptyList();
+        }
+
+        // post_ids 褰㈠ "[38]" 鎴� "[1,2]"锛氬幓鎺変腑鎷彿鍚庢寜閫楀彿瑙f瀽
+        return Arrays.stream(postIds.replace("[", "").replace("]", "").split(","))
+                .map(String::trim)
+                .filter(StrUtil::isNotBlank)
+                .map(s -> {
+                    try {
+                        return Long.valueOf(s);
+                    } catch (NumberFormatException ex) {
+                        return null;
+                    }
+                })
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+    }
+
 
     @Override
     public HrmEmployeeDO getEmployeeByUserId(Long userId) {
@@ -384,8 +449,6 @@
     }
 
     @Override
-    @LogRecord(type = HRM_EMPLOYEE_TYPE, subType = HRM_EMPLOYEE_IMPORT_SUB_TYPE, bizNo = "0",
-            success = HRM_EMPLOYEE_IMPORT_SUCCESS)
     public HrmEmployeeImportRespVO importEmployeeList(List<HrmEmployeeImportExcelVO> importEmployees,
                                                       HrmEmployeeImportReqVO importReqVO) {
         // 1. 鏍¢獙闈炵┖
@@ -435,9 +498,6 @@
                 respVO.getFailureNames().put(name, ex.getMessage());
             }
         }
-        // 璁板綍瀵煎叆缁撴灉姹囨�伙紝渚� @LogRecord 鐨� success 鏂囨寮曠敤
-        OperateLogUtils.putImportSummary(respVO.getCreateNames(), respVO.getUpdateNames(),
-                respVO.getFailureNames());
         return respVO;
     }
 
@@ -449,8 +509,9 @@
         if (StrUtil.isBlank(importEmployee.getPhone())) {
             throw exception(EMPLOYEE_IMPORT_FIELD_REQUIRED, "鎵嬫満鍙�");
         }
-        if (importEmployee.getHireDate() == null) {
-            throw exception(EMPLOYEE_IMPORT_FIELD_REQUIRED, "鍏ヨ亴鏃ユ湡");
+        LocalDate hireDate = parseImportDate(importEmployee.getHireDate());
+        if (hireDate == null) {
+            throw exception(EMPLOYEE_IMPORT_FIELD_REQUIRED, "鍏ヨ亴鏃ユ湡(鏍煎紡锛�2015 鎴� 2015-01-01)");
         }
         HrmEmployeeSaveReqVO reqVO = new HrmEmployeeSaveReqVO();
         reqVO.setName(importEmployee.getName());
@@ -459,11 +520,11 @@
         reqVO.setDeptId(deptId);
         reqVO.setPostIds(CollUtil.isEmpty(postIds) ? null : new ArrayList<>(postIds));
         reqVO.setRoleIds(CollUtil.isEmpty(roleIds) ? null : new ArrayList<>(roleIds));
-        reqVO.setHireDate(importEmployee.getHireDate());
+        reqVO.setHireDate(hireDate);
         reqVO.setEmployeeStatus(importEmployee.getEmployeeStatus() != null
                 ? importEmployee.getEmployeeStatus() : 1); // 榛樿鍦ㄨ亴
         reqVO.setEmail(importEmployee.getEmail());
-        reqVO.setBirthday(importEmployee.getBirthday());
+        reqVO.setBirthday(parseImportDate(importEmployee.getBirthday()));
         reqVO.setIdCard(importEmployee.getIdCard());
         reqVO.setNation(importEmployee.getNation());
         reqVO.setMarriageStatus(importEmployee.getMarriageStatus());
@@ -471,6 +532,11 @@
         reqVO.setEducation(importEmployee.getEducation());
         reqVO.setPoliticalStatus(importEmployee.getPoliticalStatus());
         reqVO.setRemark(importEmployee.getRemark());
+        reqVO.setEmployeeCategory(importEmployee.getEmployeeCategory());
+        reqVO.setBaseSalary(importEmployee.getBaseSalary());
+        reqVO.setBankName(importEmployee.getBankName());
+        reqVO.setBankAccount(importEmployee.getBankAccount());
+        reqVO.setAddress(importEmployee.getAddress());
         return reqVO;
     }
 
@@ -526,4 +592,108 @@
         return roleIds;
     }
 
+    /**
+     * 瀹归敊瑙f瀽瀵煎叆鏃ユ湡鏂囨湰锛屾敮鎸侊細2015 / 2015骞� / 2015-01 / 2015-01-02 / 2015/1/2 / 2015.1.2 /
+     * 2015-01-02 00:00:00 / 20150102锛屼互鍙� Excel 鏃ユ湡搴忓垪鍙凤紱瑙f瀽涓嶅嚭杩斿洖 null銆�
+     */
+    private static LocalDate parseImportDate(String raw) {
+        if (StrUtil.isBlank(raw)) {
+            return null;
+        }
+        String s = raw.trim();
+        // 鍘绘帀鏃堕棿閮ㄥ垎
+        int sp = s.indexOf(' ');
+        if (sp > 0) {
+            s = s.substring(0, sp);
+        }
+        // 涓枃骞存湀鏃� / 鏂滄潬 / 鐐� / 涓嬪垝绾� 缁熶竴鎴� - 鍒嗛殧
+        s = s.replace("骞�", "-").replace("鏈�", "-").replace("鏃�", "")
+                .replace("/", "-").replace(".", "-").replace("_", "-").trim();
+        s = s.replaceAll("^-+|-+$", "");
+        if (StrUtil.isBlank(s)) {
+            return null;
+        }
+        try {
+            if (s.matches("\\d+")) {
+                int len = s.length();
+                if (len == 4) { // 2015
+                    return LocalDate.of(Integer.parseInt(s), 1, 1);
+                }
+                if (len == 5) { // Excel 鏃ユ湡搴忓垪鍙凤紙1900 鏃ユ湡绯荤粺锛屽熀鍑� 1899-12-30锛�
+                    return LocalDate.of(1899, 12, 30).plusDays(Long.parseLong(s));
+                }
+                if (len == 6) { // 201506
+                    return LocalDate.of(Integer.parseInt(s.substring(0, 4)), Integer.parseInt(s.substring(4, 6)), 1);
+                }
+                if (len == 8) { // 20150601
+                    return LocalDate.of(Integer.parseInt(s.substring(0, 4)), Integer.parseInt(s.substring(4, 6)), Integer.parseInt(s.substring(6, 8)));
+                }
+                return null;
+            }
+            String[] parts = s.split("-");
+            if (parts.length == 2) { // 2015-06
+                return LocalDate.of(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), 1);
+            }
+            if (parts.length >= 3) { // 2015-06-01
+                return LocalDate.of(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2]));
+            }
+        } catch (Exception e) {
+            return null;
+        }
+        return null;
+    }
+
+    // ========== 杞 ==========
+
+    @Override
+    public void regularizeEmployee(Long id) {
+        validateEmployee(id);
+        HrmEmployeeContractDO contract = findCurrentContract(id);
+        // 浠呫�屽姵鍔ㄥ悎鍚屻�嶅彲杞锛涘姵鍔″悎鍚屼笉杞
+        if (contract == null || !Integer.valueOf(1).equals(contract.getContractType())) {
+            throw exception(EMPLOYEE_REGULARIZE_NEED_LABOR_CONTRACT);
+        }
+        HrmEmployeeDO updateObj = new HrmEmployeeDO();
+        updateObj.setId(id);
+        updateObj.setEmployeeStatus(1); // 1-鍦ㄨ亴
+        updateObj.setRegularDate(LocalDate.now());
+        employeeMapper.updateById(updateObj);
+    }
+
+    @Override
+    public List<HrmEmployeeDO> getRegularizeReminderList(Integer days) {
+        int aheadDays = days == null ? 7 : days;
+        LocalDate limit = LocalDate.now().plusDays(aheadDays);
+        // 璇曠敤涓殑鍛樺伐
+        List<HrmEmployeeDO> trials = employeeMapper.selectList(
+                new LambdaQueryWrapperX<HrmEmployeeDO>().eq(HrmEmployeeDO::getEmployeeStatus, 2));
+        List<HrmEmployeeDO> result = new ArrayList<>();
+        for (HrmEmployeeDO employee : trials) {
+            HrmEmployeeContractDO contract = findCurrentContract(employee.getId());
+            // 浠呭姵鍔ㄥ悎鍚屻�佷笖璇曠敤鏈熷嵆灏嗗埌鏈�
+            if (contract == null || !Integer.valueOf(1).equals(contract.getContractType())) {
+                continue;
+            }
+            LocalDate probationEnd = contract.getProbationEndDate();
+            if (probationEnd != null && !probationEnd.isAfter(limit)) {
+                result.add(employee);
+            }
+        }
+        return result;
+    }
+
+    /** 鏌ヨ鍛樺伐褰撳墠鐢熸晥鍚堝悓 */
+    private HrmEmployeeContractDO findCurrentContract(Long employeeId) {
+        List<HrmEmployeeContractDO> list = contractMapper.selectListByEmployee(employeeId);
+        if (CollUtil.isEmpty(list)) {
+            return null;
+        }
+        for (HrmEmployeeContractDO contract : list) {
+            if (Boolean.TRUE.equals(contract.getIsCurrent())) {
+                return contract;
+            }
+        }
+        return null;
+    }
+
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ByteArrayMultipartFile.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ByteArrayMultipartFile.java
new file mode 100644
index 0000000..4fc2c2e
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ByteArrayMultipartFile.java
@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.hrm.service.employee.contract;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * 瀛楄妭鏁扮粍鐗� MultipartFile锛氭妸鍐呭瓨涓殑瀛楄妭鍖呰鎴� MultipartFile锛�
+ * 渚夸簬澶嶇敤 system 鐨� SystemStorageBlobService.upload(...) 瀛樺偍鏂囦欢骞舵嬁鍒� blobId銆�
+ */
+public class ByteArrayMultipartFile implements MultipartFile {
+
+    private final String name;
+    private final String originalFilename;
+    private final String contentType;
+    private final byte[] content;
+
+    public ByteArrayMultipartFile(String name, String originalFilename, String contentType, byte[] content) {
+        this.name = name;
+        this.originalFilename = originalFilename;
+        this.contentType = contentType;
+        this.content = content == null ? new byte[0] : content;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getOriginalFilename() {
+        return originalFilename;
+    }
+
+    @Override
+    public String getContentType() {
+        return contentType;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return content.length == 0;
+    }
+
+    @Override
+    public long getSize() {
+        return content.length;
+    }
+
+    @Override
+    public byte[] getBytes() {
+        return content;
+    }
+
+    @Override
+    public InputStream getInputStream() {
+        return new ByteArrayInputStream(content);
+    }
+
+    @Override
+    public void transferTo(File dest) throws IOException {
+        try (FileOutputStream fos = new FileOutputStream(dest)) {
+            fos.write(content);
+        }
+    }
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ContractDocumentService.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ContractDocumentService.java
new file mode 100644
index 0000000..ae7a69a
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ContractDocumentService.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.hrm.service.employee.contract;
+
+/**
+ * 鍛樺伐鍚堝悓鏂囨。鐢熸垚 Service
+ *
+ * 鎸夊悎鍚� + 鍛樺伐鏁版嵁锛屽鐢� Word 妯℃澘鐢熸垚鍔冲姩鍚堝悓 / 鍔冲姟鍚堝悓 docx銆�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+public interface ContractDocumentService {
+
+    /**
+     * 鐢熸垚鍚堝悓 docx
+     *
+     * @param contractId   鍚堝悓缂栧彿
+     * @param templateType 妯℃澘绫诲瀷锛�1-鍔冲姩鍚堝悓(绠�鐗�) 2-鍔冲姩鍚堝悓(鏍囧噯) 3-鍔冲姟鍚堝悓
+     * @return docx 瀛楄妭
+     */
+    byte[] generateDocx(Long contractId, Integer templateType);
+
+    /**
+     * 鐢熸垚鏂囦欢鍚�
+     */
+    String buildFileName(Long contractId, Integer templateType);
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ContractDocumentServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ContractDocumentServiceImpl.java
new file mode 100644
index 0000000..dbb8373
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/contract/ContractDocumentServiceImpl.java
@@ -0,0 +1,204 @@
+package cn.iocoder.yudao.module.hrm.service.employee.contract;
+
+import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeContractDO;
+import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO;
+import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeContractMapper;
+import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper;
+import com.deepoove.poi.XWPFTemplate;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.HashMap;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.CONTRACT_TEMPLATE_LOAD_FAILED;
+import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.CONTRACT_TEMPLATE_TYPE_NOT_SUPPORT;
+
+/**
+ * 鍛樺伐鍚堝悓鏂囨。鐢熸垚 Service 瀹炵幇绫�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Slf4j
+@Service
+public class ContractDocumentServiceImpl implements ContractDocumentService {
+
+    /** 鍔冲姩鍚堝悓锛堢畝鐗埪风ぞ淇濇姌鐜帮級 */
+    public static final int TYPE_LABOR_SIMPLE = 1;
+    /** 鍔冲姩鍚堝悓锛堟爣鍑喡峰畼鏂瑰埗寮忥級 */
+    public static final int TYPE_LABOR_STANDARD = 2;
+    /** 鍔冲姟鍚堝悓 */
+    public static final int TYPE_SERVICE = 3;
+
+    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy骞碝M鏈坉d鏃�");
+
+    private static final Map<Integer, String> TEMPLATE_PATHS = Map.of(
+            TYPE_LABOR_SIMPLE, "template/contract/contract_labor_simple.docx",
+            TYPE_LABOR_STANDARD, "template/contract/contract_labor_standard.docx",
+            TYPE_SERVICE, "template/contract/contract_service.docx");
+
+    private static final Map<Integer, String> TEMPLATE_NAMES = Map.of(
+            TYPE_LABOR_SIMPLE, "鍔冲姩鍚堝悓(绠�鐗�)",
+            TYPE_LABOR_STANDARD, "鍔冲姩鍚堝悓(鏍囧噯)",
+            TYPE_SERVICE, "鍔冲姟鍚堝悓");
+
+    @Resource
+    private HrmEmployeeContractMapper contractMapper;
+    @Resource
+    private HrmEmployeeMapper employeeMapper;
+
+    @Override
+    public byte[] generateDocx(Long contractId, Integer templateType) {
+        HrmEmployeeContractDO contract = contractMapper.selectById(contractId);
+        if (contract == null) {
+            throw exception(CONTRACT_TEMPLATE_LOAD_FAILED);
+        }
+        HrmEmployeeDO employee = contract.getEmployeeId() == null ? null
+                : employeeMapper.selectById(contract.getEmployeeId());
+        Map<String, Object> vars = buildVariables(contract, employee);
+
+        String path = TEMPLATE_PATHS.get(templateType);
+        if (path == null) {
+            throw exception(CONTRACT_TEMPLATE_TYPE_NOT_SUPPORT);
+        }
+        try (InputStream in = getClass().getClassLoader().getResourceAsStream(path)) {
+            if (in == null) {
+                throw exception(CONTRACT_TEMPLATE_LOAD_FAILED);
+            }
+            XWPFTemplate template = XWPFTemplate.compile(in).render(vars);
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            template.write(out);
+            template.close();
+            return out.toByteArray();
+        } catch (Exception e) {
+            log.error("[generateDocx][鍚堝悓({}) 妯℃澘({}) 鐢熸垚澶辫触]", contractId, templateType, e);
+            throw exception(CONTRACT_TEMPLATE_LOAD_FAILED);
+        }
+    }
+
+    @Override
+    public String buildFileName(Long contractId, Integer templateType) {
+        HrmEmployeeContractDO contract = contractMapper.selectById(contractId);
+        String no = contract != null && contract.getContractNo() != null ? contract.getContractNo() : String.valueOf(contractId);
+        String name = TEMPLATE_NAMES.getOrDefault(templateType, "鍚堝悓");
+        return no + "-" + name + ".docx";
+    }
+
+    private Map<String, Object> buildVariables(HrmEmployeeContractDO contract, HrmEmployeeDO employee) {
+        Map<String, Object> vars = new HashMap<>();
+        // 鐢叉柟锛堝叕鍙革級鈥斺�� 鐩墠鍙栫绾︿富浣擄紝鍏朵綑鐣欑┖鍚庣画鍙帴鍏ュ叕鍙搁厤缃�
+        vars.put("companyName", nvl(contract.getSignCompany()));
+        vars.put("companyAddress", "");
+        vars.put("legalPerson", "");
+        vars.put("companyPhone", "");
+        vars.put("creditCode", "");
+        // 涔欐柟锛堝憳宸ワ級
+        vars.put("employeeName", employee != null ? nvl(employee.getName()) : "");
+        vars.put("gender", employee != null ? genderText(employee.getGender()) : "");
+        vars.put("age", employee != null ? nvl(employee.getAge()) : "");
+        vars.put("idCard", employee != null ? nvl(employee.getIdCard()) : "");
+        vars.put("householdAddress", employee != null ? nvl(employee.getAddress()) : "");
+        vars.put("address", employee != null ? nvl(employee.getAddress()) : "");
+        vars.put("phone", employee != null ? nvl(employee.getPhone()) : "");
+        vars.put("emergencyPhone", "");
+        // 鍚堝悓
+        vars.put("contractNo", nvl(contract.getContractNo()));
+        vars.put("postName", "");
+        vars.put("postDuty", "");
+        vars.put("workPlace", "");
+        vars.put("contractStart", formatDate(contract.getStartDate()));
+        vars.put("contractEnd", formatDate(contract.getEndDate()));
+        vars.put("contractMonths", monthsBetween(contract.getStartDate(), contract.getEndDate()));
+        vars.put("probationStart", formatDate(contract.getProbationStartDate()));
+        vars.put("probationEnd", formatDate(contract.getProbationEndDate()));
+        vars.put("probationMonths", monthsBetween(contract.getProbationStartDate(), contract.getProbationEndDate()));
+        vars.put("probationDays", daysBetween(contract.getProbationStartDate(), contract.getProbationEndDate()));
+        vars.put("birthday", employee != null ? formatDate(employee.getBirthday()) : "");
+        // 骞存湀鏃ワ紙渚涖�宊__骞確__鏈坃__鏃ャ�嶉�愭牸濉啓锛�
+        vars.put("contractStartY", y(contract.getStartDate()));
+        vars.put("contractStartM", mo(contract.getStartDate()));
+        vars.put("contractStartD", d(contract.getStartDate()));
+        vars.put("contractEndY", y(contract.getEndDate()));
+        vars.put("contractEndM", mo(contract.getEndDate()));
+        vars.put("contractEndD", d(contract.getEndDate()));
+        vars.put("probationStartY", y(contract.getProbationStartDate()));
+        vars.put("probationStartM", mo(contract.getProbationStartDate()));
+        vars.put("probationStartD", d(contract.getProbationStartDate()));
+        vars.put("probationEndY", y(contract.getProbationEndDate()));
+        vars.put("probationEndM", mo(contract.getProbationEndDate()));
+        vars.put("probationEndD", d(contract.getProbationEndDate()));
+        vars.put("probationSalary", nvl(contract.getProbationSalary()));
+        vars.put("regularSalary", nvl(contract.getRegularSalary()));
+        vars.put("baseSalary", nvl(contract.getRegularSalary()));
+        vars.put("performanceSalary", "");
+        vars.put("socialSecuritySalary", "");
+        vars.put("signDate", formatDate(contract.getSignDate()));
+        // 鍔冲姟鍚堝悓閲岀殑鍙�夐」
+        vars.put("payType", "涓�");
+        vars.put("payDay", "");
+        vars.put("workVolume", "");
+        vars.put("workAmount", "");
+        vars.put("piecePrice", "");
+        vars.put("noticeCompensation", "");
+        vars.put("copies", "涓�");
+        vars.put("eachCopies", "涓�");
+        return vars;
+    }
+
+    private static String nvl(Object o) {
+        return o == null ? "" : o.toString();
+    }
+
+    private static String formatDate(LocalDate d) {
+        return d == null ? "" : d.format(DATE_FMT);
+    }
+
+    private static String monthsBetween(LocalDate start, LocalDate end) {
+        if (start == null || end == null) {
+            return "";
+        }
+        long months = ChronoUnit.MONTHS.between(start, end);
+        return String.valueOf(Math.max(months, 0));
+    }
+
+    private static String daysBetween(LocalDate start, LocalDate end) {
+        if (start == null || end == null) {
+            return "";
+        }
+        long days = ChronoUnit.DAYS.between(start, end);
+        return String.valueOf(Math.max(days, 0));
+    }
+
+    private static String y(LocalDate date) {
+        return date == null ? "" : String.format("%04d", date.getYear());
+    }
+
+    private static String mo(LocalDate date) {
+        return date == null ? "" : String.format("%02d", date.getMonthValue());
+    }
+
+    private static String d(LocalDate date) {
+        return date == null ? "" : String.format("%02d", date.getDayOfMonth());
+    }
+
+    private static String genderText(Integer sex) {
+        if (sex == null) {
+            return "";
+        }
+        return sex == 1 ? "鐢�" : sex == 2 ? "濂�" : "";
+    }
+
+    // 鍏煎 BigDecimal 鐩存帴 toString
+    private static String nvl(BigDecimal v) {
+        return v == null ? "" : v.toPlainString();
+    }
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmOvertimeWageConfigService.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmOvertimeWageConfigService.java
new file mode 100644
index 0000000..34e380d
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmOvertimeWageConfigService.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.hrm.service.salary;
+
+import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmOvertimeWageConfigDO;
+
+import java.util.List;
+
+/**
+ * 宀椾綅鍔犵彮宸ヨ祫閰嶇疆 Service
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+public interface HrmOvertimeWageConfigService {
+
+    Long createOvertimeWageConfig(HrmOvertimeWageConfigDO config);
+
+    void updateOvertimeWageConfig(HrmOvertimeWageConfigDO config);
+
+    void deleteOvertimeWageConfig(Long id);
+
+    HrmOvertimeWageConfigDO getOvertimeWageConfig(Long id);
+
+    List<HrmOvertimeWageConfigDO> getOvertimeWageConfigList(Long postId, Integer status);
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmOvertimeWageConfigServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmOvertimeWageConfigServiceImpl.java
new file mode 100644
index 0000000..f7f035e
--- /dev/null
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmOvertimeWageConfigServiceImpl.java
@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.module.hrm.service.salary;
+
+import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmOvertimeWageConfigDO;
+import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmOvertimeWageConfigMapper;
+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.OVERTIME_WAGE_CONFIG_NOT_EXISTS;
+import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.OVERTIME_WAGE_CONFIG_POST_EXISTS;
+
+/**
+ * 宀椾綅鍔犵彮宸ヨ祫閰嶇疆 Service 瀹炵幇绫�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Service
+@Validated
+public class HrmOvertimeWageConfigServiceImpl implements HrmOvertimeWageConfigService {
+
+    /**
+     * 榛樿鍔犵彮鏃惰柂锛堝厓/灏忔椂锛�
+     */
+    private static final BigDecimal DEFAULT_HOURLY_RATE = new BigDecimal("20");
+
+    @Resource
+    private HrmOvertimeWageConfigMapper overtimeWageConfigMapper;
+
+    @Override
+    public Long createOvertimeWageConfig(HrmOvertimeWageConfigDO config) {
+        validatePostUnique(null, config.getPostId());
+        // 鏈~鍐欐椂钖椂锛屼娇鐢ㄩ粯璁� 20 鍏�/灏忔椂
+        if (config.getHourlyRate() == null) {
+            config.setHourlyRate(DEFAULT_HOURLY_RATE);
+        }
+        overtimeWageConfigMapper.insert(config);
+        return config.getId();
+    }
+
+    @Override
+    public void updateOvertimeWageConfig(HrmOvertimeWageConfigDO config) {
+        validateExists(config.getId());
+        validatePostUnique(config.getId(), config.getPostId());
+        overtimeWageConfigMapper.updateById(config);
+    }
+
+    @Override
+    public void deleteOvertimeWageConfig(Long id) {
+        validateExists(id);
+        overtimeWageConfigMapper.deleteById(id);
+    }
+
+    @Override
+    public HrmOvertimeWageConfigDO getOvertimeWageConfig(Long id) {
+        return overtimeWageConfigMapper.selectById(id);
+    }
+
+    @Override
+    public List<HrmOvertimeWageConfigDO> getOvertimeWageConfigList(Long postId, Integer status) {
+        return overtimeWageConfigMapper.selectListByCondition(postId, status);
+    }
+
+    private void validateExists(Long id) {
+        if (id == null || overtimeWageConfigMapper.selectById(id) == null) {
+            throw exception(OVERTIME_WAGE_CONFIG_NOT_EXISTS);
+        }
+    }
+
+    private void validatePostUnique(Long id, Long postId) {
+        if (postId == null) {
+            return;
+        }
+        HrmOvertimeWageConfigDO config = overtimeWageConfigMapper.selectByPostId(postId);
+        if (config != null && !config.getId().equals(id)) {
+            throw exception(OVERTIME_WAGE_CONFIG_POST_EXISTS);
+        }
+    }
+
+}
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationService.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationService.java
index cf9d519..5c12c9c 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationService.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationService.java
@@ -81,4 +81,11 @@
      */
     void saveSalaryCalculationList(List<HrmSalaryCalculationDO> calculationList);
 
+    /**
+     * 淇敼鍗曟潯钖叕鏍哥畻璁板綍锛堜粎寰呯‘璁ょ姸鎬佸彲淇敼锛屽疄鍙戝伐璧勭敱鍚庣閲嶇畻锛�
+     *
+     * @param calculation 鏍哥畻璁板綍
+     */
+    void updateSalaryCalculation(HrmSalaryCalculationDO calculation);
+
 }
\ No newline at end of file
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java
index 6cf8b19..2d8be45 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java
@@ -32,6 +32,11 @@
 import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSalaryStructureMapper;
 import cn.iocoder.yudao.module.hrm.dal.redis.HrmNoRedisDAO;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmOvertimeWageConfigDO;
+import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmOvertimeWageConfigMapper;
+import cn.iocoder.yudao.module.hrm.enums.HrmEmployeeCategoryEnum;
 import cn.iocoder.yudao.module.hrm.enums.HrmOvertimeTypeEnum;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
@@ -97,6 +102,8 @@
     private HrmOvertimeApplicationMapper overtimeApplicationMapper;
     @Resource
     private HrmSalaryStructureMapper salaryStructureMapper;
+    @Resource
+    private HrmOvertimeWageConfigMapper overtimeWageConfigMapper;
     @Resource
     private HrmLeaveTypeConfigMapper leaveTypeConfigMapper;
     @Resource
@@ -228,7 +235,9 @@
                                                           HrmSocialSecuritySchemeDO scheme,
                                                           LocalDate effectiveDate) {
         // 璁$畻搴斿彂钖祫
-        BigDecimal baseSalary = employeeSalary.getBaseSalary() != null ? employeeSalary.getBaseSalary() : BigDecimal.ZERO;
+        // 鍩烘湰宸ヨ祫缁熶竴鍙栥�屽憳宸ヤ俊鎭�嶄腑缁存姢鐨勫熀鏈柂璧勶紙钖叕妗f閲岀殑 baseSalary 涓嶅啀浣滀负鏍哥畻鏉ユ簮锛�
+        // 閬垮厤鍛樺伐淇℃伅涓庤柂閰。妗堜笉涓�鑷存椂锛屾牳绠楃粨鏋滀笌鍛樺伐妗f瀵逛笉涓婏級
+        BigDecimal baseSalary = employee.getBaseSalary() != null ? employee.getBaseSalary() : BigDecimal.ZERO;
         BigDecimal performanceSalary = employeeSalary.getPerformanceSalary() != null ? employeeSalary.getPerformanceSalary() : BigDecimal.ZERO;
         BigDecimal mealAllowance = employeeSalary.getMealAllowance() != null ? employeeSalary.getMealAllowance() : BigDecimal.ZERO;
         BigDecimal transportAllowance = employeeSalary.getTransportAllowance() != null ? employeeSalary.getTransportAllowance() : BigDecimal.ZERO;
@@ -371,8 +380,16 @@
     }
 
     /**
-     * 姹囨�诲綋鏈堝鎵归�氳繃鐨勫姞鐝敵璇枫�傚皬鏃跺伐璧勬寜鍩烘湰宸ヨ祫 / 21.75 / 8 璁$畻锛�
-     * 宸ヤ綔鏃ラ粯璁� 1.5 鍊嶃�佷紤鎭棩榛樿 2 鍊嶃�佹硶瀹氳妭鍋囨棩榛樿 3 鍊嶏紝鍧囧彲鐢辫柂閰粨鏋勮鐩栥��
+     * 姹囨�诲綋鏈堝鎵归�氳繃鐨勫姞鐝敵璇凤紝璁$畻鍔犵彮宸ヨ祫涓庡姞鐝椂闀裤��
+     *
+     * <p>鎸夈�屽憳宸ョ被鍒�嶅樊寮傚寲鏍哥畻锛�
+     * <ul>
+     *     <li>鎶�宸ワ細鍔犵彮钖祫鎸� 1:1 鏍哥畻锛屼笌骞虫椂鏃惰柂涓�鑷达紙鍩烘湰宸ヨ祫 / 21.75 / 8锛夛紱</li>
+     *     <li>鏅�氬憳宸ワ細鎸夊矖浣嶉厤缃殑鍥哄畾鍔犵彮鏃惰柂锛堥粯璁� 20 鍏�/灏忔椂锛夋牳绠楋紱</li>
+     *     <li>绠$悊锛氫笉璁″姞鐝伐璧勶紱</li>
+     * </ul>
+     * 鍛戒腑宀椾綅閰嶇疆鏃讹紝鎸夐厤缃殑鏈�澶у姞鐝椂闀夸笂闄愬鍔犵彮鏃堕暱灏侀《锛�
+     * 鏈懡涓换浣曞矖浣嶉厤缃笖闈炴妧宸�/绠$悊鏃讹紝鍥為��鏃ч�昏緫锛堣柂閰粨鏋勫�嶇巼 / 鍔犵彮绫诲瀷榛樿鍊嶇巼锛夈��
      */
     private OvertimeSalary calculateOvertimeSalary(HrmEmployeeDO employee, HrmEmployeeSalaryDO employeeSalary,
                                                     String period, BigDecimal baseSalary) {
@@ -385,36 +402,108 @@
         if (CollUtil.isEmpty(applications)) {
             return new OvertimeSalary(BigDecimal.ZERO, BigDecimal.ZERO);
         }
-        Long structureId = employeeSalary.getSalaryStructureId() != null
-                ? employeeSalary.getSalaryStructureId() : employee.getSalaryStructureId();
-        HrmSalaryStructureDO structure = structureId == null ? null : salaryStructureMapper.selectById(structureId);
-        BigDecimal workdayMultiplier = structure != null && structure.getOvertimePayRatio() != null
-                ? structure.getOvertimePayRatio() : HrmOvertimeTypeEnum.WORKDAY.getSalaryMultiplier();
-        BigDecimal restDayMultiplier = structure != null && structure.getRestDayOvertimePayRatio() != null
-                ? structure.getRestDayOvertimePayRatio() : HrmOvertimeTypeEnum.REST_DAY.getSalaryMultiplier();
-        BigDecimal legalHolidayMultiplier = structure != null && structure.getLegalHolidayOvertimePayRatio() != null
-                ? structure.getLegalHolidayOvertimePayRatio() : HrmOvertimeTypeEnum.LEGAL_HOLIDAY.getSalaryMultiplier();
-        BigDecimal hourlySalary = baseSalary.divide(new BigDecimal("21.75"), 8, RoundingMode.HALF_UP)
+        // 绠$悊绫诲埆涓嶈鍔犵彮宸ヨ祫
+        HrmEmployeeCategoryEnum category = HrmEmployeeCategoryEnum.valueOfCategory(employee.getEmployeeCategory());
+        if (category == HrmEmployeeCategoryEnum.MANAGER) {
+            return new OvertimeSalary(BigDecimal.ZERO, BigDecimal.ZERO);
+        }
+        // 鍛樺伐宀椾綅鍛戒腑鐨勫姞鐝伐璧勯厤缃紙鍙栨椂钖渶楂樸�佷笂闄愭渶瀹界殑涓�鏉★級
+        OvertimeWageRule wageRule = resolveOvertimeWageRule(employee);
+        // 骞虫椂鏃惰柂 = 鍩烘湰宸ヨ祫 / 21.75 / 8
+        BigDecimal baseHourlySalary = baseSalary.divide(new BigDecimal("21.75"), 8, RoundingMode.HALF_UP)
                 .divide(new BigDecimal("8"), 8, RoundingMode.HALF_UP);
+
         BigDecimal totalHours = BigDecimal.ZERO;
         BigDecimal totalPay = BigDecimal.ZERO;
-        for (HrmOvertimeApplicationDO application : applications) {
-            BigDecimal hours = application.getDuration() == null ? BigDecimal.ZERO : application.getDuration();
-            HrmOvertimeTypeEnum type = HrmOvertimeTypeEnum.valueOfType(application.getOvertimeType());
-            if (type == null || hours.signum() <= 0) {
-                continue;
+        if (category == HrmEmployeeCategoryEnum.TECHNICIAN || wageRule != null) {
+            // 鎶�宸ワ細1:1锛堜笌骞虫椂鏃惰柂涓�鑷达級锛涙櫘閫氬憳宸ュ懡涓厤缃細鎸夐厤缃浐瀹氭椂钖紝鍧囦笉鍖哄垎鍔犵彮绫诲瀷鍊嶇巼
+            BigDecimal hourlySalary = category == HrmEmployeeCategoryEnum.TECHNICIAN
+                    ? baseHourlySalary : wageRule.hourlyRate();
+            for (HrmOvertimeApplicationDO application : applications) {
+                BigDecimal hours = application.getDuration() == null ? BigDecimal.ZERO : application.getDuration();
+                HrmOvertimeTypeEnum type = HrmOvertimeTypeEnum.valueOfType(application.getOvertimeType());
+                if (type == null || hours.signum() <= 0) {
+                    continue;
+                }
+                totalHours = totalHours.add(hours);
             }
-            BigDecimal multiplier = switch (type) {
-                case WORKDAY -> workdayMultiplier;
-                case REST_DAY -> restDayMultiplier;
-                case LEGAL_HOLIDAY -> legalHolidayMultiplier;
-            };
-            totalHours = totalHours.add(hours);
-            totalPay = totalPay.add(hourlySalary.multiply(hours).multiply(multiplier));
+            // 鎸夊矖浣嶉厤缃皝椤跺姞鐝椂闀�
+            BigDecimal paidHours = wageRule != null && wageRule.maxOvertimeHours() != null
+                    && totalHours.compareTo(wageRule.maxOvertimeHours()) > 0
+                    ? wageRule.maxOvertimeHours() : totalHours;
+            totalPay = hourlySalary.multiply(paidHours);
+        } else {
+            // 鍏煎鏃ч�昏緫锛氭棤宀椾綅閰嶇疆銆佷笖闈炴妧宸�/绠$悊
+            Long structureId = employeeSalary.getSalaryStructureId() != null
+                    ? employeeSalary.getSalaryStructureId() : employee.getSalaryStructureId();
+            HrmSalaryStructureDO structure = structureId == null ? null : salaryStructureMapper.selectById(structureId);
+            BigDecimal workdayMultiplier = structure != null && structure.getOvertimePayRatio() != null
+                    ? structure.getOvertimePayRatio() : HrmOvertimeTypeEnum.WORKDAY.getSalaryMultiplier();
+            BigDecimal restDayMultiplier = structure != null && structure.getRestDayOvertimePayRatio() != null
+                    ? structure.getRestDayOvertimePayRatio() : HrmOvertimeTypeEnum.REST_DAY.getSalaryMultiplier();
+            BigDecimal legalHolidayMultiplier = structure != null && structure.getLegalHolidayOvertimePayRatio() != null
+                    ? structure.getLegalHolidayOvertimePayRatio() : HrmOvertimeTypeEnum.LEGAL_HOLIDAY.getSalaryMultiplier();
+            for (HrmOvertimeApplicationDO application : applications) {
+                BigDecimal hours = application.getDuration() == null ? BigDecimal.ZERO : application.getDuration();
+                HrmOvertimeTypeEnum type = HrmOvertimeTypeEnum.valueOfType(application.getOvertimeType());
+                if (type == null || hours.signum() <= 0) {
+                    continue;
+                }
+                BigDecimal multiplier = switch (type) {
+                    case WORKDAY -> workdayMultiplier;
+                    case REST_DAY -> restDayMultiplier;
+                    case LEGAL_HOLIDAY -> legalHolidayMultiplier;
+                };
+                totalHours = totalHours.add(hours);
+                totalPay = totalPay.add(baseHourlySalary.multiply(hours).multiply(multiplier));
+            }
         }
         return new OvertimeSalary(totalHours.setScale(1, RoundingMode.HALF_UP),
                 totalPay.setScale(2, RoundingMode.HALF_UP));
     }
+
+    /**
+     * 瑙f瀽鍛樺伐宀椾綅瀵瑰簲鐨勫姞鐝伐璧勮鍒欙細鏃惰柂鍙栧懡涓厤缃腑鐨勬渶澶у�硷紱
+     * 涓婇檺鍙栤�滄渶瀹解�濓紙瀛樺湪鏈缃笂闄愮殑閰嶇疆鍒欒涓轰笉闄愶紝鍚﹀垯鍙栨渶澶у�硷級銆�
+     */
+    private OvertimeWageRule resolveOvertimeWageRule(HrmEmployeeDO employee) {
+        if (StrUtil.isEmpty(employee.getPostIds())) {
+            return null;
+        }
+        List<Long> postIds;
+        try {
+            postIds = JSONUtil.toList(employee.getPostIds(), Long.class);
+        } catch (Exception ex) {
+            return null;
+        }
+        if (CollUtil.isEmpty(postIds)) {
+            return null;
+        }
+        List<HrmOvertimeWageConfigDO> configs = overtimeWageConfigMapper.selectEnabledListByPostIds(postIds);
+        if (CollUtil.isEmpty(configs)) {
+            return null;
+        }
+        BigDecimal hourlyRate = null;
+        BigDecimal maxHours = null;
+        boolean unlimited = false;
+        for (HrmOvertimeWageConfigDO config : configs) {
+            if (config.getHourlyRate() != null
+                    && (hourlyRate == null || config.getHourlyRate().compareTo(hourlyRate) > 0)) {
+                hourlyRate = config.getHourlyRate();
+            }
+            if (config.getMaxOvertimeHours() == null) {
+                unlimited = true;
+            } else if (!unlimited && (maxHours == null || config.getMaxOvertimeHours().compareTo(maxHours) > 0)) {
+                maxHours = config.getMaxOvertimeHours();
+            }
+        }
+        if (hourlyRate == null) {
+            return null;
+        }
+        return new OvertimeWageRule(hourlyRate, unlimited ? null : maxHours);
+    }
+
+    private record OvertimeWageRule(BigDecimal hourlyRate, BigDecimal maxOvertimeHours) {}
 
     private record OvertimeSalary(BigDecimal hours, BigDecimal pay) {}
 
@@ -576,6 +665,66 @@
         }
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateSalaryCalculation(HrmSalaryCalculationDO calculation) {
+        HrmSalaryCalculationDO exist = salaryCalculationMapper.selectById(calculation.getId());
+        if (exist == null) {
+            throw exception(SALARY_CALCULATION_NOT_EXISTS);
+        }
+        // 浠呭緟纭鐘舵�佸彲淇敼锛氬凡纭闇�鍏堟挙閿�锛涘凡鍙戞斁涓嶅彲鏀�
+        if (exist.getStatus() == null || !Objects.equals(exist.getStatus(), 0)) {
+            throw exception(SALARY_CALCULATION_UPDATE_FAIL);
+        }
+        // 浠ヤ笅瀛楁涓嶅厑璁搁�氳繃淇敼鎺ュ彛鍙樻洿锛屼竴寰嬩互搴撲腑涓哄噯
+        calculation.setNo(exist.getNo());
+        calculation.setPeriod(exist.getPeriod());
+        calculation.setUserId(exist.getUserId());
+        calculation.setDeptId(exist.getDeptId());
+        calculation.setStatus(exist.getStatus());
+        calculation.setConfirmTime(exist.getConfirmTime());
+        calculation.setConfirmUserId(exist.getConfirmUserId());
+        calculation.setPaymentTime(exist.getPaymentTime());
+        // 閲戦瀛楁涓� null 鏃剁粺涓�鎸� 0 澶勭悊锛歁yBatis-Plus 鐨� updateById 榛樿蹇界暐 null锛�
+        // 鍚﹀垯浼氬嚭鐜般�屽疄鍙戝伐璧勬寜 0 璁$畻銆佷絾鏄庣粏浠嶄繚鐣欐棫鍊笺�嶇殑涓嶄竴鑷�
+        calculation.setBaseSalary(nvl(calculation.getBaseSalary()));
+        calculation.setPerformanceSalary(nvl(calculation.getPerformanceSalary()));
+        calculation.setOvertimePay(nvl(calculation.getOvertimePay()));
+        calculation.setMealAllowance(nvl(calculation.getMealAllowance()));
+        calculation.setTransportAllowance(nvl(calculation.getTransportAllowance()));
+        calculation.setOtherAllowance(nvl(calculation.getOtherAllowance()));
+        calculation.setSocialSecurityDeduction(nvl(calculation.getSocialSecurityDeduction()));
+        calculation.setHousingFundDeduction(nvl(calculation.getHousingFundDeduction()));
+        calculation.setTaxDeduction(nvl(calculation.getTaxDeduction()));
+        calculation.setOtherDeduction(nvl(calculation.getOtherDeduction()));
+        calculation.setLeaveDeduction(nvl(calculation.getLeaveDeduction()));
+        // 瀹炲彂宸ヨ祫鐢卞悗绔噸绠楋紝閬垮厤鍓嶇浼犲叆鍊间笌鏄庣粏涓嶄竴鑷�
+        calculation.setActualSalary(calcActualSalary(calculation));
+        salaryCalculationMapper.updateById(calculation);
+    }
+
+    /**
+     * 璁$畻瀹炲彂宸ヨ祫 = 鏀跺叆椤瑰悎璁� - 鎵i櫎椤瑰悎璁★紝淇濈暀涓や綅灏忔暟
+     */
+    private static BigDecimal calcActualSalary(HrmSalaryCalculationDO c) {
+        BigDecimal income = nvl(c.getBaseSalary())
+                .add(nvl(c.getPerformanceSalary()))
+                .add(nvl(c.getOvertimePay()))
+                .add(nvl(c.getMealAllowance()))
+                .add(nvl(c.getTransportAllowance()))
+                .add(nvl(c.getOtherAllowance()));
+        BigDecimal deduction = nvl(c.getSocialSecurityDeduction())
+                .add(nvl(c.getHousingFundDeduction()))
+                .add(nvl(c.getTaxDeduction()))
+                .add(nvl(c.getOtherDeduction()))
+                .add(nvl(c.getLeaveDeduction()));
+        return income.subtract(deduction).setScale(2, RoundingMode.HALF_UP);
+    }
+
+    private static BigDecimal nvl(BigDecimal v) {
+        return v == null ? BigDecimal.ZERO : v;
+    }
+
     /**
      * 鍐呴儴鐢熸垚鍙戞斁鍙拌处鏂规硶锛堜緵鑷姩鐢熸垚璋冪敤锛�
      */
diff --git a/yudao-module-hrm/src/main/resources/template/contract/contract_labor_simple.docx b/yudao-module-hrm/src/main/resources/template/contract/contract_labor_simple.docx
new file mode 100644
index 0000000..dec68c1
--- /dev/null
+++ b/yudao-module-hrm/src/main/resources/template/contract/contract_labor_simple.docx
Binary files differ
diff --git a/yudao-module-hrm/src/main/resources/template/contract/contract_labor_standard.docx b/yudao-module-hrm/src/main/resources/template/contract/contract_labor_standard.docx
new file mode 100644
index 0000000..3dc11f4
--- /dev/null
+++ b/yudao-module-hrm/src/main/resources/template/contract/contract_labor_standard.docx
Binary files differ
diff --git a/yudao-module-hrm/src/main/resources/template/contract/contract_service.docx b/yudao-module-hrm/src/main/resources/template/contract/contract_service.docx
new file mode 100644
index 0000000..1973d91
--- /dev/null
+++ b/yudao-module-hrm/src/main/resources/template/contract/contract_service.docx
Binary files differ
diff --git a/yudao-module-hrm/src/main/resources/template/contract/original/labor_simple.docx b/yudao-module-hrm/src/main/resources/template/contract/original/labor_simple.docx
new file mode 100644
index 0000000..b74e9f4
--- /dev/null
+++ b/yudao-module-hrm/src/main/resources/template/contract/original/labor_simple.docx
Binary files differ
diff --git a/yudao-module-hrm/src/main/resources/template/contract/original/labor_standard.docx b/yudao-module-hrm/src/main/resources/template/contract/original/labor_standard.docx
new file mode 100644
index 0000000..3ac5a24
--- /dev/null
+++ b/yudao-module-hrm/src/main/resources/template/contract/original/labor_standard.docx
Binary files differ
diff --git a/yudao-module-hrm/src/main/resources/template/contract/original/retire.docx b/yudao-module-hrm/src/main/resources/template/contract/original/retire.docx
new file mode 100644
index 0000000..c249647
--- /dev/null
+++ b/yudao-module-hrm/src/main/resources/template/contract/original/retire.docx
Binary files differ
diff --git a/yudao-module-hrm/src/main/resources/template/contract/original/service.doc b/yudao-module-hrm/src/main/resources/template/contract/original/service.doc
new file mode 100644
index 0000000..b1e1073
--- /dev/null
+++ b/yudao-module-hrm/src/main/resources/template/contract/original/service.doc
Binary files differ

--
Gitblit v1.9.3