From 5cd5a5baa076377f3136338db7a9336d0d570d33 Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期六, 24 十月 2026 19:47:33 +0800
Subject: [PATCH] feat(hrm): 前端同步新疆中亿装配的人力资源模块

---
 src/views/hrm/overtime/index.vue                             |   10 
 src/api/hrm/attendance/holiday/index.ts                      |    5 
 src/api/hrm/employee/index.ts                                |   23 
 src/views/hrm/employee/contract/index.vue                    |  157 ++++-
 src/views/hrm/employee/contract/data.ts                      |    2 
 src/views/hrm/salary/leave-type-config/data.ts               |    2 
 src/views/hrm/salary/overtime-wage/modules/form.vue          |   90 +++
 src/api/hrm/salary/social-security-scheme/index.ts           |    8 
 src/views/hrm/salary/structure/data.ts                       |    2 
 src/views/hrm/overtime/data.ts                               |    2 
 src/views/hrm/employee/data.ts                               |   44 +
 src/views/hrm/attendance/exception/detail/approve/index.vue  |    4 
 src/views/hrm/resignation/index.vue                          |    2 
 src/views/hrm/resignation/detail/approve/index.vue           |    6 
 src/api/hrm/salary/overtime-wage/index.ts                    |   62 ++
 src/views/hrm/attendance/holiday/data.ts                     |   18 
 src/api/hrm/resignation/index.ts                             |    2 
 src/views/hrm/attendance/rule/data.ts                        |   29 +
 src/views/hrm/employee/modules/form.vue                      |   13 
 src/views/hrm/salary/calculation/modules/form.vue            |  120 +++++
 src/views/hrm/salary/employee-social-security/data.ts        |    2 
 src/views/hrm/attendance/record/modules/import-form.vue      |    3 
 src/views/hrm/employee/contract/modules/attachment-modal.vue |   47 +
 src/api/hrm/attendance/rule/index.ts                         |    2 
 src/views/hrm/transfer/data.ts                               |   26 
 src/views/hrm/attendance/exception/data.ts                   |    2 
 src/views/hrm/attendance/holiday/index.vue                   |    5 
 src/views/hrm/leave/detail/approve/index.vue                 |    4 
 src/views/hrm/overtime/detail/approve/index.vue              |    4 
 src/api/hrm/transfer/index.ts                                |    8 
 src/views/hrm/attendance/holiday/modules/form.vue            |   19 
 src/views/hrm/salary/social-security-scheme/index.vue        |   16 
 src/views/hrm/resignation/data.ts                            |    2 
 src/views/hrm/salary/calculation/data.ts                     |   32 
 src/views/hrm/salary/payment/data.ts                         |    2 
 src/views/hrm/leave/data.ts                                  |    2 
 src/views/hrm/salary/overtime-wage/index.vue                 |  125 +++++
 src/views/hrm/salary/social-security-scheme/data.ts          |  101 ++++
 src/api/hrm/employee/contract/index.ts                       |   25 +
 src/views/hrm/transfer/modules/form.vue                      |   67 ++
 src/views/hrm/salary/social-security-scheme/modules/form.vue |    4 
 src/views/hrm/employee/index.vue                             |   48 +
 src/views/hrm/transfer/detail/approve/index.vue              |   12 
 src/views/hrm/attendance/exception/index.vue                 |   10 
 src/views/hrm/leave/index.vue                                |    8 
 src/views/hrm/employee/modules/detail.vue                    |   14 
 src/views/hrm/salary/calculation/index.vue                   |   99 ++++
 src/views/hrm/salary/overtime-wage/data.ts                   |  146 ++++++
 48 files changed, 1,256 insertions(+), 180 deletions(-)

diff --git a/src/api/hrm/attendance/holiday/index.ts b/src/api/hrm/attendance/holiday/index.ts
index b030fac..89da4ec 100644
--- a/src/api/hrm/attendance/holiday/index.ts
+++ b/src/api/hrm/attendance/holiday/index.ts
@@ -7,10 +7,7 @@
   export interface Holiday {
     id?: number;
     name?: string;
-    /** 寮�濮嬫棩鏈� */
-    startDate?: string;
-    /** 缁撴潫鏃ユ湡 */
-    endDate?: string;
+    date?: string;
     type?: number;
     typeName?: string;
     isLegal?: number;
diff --git a/src/api/hrm/attendance/rule/index.ts b/src/api/hrm/attendance/rule/index.ts
index 2ba8920..4645d8f 100644
--- a/src/api/hrm/attendance/rule/index.ts
+++ b/src/api/hrm/attendance/rule/index.ts
@@ -14,6 +14,8 @@
     lateAllowMinutes?: number;
     earlyAllowMinutes?: number;
     overtimeThreshold?: number;
+    effectiveStartDate?: string;
+    effectiveEndDate?: string;
     status?: number;
     remark?: string;
     createTime?: string;
diff --git a/src/api/hrm/employee/contract/index.ts b/src/api/hrm/employee/contract/index.ts
index a252c3e..8efc7b2 100644
--- a/src/api/hrm/employee/contract/index.ts
+++ b/src/api/hrm/employee/contract/index.ts
@@ -154,3 +154,28 @@
     { file, updateSupport },
   );
 }
+
+/** 鐢熸垚骞朵笅杞藉悎鍚屾枃妗o紙docx锛�
+ * @param templateType 1-鍔冲姩鍚堝悓(绠�鐗�) 2-鍔冲姩鍚堝悓(鏍囧噯) 3-鍔冲姟鍚堝悓
+ */
+export function generateContractDocx(id: number, templateType: number) {
+  return requestClient.download(
+    `/hrm/employee-contract/generate-docx?id=${id}&templateType=${templateType}`,
+  );
+}
+
+/** 鐢熸垚鍚堝悓骞跺洖瀛樹负鍚堝悓闄勪欢锛岃繑鍥� blobId */
+export function generateContractArchive(id: number, templateType: number) {
+  return requestClient.post<number>(
+    `/hrm/employee-contract/generate?id=${id}&templateType=${templateType}`,
+  );
+}
+
+/** 涓嬭浇鍚堝悓绌虹櫧妯℃澘
+ * @param type 1-鍔冲姩鍚堝悓(绠�鐗�) 2-鍔冲姩鍚堝悓(鏍囧噯) 3-鍔冲姟鍚堝悓 4-閫�浼戣繑鑱樺悎鍚�
+ */
+export function downloadContractTemplate(type: number) {
+  return requestClient.download(
+    `/hrm/employee-contract/download-template?type=${type}`,
+  );
+}
diff --git a/src/api/hrm/employee/index.ts b/src/api/hrm/employee/index.ts
index 4c0360a..fdf7207 100644
--- a/src/api/hrm/employee/index.ts
+++ b/src/api/hrm/employee/index.ts
@@ -27,6 +27,8 @@
     regularDate?: string;
     leaveDate?: string;
     employeeStatus?: number;
+    /** 鍛樺伐绫诲埆锛�1-鏅�氬憳宸ワ紝2-鎶�宸ワ紝3-绠$悊 */
+    employeeCategory?: number;
     annualLeaveBalance?: number;
     sickLeaveBalance?: number;
     salaryStructureId?: number;
@@ -44,6 +46,10 @@
     workHistories?: WorkHistory[];
     /** 绱ф�ヨ仈绯讳汉鍒楄〃 */
     emergencyContacts?: EmergencyContact[];
+    /** 闄勪欢 blobId 鍒楄〃锛堜繚瀛樻椂浼犲叆锛� */
+    blobIds?: number[];
+    /** 闄勪欢鍒楄〃锛堣鎯呮椂杩斿洖锛� */
+    attachmentList?: { id: number; name?: string; url?: string }[];
   }
 
   /** 鏁欒偛缁忓巻 */
@@ -85,8 +91,13 @@
     id: number;
     employeeNo: string;
     name: string;
+    /** 閮ㄩ棬ID */
+    deptId?: number;
     deptName?: string;
+    /** 宀椾綅ID鍒楄〃 */
+    postIds?: number[];
     postName?: string;
+    employeeStatus?: number;
   }
 
   /** 鍛樺伐瀵煎叆缁撴灉 */
@@ -169,3 +180,15 @@
 export function deleteEmergencyContact(id: number) {
   return requestClient.delete(`/hrm/employee/emergency-contact/delete?id=${id}`);
 }
+
+/** 鍛樺伐杞锛堜粎鍔冲姩鍚堝悓鍙浆姝o級 */
+export function regularizeEmployee(id: number) {
+  return requestClient.put(`/hrm/employee/regular?id=${id}`);
+}
+
+/** 寰呰浆姝f彁閱掑垪琛紙璇曠敤涓�佸姵鍔ㄥ悎鍚屻�佽瘯鐢ㄦ湡鍗冲皢鍒版湡锛� */
+export function getRegularizeReminders(days = 7) {
+  return requestClient.get<HrmEmployeeApi.Employee[]>(
+    `/hrm/employee/regularize-reminders?days=${days}`,
+  );
+}
diff --git a/src/api/hrm/resignation/index.ts b/src/api/hrm/resignation/index.ts
index 88c8929..8b90cd2 100644
--- a/src/api/hrm/resignation/index.ts
+++ b/src/api/hrm/resignation/index.ts
@@ -58,7 +58,7 @@
 
 /** 鎻愪氦绂昏亴鐢宠锛堝彂璧峰鎵癸級 */
 export function submitResignation(id: number) {
-  return requestClient.post(`/hrm/resignation/submit?id=${id}&processDefinitionKey=hrm_resignation_approve`);
+  return requestClient.post(`/hrm/resignation/submit?id=${id}`);
 }
 
 /** 鎾ら攢绂昏亴鐢宠 */
diff --git a/src/api/hrm/salary/overtime-wage/index.ts b/src/api/hrm/salary/overtime-wage/index.ts
new file mode 100644
index 0000000..daf9884
--- /dev/null
+++ b/src/api/hrm/salary/overtime-wage/index.ts
@@ -0,0 +1,62 @@
+import { requestClient } from '#/api/request';
+
+export namespace HrmOvertimeWageApi {
+  /** 宀椾綅鍔犵彮宸ヨ祫閰嶇疆 */
+  export interface OvertimeWageConfig {
+    id?: number;
+    /** 宀椾綅ID */
+    postId?: number;
+    /** 宀椾綅鍚嶇О */
+    postName?: string;
+    /** 鍔犵彮鏃惰柂锛堝厓/灏忔椂锛夛紝榛樿 20 */
+    hourlyRate?: number;
+    /** 姣忔湀鏈�澶у姞鐝椂闀夸笂闄愶紙灏忔椂锛夛紝涓虹┖琛ㄧず涓嶉檺 */
+    maxOvertimeHours?: number;
+    /** 鐘舵�侊細0-鍚敤锛�1-绂佺敤 */
+    status?: number;
+    remark?: string;
+    createTime?: string;
+  }
+
+  /** 鏌ヨ鍙傛暟 */
+  export interface OvertimeWageConfigQueryParam {
+    postId?: number;
+    status?: number;
+  }
+}
+
+/** 鏌ヨ宀椾綅鍔犵彮宸ヨ祫閰嶇疆鍒楄〃 */
+export function getOvertimeWageConfigList(
+  params?: HrmOvertimeWageApi.OvertimeWageConfigQueryParam,
+) {
+  return requestClient.get<HrmOvertimeWageApi.OvertimeWageConfig[]>(
+    '/hrm/salary/overtime-wage/list',
+    { params },
+  );
+}
+
+/** 鏌ヨ宀椾綅鍔犵彮宸ヨ祫閰嶇疆璇︽儏 */
+export function getOvertimeWageConfig(id: number) {
+  return requestClient.get<HrmOvertimeWageApi.OvertimeWageConfig>(
+    `/hrm/salary/overtime-wage/get?id=${id}`,
+  );
+}
+
+/** 鏂板宀椾綅鍔犵彮宸ヨ祫閰嶇疆 */
+export function createOvertimeWageConfig(
+  data: HrmOvertimeWageApi.OvertimeWageConfig,
+) {
+  return requestClient.post('/hrm/salary/overtime-wage/create', data);
+}
+
+/** 鏇存柊宀椾綅鍔犵彮宸ヨ祫閰嶇疆 */
+export function updateOvertimeWageConfig(
+  data: HrmOvertimeWageApi.OvertimeWageConfig,
+) {
+  return requestClient.put('/hrm/salary/overtime-wage/update', data);
+}
+
+/** 鍒犻櫎宀椾綅鍔犵彮宸ヨ祫閰嶇疆 */
+export function deleteOvertimeWageConfig(id: number) {
+  return requestClient.delete(`/hrm/salary/overtime-wage/delete?id=${id}`);
+}
diff --git a/src/api/hrm/salary/social-security-scheme/index.ts b/src/api/hrm/salary/social-security-scheme/index.ts
index 4b1c69a..fcd385c 100644
--- a/src/api/hrm/salary/social-security-scheme/index.ts
+++ b/src/api/hrm/salary/social-security-scheme/index.ts
@@ -16,6 +16,14 @@
     unemploymentPersonalRatio?: number;
     workInjuryRatio?: number;
     maternityRatio?: number;
