| | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { HrmSalaryCalculationApi } from '#/api/hrm/salary/calculation'; |
| | | |
| | | import { ref } from 'vue'; |
| | | import { ref, watch } from 'vue'; |
| | | |
| | | import { Page } from '#/packages/effects/common-ui/src'; |
| | | import { downloadFileFromBlobPart } from '#/packages/utils/src'; |
| | |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | calculateSalary, |
| | | confirmSalary, |
| | | deleteSalaryCalculation, |
| | | exportSalaryCalculation, |
| | | getSalaryCalculationPage, |
| | | previewSalaryCalculation, |
| | | revokeSalaryCalculation, |
| | | saveSalaryCalculation, |
| | | } from '#/api/hrm/salary/calculation'; |
| | | import { getDeptList } from '#/api/system/dept'; |
| | |
| | | const previewLoading = ref(false); |
| | | const previewData = ref<HrmSalaryCalculationApi.SalaryCalculation[]>([]); |
| | | const submitLoading = ref(false); |
| | | const calculateLoading = ref(false); |
| | | |
| | | // 打开核算弹窗 |
| | | async function openCalculateModal() { |
| | |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** 执行薪酬核算(自动计算并保存) */ |
| | | async function handleCalculate() { |
| | | if (!calculatePeriod.value) { |
| | | message.warning('请选择核算周期'); |
| | | return; |
| | | // 核算成果只允许在「预览 → 保存」之间流转:改了周期/部门就必须重新预览, |
| | | // 否则会把上一轮的预览结果按新的周期存下去 |
| | | watch([calculatePeriod, calculateDeptId], () => { |
| | | if (previewData.value.length > 0) { |
| | | previewData.value = []; |
| | | message.info('核算周期或部门已变更,请重新预览数据'); |
| | | } |
| | | calculateLoading.value = true; |
| | | try { |
| | | await calculateSalary({ |
| | | period: calculatePeriod.value, |
| | | deptId: calculateDeptId.value, |
| | | }); |
| | | message.success('薪酬核算执行成功'); |
| | | calculateVisible.value = false; |
| | | handleRefresh(); |
| | | } finally { |
| | | calculateLoading.value = false; |
| | | } |
| | | } |
| | | }); |
| | | |
| | | /** 预览核算数据 */ |
| | | async function handlePreview() { |
| | |
| | | handleRefresh(); |
| | | } |
| | | |
| | | /** 批量确认 */ |
| | | /** 批量确认选中的记录 */ |
| | | async function handleBatchConfirm() { |
| | | const records = gridApi.grid.getCheckboxRecords() as HrmSalaryCalculationApi.SalaryCalculation[]; |
| | | if (records.length === 0) { |
| | |
| | | await confirmSalary(ids); |
| | | message.success('确认成功'); |
| | | handleRefresh(); |
| | | } |
| | | |
| | | /** 批量保存选中的核算记录(仅待确认状态) */ |
| | | async function handleBatchSave() { |
| | | const records = gridApi.grid.getCheckboxRecords() as HrmSalaryCalculationApi.SalaryCalculation[]; |
| | | if (records.length === 0) { |
| | | message.warning('请选择要保存的记录'); |
| | | return; |
| | | } |
| | | const pending = records.filter((r) => r.status === 0); |
| | | if (pending.length === 0) { |
| | | message.warning('选中的记录均非待确认状态,无需保存'); |
| | | return; |
| | | } |
| | | const first = pending[0]; |
| | | if (!first?.period) { |
| | | message.warning('缺少核算周期'); |
| | | return; |
| | | } |
| | | await saveSalaryCalculation({ period: first.period, list: pending }); |
| | | message.success('批量保存成功'); |
| | | handleRefresh(); |
| | | } |
| | | |
| | | /** 撤销确认(已确认 → 待确认,可重新核算) */ |
| | | async function handleRevoke(row: HrmSalaryCalculationApi.SalaryCalculation) { |
| | | Modal.confirm({ |
| | | title: '撤销确认', |
| | | content: `确定撤销【${row.no}】的确认吗?撤销后可重新核算。`, |
| | | okText: '确定', |
| | | cancelText: '取消', |
| | | onOk: async () => { |
| | | await revokeSalaryCalculation([row.id!]); |
| | | message.success('撤销成功'); |
| | | handleRefresh(); |
| | | }, |
| | | }); |
| | | } |
| | | |
| | | /** 删除待确认的核算记录 */ |
| | | async function handleDelete(row: HrmSalaryCalculationApi.SalaryCalculation) { |
| | | Modal.confirm({ |
| | | title: '确认删除', |
| | | content: `确定删除【${row.no}】的核算记录吗?删除后需重新核算。`, |
| | | okText: '确定', |
| | | cancelText: '取消', |
| | | onOk: async () => { |
| | | await deleteSalaryCalculation(row.id!); |
| | | message.success('删除成功'); |
| | | handleRefresh(); |
| | | }, |
| | | }); |
| | | } |
| | | |
| | | /** 导出薪酬核算 */ |
| | |
| | | keepSource: true, |
| | | checkboxConfig: { |
| | | highlight: true, |
| | | reserve: true, |
| | | }, |
| | | proxyConfig: { |
| | | ajax: { |
| | |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | pagingConfig: { |
| | | pageSize: 20, |
| | | pageSizes: [20, 50, 100], |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | |
| | | :maskClosable="false" |
| | | > |
| | | <Alert |
| | | message="两种核算方式:1. 执行核算 - 自动计算并保存;2. 预览数据 - 手动调整后保存" |
| | | message="核算流程:选好核算周期与部门后点「预览数据」→ 核对/调整各项金额 → 点「保存核算」落库" |
| | | type="info" |
| | | show-icon |
| | | style="margin-bottom: 16px" |
| | |
| | | /> |
| | | </FormItem> |
| | | <FormItem> |
| | | <a-button type="primary" :loading="calculateLoading" @click="handleCalculate"> |
| | | 执行核算 |
| | | </a-button> |
| | | </FormItem> |
| | | <FormItem> |
| | | <a-button :loading="previewLoading" @click="handlePreview"> |
| | | <a-button type="primary" :loading="previewLoading" @click="handlePreview"> |
| | | 预览数据 |
| | | </a-button> |
| | | </FormItem> |
| | |
| | | v-if="previewData.length > 0" |
| | | :columns="usePreviewColumns()" |
| | | :data-source="previewData" |
| | | :pagination="false" |
| | | :pagination="{ pageSize: 20, showSizeChanger: true, showTotal: (t) => `共 ${t} 人` }" |
| | | :scroll="{ x: 1800, y: 400 }" |
| | | size="small" |
| | | row-key="userId" |
| | |
| | | onClick: handleBatchConfirm, |
| | | }, |
| | | { |
| | | label: '批量保存', |
| | | type: 'primary', |
| | | auth: ['hrm:salary-calculation:save'], |
| | | onClick: handleBatchSave, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | |
| | | ifShow: row.status === 0, |
| | | onClick: handleConfirm.bind(null, row), |
| | | }, |
| | | { |
| | | label: '删除', |
| | | type: 'link', |
| | | danger: true, |
| | | auth: ['hrm:salary-calculation:delete'], |
| | | ifShow: row.status === 0, |
| | | onClick: handleDelete.bind(null, row), |
| | | }, |
| | | { |
| | | label: '撤销确认', |
| | | type: 'link', |
| | | auth: ['hrm:salary-calculation:confirm'], |
| | | ifShow: row.status === 10, |
| | | onClick: handleRevoke.bind(null, row), |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |