tuqin
3 小时以前 5b2222922a23a307a97204a01d7c2ca951855c6f
feat(hrm): 薪酬核算列表新增「修改」,支持自定义各金额字段

- 操作栏新增「修改」(仅待确认状态显示)
- 新增编辑弹窗:收入项/扣除项/出勤天数/加班时长/备注,实发工资实时自动计算
- 操作列宽度 120→220
已添加1个文件
已修改2个文件
132 ■■■■■ 文件已修改
src/views/hrm/salary/calculation/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/hrm/salary/calculation/index.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/hrm/salary/calculation/modules/form.vue 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/hrm/salary/calculation/data.ts
@@ -101,7 +101,7 @@
    },
    {
      title: '操作',
      width: 120,
      width: 220,
      fixed: 'right',
      slots: {
        default: 'actions',
src/views/hrm/salary/calculation/index.vue
@@ -28,8 +28,10 @@
import { $t } from '#/locales';
import { useGridColumns, useGridFormSchema, usePreviewColumns } from './data';
import FormModal from './modules/form.vue';
// æ ¸ç®—弹窗相关
const formModalRef = ref();
const calculateVisible = ref(false);
const calculatePeriod = ref<string>();
const calculateDeptId = ref<number>();
@@ -469,6 +471,7 @@
      </div>
    </Modal>
    <FormModal ref="formModalRef" @success="handleRefresh" />
    <Grid table-title="薪酬核算列表">
      <template #toolbar-tools>
        <TableAction
@@ -511,6 +514,13 @@
        <TableAction
          :actions="[
            {
              label: '修改',
              type: 'link',
              auth: ['hrm:salary-calculation:calculate'],
              ifShow: row.status === 0,
              onClick: () => formModalRef.value?.open(row),
            },
            {
              label: '确认',
              type: 'link',
              auth: ['hrm:salary-calculation:confirm'],
src/views/hrm/salary/calculation/modules/form.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,120 @@
<script lang="ts" setup>
import type { HrmSalaryCalculationApi } from '#/api/hrm/salary/calculation';
import { computed, ref } from 'vue';
import { message, Modal, Form, FormItem, Input, InputNumber } from 'ant-design-vue';
import { updateSalaryCalculation } from '#/api/hrm/salary/calculation';
const emit = defineEmits(['success']);
const visible = ref(false);
const loading = ref(false);
/** å½“前编辑的记录(含所有可编辑字段) */
const current = ref<Record<string, any>>({});
/** æ”¶å…¥é¡¹ */
const incomeFields = [
  { key: 'baseSalary', label: '基本工资' },
  { key: 'performanceSalary', label: '绩效工资' },
  { key: 'overtimePay', label: '加班费' },
  { key: 'mealAllowance', label: '餐补' },
  { key: 'transportAllowance', label: '交通补贴' },
  { key: 'otherAllowance', label: '其他补贴' },
];
/** æ‰£é™¤é¡¹ */
const deductionFields = [
  { key: 'socialSecurityDeduction', label: '社保扣款' },
  { key: 'housingFundDeduction', label: '公积金扣款' },
  { key: 'taxDeduction', label: '个税扣款' },
  { key: 'otherDeduction', label: '其他扣款' },
  { key: 'leaveDeduction', label: '请假扣款' },
];
/** å®žå‘工资(实时计算,与后端口径一致) */
const actualSalary = computed(() => {
  const num = (v: any) => (v === undefined || v === null || v === '' ? 0 : Number(v));
  const income = incomeFields.reduce((sum, f) => sum + num(current.value[f.key]), 0);
  const deduction = deductionFields.reduce((sum, f) => sum + num(current.value[f.key]), 0);
  return Number((income - deduction).toFixed(2));
});
function open(row: HrmSalaryCalculationApi.SalaryCalculation) {
  current.value = { ...row };
  visible.value = true;
}
async function handleOk() {
  loading.value = true;
  try {
    await updateSalaryCalculation({
      ...(current.value as HrmSalaryCalculationApi.SalaryCalculation),
      actualSalary: actualSalary.value,
    });
    message.success('修改成功');
    visible.value = false;
    emit('success');
  } finally {
    loading.value = false;
  }
}
defineExpose({ open });
</script>
<template>
  <Modal
    v-model:open="visible"
    :title="`修改薪酬核算${current.no ? ' - ' + current.no : ''}`"
    :width="760"
    :confirm-loading="loading"
    ok-text="保存"
    cancel-text="取消"
    @ok="handleOk"
  >
    <Form layout="vertical" class="mt-2">
      <div class="mb-2 text-sm font-semibold text-gray-700">收入项</div>
      <div class="grid grid-cols-3 gap-x-4">
        <FormItem v-for="f in incomeFields" :key="f.key" :label="f.label">
          <InputNumber
            v-model:value="current[f.key]"
            :min="0"
            :precision="2"
            style="width: 100%"
          />
        </FormItem>
      </div>
      <div class="mb-2 mt-2 text-sm font-semibold text-gray-700">扣除项</div>
      <div class="grid grid-cols-3 gap-x-4">
        <FormItem v-for="f in deductionFields" :key="f.key" :label="f.label">
          <InputNumber
            v-model:value="current[f.key]"
            :min="0"
            :precision="2"
            style="width: 100%"
          />
        </FormItem>
      </div>
      <div class="mb-2 mt-2 text-sm font-semibold text-gray-700">考勤 / å…¶ä»–</div>
      <div class="grid grid-cols-3 gap-x-4">
        <FormItem label="出勤天数">
          <InputNumber v-model:value="current.workDays" :min="0" :max="31" :precision="0" style="width: 100%" />
        </FormItem>
        <FormItem label="加班时长(h)">
          <InputNumber v-model:value="current.overtimeHours" :min="0" :precision="1" style="width: 100%" />
        </FormItem>
        <FormItem label="实发工资(自动计算)">
          <Input :value="actualSalary.toFixed(2)" disabled class="font-bold text-green-600" />
        </FormItem>
      </div>
      <FormItem label="备注">
        <Input.TextArea v-model:value="current.remark" :rows="2" placeholder="请输入备注" />
      </FormItem>
    </Form>
  </Modal>
</template>