From 1ae52b4e9e4fea731844fae1a9217d2128a9335c Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期五, 12 六月 2026 14:19:40 +0800
Subject: [PATCH] 工资计算逻辑放到后端
---
src/api/personnelManagement/staffSalaryMain.js | 9 +
src/views/personnelManagement/monthlyStatistics/components/formDia.vue | 260 ++++++++++++++++++++++++++++++----------------------
2 files changed, 158 insertions(+), 111 deletions(-)
diff --git a/src/api/personnelManagement/staffSalaryMain.js b/src/api/personnelManagement/staffSalaryMain.js
index a42f96b..08de85c 100644
--- a/src/api/personnelManagement/staffSalaryMain.js
+++ b/src/api/personnelManagement/staffSalaryMain.js
@@ -17,6 +17,14 @@
});
}
+export function staffSalaryMainCalculateByEmployeeId(data) {
+ return request({
+ url: "/staffSalaryMain/calculateByEmployeeId",
+ method: "post",
+ data,
+ });
+}
+
export function staffSalaryMainAdd(data) {
return request({
url: "/staffSalaryMain/add",
@@ -40,4 +48,3 @@
data: ids,
});
}
-
diff --git a/src/views/personnelManagement/monthlyStatistics/components/formDia.vue b/src/views/personnelManagement/monthlyStatistics/components/formDia.vue
index 26b5c73..b3437e7 100644
--- a/src/views/personnelManagement/monthlyStatistics/components/formDia.vue
+++ b/src/views/personnelManagement/monthlyStatistics/components/formDia.vue
@@ -141,7 +141,7 @@
type="number"
placeholder="0"
size="small"
- @input="calculateRow(row)" />
+ @input="handleSalaryInput(row)" />
</template>
</el-table-column>
<el-table-column label="鐧界彮澶╂暟"
@@ -151,7 +151,7 @@
type="number"
placeholder="0"
size="small"
- @input="calculateRow(row)" />
+ @input="handleSalaryInput(row)" />
</template>
</el-table-column>
<el-table-column label="澶滅彮澶╂暟"
@@ -161,7 +161,7 @@
type="number"
placeholder="0"
size="small"
- @input="calculateRow(row)" />
+ @input="handleSalaryInput(row)" />
</template>
</el-table-column>
<el-table-column label="椁愯ˉ"
@@ -191,7 +191,7 @@
type="number"
placeholder="0"
size="small"
- @input="calculateRow(row)" />
+ @input="handleSalaryInput(row)" />
</template>
</el-table-column>
<el-table-column label="绀句繚涓汉"
@@ -201,8 +201,7 @@
type="number"
placeholder="0"
size="small"
- disabled
- @input="calculateRow(row)" />
+ disabled />
</template>
</el-table-column>
<el-table-column label="鍏Н閲戜釜浜�"
@@ -222,7 +221,7 @@
type="number"
placeholder="0"
size="small"
- @input="calculateRow(row)" />
+ @input="handleSalaryInput(row)" />
</template>
</el-table-column>
<el-table-column label="绀句繚琛ョ即"
@@ -370,9 +369,9 @@
staffSalaryMainAdd,
staffSalaryMainUpdate,
staffSalaryMainCalculateSalary,
+ staffSalaryMainCalculateByEmployeeId,
} from "@/api/personnelManagement/staffSalaryMain.js";
import { userListNoPageByTenantId } from "@/api/system/user.js";
- import { listSubsidyConfiguration } from "@/api/personnelManagement/subsidyConfig.js";
const emit = defineEmits(["update:modelValue", "close"]);
const props = defineProps({
@@ -399,59 +398,149 @@
const selectedEmployees = ref([]);
const bankOptions = ref([]);
const userList = ref([]);
- const subsidyStandard = ref({
+ const recalcTimers = new Map();
+ const recalcVersions = new Map();
+
+ const getEmployeeKey = row => row?.staffOnJobId ?? row?.staffId ?? row?.id;
+
+ const createEmptySalaryRow = () => ({
+ staffOnJobId: undefined,
+ id: undefined,
+ staffName: "",
+ postName: "",
+ deptName: "",
+ nation: "",
+ basicSalary: 0,
+ dayDays: 0,
+ nightDays: 0,
mealAmount: 0,
nightAmount: 0,
+ pieceSalary: 0,
+ hourlySalary: 0,
+ otherIncome: 0,
+ socialPersonal: 0,
+ fundPersonal: 0,
+ otherDeduct: 0,
+ socialSupplementAmount: 0,
+ salaryTax: 0,
+ grossSalary: 0,
+ deductSalary: 0,
+ netSalary: 0,
+ remark: "",
});
- const loadSubsidyStandard = () => {
- listSubsidyConfiguration().then(res => {
- if (res.data && res.data.length > 0) {
- subsidyStandard.value = {
- mealAmount: res.data[0].mealAmount || 0,
- nightAmount: res.data[0].nightAmount || 0,
- };
- }
+ const normalizeSalaryRow = source => ({
+ ...createEmptySalaryRow(),
+ ...source,
+ staffOnJobId: source?.staffOnJobId ?? source?.staffId ?? source?.id,
+ id: source?.staffOnJobId ?? source?.staffId ?? source?.id,
+ basicSalary: parseNum(source?.basicSalary),
+ dayDays: parseNum(source?.dayDays ?? source?.dayShiftDays),
+ nightDays: parseNum(source?.nightDays ?? source?.nightShiftDays),
+ mealAmount: parseNum(source?.mealAmount ?? source?.mealSubsidy),
+ nightAmount: parseNum(source?.nightAmount ?? source?.nightSubsidy),
+ pieceSalary: parseNum(source?.pieceSalary),
+ hourlySalary: parseNum(source?.hourlySalary),
+ otherIncome: parseNum(source?.otherIncome),
+ socialPersonal: parseNum(source?.socialPersonal),
+ fundPersonal: parseNum(source?.fundPersonal),
+ otherDeduct: parseNum(source?.otherDeduct),
+ socialSupplementAmount: parseNum(source?.socialSupplementAmount),
+ salaryTax: parseNum(source?.salaryTax),
+ grossSalary: parseNum(source?.grossSalary),
+ deductSalary: parseNum(source?.deductSalary),
+ netSalary: parseNum(source?.netSalary),
+ remark: source?.remark ?? "",
+ });
+
+ const applyBackendRow = (targetRow, sourceRow) => {
+ const normalized = normalizeSalaryRow(sourceRow);
+ Object.assign(targetRow, {
+ staffOnJobId: targetRow.staffOnJobId ?? normalized.staffOnJobId,
+ id: targetRow.id ?? normalized.id,
+ staffName: normalized.staffName || targetRow.staffName || "",
+ postName: normalized.postName || targetRow.postName || "",
+ deptName: normalized.deptName || targetRow.deptName || "",
+ nation: normalized.nation || targetRow.nation || "",
+ basicSalary: normalized.basicSalary,
+ dayDays: normalized.dayDays,
+ nightDays: normalized.nightDays,
+ mealAmount: normalized.mealAmount,
+ nightAmount: normalized.nightAmount,
+ pieceSalary: normalized.pieceSalary,
+ hourlySalary: normalized.hourlySalary,
+ otherIncome: normalized.otherIncome,
+ socialPersonal: normalized.socialPersonal,
+ fundPersonal: normalized.fundPersonal,
+ otherDeduct: normalized.otherDeduct,
+ socialSupplementAmount: normalized.socialSupplementAmount,
+ salaryTax: normalized.salaryTax,
+ grossSalary: normalized.grossSalary,
+ deductSalary: normalized.deductSalary,
+ netSalary: normalized.netSalary,
+ remark: normalized.remark || targetRow.remark || "",
});
};
- const calculateRow = row => {
- // 纭繚鎵�鏈夋暟鍊煎瓧娈典负鏁板瓧
+ const requestBackendRecalculate = row => {
+ const key = String(getEmployeeKey(row) ?? "");
+ if (!key || !form.value.deptIds?.length || !form.value.salaryMonth) {
+ return;
+ }
+ const version = (recalcVersions.get(key) || 0) + 1;
+ recalcVersions.set(key, version);
+ clearTimeout(recalcTimers.get(key));
+ const payload = {
+ staffOnJobId: getEmployeeKey(row),
+ salaryMonth: form.value.salaryMonth,
+ basicSalary: parseNum(row.basicSalary),
+ dayDays: parseNum(row.dayDays),
+ nightDays: parseNum(row.nightDays),
+ pieceSalary: parseNum(row.pieceSalary),
+ hourlySalary: parseNum(row.hourlySalary),
+ otherIncome: parseNum(row.otherIncome),
+ otherDeduct: parseNum(row.otherDeduct),
+ socialPersonal: parseNum(row.socialPersonal),
+ fundPersonal: parseNum(row.fundPersonal),
+ remark: row.remark ?? "",
+ };
+ recalcTimers.set(
+ key,
+ setTimeout(() => {
+ staffSalaryMainCalculateByEmployeeId(payload)
+ .then(res => {
+ if (recalcVersions.get(key) !== version) return;
+ applyBackendRow(row, res?.data || {});
+ })
+ .catch(() => {
+ });
+ }, 300)
+ );
+ };
+
+ const handleSalaryInput = row => {
row.basicSalary = parseNum(row.basicSalary);
row.dayDays = parseNum(row.dayDays);
row.nightDays = parseNum(row.nightDays);
+ row.pieceSalary = parseNum(row.pieceSalary);
+ row.hourlySalary = parseNum(row.hourlySalary);
row.otherIncome = parseNum(row.otherIncome);
- row.socialPersonal = parseNum(row.socialPersonal);
- row.fundPersonal = parseNum(row.fundPersonal);
row.otherDeduct = parseNum(row.otherDeduct);
- row.socialSupplementAmount = parseNum(row.socialSupplementAmount);
- row.salaryTax = parseNum(row.salaryTax);
+ requestBackendRecalculate(row);
+ };
- // 1. 璁$畻澶滅彮琛ヨ创锛氬鐝ぉ鏁� * 鏍囧噯
- row.nightAmount = row.nightDays * subsidyStandard.value.nightAmount;
+ const resetRecalcState = () => {
+ recalcTimers.forEach(timer => clearTimeout(timer));
+ recalcTimers.clear();
+ recalcVersions.clear();
+ };
- // 2. 璁$畻椁愯ˉ锛氫粎闄愬洖鏃忥紝(鐧界彮 + 澶滅彮) * 鏍囧噯
- if (row.nation && (row.nation === "鍥炴棌" || row.nation.includes("鍥�"))) {
- row.mealAmount =
- (row.dayDays + row.nightDays) * subsidyStandard.value.mealAmount;
- } else {
- row.mealAmount = 0;
- }
-
- // 3. 璁$畻搴斿彂宸ヨ祫 = 鍩烘湰宸ヨ祫 + 椁愯ˉ + 澶滅彮琛ュ姪 + 鍏朵粬鏀跺叆
- row.grossSalary =
- row.basicSalary + row.mealAmount + row.nightAmount + row.otherIncome;
-
- // 4. 璁$畻搴旀墸宸ヨ祫 = 绀句繚涓汉 + 鍏Н閲戜釜浜� + 鍏朵粬鏀嚭 + 绀句繚琛ョ即 + 宸ヨ祫涓◣
- row.deductSalary =
- row.socialPersonal +
- row.fundPersonal +
- row.otherDeduct +
- row.socialSupplementAmount +
- row.salaryTax;
-
- // 5. 璁$畻瀹炲彂宸ヨ祫 = 搴斿彂宸ヨ祫 - 搴旀墸宸ヨ祫
- row.netSalary = row.grossSalary - row.deductSalary;
+ const clearRowRecalcState = row => {
+ const key = String(getEmployeeKey(row) ?? "");
+ if (!key) return;
+ clearTimeout(recalcTimers.get(key));
+ recalcTimers.delete(key);
+ recalcVersions.delete(key);
};
const taxTableData = ref([
{ level: 1, range: "涓嶈秴杩�36000鍏�", rate: 3, quickDeduction: 0 },
@@ -579,10 +668,10 @@
const openDialog = (type, row) => {
nextTick(() => {
+ resetRecalcState();
loadDeptOptions();
loadBankOptions();
loadUserList();
- loadSubsidyStandard();
employeeList.value = [];
Object.assign(form.value, {
id: undefined,
@@ -611,29 +700,7 @@
// 濡傛灉鏈夊憳宸ユ槑缁嗘暟鎹紝鐩存帴鍙嶆樉
if (row.staffSalaryDetailList && row.staffSalaryDetailList.length > 0) {
- employeeList.value = row.staffSalaryDetailList.map(e => ({
- staffOnJobId: e.staffOnJobId ?? e.staffId ?? e.id,
- id: e.staffOnJobId ?? e.staffId ?? e.id,
- staffName: e.staffName ?? "",
- postName: e.postName ?? "",
- deptName: e.deptName ?? "",
- nation: e.nation ?? "",
- basicSalary: parseNum(e.basicSalary),
- dayDays: parseNum(e.dayDays ?? e.dayShiftDays),
- nightDays: parseNum(e.nightDays ?? e.nightShiftDays),
- mealAmount: parseNum(e.mealAmount ?? e.mealSubsidy),
- nightAmount: parseNum(e.nightAmount ?? e.nightSubsidy),
- otherIncome: parseNum(e.otherIncome),
- socialPersonal: parseNum(e.socialPersonal),
- fundPersonal: parseNum(e.fundPersonal),
- otherDeduct: parseNum(e.otherDeduct),
- socialSupplementAmount: parseNum(e.socialSupplementAmount),
- salaryTax: parseNum(e.salaryTax),
- grossSalary: parseNum(e.grossSalary),
- deductSalary: parseNum(e.deductSalary),
- netSalary: parseNum(e.netSalary),
- remark: e.remark ?? "",
- }));
+ employeeList.value = row.staffSalaryDetailList.map(e => normalizeSalaryRow(e));
}
}
});
@@ -662,7 +729,8 @@
const id = node.staffId ?? node.id;
if (existIds.has(id)) return;
existIds.add(id);
- employeeList.value.push({
+ const newRow = {
+ ...createEmptySalaryRow(),
staffOnJobId: id,
id,
staffName: node.label,
@@ -670,26 +738,15 @@
deptName: node.deptName ?? "",
nation: node.nation ?? "",
basicSalary: parseNum(node.basicSalary),
- dayDays: 0,
- nightDays: 0,
- mealAmount: 0,
- nightAmount: 0,
- otherIncome: 0,
- socialPersonal: 0,
- fundPersonal: 0,
- otherDeduct: 0,
- socialSupplementAmount: 0,
- salaryTax: 0,
- grossSalary: 0,
- deductSalary: 0,
- netSalary: 0,
- remark: "",
- });
+ };
+ employeeList.value.push(newRow);
+ requestBackendRecalculate(newRow);
});
addPersonVisible.value = false;
};
const removeEmployee = row => {
+ clearRowRecalcState(row);
employeeList.value = employeeList.value.filter(
e => (e.staffOnJobId || e.id) !== (row.staffOnJobId || row.id)
);
@@ -705,6 +762,7 @@
return;
}
const ids = new Set(selectedEmployees.value.map(e => e.staffOnJobId || e.id));
+ selectedEmployees.value.forEach(item => clearRowRecalcState(item));
employeeList.value = employeeList.value.filter(
e => !ids.has(e.staffOnJobId || e.id)
);
@@ -729,29 +787,7 @@
proxy.$modal.msgWarning("鏈绠楀埌宸ヨ祫鏁版嵁");
return;
}
- employeeList.value = list.map(e => ({
- ...e,
- staffOnJobId: e.staffOnJobId ?? e.staffId ?? e.id,
- staffName: e.staffName,
- postName: e.postName,
- deptName: e.deptName,
- nation: e.nation ?? "",
- basicSalary: parseNum(e.basicSalary),
- dayDays: parseNum(e.dayDays ?? e.dayShiftDays),
- nightDays: parseNum(e.nightDays ?? e.nightShiftDays),
- mealAmount: parseNum(e.mealAmount ?? e.mealSubsidy),
- nightAmount: parseNum(e.nightAmount ?? e.nightSubsidy),
- otherIncome: parseNum(e.otherIncome),
- socialPersonal: parseNum(e.socialPersonal),
- fundPersonal: parseNum(e.fundPersonal),
- otherDeduct: parseNum(e.otherDeduct),
- socialSupplementAmount: parseNum(e.socialSupplementAmount),
- salaryTax: parseNum(e.salaryTax),
- grossSalary: parseNum(e.grossSalary),
- deductSalary: parseNum(e.deductSalary),
- netSalary: parseNum(e.netSalary),
- remark: e.remark ?? "",
- }));
+ employeeList.value = list.map(e => normalizeSalaryRow(e));
proxy.$modal.msgSuccess("鐢熸垚鎴愬姛");
});
};
@@ -760,6 +796,7 @@
proxy.$modal
.confirm("纭畾娓呯┖褰撳墠鍛樺伐鍒楄〃鍚楋紵")
.then(() => {
+ resetRecalcState();
employeeList.value = [];
})
.catch(() => {});
@@ -805,6 +842,8 @@
nightDays: parseNum(e.nightDays),
mealAmount: parseNum(e.mealAmount),
nightAmount: parseNum(e.nightAmount),
+ pieceSalary: parseNum(e.pieceSalary),
+ hourlySalary: parseNum(e.hourlySalary),
otherIncome: parseNum(e.otherIncome),
socialPersonal: parseNum(e.socialPersonal),
fundPersonal: parseNum(e.fundPersonal),
@@ -831,6 +870,7 @@
};
const closeDia = () => {
+ resetRecalcState();
dialogVisible.value = false;
emit("close");
};
--
Gitblit v1.9.3