<script lang="ts" setup>
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { HrmEmployeeContractApi } from '#/api/hrm/employee/contract';
|
|
import { Page, useVbenModal } from '#/packages/effects/common-ui/src';
|
import { downloadFileFromBlobPart } from '#/packages/utils/src';
|
|
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';
|
|
import { useGridColumns, useGridFormSchema } from './data';
|
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,
|
destroyOnClose: true,
|
});
|
|
const [ImportModal, importModalApi] = useVbenModal({
|
connectedComponent: ImportForm,
|
destroyOnClose: true,
|
});
|
|
const [TerminateModal, terminateModalApi] = useVbenModal({
|
connectedComponent: Terminate,
|
destroyOnClose: true,
|
});
|
|
const [AttachmentModal, attachmentModalApi] = useVbenModal({
|
connectedComponent: Attachment,
|
destroyOnClose: true,
|
});
|
|
/** 刷新表格 */
|
function handleRefresh() {
|
gridApi.query();
|
}
|
|
/** 新增合同 */
|
function handleCreate() {
|
formModalApi.setData({ formType: 'create' }).open();
|
}
|
|
/** 导入合同 */
|
function handleImport() {
|
importModalApi.open();
|
}
|
|
/** 下载合同空白模板:type 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();
|
}
|
|
/** 续签合同:带入上份合同基础信息,创建新合同(后端自动关联 parentId) */
|
function handleRenew(row: HrmEmployeeContractApi.EmployeeContract) {
|
formModalApi.setData({ formType: 'create', renewFrom: row }).open();
|
}
|
|
/** 解除/终止合同 */
|
function handleTerminate(row: HrmEmployeeContractApi.EmployeeContract) {
|
terminateModalApi.setData({ id: row.id }).open();
|
}
|
|
/** 查看合同附件 */
|
function handleAttachments(row: HrmEmployeeContractApi.EmployeeContract) {
|
attachmentModalApi.setData({ id: row.id }).open();
|
}
|
|
/** 生成合同(docx):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('合同已生成,并归档到该合同附件');
|
handleRefresh();
|
}
|
|
/** “更多”菜单:修改 / 续签 / 解除终止 / 删除 */
|
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;
|
}
|
}
|
}
|
|
/** 删除合同 */
|
async function handleDelete(row: HrmEmployeeContractApi.EmployeeContract) {
|
await deleteEmployeeContract(row.id!);
|
message.success($t('ui.actionMessage.deleteSuccess', ['员工合同']));
|
handleRefresh();
|
}
|
|
/** 是否可解除/终止:仅未解除/未终止的合同可操作 */
|
function isTerminable(row: HrmEmployeeContractApi.EmployeeContract) {
|
return row.terminateStatus === 0;
|
}
|
|
const [Grid, gridApi] = useVbenVxeGrid({
|
formOptions: {
|
schema: useGridFormSchema(),
|
},
|
gridOptions: {
|
columns: useGridColumns(),
|
height: 'auto',
|
keepSource: true,
|
proxyConfig: {
|
ajax: {
|
query: async ({ page }, formValues) =>
|
await getEmployeeContractPage({
|
pageNo: page.currentPage,
|
pageSize: page.pageSize,
|
...formValues,
|
}),
|
},
|
},
|
rowConfig: {
|
keyField: 'id',
|
isHover: true,
|
},
|
toolbarConfig: {
|
refresh: true,
|
search: true,
|
},
|
} as VxeTableGridOptions<HrmEmployeeContractApi.EmployeeContract>,
|
});
|
</script>
|
|
<template>
|
<Page auto-content-height>
|
<FormModal @success="handleRefresh" />
|
<ImportModal @success="handleRefresh" />
|
<TerminateModal @success="handleRefresh" />
|
<AttachmentModal />
|
<Grid table-title="员工合同列表">
|
<template #parentNo="{ row }">
|
<span>{{ row.parentNo || '-' }}</span>
|
</template>
|
<template #isCurrent="{ row }">
|
<Tag v-if="row.isCurrent" color="processing">当前</Tag>
|
<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="[
|
{
|
label: $t('ui.actionTitle.create', ['员工合同']),
|
type: 'primary',
|
icon: ACTION_ICON.ADD,
|
auth: ['hrm:employee-contract:create'],
|
onClick: handleCreate,
|
},
|
{
|
label: '导入',
|
type: 'primary',
|
icon: ACTION_ICON.UPLOAD,
|
auth: ['hrm:employee-contract:import'],
|
onClick: handleImport,
|
},
|
]"
|
/>
|
</template>
|
<template #actions="{ 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">解除/终止</Menu.Item>
|
<Menu.Divider />
|
<Menu.Item danger key="delete">删除</Menu.Item>
|
</Menu>
|
</template>
|
</Dropdown>
|
</template>
|
</Grid>
|
</Page>
|
</template>
|