+    /** 澶х梾鍖荤枟浼佷笟缂寸撼姣斾緥 */
+    seriousIllnessCompanyRatio?: number;
+    /** 澶х梾鍖荤枟涓汉缂寸撼姣斾緥 */
+    seriousIllnessPersonalRatio?: number;
+    /** 闀挎湡鎶ょ悊浼佷笟缂寸撼姣斾緥 */
+    longTermCareCompanyRatio?: number;
+    /** 闀挎湡鎶ょ悊涓汉缂寸撼姣斾緥 */
+    longTermCarePersonalRatio?: number;
     housingFundCompanyRatio?: number;
     housingFundPersonalRatio?: number;
     status?: number;
diff --git a/src/api/hrm/transfer/index.ts b/src/api/hrm/transfer/index.ts
index a18488d..926f8f1 100644
--- a/src/api/hrm/transfer/index.ts
+++ b/src/api/hrm/transfer/index.ts
@@ -7,8 +7,10 @@
   /** 璋冨矖鐢宠 */
   export interface Transfer {
     id?: number;
-    employeeId?: number;
-    employeeName?: string;
+    /** 璋冨矖浜猴紙鍛樺伐ID锛� */
+    userId?: number;
+    /** 璋冨矖浜哄鍚� */
+    userName?: string;
     currentDeptId?: number;
     currentDeptName?: string;
     currentPostId?: number;
@@ -59,7 +61,7 @@
 
 /** 鎻愪氦璋冨矖鐢宠锛堝彂璧峰鎵癸級 */
 export function submitTransfer(id: number) {
-  return requestClient.post(`/hrm/transfer/submit?id=${id}&processDefinitionKey=hrm_transfer_approve`);
+  return requestClient.post(`/hrm/transfer/submit?id=${id}`);
 }
 
 /** 鎾ら攢璋冨矖鐢宠 */
diff --git a/src/views/hrm/attendance/exception/data.ts b/src/views/hrm/attendance/exception/data.ts
index ae61c76..6c6784d 100644
--- a/src/views/hrm/attendance/exception/data.ts
+++ b/src/views/hrm/attendance/exception/data.ts
@@ -129,7 +129,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/attendance/exception/detail/approve/index.vue b/src/views/hrm/attendance/exception/detail/approve/index.vue
index b2fb2fb..e0fef3a 100644
--- a/src/views/hrm/attendance/exception/detail/approve/index.vue
+++ b/src/views/hrm/attendance/exception/detail/approve/index.vue
@@ -6,7 +6,7 @@
 
 import { ContentWrap } from '@vben/common-ui';
 import { DICT_TYPE } from '@vben/constants';
-import { formatDateTime, formatDate } from '@vben/utils';
+import { formatDateTime } from '@vben/utils';
 
 import { Spin } from 'ant-design-vue';
 
@@ -49,7 +49,7 @@
     {
       label: '鍒涘缓鏃堕棿',
       field: 'createTime',
-      render: (val) => formatDate(val) as string,
+      render: (val) => formatDateTime(val) as string,
     },
   ] as DescriptionItemSchema[],
 });
diff --git a/src/views/hrm/attendance/exception/index.vue b/src/views/hrm/attendance/exception/index.vue
index 23522fb..acd5d7a 100644
--- a/src/views/hrm/attendance/exception/index.vue
+++ b/src/views/hrm/attendance/exception/index.vue
@@ -1,5 +1,4 @@
 <script lang="ts" setup>
-import { automaticApproval } from '#/store/audit-policy';
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { HrmAttendanceExceptionApi } from '#/api/hrm/attendance/exception';
 
@@ -49,15 +48,10 @@
 
 /** 鎻愪氦鑰冨嫟寮傚父鐢宠 */
 async function handleSubmit(row: HrmAttendanceExceptionApi.AttendanceException) {
-  const res = automaticApproval.value ? [] : await getAttendanceExceptionApproveProcessList();
+  const res = await getAttendanceExceptionApproveProcessList();
   processList.value = res;
   currentRow.value = row;
   selectedProcessKey.value = undefined;
-  if (automaticApproval.value) {
-    selectedProcessKey.value = 'hrm_attendance_exception';
-    await confirmSubmit();
-    return;
-  }
   submitModalVisible.value = true;
 }
 
