gaoluyang
7 天以前 e4994fccfb49ebfb108ba62cbd82aea4e004f6d8
src/views/hrm/salary/calculation/index.vue
@@ -2,7 +2,7 @@
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';
@@ -14,11 +14,12 @@
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';
@@ -35,7 +36,6 @@
const previewLoading = ref(false);
const previewData = ref<HrmSalaryCalculationApi.SalaryCalculation[]>([]);
const submitLoading = ref(false);
const calculateLoading = ref(false);
// 打开核算弹窗
async function openCalculateModal() {
@@ -54,25 +54,14 @@
  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() {
@@ -153,7 +142,7 @@
  handleRefresh();
}
/** 批量确认 */
/** 批量确认选中的记录 */
async function handleBatchConfirm() {
  const records = gridApi.grid.getCheckboxRecords() as HrmSalaryCalculationApi.SalaryCalculation[];
  if (records.length === 0) {
@@ -164,6 +153,58 @@
  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();
    },
  });
}
/** 导出薪酬核算 */
@@ -182,7 +223,6 @@
    keepSource: true,
    checkboxConfig: {
      highlight: true,
      reserve: true,
    },
    proxyConfig: {
      ajax: {
@@ -193,6 +233,10 @@
            ...formValues,
          }),
      },
    },
    pagingConfig: {
      pageSize: 20,
      pageSizes: [20, 50, 100],
    },
    rowConfig: {
      keyField: 'id',
@@ -217,7 +261,7 @@
      :maskClosable="false"
    >
      <Alert
        message="两种核算方式:1. 执行核算 - 自动计算并保存;2. 预览数据 - 手动调整后保存"
        message="核算流程:选好核算周期与部门后点「预览数据」→ 核对/调整各项金额 → 点「保存核算」落库"
        type="info"
        show-icon
        style="margin-bottom: 16px"
@@ -246,12 +290,7 @@
          />
        </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>
@@ -261,7 +300,7 @@
        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"
@@ -430,6 +469,12 @@
              onClick: handleBatchConfirm,
            },
            {
              label: '批量保存',
              type: 'primary',
              auth: ['hrm:salary-calculation:save'],
              onClick: handleBatchSave,
            },
            {
              label: $t('ui.actionTitle.export'),
              type: 'primary',
              icon: ACTION_ICON.DOWNLOAD,
@@ -454,6 +499,21 @@
              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>