From 55e155a169b63cea3262d95cf51705ef173a36c2 Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期一, 12 十月 2026 10:09:40 +0800
Subject: [PATCH] feat(hrm): 合同生成与模板下载、员工转正、导入导出字段对齐

---
 src/views/hrm/employee/contract/index.vue |  156 +++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 117 insertions(+), 39 deletions(-)

diff --git a/src/views/hrm/employee/contract/index.vue b/src/views/hrm/employee/contract/index.vue
index 02aa33c..c28ef57 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 { DownOutlined } from '@ant-design/icons-vue';
+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,18 @@
         <span v-else>-</span>
       </template>
       <template #toolbar-tools>
+        <Dropdown>
+          <Button class="mr-2" type="primary">
+            涓嬭浇鍚堝悓妯℃澘 <DownOutlined />
+          </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>
+          </template>
+        </Dropdown>
         <TableAction
           :actions="[
             {
@@ -139,44 +232,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>鐢熸垚鍚堝悓 <DownOutlined /></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>鏇村 <DownOutlined /></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>

--
Gitblit v1.9.3