@@ -70,7 +64,7 @@
   submitLoading.value = true;
   try {
     await submitAttendanceException(currentRow.value!.id!, selectedProcessKey.value);
-    message.success(automaticApproval.value ? '宸叉彁浜ょ敓鏁�' : '鎻愪氦瀹℃壒鎴愬姛');
+    message.success('鎻愪氦瀹℃壒鎴愬姛');
     submitModalVisible.value = false;
     handleRefresh();
   } finally {
diff --git a/src/views/hrm/attendance/holiday/data.ts b/src/views/hrm/attendance/holiday/data.ts
index 29f871a..822451b 100644
--- a/src/views/hrm/attendance/holiday/data.ts
+++ b/src/views/hrm/attendance/holiday/data.ts
@@ -29,10 +29,11 @@
       rules: 'required',
     },
     {
-      fieldName: 'dateRange',
-      label: '鏃ユ湡鍖洪棿',
-      component: 'RangePicker',
+      fieldName: 'date',
+      label: '鏃ユ湡',
+      component: 'DatePicker',
       componentProps: {
+        placeholder: '閫夋嫨鏃ユ湡',
         valueFormat: 'YYYY-MM-DD',
         style: { width: '100%' },
       },
@@ -125,14 +126,7 @@
 export function useGridColumns(): VxeTableGridOptions<HrmAttendanceHolidayApi.Holiday>['columns'] {
   return [
     { field: 'name', title: '鑺傚亣鏃ュ悕绉�', minWidth: 150 },
-    {
-      field: 'startDate',
-      title: '鏃ユ湡鍖洪棿',
-      minWidth: 200,
-      slots: {
-        default: 'dateRange',
-      },
-    },
+    { field: 'date', title: '鏃ユ湡', width: 120 },
     {
       field: 'type',
       title: '绫诲瀷',
@@ -155,7 +149,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/attendance/holiday/index.vue b/src/views/hrm/attendance/holiday/index.vue
index e5e0b51..8a33871 100644
--- a/src/views/hrm/attendance/holiday/index.vue
+++ b/src/views/hrm/attendance/holiday/index.vue
@@ -114,11 +114,6 @@
           ]"
         />
       </template>
-      <template #dateRange="{ row }">
-        <span v-if="!row.startDate && !row.endDate">-</span>
-        <span v-else-if="row.startDate === row.endDate">{{ row.startDate }}</span>
-        <span v-else>{{ row.startDate }} ~ {{ row.endDate }}</span>
-      </template>
       <template #isLegal="{ row }">
         <Tag v-if="row.isLegal === 1" color="red">娉曞畾</Tag>
         <span v-else>-</span>
diff --git a/src/views/hrm/attendance/holiday/modules/form.vue b/src/views/hrm/attendance/holiday/modules/form.vue
index 614daa0..2ae9c5d 100644
--- a/src/views/hrm/attendance/holiday/modules/form.vue
+++ b/src/views/hrm/attendance/holiday/modules/form.vue
@@ -53,15 +53,7 @@
       return;
     }
     modalApi.lock();
-    const values = (await formApi.getValues()) as HrmAttendanceHolidayApi.Holiday & {
-      dateRange?: string[];
-    };
-    const { dateRange, ...rest } = values;
-    const data: HrmAttendanceHolidayApi.Holiday = {
-      ...rest,
-      startDate: dateRange?.[0],
-      endDate: dateRange?.[1],
-    };
+    const data = (await formApi.getValues()) as HrmAttendanceHolidayApi.Holiday;
     try {
       if (formType.value === 'update') {
         await updateAttendanceHoliday(data);
@@ -89,14 +81,7 @@
     }
     modalApi.lock();
     try {
-      const detail = await getAttendanceHoliday(data.id);
-      await formApi.setValues({
-        ...detail,
-        dateRange:
-          detail.startDate && detail.endDate
-            ? [detail.startDate, detail.endDate]
-            : undefined,
-      });
+      await formApi.setValues(await getAttendanceHoliday(data.id));
     } finally {
       modalApi.unlock();
     }
diff --git a/src/views/hrm/attendance/record/modules/import-form.vue b/src/views/hrm/attendance/record/modules/import-form.vue
index e20e2cb..ccc0e50 100644
--- a/src/views/hrm/attendance/record/modules/import-form.vue
+++ b/src/views/hrm/attendance/record/modules/import-form.vue
@@ -31,8 +31,7 @@
       emit('success');
       // 鍚庣杩斿洖瀵煎叆缁撴灉锛堝惈澶辫触鍘熷洜锛屼緥濡傗�滀互涓嬪憳宸ヤ笉瀛樺湪...锛涢渶琛ュ厖鎵嬫満鍙�...鈥濓級
       if (res && res.length > 0) {
-        // 澶辫触鏃跺悗绔細鎷间笂銆屾湭鑳藉鍏ワ細銆嶆槑缁嗘锛岀敤瀹冨垽瀹氾紝閬垮厤鎴愬姛鏂囨閲屽嚭鐜般�屾湭銆嶅氨璇姤璀﹀憡
-        message[res.includes('鏈兘瀵煎叆') ? 'warning' : 'success'](res);
+        message[res.includes('鏈�') || res.includes('涓嶅畬鏁�') ? 'warning' : 'success'](res);
       } else {
         message.success('瀵煎叆鎴愬姛');
       }
diff --git a/src/views/hrm/attendance/rule/data.ts b/src/views/hrm/attendance/rule/data.ts
index 50bca13..718e3b8 100644
--- a/src/views/hrm/attendance/rule/data.ts
+++ b/src/views/hrm/attendance/rule/data.ts
@@ -106,6 +106,28 @@
       },
     },
     {
+      fieldName: 'effectiveStartDate',
+      label: '鐢熸晥寮�濮嬫棩鏈�',
+      component: 'DatePicker',
+      componentProps: {
+        placeholder: '涓嶉�夎〃绀轰笉闄�',
+        valueFormat: 'YYYY-MM-DD',
+        format: 'YYYY-MM-DD',
+        style: { width: '100%' },
+      },
+    },
+    {
+      fieldName: 'effectiveEndDate',
+      label: '鐢熸晥缁撴潫鏃ユ湡',
+      component: 'DatePicker',
+      componentProps: {
+        placeholder: '涓嶉�夎〃绀洪暱鏈熸湁鏁�',
+        valueFormat: 'YYYY-MM-DD',
+        format: 'YYYY-MM-DD',
+        style: { width: '100%' },
+      },
+    },
+    {
       fieldName: 'status',
       label: '鐘舵��',
       component: 'RadioGroup',
@@ -186,6 +208,13 @@
     { field: 'earlyAllowMinutes', title: '鏃╅��鍏佽(鍒嗛挓)', width: 120 },
     { field: 'overtimeThreshold', title: '鍔犵彮璧风畻(灏忔椂)', width: 120 },
     {
+      field: 'effectiveStartDate',
+      title: '鐢熸晥鍖洪棿',
+      minWidth: 200,
+      formatter: ({ row }) =>
+        `${row.effectiveStartDate || '涓嶉檺'} ~ ${row.effectiveEndDate || '涓嶉檺'}`,
+    },
+    {
       field: 'status',
       title: '鐘舵��',
       width: 80,
diff --git a/src/views/hrm/employee/contract/data.ts b/src/views/hrm/employee/contract/data.ts
index aa828d8..a978d4c 100644
--- a/src/views/hrm/employee/contract/data.ts
+++ b/src/views/hrm/employee/contract/data.ts
@@ -285,7 +285,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/employee/contract/index.vue b/src/views/hrm/employee/contract/index.vue
index 02aa33c..53c329f 100644
--- a/src/views/hrm/employee/contract/index.vue
+++ b/src/views/hrm/employee/contract/index.vue
@@ -3,12 +3,17 @@
 import type { HrmEmployeeContractApi } from '#/api/hrm/employee/contract';
 
 import { Page, useVbenModal } from '#/packages/effects/common-ui/src';
+import { downloadFileFromBlobPart } from '#/packages/utils/src';
 
-import { message, Tag } from 'ant-design-vue';
+import { IconifyIcon } from '@vben/icons';
+import { Button, Dropdown, Menu, message, Modal, Tag } from 'ant-design-vue';
 
 import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
 import {
   deleteEmployeeContract,
+  downloadContractTemplate,
+  generateContractArchive,
+  generateContractDocx,
   getEmployeeContractPage,
 } from '#/api/hrm/employee/contract';
 import { $t } from '#/locales';
@@ -17,6 +22,7 @@
 import Form from './modules/form.vue';
 import ImportForm from './modules/import-form.vue';
 import Terminate from './modules/terminate.vue';
+import Attachment from './modules/attachment-modal.vue';
 
 const [FormModal, formModalApi] = useVbenModal({
   connectedComponent: Form,
@@ -30,6 +36,11 @@
 
 const [TerminateModal, terminateModalApi] = useVbenModal({
   connectedComponent: Terminate,
+  destroyOnClose: true,
+});
+
+const [AttachmentModal, attachmentModalApi] = useVbenModal({
+  connectedComponent: Attachment,
   destroyOnClose: true,
 });
 
@@ -48,6 +59,21 @@
   importModalApi.open();
 }
 
+/** 涓嬭浇鍚堝悓绌虹櫧妯℃澘锛歵ype 1-鍔冲姩鍚堝悓绠�鐗� 2-鍔冲姩鍚堝悓鏍囧噯 3-鍔冲姟鍚堝悓 */
+const TEMPLATE_NAMES: Record<number, string> = {
+  1: '鍔冲姩鍚堝悓锛堢畝鐗堬級.docx',
+  2: '鍔冲姩鍚堝悓锛堟爣鍑嗭級.docx',
+  3: '鍔冲姟鍚堝悓.doc',
+};
+async function handleDownloadTemplate(type: number) {
+  const data = await downloadContractTemplate(type);
+  downloadFileFromBlobPart({
+    fileName: TEMPLATE_NAMES[type] || '鍚堝悓妯℃澘',
+    source: data,
+  });
+  message.success('妯℃澘宸蹭笅杞�');
+}
+
 /** 缂栬緫鍚堝悓 */
 function handleEdit(row: HrmEmployeeContractApi.EmployeeContract) {
   formModalApi.setData({ id: row.id, formType: 'update' }).open();
@@ -61,6 +87,60 @@
 /** 瑙i櫎/缁堟鍚堝悓 */
 function handleTerminate(row: HrmEmployeeContractApi.EmployeeContract) {
   terminateModalApi.setData({ id: row.id }).open();
+}
+
+/** 鏌ョ湅鍚堝悓闄勪欢 */
+function handleAttachments(row: HrmEmployeeContractApi.EmployeeContract) {
+  attachmentModalApi.setData({ id: row.id }).open();
+}
+
+/** 鐢熸垚鍚堝悓锛坉ocx锛夛細templateType 1-鍔冲姩鍚堝悓绠�鐗� 2-鍔冲姩鍚堝悓鏍囧噯 3-鍔冲姟鍚堝悓 */
+async function handleGenerate(
+  row: HrmEmployeeContractApi.EmployeeContract,
+  templateType: number,
+) {
+  // 1. 鐢熸垚骞跺洖瀛樹负鍚堝悓闄勪欢
+  await generateContractArchive(row.id!, templateType);
+  // 2. 鍚屾椂涓嬭浇涓�浠�
+  const data = await generateContractDocx(row.id!, templateType);
+  const genName =
+    { 1: '鍔冲姩鍚堝悓(绠�鐗�).docx', 2: '鍔冲姩鍚堝悓(鏍囧噯).docx', 3: '鍔冲姟鍚堝悓.docx' }[
+      templateType
+    ] || '鍚堝悓.docx';
+  downloadFileFromBlobPart({
+    fileName: `${row.contractNo || row.id}-${genName}`,
+    source: data,
+  });
+  message.success('鍚堝悓宸茬敓鎴愶紝骞跺綊妗e埌璇ュ悎鍚岄檮浠�');
+  handleRefresh();
+}
+
+/** 鈥滄洿澶氣�濊彍鍗曪細淇敼 / 缁 / 瑙i櫎缁堟 / 鍒犻櫎 */
+function handleMore({ key }: { key: number | string }, row: HrmEmployeeContractApi.EmployeeContract) {
+  switch (key) {
+    case 'edit': {
+      handleEdit(row);
+      break;
+    }
+    case 'renew': {
+      handleRenew(row);
+      break;
+    }
+    case 'terminate': {
+      handleTerminate(row);
+      break;
+    }
+    case 'delete': {
+      Modal.confirm({
+        title: `纭鍒犻櫎鍚堝悓銆�${row.contractNo || row.id}銆戝悧锛焋,
+        okText: '鍒犻櫎',
+        okType: 'danger',
+        cancelText: '鍙栨秷',
+        onOk: () => handleDelete(row),
+      });
+      break;
+    }
+  }
 }
 
 /** 鍒犻櫎鍚堝悓 */
@@ -110,6 +190,7 @@
     <FormModal @success="handleRefresh" />
     <ImportModal @success="handleRefresh" />
     <TerminateModal @success="handleRefresh" />
+    <AttachmentModal />
     <Grid table-title="鍛樺伐鍚堝悓鍒楄〃">
       <template #parentNo="{ row }">
         <span>{{ row.parentNo || '-' }}</span>
@@ -119,6 +200,19 @@
         <span v-else>-</span>
       </template>
       <template #toolbar-tools>
+        <Dropdown>
+          <Button class="mr-2" type="primary">
+            涓嬭浇鍚堝悓妯℃澘 <IconifyIcon class="size-3" icon="lucide:chevron-down" />
+          </Button>
+          <template #overlay>
+            <Menu @click="({ key }) => handleDownloadTemplate(Number(key))">
+              <Menu.Item key="1">鍔冲姩鍚堝悓锛堢畝鐗堬級</Menu.Item>
+              <Menu.Item key="2">鍔冲姩鍚堝悓锛堟爣鍑嗭級</Menu.Item>
+              <Menu.Item key="3">鍔冲姟鍚堝悓</Menu.Item>
+              <Menu.Item key="4">閫�浼戣繑鑱樺悎鍚�</Menu.Item>
+            </Menu>
+          </template>
+        </Dropdown>
         <TableAction
           :actions="[
             {
@@ -139,44 +233,29 @@
         />
       </template>
       <template #actions="{ row }">
-        <TableAction
-          :actions="[
-            {
-              label: '缁',
-              type: 'link',
-              icon: ACTION_ICON.ADD,
-              auth: ['hrm:employee-contract:create'],
-              ifShow: isTerminable(row),
-              onClick: handleRenew.bind(null, row),
-            },
-            {
-              label: $t('common.edit'),
-              type: 'link',
-              icon: ACTION_ICON.EDIT,
-              auth: ['hrm:employee-contract:update'],
-              onClick: handleEdit.bind(null, row),
-            },
-            {
-              label: '瑙i櫎/缁堟',
-              type: 'link',
-              icon: ACTION_ICON.CLOSE,
-              auth: ['hrm:employee-contract:update'],
-              ifShow: isTerminable(row),
-              onClick: handleTerminate.bind(null, row),
-            },
-            {
-              label: $t('common.delete'),
-              type: 'link',
-              danger: true,
-              icon: ACTION_ICON.DELETE,
-              auth: ['hrm:employee-contract:delete'],
-              popConfirm: {
-                title: $t('ui.actionMessage.deleteConfirm', ['鍛樺伐鍚堝悓']),
-                confirm: handleDelete.bind(null, row),
-              },
-            },
-          ]"
-        />
+        <Dropdown>
+          <a class="text-primary" @click.prevent>鐢熸垚鍚堝悓 <IconifyIcon class="size-3" icon="lucide:chevron-down" /></a>
+          <template #overlay>
+            <Menu @click="({ key }) => handleGenerate(row, Number(key))">
+              <Menu.Item key="1">鍔冲姩鍚堝悓锛堢畝鐗堬級</Menu.Item>
+              <Menu.Item key="2">鍔冲姩鍚堝悓锛堟爣鍑嗭級</Menu.Item>
+              <Menu.Item key="3">鍔冲姟鍚堝悓</Menu.Item>
+            </Menu>
+          </template>
+        </Dropdown>
+        <a class="ml-3 text-primary" @click="handleAttachments(row)">闄勪欢</a>
+        <Dropdown>
+          <a class="ml-3 text-primary" @click.prevent>鏇村 <IconifyIcon class="size-3" icon="lucide:chevron-down" /></a>
+          <template #overlay>
+            <Menu @click="(e) => handleMore(e, row)">
+              <Menu.Item key="edit">淇敼</Menu.Item>
+              <Menu.Item v-if="isTerminable(row)" key="renew">缁</Menu.Item>
+              <Menu.Item v-if="isTerminable(row)" key="terminate">瑙i櫎/缁堟</Menu.Item>
+              <Menu.Divider />
+              <Menu.Item danger key="delete">鍒犻櫎</Menu.Item>
+            </Menu>
+          </template>
+        </Dropdown>
       </template>
     </Grid>
   </Page>
diff --git a/src/views/hrm/employee/contract/modules/attachment-modal.vue b/src/views/hrm/employee/contract/modules/attachment-modal.vue
new file mode 100644
index 0000000..56817be
--- /dev/null
+++ b/src/views/hrm/employee/contract/modules/attachment-modal.vue
@@ -0,0 +1,47 @@
+<script lang="ts" setup>
+import type { HrmEmployeeContractApi } from '#/api/hrm/employee/contract';
+
+import { ref } from 'vue';
+
+import { useVbenModal } from '#/packages/effects/common-ui/src';
+
+import { getEmployeeContract } from '#/api/hrm/employee/contract';
+
+const attachments = ref<HrmEmployeeContractApi.AttachmentItem[]>([]);
+const loading = ref(false);
+
+const [Modal, modalApi] = useVbenModal({
+  async onOpenChange(isOpen: boolean) {
+    if (!isOpen) {
+      return;
+    }
+    const data = modalApi.getData<{ id?: number }>();
+    if (!data?.id) {
+      return;
+    }
+    loading.value = true;
+    try {
+      const detail = await getEmployeeContract(data.id);
+      attachments.value = detail.attachmentList || [];
+    } finally {
+      loading.value = false;
+    }
+  },
+});
+</script>
+
+<template>
+  <Modal title="鍚堝悓闄勪欢" class="w-[560px]">
+    <div v-if="loading" class="py-6 text-center text-gray-400">鍔犺浇涓�...</div>
+    <div v-else-if="attachments.length === 0" class="py-6 text-center text-gray-400">
+      鏆傛棤闄勪欢锛堝彲鍦ㄣ�屾洿澶� 鈫� 淇敼銆嶉噷涓婁紶锛屾垨鐢ㄣ�岀敓鎴愬悎鍚屻�嶇敓鎴愬悗鑷姩褰掓。锛�
+    </div>
+    <ul v-else class="max-h-[50vh] overflow-auto pl-5">
+      <li v-for="f in attachments" :key="f.id" class="mb-2 list-disc">
+        <a :href="f.url" target="_blank" rel="noopener" class="text-primary">
+          {{ f.name || `闄勪欢${f.id}` }}
+        </a>
+      </li>
+    </ul>
+  </Modal>
+</template>
diff --git a/src/views/hrm/employee/data.ts b/src/views/hrm/employee/data.ts
index 93cc220..1307eea 100644
--- a/src/views/hrm/employee/data.ts
+++ b/src/views/hrm/employee/data.ts
@@ -153,6 +153,18 @@
       rules: z.number().default(1),
     },
     {
+      fieldName: 'employeeCategory',
+      label: '鍛樺伐绫诲埆',
+      component: 'RadioGroup',
+      componentProps: {
+        buttonStyle: 'solid',
+        optionType: 'button',
+        options: getDictOptions(DICT_TYPE.HRM_EMPLOYEE_CATEGORY, 'number'),
+      },
+      rules: z.number().default(1),
+      help: '鏅�氬憳宸ユ寜宀椾綅鍔犵彮鏃惰柂锛涙妧宸ュ姞鐝寜 1:1锛涚鐞嗕笉璁″姞鐝伐璧�',
+    },
+    {
       fieldName: 'birthday',
       label: '鍑虹敓鏃ユ湡',
       component: 'DatePicker',
@@ -292,6 +304,18 @@
         placeholder: '璇疯緭鍏ュ眳浣忓湴鍧�',
       },
     },
+    {
+      fieldName: 'blobIds',
+      label: '闄勪欢',
+      component: 'FileUpload',
+      componentProps: {
+        valueKey: 'id',
+        maxNumber: 10,
+        multiple: true,
+        help: '鍙笂浼犺韩浠借瘉銆佸鍘嗚瘉涔︺�佷綋妫�鎶ュ憡绛夎祫鏂欎綔涓虹暀妗�',
+      },
+      formItemClass: 'col-span-2',
+    },
   ];
 }
 
@@ -343,6 +367,16 @@
         placeholder: '璇烽�夋嫨鍛樺伐鐘舵��',
       },
     },
+    {
+      fieldName: 'employeeCategory',
+      label: '鍛樺伐绫诲埆',
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        options: getDictOptions(DICT_TYPE.HRM_EMPLOYEE_CATEGORY, 'number'),
+        placeholder: '璇烽�夋嫨鍛樺伐绫诲埆',
+      },
+    },
   ];
 }
 
@@ -380,12 +414,20 @@
         default: 'employeeStatus',
       },
     },
+    {
+      field: 'employeeCategory',
+      title: '鍛樺伐绫诲埆',
+      width: 100,
+      slots: {
+        default: 'employeeCategory',
+      },
+    },
     { field: 'hireDate', title: '鍏ヨ亴鏃ユ湡', width: 110 },
     {
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/employee/index.vue b/src/views/hrm/employee/index.vue
index 9f5cb70..57f2d62 100644
--- a/src/views/hrm/employee/index.vue
+++ b/src/views/hrm/employee/index.vue
@@ -5,15 +5,15 @@
 import { Page, useVbenModal } from '#/packages/effects/common-ui/src';
 import { downloadFileFromBlobPart } from '#/packages/utils/src';
 
-import { Button, message, Progress, Tag } from 'ant-design-vue';
+import { Button, message, Progress, Tag, Alert } from 'ant-design-vue';
 
-import { ref } from 'vue';
+import { onMounted, ref } from 'vue';
 
 import { DICT_TYPE } from '#/packages/constants/src';
 import { getDictLabel } from '#/packages/effects/hooks/src';
 
 import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
-import { deleteEmployee, exportEmployee, getEmployeePage } from '#/api/hrm/employee';
+import { deleteEmployee, exportEmployee, getEmployeePage, getRegularizeReminders, regularizeEmployee } from '#/api/hrm/employee';
 import { $t } from '#/locales';
 
 import { useGridColumns, useGridFormSchema } from './data';
@@ -116,6 +116,26 @@
   importModalApi.open();
 }
 
+/** 寰呰浆姝f彁閱掓暟 */
+const regularizeCount = ref(0);
+async function refreshRegularizeReminders() {
+  try {
+    const list = await getRegularizeReminders(7);
+    regularizeCount.value = list?.length ?? 0;
+  } catch {
+    regularizeCount.value = 0;
+  }
+}
+onMounted(refreshRegularizeReminders);
+
+/** 鍛樺伐杞锛堜粎鍔冲姩鍚堝悓鍙浆姝o級 */
+async function handleRegularize(row: HrmEmployeeApi.Employee) {
+  await regularizeEmployee(row.id!);
+  message.success(`銆�${row.name}銆戝凡杞`);
+  handleRefresh();
+  refreshRegularizeReminders();
+}
+
 const [Grid, gridApi] = useVbenVxeGrid({
   formOptions: {
     schema: useGridFormSchema(),
@@ -150,6 +170,13 @@
   <Page auto-content-height>
     <ImportModal @success="handleRefresh" />
     <FormModal @success="handleRefresh" />
+    <Alert
+      v-if="regularizeCount > 0"
+      class="mb-3"
+      :message="`寰呰浆姝f彁閱掞細鏈� ${regularizeCount} 鍚嶅憳宸ヨ瘯鐢ㄦ湡鍗冲皢鍒版湡锛岃鍙婃椂杞`"
+      show-icon
+      type="warning"
+    />
     <Grid table-title="鍛樺伐鍒楄〃">
       <template #toolbar-tools>
         <TableAction
@@ -191,6 +218,11 @@
           {{ getDictLabel(DICT_TYPE.HRM_EMPLOYEE_STATUS, row.employeeStatus) }}
         </Tag>
       </template>
+      <template #employeeCategory="{ row }">
+        <Tag :color="row.employeeCategory === 2 ? 'orange' : row.employeeCategory === 3 ? 'purple' : 'blue'">
+          {{ getDictLabel(DICT_TYPE.HRM_EMPLOYEE_CATEGORY, row.employeeCategory) }}
+        </Tag>
+      </template>
       <template #actions="{ row }">
         <TableAction
           :actions="[
@@ -202,6 +234,16 @@
               onClick: handleEdit.bind(null, row),
             },
             {
+              label: '杞',
+              type: 'link',
+              auth: ['hrm:employee:update'],
+              ifShow: () => row.employeeStatus === 2,
+              popConfirm: {
+                title: `纭灏嗐��${row.name}銆戣浆姝e悧锛燂紙浠呭姵鍔ㄥ悎鍚屽彲杞锛屼笉鍚皟宀楋級`,
+                confirm: handleRegularize.bind(null, row),
+              },
+            },
+            {
               label: $t('common.delete'),
               type: 'link',
               danger: true,
diff --git a/src/views/hrm/employee/modules/detail.vue b/src/views/hrm/employee/modules/detail.vue
index ccd7122..9cd2df2 100644
--- a/src/views/hrm/employee/modules/detail.vue
+++ b/src/views/hrm/employee/modules/detail.vue
@@ -78,6 +78,20 @@
       <DescriptionsItem label="灞呬綇鍦板潃" :span="2">{{ employee.address || '-' }}</DescriptionsItem>
     </Descriptions>
 
+    <!-- 闄勪欢鐣欐。 -->
+    <Descriptions title="闄勪欢鐣欐。" bordered :column="1" class="mb-4">
+      <DescriptionsItem label="闄勪欢">
+        <template v-if="employee.attachmentList && employee.attachmentList.length">
+          <div v-for="file in employee.attachmentList" :key="file.id" class="mb-1">
+            <a :href="file.url" target="_blank" rel="noopener">
+              {{ file.name || `闄勪欢${file.id}` }}
+            </a>
+          </div>
+        </template>
+        <span v-else>-</span>
+      </DescriptionsItem>
+    </Descriptions>
+
     <!-- 澶囨敞 -->
     <Descriptions title="鍏朵粬淇℃伅" bordered :column="1" class="mb-4">
       <DescriptionsItem label="澶囨敞">{{ employee.remark || '-' }}</DescriptionsItem>
diff --git a/src/views/hrm/employee/modules/form.vue b/src/views/hrm/employee/modules/form.vue
index e24e6ce..dbae5ef 100644
--- a/src/views/hrm/employee/modules/form.vue
+++ b/src/views/hrm/employee/modules/form.vue
@@ -66,6 +66,10 @@
     // 鎻愪氦琛ㄥ崟
     const data = (await formApi.getValues()) as HrmEmployeeApi.Employee;
     data.remark = remark.value;
+    // 闄勪欢锛氭妸 FileUpload 鐨勫�艰浆鎴� blobId 鏁扮粍
+    if (Array.isArray(data.blobIds)) {
+      data.blobIds = (data.blobIds as any[]).map((item) => item?.id ?? item);
+    }
     // 鑾峰彇瀛愯〃鏁版嵁
     data.educations = educationListRef.value?.getData();
     data.workHistories = workHistoryListRef.value?.getData();
@@ -111,7 +115,14 @@
       employeeData.value = formData;
       remark.value = formData.remark;
       if (data.formType !== 'detail') {
-        await formApi.setValues(formData);
+        const blobIds = (formData.attachmentList || []).map((item) => ({
+          uid: String(item.id),
+          name: item.name || '',
+          url: item.url || '',
+          status: 'done',
+          id: item.id,
+        }));
+        await formApi.setValues({ ...formData, blobIds });
       }
     } finally {
       modalApi.unlock();
diff --git a/src/views/hrm/leave/data.ts b/src/views/hrm/leave/data.ts
index 4f2d0bf..6e8570e 100644
--- a/src/views/hrm/leave/data.ts
+++ b/src/views/hrm/leave/data.ts
@@ -173,7 +173,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/leave/detail/approve/index.vue b/src/views/hrm/leave/detail/approve/index.vue
index bbeefb0..0573837 100644
--- a/src/views/hrm/leave/detail/approve/index.vue
+++ b/src/views/hrm/leave/detail/approve/index.vue
@@ -6,7 +6,7 @@
 
 import { ContentWrap } from '@vben/common-ui';
 import { DICT_TYPE } from '@vben/constants';
-import { formatDateTime, formatDate } from '@vben/utils';
+import { formatDateTime } from '@vben/utils';
 
 import { Spin } from 'ant-design-vue';
 
@@ -60,7 +60,7 @@
     {
       label: '鍒涘缓鏃堕棿',
       field: 'createTime',
-      render: (val) => formatDate(val) as string,
+      render: (val) => formatDateTime(val) as string,
     },
   ] as DescriptionItemSchema[],
 });
diff --git a/src/views/hrm/leave/index.vue b/src/views/hrm/leave/index.vue
index e1585a2..d088fc2 100644
--- a/src/views/hrm/leave/index.vue
+++ b/src/views/hrm/leave/index.vue
@@ -1,5 +1,4 @@
 <script lang="ts" setup>
-import { automaticApproval } from '#/store/audit-policy';
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { HrmLeaveApi } from '#/api/hrm/leave';
 
@@ -73,14 +72,9 @@
 
 /** 鎻愪氦璇峰亣鐢宠锛堝厛閫夋嫨瀹℃壒娴佺▼锛� */
 async function handleSubmit(row: HrmLeaveApi.Leave) {
-  processList.value = automaticApproval.value ? [] : await getLeaveApproveProcessDefinitionList();
+  processList.value = await getLeaveApproveProcessDefinitionList();
   currentRow.value = row;
   selectedProcessKey.value = undefined;
-  if (automaticApproval.value) {
-    selectedProcessKey.value = 'hrm_leave';
-    await confirmSubmit();
-    return;
-  }
   submitModalVisible.value = true;
 }
 
diff --git a/src/views/hrm/overtime/data.ts b/src/views/hrm/overtime/data.ts
index 8c33fc7..a4985b5 100644
--- a/src/views/hrm/overtime/data.ts
+++ b/src/views/hrm/overtime/data.ts
@@ -308,7 +308,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/overtime/detail/approve/index.vue b/src/views/hrm/overtime/detail/approve/index.vue
index f35e716..bfab940 100644
--- a/src/views/hrm/overtime/detail/approve/index.vue
+++ b/src/views/hrm/overtime/detail/approve/index.vue
@@ -6,7 +6,7 @@
 
 import { ContentWrap } from '@vben/common-ui';
 import { DICT_TYPE } from '@vben/constants';
-import { formatDate } from '@vben/utils';
+import { formatDateTime } from '@vben/utils';
 
 import { Spin, Tag } from 'ant-design-vue';
 
@@ -54,7 +54,7 @@
       field: 'status',
       render: (value) => h(DictTag, { type: DICT_TYPE.HRM_AUDIT_STATUS, value }),
     },
-    { label: '鍒涘缓鏃堕棿', field: 'createTime', render: (value) => formatDate(value) as string },
+    { label: '鍒涘缓鏃堕棿', field: 'createTime', render: (value) => formatDateTime(value) as string },
   ] as DescriptionItemSchema[],
 });
 
diff --git a/src/views/hrm/overtime/index.vue b/src/views/hrm/overtime/index.vue
index b4e116e..9b58111 100644
--- a/src/views/hrm/overtime/index.vue
+++ b/src/views/hrm/overtime/index.vue
@@ -1,5 +1,4 @@
 <script lang="ts" setup>
-import { automaticApproval } from '#/store/audit-policy';
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { HrmOvertimeApi } from '#/api/hrm/overtime';
 
@@ -65,14 +64,9 @@
 const submitLoading = ref(false);
 
 async function handleSubmit(row: HrmOvertimeApi.Overtime) {
-  processList.value = automaticApproval.value ? [] : await getOvertimeApproveProcessDefinitionList();
+  processList.value = await getOvertimeApproveProcessDefinitionList();
   currentRow.value = row;
   selectedProcessKey.value = undefined;
-  if (automaticApproval.value) {
-    selectedProcessKey.value = 'hrm_overtime';
-    await confirmSubmit();
-    return;
-  }
   submitModalVisible.value = true;
 }
 
@@ -84,7 +78,7 @@
   submitLoading.value = true;
   try {
     await submitOvertime(currentRow.value!.id!, selectedProcessKey.value);
-    message.success(automaticApproval.value ? '宸叉彁浜ょ敓鏁�' : '宸叉彁浜よ嚦鍗忓悓鍔炲叕瀹℃壒');
+    message.success('宸叉彁浜よ嚦鍗忓悓鍔炲叕瀹℃壒');
     submitModalVisible.value = false;
     handleRefresh();
   } finally {
diff --git a/src/views/hrm/resignation/data.ts b/src/views/hrm/resignation/data.ts
index dc7a0fe..3131c33 100644
--- a/src/views/hrm/resignation/data.ts
+++ b/src/views/hrm/resignation/data.ts
@@ -157,7 +157,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/resignation/detail/approve/index.vue b/src/views/hrm/resignation/detail/approve/index.vue
index e9c9619..4e3a587 100644
--- a/src/views/hrm/resignation/detail/approve/index.vue
+++ b/src/views/hrm/resignation/detail/approve/index.vue
@@ -6,7 +6,7 @@
 
 import { ContentWrap } from '@vben/common-ui';
 import { DICT_TYPE } from '@vben/constants';
-import { formatDate } from '@vben/utils';
+import { formatDateTime } from '@vben/utils';
 
 import { Spin } from 'ant-design-vue';
 
@@ -42,7 +42,7 @@
     {
       label: '棰勮绂昏亴鏃ユ湡',
       field: 'expectedDate',
-      render: (val) => formatDate(val) as string,
+      render: (val) => formatDateTime(val) as string,
     },
     { label: '绂昏亴鍘熷洜', field: 'reason', render: textRender },
     { label: '浜ゆ帴浜�', field: 'handoverUserName', render: textRender },
@@ -62,7 +62,7 @@
     {
       label: '鍒涘缓鏃堕棿',
       field: 'createTime',
-      render: (val) => formatDate(val) as string,
+      render: (val) => formatDateTime(val) as string,
     },
   ] as DescriptionItemSchema[],
 });
diff --git a/src/views/hrm/resignation/index.vue b/src/views/hrm/resignation/index.vue
index 0166dd8..cdf72da 100644
--- a/src/views/hrm/resignation/index.vue
+++ b/src/views/hrm/resignation/index.vue
@@ -163,7 +163,7 @@
             {
               label: '浜ゆ帴',
               type: 'link',
-              auth: ['hrm:resignation:update'],
+              auth: ['hrm:resignation:handover'],
               ifShow: row.status === 20 && row.handoverStatus !== 20,
               popConfirm: {
                 title: row.handoverStatus === 0 ? '纭寮�濮嬩氦鎺ュ悧锛�' : '纭瀹屾垚浜ゆ帴鍚楋紵',
diff --git a/src/views/hrm/salary/calculation/data.ts b/src/views/hrm/salary/calculation/data.ts
index bd96225..d52945d 100644
--- a/src/views/hrm/salary/calculation/data.ts
+++ b/src/views/hrm/salary/calculation/data.ts
@@ -75,21 +75,21 @@
     { field: 'period', title: '鏍哥畻鍛ㄦ湡', width: 100 },
     { field: 'userName', title: '鍛樺伐濮撳悕', minWidth: 100 },
     { field: 'deptName', title: '閮ㄩ棬', minWidth: 120 },
-    { field: 'baseSalary', title: '鍩烘湰宸ヨ祫', width: 100, formatter: 'formatAmount2' },
-    { field: 'performanceSalary', title: '缁╂晥宸ヨ祫', width: 100, formatter: 'formatAmount2' },
-    { field: 'overtimePay', title: '鍔犵彮璐�', width: 100, formatter: 'formatAmount2' },
-    { field: 'mealAllowance', title: '椁愯ˉ', width: 80, formatter: 'formatAmount2' },
-    { field: 'transportAllowance', title: '浜ら�氳ˉ璐�', width: 80, formatter: 'formatAmount2' },
-    { field: 'otherAllowance', title: '鍏朵粬琛ヨ创', width: 80, formatter: 'formatAmount2' },
-    { field: 'socialSecurityDeduction', title: '绀句繚鎵f', width: 100, formatter: 'formatAmount2' },
-    { field: 'housingFundDeduction', title: '鍏Н閲戞墸娆�', width: 100, formatter: 'formatAmount2' },
-    { field: 'taxDeduction', title: '涓◣鎵f', width: 100, formatter: 'formatAmount2' },
-    { field: 'otherDeduction', title: '鍏朵粬鎵f', width: 80, formatter: 'formatAmount2' },
-    { field: 'leaveDeduction', title: '璇峰亣鎵f', width: 100, formatter: 'formatAmount2' },
-    { field: 'actualSalary', title: '瀹炲彂宸ヨ祫', width: 100, formatter: 'formatAmount2' },
-    { field: 'workDays', title: '鍑哄嫟澶╂暟', width: 80 },
-    { field: 'overtimeHours', title: '鍔犵彮鏃堕暱(h)', width: 100 },
-    { field: 'totalWorkHours', title: '鎺掔彮宸ユ椂(h)', width: 100 },
+    { field: 'baseSalary', title: '鍩烘湰宸ヨ祫', width: 120, slots: { default: 'editableCell' } },
+    { field: 'performanceSalary', title: '缁╂晥宸ヨ祫', width: 120, slots: { default: 'editableCell' } },
+    { field: 'overtimePay', title: '鍔犵彮璐�', width: 120, slots: { default: 'editableCell' } },
+    { field: 'mealAllowance', title: '椁愯ˉ', width: 110, slots: { default: 'editableCell' } },
+    { field: 'transportAllowance', title: '浜ら�氳ˉ璐�', width: 110, slots: { default: 'editableCell' } },
+    { field: 'otherAllowance', title: '鍏朵粬琛ヨ创', width: 110, slots: { default: 'editableCell' } },
+    { field: 'socialSecurityDeduction', title: '绀句繚鎵f', width: 120, slots: { default: 'editableCell' } },
+    { field: 'housingFundDeduction', title: '鍏Н閲戞墸娆�', width: 120, slots: { default: 'editableCell' } },
+    { field: 'taxDeduction', title: '涓◣鎵f', width: 120, slots: { default: 'editableCell' } },
+    { field: 'otherDeduction', title: '鍏朵粬鎵f', width: 110, slots: { default: 'editableCell' } },
+    { field: 'leaveDeduction', title: '璇峰亣鎵f', width: 120, slots: { default: 'editableCell' } },
+    { field: 'actualSalary', title: '瀹炲彂宸ヨ祫', width: 110, formatter: 'formatAmount2' },
+    { field: 'workDays', title: '鍑哄嫟澶╂暟', width: 110, slots: { default: 'editableCell' } },
+    { field: 'overtimeHours', title: '鍔犵彮鏃堕暱(h)', width: 120, slots: { default: 'editableCell' } },
+    { field: 'totalWorkHours', title: '鎺掔彮宸ユ椂(h)', width: 110 },
     {
       field: 'status',
       title: '鐘舵��',
@@ -101,7 +101,7 @@
     },
     {
       title: '鎿嶄綔',
-      width: 120,
+      width: 220,
       fixed: 'right',
       slots: {
         default: 'actions',
diff --git a/src/views/hrm/salary/calculation/index.vue b/src/views/hrm/salary/calculation/index.vue
index 33a1f36..1636793 100644
--- a/src/views/hrm/salary/calculation/index.vue
+++ b/src/views/hrm/salary/calculation/index.vue
@@ -7,7 +7,7 @@
 import { Page } from '#/packages/effects/common-ui/src';
 import { downloadFileFromBlobPart } from '#/packages/utils/src';
 
-import { message, Modal, Form, FormItem, DatePicker, TreeSelect, Table, InputNumber, Alert, Tag } from 'ant-design-vue';
+import { message, Modal, Form, FormItem, DatePicker, TreeSelect, Table, Input, InputNumber, Alert, Tag } from 'ant-design-vue';
 
 import { DICT_TYPE } from '#/packages/constants/src';
 import { getDictLabel } from '#/packages/effects/hooks/src';
@@ -22,14 +22,18 @@
   previewSalaryCalculation,
   revokeSalaryCalculation,
   saveSalaryCalculation,
+  updateSalaryCalculation,
 } from '#/api/hrm/salary/calculation';
 import { getDeptList } from '#/api/system/dept';
 import { handleTree } from '#/packages/utils/src';
 import { $t } from '#/locales';
 
 import { useGridColumns, useGridFormSchema, usePreviewColumns } from './data';
+import FormModal from './modules/form.vue';
 
 // 鏍哥畻寮圭獥鐩稿叧
+const formModalRef = ref();
+const saving = ref(false);
 const calculateVisible = ref(false);
 const calculatePeriod = ref<string>();
 const calculateDeptId = ref<number>();
@@ -148,19 +152,35 @@
   previewData.value = [];
 }
 
-/** 纭钖叕鏍哥畻 */
+/** 鎶婅鍐呯紪杈戠殑鏂囨湰鍊煎綊涓�涓烘暟瀛楀悗鎻愪氦淇濆瓨 */
+async function saveRowEdits(row: any) {
+  const payload: any = { ...row };
+  EDITABLE_NUMBER_FIELDS.forEach((f) => {
+    payload[f] = toNumberOrZero(payload[f]);
+  });
+  await updateSalaryCalculation(payload);
+}
+
+/** 纭钖叕鏍哥畻锛堟柟妗圓锛氱‘璁ゅ墠鍏堜繚瀛樺綋鍓嶈鐨勪慨鏀癸紝閬垮厤銆屾敼浜嗘病淇濆瓨灏辩‘璁ゃ�嶅鑷撮噾棰濅涪澶憋級 */
 async function handleConfirm(row: HrmSalaryCalculationApi.SalaryCalculation) {
+  if (row.status === 0) {
+    await saveRowEdits(row);
+  }
   await confirmSalary([row.id!]);
   message.success('纭鎴愬姛');
   handleRefresh();
 }
 
-/** 鎵归噺纭閫変腑鐨勮褰� */
+/** 鎵归噺纭閫変腑鐨勮褰曪紙鍚屾牱鍏堜繚瀛樺嬀閫夌殑寰呯‘璁よ褰曪紝鍐嶇‘璁わ級 */
 async function handleBatchConfirm() {
   const records = gridApi.grid.getCheckboxRecords() as HrmSalaryCalculationApi.SalaryCalculation[];
   if (records.length === 0) {
     message.warning('璇烽�夋嫨瑕佺‘璁ょ殑璁板綍');
     return;
+  }
+  const pending = records.filter((r) => r.status === 0);
+  for (const row of pending) {
+    await saveRowEdits(row);
   }
   const ids = records.map((r) => r.id!);
   await confirmSalary(ids);
@@ -224,6 +244,55 @@
 async function handleExport() {
   const data = await exportSalaryCalculation(await gridApi.formApi.getValues());
   downloadFileFromBlobPart({ fileName: '钖叕鏍哥畻琛�.xls', source: data });
+}
+
+/** 鍒楄〃鍙紪杈戠殑鏁板�煎瓧娈� */
+const EDITABLE_NUMBER_FIELDS = [
+  'baseSalary',
+  'performanceSalary',
+  'overtimePay',
+  'mealAllowance',
+  'transportAllowance',
+  'otherAllowance',
+  'socialSecurityDeduction',
+  'housingFundDeduction',
+  'taxDeduction',
+  'otherDeduction',
+  'leaveDeduction',
+  'workDays',
+  'overtimeHours',
+];
+
+/** 鏂囨湰杈撳叆杞暟瀛楋紙绌哄�兼寜 0锛� */
+function toNumberOrZero(val: any) {
+  if (val === '' || val === null || val === undefined) {
+    return 0;
+  }
+  const num = Number(String(val).replace(/,/g, ''));
+  return Number.isNaN(num) ? 0 : num;
+}
+
+/** 淇濆瓨鍒楄〃鍐呰仈淇敼锛堜粎寰呯‘璁ょ姸鎬侊級 */
+async function handleSaveEdits() {
+  const rows = (gridApi.grid.getData() as any[]).filter((r) => r.status === 0);
+  if (rows.length === 0) {
+    message.warning('褰撳墠椤垫病鏈夊緟纭鐨勮褰曞彲淇敼');
+    return;
+  }
+  saving.value = true;
+  try {
+    for (const row of rows) {
+      const payload: any = { ...row };
+      EDITABLE_NUMBER_FIELDS.forEach((f) => {
+        payload[f] = toNumberOrZero(payload[f]);
+      });
+      await updateSalaryCalculation(payload);
+    }
+    message.success(`宸蹭繚瀛� ${rows.length} 鏉℃牳绠楄褰昤);
+    handleRefresh();
+  } finally {
+    saving.value = false;
+  }
 }
 
 const [Grid, gridApi] = useVbenVxeGrid({
@@ -469,6 +538,7 @@
       </div>
     </Modal>
 
+    <FormModal ref="formModalRef" @success="handleRefresh" />
     <Grid table-title="钖叕鏍哥畻鍒楄〃">
       <template #toolbar-tools>
         <TableAction
@@ -493,6 +563,13 @@
               onClick: handleBatchSave,
             },
             {
+              label: '淇濆瓨淇敼',
+              type: 'primary',
+              auth: ['hrm:salary-calculation:calculate'],
+              loading: saving,
+              onClick: handleSaveEdits,
+            },
+            {
               label: $t('ui.actionTitle.export'),
               type: 'primary',
               icon: ACTION_ICON.DOWNLOAD,
@@ -502,6 +579,15 @@
           ]"
         />
       </template>
+      <template #editableCell="{ row, column }">
+        <Input
+          v-if="row.status === 0"
+          v-model:value="row[column.field]"
+          size="small"
+          :style="{ width: '100%' }"
+        />
+        <span v-else>{{ row[column.field] ?? '' }}</span>
+      </template>
       <template #status="{ row }">
         <Tag :color="row.status === 0 ? 'warning' : row.status === 10 ? 'success' : 'processing'">
           {{ getDictLabel(DICT_TYPE.HRM_SALARY_STATUS, row.status) }}
@@ -511,6 +597,13 @@
         <TableAction
           :actions="[
             {
+              label: '淇敼',
+              type: 'link',
+              auth: ['hrm:salary-calculation:calculate'],
+              ifShow: row.status === 0,
+              onClick: () => formModalRef.value?.open(row),
+            },
+            {
               label: '纭',
               type: 'link',
               auth: ['hrm:salary-calculation:confirm'],
diff --git a/src/views/hrm/salary/calculation/modules/form.vue b/src/views/hrm/salary/calculation/modules/form.vue
new file mode 100644
index 0000000..6369f76
--- /dev/null
+++ b/src/views/hrm/salary/calculation/modules/form.vue
@@ -0,0 +1,120 @@
+<script lang="ts" setup>
+import type { HrmSalaryCalculationApi } from '#/api/hrm/salary/calculation';
+
+import { computed, ref } from 'vue';
+
+import { message, Modal, Form, FormItem, Input, InputNumber } from 'ant-design-vue';
+
+import { updateSalaryCalculation } from '#/api/hrm/salary/calculation';
+
+const emit = defineEmits(['success']);
+
+const visible = ref(false);
+const loading = ref(false);
+/** 褰撳墠缂栬緫鐨勮褰曪紙鍚墍鏈夊彲缂栬緫瀛楁锛� */
+const current = ref<Record<string, any>>({});
+
+/** 鏀跺叆椤� */
+const incomeFields = [
+  { key: 'baseSalary', label: '鍩烘湰宸ヨ祫' },
+  { key: 'performanceSalary', label: '缁╂晥宸ヨ祫' },
+  { key: 'overtimePay', label: '鍔犵彮璐�' },
+  { key: 'mealAllowance', label: '椁愯ˉ' },
+  { key: 'transportAllowance', label: '浜ら�氳ˉ璐�' },
+  { key: 'otherAllowance', label: '鍏朵粬琛ヨ创' },
+];
+
+/** 鎵i櫎椤� */
+const deductionFields = [
+  { key: 'socialSecurityDeduction', label: '绀句繚鎵f' },
+  { key: 'housingFundDeduction', label: '鍏Н閲戞墸娆�' },
+  { key: 'taxDeduction', label: '涓◣鎵f' },
+  { key: 'otherDeduction', label: '鍏朵粬鎵f' },
+  { key: 'leaveDeduction', label: '璇峰亣鎵f' },
+];
+
+/** 瀹炲彂宸ヨ祫锛堝疄鏃惰绠楋紝涓庡悗绔彛寰勪竴鑷达級 */
+const actualSalary = computed(() => {
+  const num = (v: any) => (v === undefined || v === null || v === '' ? 0 : Number(v));
+  const income = incomeFields.reduce((sum, f) => sum + num(current.value[f.key]), 0);
+  const deduction = deductionFields.reduce((sum, f) => sum + num(current.value[f.key]), 0);
+  return Number((income - deduction).toFixed(2));
+});
+
+function open(row: HrmSalaryCalculationApi.SalaryCalculation) {
+  current.value = { ...row };
+  visible.value = true;
+}
+
+async function handleOk() {
+  loading.value = true;
+  try {
+    await updateSalaryCalculation({
+      ...(current.value as HrmSalaryCalculationApi.SalaryCalculation),
+      actualSalary: actualSalary.value,
+    });
+    message.success('淇敼鎴愬姛');
+    visible.value = false;
+    emit('success');
+  } finally {
+    loading.value = false;
+  }
+}
+
+defineExpose({ open });
+</script>
+
+<template>
+  <Modal
+    v-model:open="visible"
+    :title="`淇敼钖叕鏍哥畻${current.no ? ' - ' + current.no : ''}`"
+    :width="760"
+    :confirm-loading="loading"
+    ok-text="淇濆瓨"
+    cancel-text="鍙栨秷"
+    @ok="handleOk"
+  >
+    <Form layout="vertical" class="mt-2">
+      <div class="mb-2 text-sm font-semibold text-gray-700">鏀跺叆椤�</div>
+      <div class="grid grid-cols-3 gap-x-4">
+        <FormItem v-for="f in incomeFields" :key="f.key" :label="f.label">
+          <InputNumber
+            v-model:value="current[f.key]"
+            :min="0"
+            :precision="2"
+            style="width: 100%"
+          />
+        </FormItem>
+      </div>
+
+      <div class="mb-2 mt-2 text-sm font-semibold text-gray-700">鎵i櫎椤�</div>
+      <div class="grid grid-cols-3 gap-x-4">
+        <FormItem v-for="f in deductionFields" :key="f.key" :label="f.label">
+          <InputNumber
+            v-model:value="current[f.key]"
+            :min="0"
+            :precision="2"
+            style="width: 100%"
+          />
+        </FormItem>
+      </div>
+
+      <div class="mb-2 mt-2 text-sm font-semibold text-gray-700">鑰冨嫟 / 鍏朵粬</div>
+      <div class="grid grid-cols-3 gap-x-4">
+        <FormItem label="鍑哄嫟澶╂暟">
+          <InputNumber v-model:value="current.workDays" :min="0" :max="31" :precision="0" style="width: 100%" />
+        </FormItem>
+        <FormItem label="鍔犵彮鏃堕暱(h)">
+          <InputNumber v-model:value="current.overtimeHours" :min="0" :precision="1" style="width: 100%" />
+        </FormItem>
+        <FormItem label="瀹炲彂宸ヨ祫锛堣嚜鍔ㄨ绠楋級">
+          <Input :value="actualSalary.toFixed(2)" disabled class="font-bold text-green-600" />
+        </FormItem>
+      </div>
+
+      <FormItem label="澶囨敞">
+        <Input.TextArea v-model:value="current.remark" :rows="2" placeholder="璇疯緭鍏ュ娉�" />
+      </FormItem>
+    </Form>
+  </Modal>
+</template>
diff --git a/src/views/hrm/salary/employee-social-security/data.ts b/src/views/hrm/salary/employee-social-security/data.ts
index 085a4b8..8d0bcac 100644
--- a/src/views/hrm/salary/employee-social-security/data.ts
+++ b/src/views/hrm/salary/employee-social-security/data.ts
@@ -166,7 +166,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/salary/leave-type-config/data.ts b/src/views/hrm/salary/leave-type-config/data.ts
index d4cd791..14cb42d 100644
--- a/src/views/hrm/salary/leave-type-config/data.ts
+++ b/src/views/hrm/salary/leave-type-config/data.ts
@@ -106,7 +106,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/salary/overtime-wage/data.ts b/src/views/hrm/salary/overtime-wage/data.ts
new file mode 100644
index 0000000..e4c9bb4
--- /dev/null
+++ b/src/views/hrm/salary/overtime-wage/data.ts
@@ -0,0 +1,146 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { HrmOvertimeWageApi } from '#/api/hrm/salary/overtime-wage';
+
+import { getSimplePostList } from '#/api/system/post';
+
+export type FormType = 'create' | 'update';
+
+const statusOptions = [
+  { label: '鍚敤', value: 0 },
+  { label: '绂佺敤', value: 1 },
+];
+
+export function useFormSchema(): VbenFormSchema[] {
+  return [
+    {
+      fieldName: 'id',
+      component: 'Input',
+      dependencies: { triggerFields: [''], show: () => false },
+    },
+    {
+      fieldName: 'postId',
+      label: '宀椾綅',
+      component: 'ApiSelect',
+      componentProps: {
+        api: getSimplePostList,
+        labelField: 'name',
+        valueField: 'id',
+        placeholder: '璇烽�夋嫨宀椾綅锛堝伐绉嶏級',
+      },
+      rules: 'selectRequired',
+      formItemClass: 'col-span-2',
+    },
+    {
+      fieldName: 'hourlyRate',
+      label: '鍔犵彮鏃惰柂',
+      component: 'InputNumber',
+      componentProps: {
+        addonAfter: '鍏�/灏忔椂',
+        min: 0,
+        precision: 2,
+        step: 1,
+        placeholder: '榛樿 20锛屾寜宀椾綅鍙笉鍚�',
+        style: { width: '100%' },
+      },
+      rules: 'required',
+    },
+    {
+      fieldName: 'maxOvertimeHours',
+      label: '鏈�澶у姞鐝椂闀�',
+      component: 'InputNumber',
+      componentProps: {
+        addonAfter: '灏忔椂/鏈�',
+        min: 0,
+        precision: 1,
+        step: 1,
+        placeholder: '鐣欑┖琛ㄧず涓嶉檺',
+        style: { width: '100%' },
+      },
+    },
+    {
+      fieldName: 'status',
+      label: '鐘舵��',
+      component: 'RadioGroup',
+      componentProps: { options: statusOptions },
+      rules: 'required',
+    },
+    {
+      fieldName: 'remark',
+      label: '澶囨敞',
+      component: 'Textarea',
+      componentProps: {
+        maxlength: 500,
+        placeholder: '鍙~鍐欓�傜敤璇存槑锛屽銆屼粎鏅�氬憳宸ャ�嶃�屾妧宸ユ寜 1:1銆嶇瓑',
+        rows: 3,
+        showCount: true,
+      },
+      formItemClass: 'col-span-2',
+    },
+  ];
+}
+
+export function useGridFormSchema(): VbenFormSchema[] {
+  return [
+    {
+      fieldName: 'postId',
+      label: '宀椾綅',
+      component: 'ApiSelect',
+      componentProps: {
+        api: getSimplePostList,
+        labelField: 'name',
+        valueField: 'id',
+        allowClear: true,
+        placeholder: '璇烽�夋嫨宀椾綅',
+      },
+    },
+    {
+      fieldName: 'status',
+      label: '鐘舵��',
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        options: statusOptions,
+        placeholder: '璇烽�夋嫨鐘舵��',
+      },
+    },
+  ];
+}
+
+export function useGridColumns(): VxeTableGridOptions<HrmOvertimeWageApi.OvertimeWageConfig>['columns'] {
+  return [
+    { field: 'postName', title: '宀椾綅锛堝伐绉嶏級', minWidth: 160 },
+    {
+      field: 'hourlyRate',
+      title: '鍔犵彮鏃惰柂',
+      width: 130,
+      slots: { default: 'hourlyRate' },
+    },
+    {
+      field: 'maxOvertimeHours',
+      title: '鏈�澶у姞鐝椂闀�',
+      width: 140,
+      slots: { default: 'maxOvertimeHours' },
+    },
+    {
+      field: 'status',
+      title: '鐘舵��',
+      width: 90,
+      slots: { default: 'status' },
+    },
+    { field: 'remark', title: '澶囨敞', minWidth: 180 },
+    {
+      field: 'createTime',
+      title: '鍒涘缓鏃堕棿',
+      width: 180,
+      formatter: 'formatDateTime',
+    },
+    {
+      field: 'actions',
+      title: '鎿嶄綔',
+      fixed: 'right',
+      slots: { default: 'actions' },
+      width: 150,
+    },
+  ];
+}
diff --git a/src/views/hrm/salary/overtime-wage/index.vue b/src/views/hrm/salary/overtime-wage/index.vue
new file mode 100644
index 0000000..043c6e2
--- /dev/null
+++ b/src/views/hrm/salary/overtime-wage/index.vue
@@ -0,0 +1,125 @@
+<script lang="ts" setup>
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { HrmOvertimeWageApi } from '#/api/hrm/salary/overtime-wage';
+
+import { Page, useVbenModal } from '#/packages/effects/common-ui/src';
+
+import { Alert, message, Tag } from 'ant-design-vue';
+
+import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
+import {
+  deleteOvertimeWageConfig,
+  getOvertimeWageConfigList,
+} from '#/api/hrm/salary/overtime-wage';
+import { $t } from '#/locales';
+
+import { useGridColumns, useGridFormSchema } from './data';
+import Form from './modules/form.vue';
+
+defineOptions({ name: 'HrmOvertimeWage' });
+
+const [FormModal, formModalApi] = useVbenModal({
+  connectedComponent: Form,
+  destroyOnClose: true,
+});
+
+function handleRefresh() {
+  gridApi.query();
+}
+
+function handleCreate() {
+  formModalApi.setData({ formType: 'create' }).open();
+}
+
+function handleEdit(row: HrmOvertimeWageApi.OvertimeWageConfig) {
+  formModalApi.setData({ id: row.id, formType: 'update' }).open();
+}
+
+async function handleDelete(row: HrmOvertimeWageApi.OvertimeWageConfig) {
+  await deleteOvertimeWageConfig(row.id!);
+  message.success($t('ui.actionMessage.deleteSuccess', ['鍔犵彮宸ヨ祫閰嶇疆']));
+  handleRefresh();
+}
+
+const [Grid, gridApi] = useVbenVxeGrid({
+  formOptions: { schema: useGridFormSchema() },
+  gridOptions: {
+    columns: useGridColumns(),
+    height: 'auto',
+    keepSource: true,
+    pagerConfig: { enabled: false },
+    proxyConfig: {
+      ajax: {
+        query: async (_params, formValues) =>
+          await getOvertimeWageConfigList(formValues),
+      },
+    },
+    rowConfig: { keyField: 'id', isHover: true },
+    toolbarConfig: { refresh: true, search: true },
+  } as VxeTableGridOptions<HrmOvertimeWageApi.OvertimeWageConfig>,
+});
+</script>
+
+<template>
+  <Page auto-content-height>
+    <FormModal @success="handleRefresh" />
+    <Alert
+      class="mb-4"
+      description="鎸夈�屽矖浣嶏紙宸ョ锛夈�嶉厤缃姞鐝椂钖細鏅�氬憳宸ユ寜姝ゅ鏃惰柂璁″姞鐝伐璧勶紝鍙缃瘡鏈堟渶澶у姞鐝椂闀夸笂闄愶紱鎶�宸ユ寜骞虫椂鏃惰柂 1:1锛岀鐞嗕笉璁″姞鐝伐璧勩�傚姞鐝伐璧勫嚟瀹℃壒閫氳繃鐨勫姞鐝崟鏍哥畻銆�"
+      message="鍔犵彮宸ヨ祫鎸夊矖浣嶅垝鍒�"
+      show-icon
+      type="info"
+    />
+    <Grid table-title="鍔犵彮宸ヨ祫绠$悊">
+      <template #toolbar-tools>
+        <TableAction
+          :actions="[
+            {
+              label: $t('ui.actionTitle.create', ['鍔犵彮宸ヨ祫']),
+              type: 'primary',
+              icon: ACTION_ICON.ADD,
+              auth: ['hrm:overtime-wage:create'],
+              onClick: handleCreate,
+            },
+          ]"
+        />
+      </template>
+      <template #hourlyRate="{ row }">
+        <Tag color="blue">{{ row.hourlyRate ?? 0 }} 鍏�/灏忔椂</Tag>
+      </template>
+      <template #maxOvertimeHours="{ row }">
+        <span v-if="row.maxOvertimeHours === null || row.maxOvertimeHours === undefined">涓嶉檺</span>
+        <span v-else>{{ row.maxOvertimeHours }} 灏忔椂/鏈�</span>
+      </template>
+      <template #status="{ row }">
+        <Tag :color="row.status === 0 ? 'success' : 'default'">
+          {{ row.status === 0 ? '鍚敤' : '绂佺敤' }}
+        </Tag>
+      </template>
+      <template #actions="{ row }">
+        <TableAction
+          :actions="[
+            {
+              label: $t('common.edit'),
+              type: 'link',
+              icon: ACTION_ICON.EDIT,
+              auth: ['hrm:overtime-wage:update'],
+              onClick: handleEdit.bind(null, row),
+            },
+            {
+              label: $t('common.delete'),
+              type: 'link',
+              danger: true,
+              icon: ACTION_ICON.DELETE,
+              auth: ['hrm:overtime-wage:delete'],
+              popConfirm: {
+                title: '纭鍒犻櫎璇ュ矖浣嶇殑鍔犵彮宸ヨ祫閰嶇疆鍚楋紵',
+                confirm: handleDelete.bind(null, row),
+              },
+            },
+          ]"
+        />
+      </template>
+    </Grid>
+  </Page>
+</template>
diff --git a/src/views/hrm/salary/overtime-wage/modules/form.vue b/src/views/hrm/salary/overtime-wage/modules/form.vue
new file mode 100644
index 0000000..46db733
--- /dev/null
+++ b/src/views/hrm/salary/overtime-wage/modules/form.vue
@@ -0,0 +1,90 @@
+<script lang="ts" setup>
+import type { HrmOvertimeWageApi } from '#/api/hrm/salary/overtime-wage';
+import type { FormType } from '../data';
+
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '#/packages/effects/common-ui/src';
+
+import { Alert, message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+import {
+  createOvertimeWageConfig,
+  getOvertimeWageConfig,
+  updateOvertimeWageConfig,
+} from '#/api/hrm/salary/overtime-wage';
+import { $t } from '#/locales';
+
+import { useFormSchema } from '../data';
+
+const emit = defineEmits(['success']);
+const formType = ref<FormType>('create');
+
+const getTitle = computed(() =>
+  formType.value === 'update' ? '淇敼鍔犵彮宸ヨ祫' : '鏂板鍔犵彮宸ヨ祫',
+);
+
+const [Form, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: { class: 'w-full' },
+    formItemClass: 'col-span-1',
+    labelWidth: 110,
+  },
+  wrapperClass: 'grid-cols-2',
+  layout: 'horizontal',
+  schema: useFormSchema(),
+  showDefaultActions: false,
+});
+
+const [Modal, modalApi] = useVbenModal({
+  async onConfirm() {
+    const { valid } = await formApi.validate();
+    if (!valid) return;
+    modalApi.lock();
+    try {
+      const data =
+        (await formApi.getValues()) as HrmOvertimeWageApi.OvertimeWageConfig;
+      if (data.id) {
+        await updateOvertimeWageConfig(data);
+      } else {
+        await createOvertimeWageConfig(data);
+      }
+      await modalApi.close();
+      emit('success');
+      message.success($t('ui.actionMessage.operationSuccess'));
+    } finally {
+      modalApi.unlock();
+    }
+  },
+  async onOpenChange(isOpen: boolean) {
+    if (!isOpen) return;
+    const data = modalApi.getData<{ formType: FormType; id?: number }>();
+    formType.value = data.formType;
+    await formApi.resetForm();
+    if (!data.id) {
+      await formApi.setValues({ hourlyRate: 20, status: 0 });
+      return;
+    }
+    modalApi.lock();
+    try {
+      await formApi.setValues(await getOvertimeWageConfig(data.id));
+    } finally {
+      modalApi.unlock();
+    }
+  },
+});
+</script>
+
+<template>
+  <Modal :title="getTitle" class="w-[640px]">
+    <Alert
+      class="mx-4 mb-4"
+      description="鏅�氬憳宸ワ細鍔犵彮宸ヨ祫 = 鏈矖浣嶉厤缃殑鏃惰柂 脳 鍔犵彮鏃堕暱锛堣秴杩囨渶澶ф椂闀夸笂闄愮殑閮ㄥ垎涓嶈锛夛紱鎶�宸ユ寜骞虫椂鏃惰柂 1:1锛涚鐞嗕笉璁″姞鐝伐璧勩��"
+      message="鍔犵彮宸ヨ祫璁$畻璇存槑"
+      show-icon
+      type="info"
+    />
+    <Form class="mx-4" />
+  </Modal>
+</template>
diff --git a/src/views/hrm/salary/payment/data.ts b/src/views/hrm/salary/payment/data.ts
index 29b66d6..b9e1873 100644
--- a/src/views/hrm/salary/payment/data.ts
+++ b/src/views/hrm/salary/payment/data.ts
@@ -65,7 +65,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/salary/social-security-scheme/data.ts b/src/views/hrm/salary/social-security-scheme/data.ts
index 1981c08..e05ed44 100644
--- a/src/views/hrm/salary/social-security-scheme/data.ts
+++ b/src/views/hrm/salary/social-security-scheme/data.ts
@@ -5,10 +5,23 @@
 /** 琛ㄥ崟绫诲瀷 */
 export type FormType = 'create' | 'update';
 
-/** 鏍煎紡鍖栨瘮渚嬭緭鍏� */
+/** 鏍煎紡鍖栨瘮渚嬭緭鍏ワ紙缁熶竴鏄剧ず涓や綅灏忔暟鐧惧垎姣旓紝濡� 8.25%锛� */
 function createRatioFormatter(step: number = 0.01) {
   return {
-    formatter: (value: number) => value !== undefined && value !== null ? `${(value * 100).toFixed(step === 0.001 ? 1 : 0)}%` : '',
+    formatter: (value: number) =>
+      value !== undefined && value !== null ? `${(value * 100).toFixed(2)}%` : '',
+    parser: (value: string) => {
+      const num = parseFloat(String(value).replace('%', ''));
+      return isNaN(num) ? 0 : num / 100;
+    },
+  };
+}
+
+/** 鏍煎紡鍖栨瘮渚嬭緭鍏ワ紙鏄剧ず涓や綅灏忔暟锛屽 0.50%锛� */
+function createRatioFormatter2() {
+  return {
+    formatter: (value: number) =>
+      value !== undefined && value !== null ? `${(value * 100).toFixed(2)}%` : '',
     parser: (value: string) => {
       const num = parseFloat(value.replace('%', ''));
       return isNaN(num) ? 0 : num / 100;
@@ -200,6 +213,76 @@
         ...createRatioFormatter(0.001),
       },
     },
+    // 澶х梾鍖荤枟
+    {
+      fieldName: 'divider_serious_illness',
+      label: '澶х梾鍖荤枟',
+      component: 'Divider',
+      formItemClass: 'col-span-2',
+    },
+    {
+      fieldName: 'seriousIllnessCompanyRatio',
+      label: '浼佷笟姣斾緥',
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '浼佷笟缂寸撼姣斾緥',
+        min: 0,
+        max: 1,
+        step: 0.0001,
+        precision: 4,
+        style: { width: '100%' },
+        ...createRatioFormatter2(),
+      },
+    },
+    {
+      fieldName: 'seriousIllnessPersonalRatio',
+      label: '涓汉姣斾緥',
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '涓汉缂寸撼姣斾緥',
+        min: 0,
+        max: 1,
+        step: 0.0001,
+        precision: 4,
+        style: { width: '100%' },
+        ...createRatioFormatter2(),
+      },
+    },
+    // 闀挎湡鎶ょ悊
+    {
+      fieldName: 'divider_long_term_care',
+      label: '闀挎湡鎶ょ悊',
+      component: 'Divider',
+      formItemClass: 'col-span-2',
+    },
+    {
+      fieldName: 'longTermCareCompanyRatio',
+      label: '浼佷笟姣斾緥',
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '浼佷笟缂寸撼姣斾緥',
+        min: 0,
+        max: 1,
+        step: 0.0001,
+        precision: 4,
+        style: { width: '100%' },
+        ...createRatioFormatter2(),
+      },
+    },
+    {
+      fieldName: 'longTermCarePersonalRatio',
+      label: '涓汉姣斾緥',
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '涓汉缂寸撼姣斾緥',
+        min: 0,
+        max: 1,
+        step: 0.0001,
+        precision: 4,
+        style: { width: '100%' },
+        ...createRatioFormatter2(),
+      },
+    },
     // 鍏Н閲�
     {
       fieldName: 'divider_housing',
@@ -307,6 +390,18 @@
       slots: { default: 'housingFundPersonalRatio' },
     },
     {
+      field: 'seriousIllnessPersonalRatio',
+      title: '澶х梾鍖荤枟(涓汉)',
+      width: 120,
+      slots: { default: 'seriousIllnessPersonalRatio' },
+    },
+    {
+      field: 'longTermCarePersonalRatio',
+      title: '闀挎湡鎶ょ悊(涓汉)',
+      width: 120,
+      slots: { default: 'longTermCarePersonalRatio' },
+    },
+    {
       field: 'status',
       title: '鐘舵��',
       width: 80,
@@ -316,7 +411,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/salary/social-security-scheme/index.vue b/src/views/hrm/salary/social-security-scheme/index.vue
index 65c71b5..45fbaa8 100644
--- a/src/views/hrm/salary/social-security-scheme/index.vue
+++ b/src/views/hrm/salary/social-security-scheme/index.vue
@@ -43,10 +43,16 @@
   handleRefresh();
 }
 
-/** 鏍煎紡鍖栨瘮渚嬫樉绀� */
+/** 鏍煎紡鍖栨瘮渚嬫樉绀猴紙淇濈暀涓や綅灏忔暟锛� */
 function formatRatio(ratio: number | undefined) {
   if (ratio === undefined || ratio === null) return '-';
-  return `${(ratio * 100).toFixed(1)}%`;
+  return `${(ratio * 100).toFixed(2)}%`;
+}
+
+/** 鏍煎紡鍖栨瘮渚嬫樉绀猴紙淇濈暀涓や綅灏忔暟锛� */
+function formatRatio2(ratio: number | undefined) {
+  if (ratio === undefined || ratio === null) return '-';
+  return `${(ratio * 100).toFixed(2)}%`;
 }
 
 const [Grid, gridApi] = useVbenVxeGrid({
@@ -107,6 +113,12 @@
       <template #housingFundPersonalRatio="{ row }">
         {{ formatRatio(row.housingFundPersonalRatio) }}
       </template>
+      <template #seriousIllnessPersonalRatio="{ row }">
+        {{ formatRatio2(row.seriousIllnessPersonalRatio) }}
+      </template>
+      <template #longTermCarePersonalRatio="{ row }">
+        {{ formatRatio2(row.longTermCarePersonalRatio) }}
+      </template>
       <template #status="{ row }">
         <Tag :color="row.status === 0 ? 'success' : 'default'">
           {{ row.status === 0 ? '鍚敤' : '绂佺敤' }}
diff --git a/src/views/hrm/salary/social-security-scheme/modules/form.vue b/src/views/hrm/salary/social-security-scheme/modules/form.vue
index 9611251..b6937f2 100644
--- a/src/views/hrm/salary/social-security-scheme/modules/form.vue
+++ b/src/views/hrm/salary/social-security-scheme/modules/form.vue
@@ -81,6 +81,10 @@
         maternityRatio: 0.005,
         housingFundCompanyRatio: 0.12,
         housingFundPersonalRatio: 0.12,
+        seriousIllnessCompanyRatio: 0,
+        seriousIllnessPersonalRatio: 0,
+        longTermCareCompanyRatio: 0,
+        longTermCarePersonalRatio: 0,
         status: 0,
       });
       return;
diff --git a/src/views/hrm/salary/structure/data.ts b/src/views/hrm/salary/structure/data.ts
index 77c2144..68d1ddf 100644
--- a/src/views/hrm/salary/structure/data.ts
+++ b/src/views/hrm/salary/structure/data.ts
@@ -150,7 +150,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       field: 'actions',
diff --git a/src/views/hrm/transfer/data.ts b/src/views/hrm/transfer/data.ts
index c0e1cf3..c4e4c31 100644
--- a/src/views/hrm/transfer/data.ts
+++ b/src/views/hrm/transfer/data.ts
@@ -7,6 +7,7 @@
 
 import { getDeptList } from '#/api/system/dept';
 import { getSimplePostList } from '#/api/system/post';
+import { getEmployeeSimpleList } from '#/api/hrm/employee';
 import { handleTree } from '#/packages/utils/src';
 
 /** 琛ㄥ崟绫诲瀷 */
@@ -40,12 +41,29 @@
       },
     },
     {
+      fieldName: 'userId',
+      label: '璋冨矖浜�',
+      component: 'ApiSelect',
+      componentProps: {
+        api: getEmployeeSimpleList,
+        labelField: 'name',
+        valueField: 'id',
+        showSearch: true,
+        filterOption: (input: string, option: any) =>
+          `${option?.label ?? ''}`.toLowerCase().includes(input.toLowerCase()),
+        allowClear: true,
+        placeholder: '璇烽�夋嫨瑕佽皟宀楃殑鍛樺伐锛堥�夋嫨鍚庤嚜鍔ㄥ甫鍑哄師閮ㄩ棬/鍘熷矖浣嶏級',
+      },
+      rules: 'selectRequired',
+      formItemClass: 'col-span-2',
+    },
+    {
       fieldName: 'currentDeptName',
       label: '鍘熼儴闂�',
       component: 'Input',
       componentProps: {
         disabled: true,
-        placeholder: '鑷姩鑾峰彇',
+        placeholder: '閫夋嫨璋冨矖浜哄悗鑷姩甯﹀嚭',
       },
     },
     {
@@ -54,7 +72,7 @@
       component: 'Input',
       componentProps: {
         disabled: true,
-        placeholder: '鑷姩鑾峰彇',
+        placeholder: '閫夋嫨璋冨矖浜哄悗鑷姩甯﹀嚭',
       },
     },
     {
@@ -175,7 +193,7 @@
 export function useGridColumns(): VxeTableGridOptions<HrmTransferApi.Transfer>['columns'] {
   return [
     { field: 'id', title: '鐢宠缂栧彿', width: 80 },
-    { field: 'employeeName', title: '鐢宠浜�', minWidth: 100 },
+    { field: 'userName', title: '璋冨矖浜�', minWidth: 100 },
     { field: 'currentDeptName', title: '鍘熼儴闂�', minWidth: 120 },
     { field: 'currentPostName', title: '鍘熷矖浣�', minWidth: 120 },
     { field: 'targetDeptName', title: '鐩爣閮ㄩ棬', minWidth: 120 },
@@ -203,7 +221,7 @@
       field: 'createTime',
       title: '鍒涘缓鏃堕棿',
       width: 180,
-      formatter: 'formatDate',
+      formatter: 'formatDateTime',
     },
     {
       title: '鎿嶄綔',
diff --git a/src/views/hrm/transfer/detail/approve/index.vue b/src/views/hrm/transfer/detail/approve/index.vue
index 03278c6..e99659d 100644
--- a/src/views/hrm/transfer/detail/approve/index.vue
+++ b/src/views/hrm/transfer/detail/approve/index.vue
@@ -6,7 +6,7 @@
 
 import { ContentWrap } from '@vben/common-ui';
 import { DICT_TYPE } from '@vben/constants';
-import { formatDate } from '@vben/utils';
+import { formatDateTime } from '@vben/utils';
 
 import { Spin } from 'ant-design-vue';
 
@@ -30,9 +30,9 @@
   bordered: true,
   column: 2,
   schema: [
-    { label: '鍛樺伐濮撳悕', field: 'employeeName', render: textRender },
-    { label: '褰撳墠閮ㄩ棬', field: 'currentDeptName', render: textRender },
-    { label: '褰撳墠鑱屼綅', field: 'currentPostName', render: textRender },
+    { label: '璋冨矖浜�', field: 'userName', render: textRender },
+    { label: '鍘熼儴闂�', field: 'currentDeptName', render: textRender },
+    { label: '鍘熷矖浣�', field: 'currentPostName', render: textRender },
     { label: '鐩爣閮ㄩ棬', field: 'targetDeptName', render: textRender },
     { label: '鐩爣鑱屼綅', field: 'targetPostName', render: textRender },
     {
@@ -44,7 +44,7 @@
     {
       label: '鐢熸晥鏃ユ湡',
       field: 'effectiveDate',
-      render: (val) => formatDate(val) as string,
+      render: (val) => formatDateTime(val) as string,
     },
     { label: '璋冨矖鍘熷洜', field: 'reason', render: textRender },
     {
@@ -57,7 +57,7 @@
     {
       label: '鍒涘缓鏃堕棿',
       field: 'createTime',
-      render: (val) => formatDate(val) as string,
+      render: (val) => formatDateTime(val) as string,
     },
   ] as DescriptionItemSchema[],
 });
diff --git a/src/views/hrm/transfer/modules/form.vue b/src/views/hrm/transfer/modules/form.vue
index 6e76835..5527a15 100644
--- a/src/views/hrm/transfer/modules/form.vue
+++ b/src/views/hrm/transfer/modules/form.vue
@@ -17,7 +17,8 @@
 
 const emit = defineEmits(['success']);
 const formType = ref<FormType>('create');
-const currentEmployeeId = ref<number>();
+/** 鍛樺伐绮剧畝鍒楄〃缂撳瓨锛堥�変汉鏃剁敤浜庡甫鍑哄師閮ㄩ棬 / 鍘熷矖浣嶏級 */
+let employeeCache: any[] = [];
 
 const isDetail = computed(() => formType.value === 'detail');
 const getTitle = computed(() => {
@@ -26,6 +27,34 @@
   }
   return formType.value === 'update' ? '淇敼璋冨矖鐢宠' : '鏂板璋冨矖鐢宠';
 });
+
+/**
+ * 鏍规嵁閫変腑鐨勫憳宸ワ紝鑷姩甯﹀嚭鍘熼儴闂� / 鍘熷矖浣嶏紙鍚� ID锛屼究浜庡悗绔惤搴擄級
+ */
+async function fillCurrentPosition(employeeId?: number) {
+  if (!employeeId) {
+    await formApi.setValues({
+      currentDeptId: undefined,
+      currentDeptName: undefined,
+      currentPostId: undefined,
+      currentPostName: undefined,
+    });
+    return;
+  }
+  if (employeeCache.length === 0) {
+    employeeCache = (await getEmployeeSimpleList()) || [];
+  }
+  const emp = employeeCache.find((item) => item.id === employeeId);
+  if (!emp) {
+    return;
+  }
+  await formApi.setValues({
+    currentDeptId: emp.deptId,
+    currentDeptName: emp.deptName,
+    currentPostId: emp.postIds?.[0],
+    currentPostName: emp.postName,
+  });
+}
 
 const [Form, formApi] = useVbenForm({
   commonConfig: {
@@ -39,6 +68,12 @@
   layout: 'horizontal',
   schema: [],
   showDefaultActions: false,
+  // 閫夋嫨銆岃皟宀椾汉銆嶅悗锛岃嚜鍔ㄥ甫鍑哄叾褰撳墠閮ㄩ棬 / 宀椾綅
+  async handleValuesChange(values: any, changedFields: string[]) {
+    if (changedFields?.includes('userId')) {
+      await fillCurrentPosition(values?.userId);
+    }
+  },
 });
 
 const [Modal, modalApi] = useVbenModal({
@@ -53,7 +88,6 @@
     }
     modalApi.lock();
     const data = (await formApi.getValues()) as HrmTransferApi.Transfer;
-    data.employeeId = currentEmployeeId.value;
     try {
       if (data.id) {
         await updateTransfer(data);
@@ -71,30 +105,31 @@
     if (!isOpen) {
       return;
     }
+    employeeCache = [];
     const data = modalApi.getData<{ formType: FormType; id?: number }>();
     formType.value = data.formType;
     formApi.setState({ schema: useFormSchema(data.formType) });
     formApi.setDisabled(data.formType === 'detail');
     modalApi.setState({ showConfirmButton: data.formType !== 'detail' });
     if (!data?.id) {
-      // 鏂板鏃讹紝鑷姩鑾峰彇褰撳墠鐧诲綍鍛樺伐鐨勯儴闂ㄥ拰宀椾綅淇℃伅
-      const employees = await getEmployeeSimpleList();
-      // TODO: 杩欓噷搴旇鏍规嵁鐧诲綍鐢ㄦ埛鑾峰彇瀵瑰簲鐨勫憳宸ヤ俊鎭紝鏆傛椂鍙栫涓�涓憳宸ヤ綔涓虹ず渚�
-      const currentEmployee = employees[0];
-      if (currentEmployee) {
-        currentEmployeeId.value = currentEmployee.id;
-        await formApi.setValues({
-          currentDeptName: currentEmployee.deptName,
-          currentPostName: currentEmployee.postName,
-        });
-      }
+      // 鏂板锛氭竻绌鸿〃鍗曪紝鐢辩敤鎴烽�夋嫨璋冨矖浜�
+      await formApi.setValues({
+        userId: undefined,
+        currentDeptId: undefined,
+        currentDeptName: undefined,
+        currentPostId: undefined,
+        currentPostName: undefined,
+      });
       return;
     }
     modalApi.lock();
     try {
       const transfer = await getTransfer(data.id);
-      currentEmployeeId.value = transfer.employeeId;
       await formApi.setValues(transfer);
+      // 鍘嗗彶鏁版嵁鍙兘娌℃湁鍘熼儴闂�/宀椾綅锛屾寜璋冨矖浜鸿ˉ榻�
+      if (transfer.userId && !transfer.currentDeptId) {
+        await fillCurrentPosition(transfer.userId);
+      }
       if (transfer.attachmentList?.length) {
         await formApi.setFieldValue('blobIds', transfer.attachmentList.map(item => ({
           uid: String(item.id),
@@ -112,7 +147,7 @@
 </script>
 
 <template>
-  <Modal :title="getTitle" class="w-[600px]">
+  <Modal :title="getTitle" class="w-[700px]">
     <Form class="mx-4" />
   </Modal>
-</template>
\ No newline at end of file
+</template>

--
Gitblit v1.9.3