From 91eff4781fa4142d1f62d30a0fa1de5cae424eaf Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期三, 16 九月 2026 18:23:12 +0800
Subject: [PATCH] refactor: 单据审核改为审批配置状态机(前端统一审核弹窗)

---
 src/views/hrm/attendance/exception/index.vue |  134 ++++++++++++++++++++++++++------------------
 1 files changed, 80 insertions(+), 54 deletions(-)

diff --git a/src/views/hrm/attendance/exception/index.vue b/src/views/hrm/attendance/exception/index.vue
index acd5d7a..bba52f3 100644
--- a/src/views/hrm/attendance/exception/index.vue
+++ b/src/views/hrm/attendance/exception/index.vue
@@ -5,28 +5,60 @@
 import { ref } from 'vue';
 
 import { Page, useVbenModal } from '#/packages/effects/common-ui/src';
+import { useUserStore } from '@vben/stores';
 
-import { message, Modal, Select } from 'ant-design-vue';
+import { message } from 'ant-design-vue';
 
 import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
 import {
-  getAttendanceExceptionApproveProcessList,
+  getAttendanceExceptionApproverIds,
   getAttendanceExceptionPage,
   submitAttendanceException,
 } from '#/api/hrm/attendance/exception';
 import { $t } from '#/locales';
 
 import { useGridColumns, useGridFormSchema } from './data';
+import AuditModal from './modules/audit-modal.vue';
 import Form from './modules/form.vue';
+
+const userStore = useUserStore();
+const currentUserId = userStore.userInfo?.id; // 褰撳墠鐧诲綍鐢ㄦ埛 ID锛岀敤浜庡鎵逛汉鏉冮檺鍒ゆ柇
+
+/** 瀹℃壒閰嶇疆涓涓氬姟鐨勫鎵逛汉缂栧彿闆嗗悎锛屽喅瀹氥�屽鏍� / 瀹℃牳涓嶉�氳繃銆嶆寜閽槸鍚﹀睍绀� */
+const approverIds = ref<number[]>([]);
+
+/** 鎷夊彇瀹℃壒浜洪泦鍚堬紱澶辫触鏃朵繚鎸佷负绌猴紙鎸夐挳涓嶅睍绀猴級锛屼笉闃绘柇鍒楄〃鍔犺浇 */
+async function loadApproverIds() {
+  try {
+    approverIds.value = (await getAttendanceExceptionApproverIds()) ?? [];
+  } catch {
+    approverIds.value = [];
+  }
+}
+
+/** 褰撳墠鐧诲綍鐢ㄦ埛鏄惁涓鸿涓氬姟鐨勫鎵逛汉锛屼笖鐢宠澶勪簬瀹℃壒涓紙10锛� */
+function canAudit(row: HrmAttendanceExceptionApi.AttendanceException) {
+  return (
+    row.status === 10 &&
+    !!currentUserId &&
+    approverIds.value.includes(currentUserId)
+  );
+}
 
 const [FormModal, formModalApi] = useVbenModal({
   connectedComponent: Form,
   destroyOnClose: true,
 });
 
-/** 鍒锋柊琛ㄦ牸 */
+const [AuditModalComp, auditModalApi] = useVbenModal({
+  connectedComponent: AuditModal,
+  destroyOnClose: true,
+});
+
+/** 鍒锋柊琛ㄦ牸涓庡鎵逛汉闆嗗悎 */
 function handleRefresh() {
   gridApi.query();
+  loadApproverIds();
 }
 
 /** 鍒涘缓鑰冨嫟寮傚父鐢宠 */
@@ -39,37 +71,27 @@
   formModalApi.setData({ id: row.id, formType: 'detail' }).open();
 }
 
-/** 鎻愪氦瀹℃壒寮圭獥 */
-const submitModalVisible = ref(false);
-const currentRow = ref<HrmAttendanceExceptionApi.AttendanceException>();
-const processList = ref<HrmAttendanceExceptionApi.ApproveProcess[]>([]);
-const selectedProcessKey = ref<string>();
-const submitLoading = ref(false);
-
-/** 鎻愪氦鑰冨嫟寮傚父鐢宠 */
+/** 鎻愪氦瀹℃壒 - 瀹℃壒浜虹敱銆岀郴缁熺鐞� - 瀹℃壒閰嶇疆銆嶇粺涓�鎸囧畾锛屾澶勬棤闇�閫夋嫨 */
 async function handleSubmit(row: HrmAttendanceExceptionApi.AttendanceException) {
-  const res = await getAttendanceExceptionApproveProcessList();
-  processList.value = res;
-  currentRow.value = row;
-  selectedProcessKey.value = undefined;
-  submitModalVisible.value = true;
-}
-
-/** 纭鎻愪氦 */
-async function confirmSubmit() {
-  if (!selectedProcessKey.value) {
-    message.warning('璇烽�夋嫨瀹℃壒娴佺▼');
-    return;
-  }
-  submitLoading.value = true;
+  const hideLoading = message.loading({
+    content: '姝e湪鎻愪氦瀹℃壒...',
+    duration: 0,
+  });
   try {
-    await submitAttendanceException(currentRow.value!.id!, selectedProcessKey.value);
+    await submitAttendanceException(row.id!);
     message.success('鎻愪氦瀹℃壒鎴愬姛');
-    submitModalVisible.value = false;
     handleRefresh();
   } finally {
-    submitLoading.value = false;
+    hideLoading();
   }
+}
+
+/** 瀹℃牳 - 閫氳繃 / 涓嶉�氳繃 */
+function handleAudit(
+  row: HrmAttendanceExceptionApi.AttendanceException,
+  pass: boolean,
+) {
+  auditModalApi.setData({ pass, row }).open();
 }
 
 const [Grid, gridApi] = useVbenVxeGrid({
@@ -100,11 +122,15 @@
     },
   } as VxeTableGridOptions<HrmAttendanceExceptionApi.AttendanceException>,
 });
+
+// 杩涘叆椤甸潰鍗虫媺鍙栧鎵逛汉闆嗗悎锛岀敤浜庢帶鍒跺鏍告寜閽樉闅�
+loadApproverIds();
 </script>
 
 <template>
   <Page auto-content-height>
     <FormModal @success="handleRefresh" />
+    <AuditModalComp @success="handleRefresh" />
     <Grid table-title="鑰冨嫟寮傚父鐢宠鍒楄〃">
       <template #toolbar-tools>
         <TableAction
@@ -128,38 +154,38 @@
               onClick: handleDetail.bind(null, row),
             },
             {
-              label: '鎻愪氦',
+              label: '鎻愪氦瀹℃壒',
               type: 'link',
               auth: ['hrm:attendance-exception:submit'],
-              ifShow: row.status === 0,
-              onClick: handleSubmit.bind(null, row),
+              // 瀹℃壒浜虹敱瀹℃壒閰嶇疆缁熶竴鎸囧畾锛屾彁浜ゅ墠浠呬簩娆$‘璁わ紝涓嶅啀寮归�夋祦绋嬫
+              popConfirm: {
+                title: '纭鎻愪氦瀹℃壒锛熸彁浜ゅ悗鐢卞鎵归厤缃腑鎸囧畾鐨勫鎵逛汉澶勭悊銆�',
+                confirm: handleSubmit.bind(null, row),
+              },
+              // 鑽夌(0) 涓� 瀹℃牳涓嶉�氳繃(30) 鍧囧彲鎻愪氦锛屽悗鑰呴渶淇敼鍚庨噸鏂版彁浜�
+              ifShow: row.status === 0 || row.status === 30,
+            },
+            {
+              label: '瀹℃牳',
+              type: 'link',
+              icon: ACTION_ICON.AUDIT,
+              auth: ['hrm:attendance-exception:audit'],
+              // 浠呫�屽鎵逛腑 + 褰撳墠鐧诲綍鐢ㄦ埛鍦ㄥ鎵归厤缃殑瀹℃壒浜哄悕鍗曞唴銆嶆墠鏄剧ず
+              ifShow: canAudit(row),
+              onClick: handleAudit.bind(null, row, true),
+            },
+            {
+              label: '瀹℃牳涓嶉�氳繃',
+              type: 'link',
+              danger: true,
+              auth: ['hrm:attendance-exception:audit'],
+              // 鍚屼笂锛屼笌銆屽鏍搞�嶆垚瀵瑰嚭鐜�
+              ifShow: canAudit(row),
+              onClick: handleAudit.bind(null, row, false),
             },
           ]"
         />
       </template>
     </Grid>
-
-    <!-- 鎻愪氦瀹℃壒寮圭獥 -->
-    <Modal
-      v-model:open="submitModalVisible"
-      title="閫夋嫨瀹℃壒娴佺▼"
-      width="400px"
-      @ok="confirmSubmit"
-      :confirmLoading="submitLoading"
-    >
-      <Select
-        v-model:value="selectedProcessKey"
-        placeholder="璇烽�夋嫨瀹℃壒娴佺▼"
-        class="w-full"
-      >
-        <Select.Option
-          v-for="item in processList"
-          :key="item.key"
-          :value="item.key"
-        >
-          {{ item.name }}
-        </Select.Option>
-      </Select>
-    </Modal>
   </Page>
 </template>
\ No newline at end of file

--
Gitblit v1.9.3