From 62294084c9c35d35594e9f2d6c41342ae84e9526 Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期三, 29 七月 2026 16:39:20 +0800
Subject: [PATCH] 修改工资
---
src/views/productionManagement/productionProcess/index.vue | 107 +++++++---
src/views/basicData/product/index.vue | 33 +++
src/views/productionManagement/productionCosting/index.vue | 10
src/views/personnelManagement/monthlyStatistics/components/formDia.vue | 343 ++++++++++++++++++++++++++++------
src/views/productionManagement/productionProcess/Edit.vue | 14
src/views/personnelManagement/monthlyStatistics/components/auditDia.vue | 74 ++++++
6 files changed, 467 insertions(+), 114 deletions(-)
diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
index b05b215..65f891d 100644
--- a/src/views/basicData/product/index.vue
+++ b/src/views/basicData/product/index.vue
@@ -112,6 +112,19 @@
</el-form-item>
</el-col>
</el-row>
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item label="鏍囧噯鏁伴噺锛�"
+ prop="standardQuantity">
+ <el-input v-model="form.standardQuantity"
+ type="number"
+ :step="0.001"
+ placeholder="璇疯緭鍏ヤ骇鍝佹爣鍑嗘暟閲�"
+ clearable
+ @keydown.enter.prevent />
+ </el-form-item>
+ </el-col>
+ </el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
@@ -331,11 +344,29 @@
const data = reactive({
form: {
productName: "",
+ standardQuantity: null,
},
rules: {
productName: [
{ required: true, message: "璇疯緭鍏�", trigger: "blur" },
{ max: 20, message: "浜у搧鍚嶇О涓嶈兘瓒呰繃20涓瓧绗�", trigger: "blur" },
+ ],
+ standardQuantity: [
+ {
+ required: false,
+ trigger: "blur",
+ validator: (rule, value, callback) => {
+ if (value == null || value === "") {
+ callback();
+ return;
+ }
+ if (isNaN(value) || value < 0) {
+ callback(new Error("鏍囧噯鏁伴噺蹇呴』鏄潪璐熸暟瀛�"));
+ } else {
+ callback();
+ }
+ },
+ },
],
},
modelForm: {
@@ -412,6 +443,8 @@
productDia.value = true;
form.value.productName =
type === "edit" && data ? data.productName : "";
+ form.value.standardQuantity =
+ type === "edit" && data ? data.standardQuantity : null;
};
// 鎵撳紑瑙勬牸鍨嬪彿寮规
const openModelDia = (type, data) => {
diff --git a/src/views/personnelManagement/monthlyStatistics/components/auditDia.vue b/src/views/personnelManagement/monthlyStatistics/components/auditDia.vue
index e615402..f8f5e18 100644
--- a/src/views/personnelManagement/monthlyStatistics/components/auditDia.vue
+++ b/src/views/personnelManagement/monthlyStatistics/components/auditDia.vue
@@ -13,6 +13,7 @@
<el-descriptions :column="3" border>
<el-descriptions-item label="宸ヨ祫涓婚">{{ auditData?.salaryTitle || '-' }}</el-descriptions-item>
<el-descriptions-item label="宸ヨ祫鏈堜唤">{{ auditData?.salaryMonth || '-' }}</el-descriptions-item>
+ <el-descriptions-item label="宸ヤ綔鏃ュぉ鏁�">{{ auditData?.monthWorkDays ?? '-' }}</el-descriptions-item>
<el-descriptions-item label="宸ヨ祫鎬婚">楼 {{ formatMoney(auditData?.totalSalary) }}</el-descriptions-item>
<el-descriptions-item label="鏀粯閾惰">{{ auditData?.payBank || '-' }}</el-descriptions-item>
<el-descriptions-item label="瀹℃牳浜�">{{ auditData?.auditUserName || '-' }}</el-descriptions-item>
@@ -32,18 +33,43 @@
<div v-else>
<el-table :data="employeeList" border max-height="300" style="width: 100%">
<el-table-column prop="staffName" label="鍛樺伐濮撳悕" width="100" />
+ <el-table-column prop="entryDate" label="鍏ュ徃鏃ユ湡" width="110" />
<el-table-column prop="deptName" label="閮ㄩ棬" width="120" />
<el-table-column prop="basicSalary" label="鍩烘湰宸ヨ祫" width="100" align="right">
<template #default="{ row }">楼 {{ formatMoney(row.basicSalary) }}</template>
</el-table-column>
- <el-table-column prop="pieceSalary" label="璁′欢宸ヨ祫" width="100" align="right">
- <template #default="{ row }">楼 {{ formatMoney(row.pieceSalary) }}</template>
+ <el-table-column prop="attendanceBonus" label="鍏ㄥ嫟濂�" width="100" align="right">
+ <template #default="{ row }">楼 {{ formatMoney(row.attendanceBonus) }}</template>
</el-table-column>
- <el-table-column prop="hourlySalary" label="璁℃椂宸ヨ祫" width="100" align="right">
- <template #default="{ row }">楼 {{ formatMoney(row.hourlySalary) }}</template>
+ <el-table-column prop="dailySalary" label="鏃ヨ宸ヨ祫" width="100" align="right">
+ <template #default="{ row }">楼 {{ formatMoney(row.dailySalary) }}</template>
+ </el-table-column>
+ <el-table-column prop="workDays" label="鍑哄嫟澶╂暟" width="90" align="right">
+ <template #default="{ row }">{{ formatNumber(row.workDays, 0) }}</template>
+ </el-table-column>
+ <el-table-column prop="conversionRatio" label="鏁堢泭" width="90" align="right">
+ <template #default="{ row }">{{ formatRate(row.conversionRatio) }}</template>
+ </el-table-column>
+ <el-table-column prop="monthTimeTotal" label="鏈堟椂闂村悎璁�" width="110" align="right">
+ <template #default="{ row }">{{ formatNumber(row.monthTimeTotal, 2) }}</template>
</el-table-column>
<el-table-column prop="otherIncome" label="鍏朵粬鏀跺叆" width="100" align="right">
<template #default="{ row }">楼 {{ formatMoney(row.otherIncome) }}</template>
+ </el-table-column>
+ <el-table-column prop="personalLeave" label="浜嬪亣" width="80" align="right">
+ <template #default="{ row }">{{ formatNumber(row.personalLeave, 0) }}</template>
+ </el-table-column>
+ <el-table-column prop="sickLeave" label="鐥呭亣" width="80" align="right">
+ <template #default="{ row }">{{ formatNumber(row.sickLeave, 0) }}</template>
+ </el-table-column>
+ <el-table-column prop="bereavementLeave" label="涓у亣" width="80" align="right">
+ <template #default="{ row }">{{ formatNumber(row.bereavementLeave, 0) }}</template>
+ </el-table-column>
+ <el-table-column prop="marriageLeave" label="濠氬亣" width="80" align="right">
+ <template #default="{ row }">{{ formatNumber(row.marriageLeave, 0) }}</template>
+ </el-table-column>
+ <el-table-column prop="allowance" label="娲ヨ创" width="100" align="right">
+ <template #default="{ row }">楼 {{ formatMoney(row.allowance) }}</template>
</el-table-column>
<el-table-column prop="socialPersonal" label="绀句繚涓汉" width="100" align="right">
<template #default="{ row }">楼 {{ formatMoney(row.socialPersonal) }}</template>
@@ -51,8 +77,20 @@
<el-table-column prop="fundPersonal" label="鍏Н閲戜釜浜�" width="120" align="right">
<template #default="{ row }">楼 {{ formatMoney(row.fundPersonal) }}</template>
</el-table-column>
+ <el-table-column prop="otherDeduct" label="鍏朵粬鏀嚭" width="100" align="right">
+ <template #default="{ row }">楼 {{ formatMoney(row.otherDeduct) }}</template>
+ </el-table-column>
+ <el-table-column prop="socialSupplementAmount" label="绀句繚琛ョ即" width="110" align="right">
+ <template #default="{ row }">楼 {{ formatMoney(row.socialSupplementAmount) }}</template>
+ </el-table-column>
<el-table-column prop="salaryTax" label="宸ヨ祫涓◣" width="100" align="right">
<template #default="{ row }">楼 {{ formatMoney(row.salaryTax) }}</template>
+ </el-table-column>
+ <el-table-column prop="grossSalary" label="搴斿彂宸ヨ祫" width="100" align="right">
+ <template #default="{ row }">楼 {{ formatMoney(row.grossSalary) }}</template>
+ </el-table-column>
+ <el-table-column prop="deductSalary" label="搴旀墸宸ヨ祫" width="100" align="right">
+ <template #default="{ row }">楼 {{ formatMoney(row.deductSalary) }}</template>
</el-table-column>
<el-table-column prop="netSalary" label="瀹炲彂宸ヨ祫" width="100" align="right" fixed="right">
<template #default="{ row }">楼 {{ formatMoney(row.netSalary) }}</template>
@@ -123,6 +161,16 @@
return num.toFixed(2);
};
+const formatNumber = (value, digits = 2) => {
+ const num = Number(value) || 0;
+ return num.toFixed(digits);
+};
+
+const formatRate = (value) => {
+ const num = Number(value) || 0;
+ return num.toFixed(4);
+};
+
// 璁$畻宸ヨ祫鎬婚
const totalSalary = computed(() => {
return employeeList.value.reduce((sum, e) => {
@@ -140,15 +188,29 @@
if (row?.staffSalaryDetailList && Array.isArray(row.staffSalaryDetailList)) {
employeeList.value = row.staffSalaryDetailList.map((e) => ({
staffName: e.staffName ?? "",
+ entryDate: e.entryDate ?? "",
deptName: e.deptName ?? "",
basicSalary: Number(e.basicSalary) || 0,
+ attendanceBonus: Number(e.attendanceBonus) || 0,
+ dailySalary: Number(e.dailySalary) || (Number(e.workDays) > 0 ? (Number(e.basicSalary) / Number(e.workDays)) : 0),
+ workDays: Number(e.workDays) || 0,
pieceSalary: Number(e.pieceSalary) || 0,
- hourlySalary: Number(e.hourlySalary) || 0,
otherIncome: Number(e.otherIncome) || 0,
+ personalLeave: Number(e.personalLeave) || 0,
+ sickLeave: Number(e.sickLeave) || 0,
+ bereavementLeave: Number(e.bereavementLeave) || 0,
+ marriageLeave: Number(e.marriageLeave) || 0,
+ allowance: Number(e.allowance) || 0,
socialPersonal: Number(e.socialPersonal) || 0,
fundPersonal: Number(e.fundPersonal) || 0,
+ otherDeduct: Number(e.otherDeduct) || 0,
+ socialSupplementAmount: Number(e.socialSupplementAmount) || 0,
salaryTax: Number(e.salaryTax) || 0,
+ grossSalary: Number(e.grossSalary) || 0,
+ deductSalary: Number(e.deductSalary) || 0,
netSalary: Number(e.netSalary) || 0,
+ monthTimeTotal: Number(e.monthTimeTotal) || 0,
+ conversionRatio: Number(e.conversionRatio) || 0,
}));
} else {
console.log('娌℃湁鎵惧埌鍛樺伐鏄庣粏鏁版嵁');
@@ -220,4 +282,4 @@
:deep(.el-descriptions__label) {
width: 100px;
}
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/personnelManagement/monthlyStatistics/components/formDia.vue b/src/views/personnelManagement/monthlyStatistics/components/formDia.vue
index 981fefe..709d316 100644
--- a/src/views/personnelManagement/monthlyStatistics/components/formDia.vue
+++ b/src/views/personnelManagement/monthlyStatistics/components/formDia.vue
@@ -48,6 +48,14 @@
</el-form-item>
</el-col>
<el-col :span="6">
+ <el-form-item label="宸ヤ綔鏃�">
+ <el-input v-model.number="monthWorkDays"
+ type="number"
+ placeholder="鑷姩璁$畻"
+ @input="handleMonthWorkDaysInput" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="6">
<el-form-item label="閫夋嫨閮ㄩ棬"
prop="deptIds">
<el-select v-model="form.deptIds"
@@ -59,12 +67,14 @@
<el-option v-for="item in deptOptions"
:key="item.deptId"
:label="item.deptName"
- :value="item.deptId"
- :disabled="isDeptDisabled(item.deptId)" />
+ :value="item.deptId"
+ :disabled="isDeptDisabled(item.deptId)" />
</el-select>
</el-form-item>
</el-col>
- <el-col :span="6">
+ </el-row>
+ <el-row :gutter="24">
+ <el-col :span="12">
<el-form-item label="澶囨敞"
prop="remark">
<el-input v-model="form.remark"
@@ -72,9 +82,7 @@
clearable />
</el-form-item>
</el-col>
- </el-row>
- <el-row :gutter="24">
- <el-col :span="6">
+ <el-col :span="4">
<el-form-item label="鏀粯閾惰"
prop="payBank">
<el-select v-model="form.payBank"
@@ -89,7 +97,7 @@
</el-select>
</el-form-item>
</el-col>
- <el-col :span="6">
+ <el-col :span="8">
<el-form-item label="瀹℃牳浜�"
prop="auditUserId">
<el-select v-model="form.auditUserId"
@@ -128,6 +136,9 @@
<el-table-column label="鍛樺伐濮撳悕"
prop="staffName"
minWidth="100" />
+ <el-table-column label="鍏ュ徃鏃ユ湡"
+ prop="entryDate"
+ minWidth="110" />
<el-table-column label="閮ㄩ棬"
prop="deptName"
minWidth="100" />
@@ -151,27 +162,28 @@
disabled />
</template>
</el-table-column>
- <el-table-column label="鏈堟椂闂村悎璁�"
+ <el-table-column label="鏃ヨ宸ヨ祫"
minWidth="110">
<template #default="{ row }">
- <el-input v-model.number="row.monthTimeTotal"
+ <el-input v-model.number="row.dailySalary"
type="number"
placeholder="0"
size="small"
disabled />
</template>
</el-table-column>
- <el-table-column label="鏈堟爣鍑嗗伐鏃�"
- minWidth="110">
+ <el-table-column label="鍑哄嫟澶╂暟"
+ minWidth="130">
<template #default="{ row }">
- <el-input v-model.number="row.standardHours"
+ <el-input v-model.number="row.workDays"
type="number"
placeholder="0"
size="small"
- disabled />
+ style="width: 100%"
+ @input="handleWorkDaysInput(row)" />
</template>
</el-table-column>
- <el-table-column label="鎶樺悎鍊嶆暟"
+ <el-table-column label="鏁堢泭"
minWidth="100">
<template #default="{ row }">
<el-input v-model.number="row.conversionRatio"
@@ -181,30 +193,70 @@
disabled />
</template>
</el-table-column>
- <el-table-column label="璁′欢宸ヨ祫"
+ <el-table-column label="鏈堟椂闂村悎璁�"
minWidth="110">
<template #default="{ row }">
- <el-input v-model.number="row.pieceSalary"
+ <el-input v-model.number="row.monthTimeTotal"
type="number"
placeholder="0"
size="small"
- @input="row.pieceSalary = parseNum(row.pieceSalary)" />
- </template>
- </el-table-column>
- <el-table-column label="璁℃椂宸ヨ祫"
- minWidth="110">
- <template #default="{ row }">
- <el-input v-model.number="row.hourlySalary"
- type="number"
- placeholder="0"
- size="small"
- @input="row.hourlySalary = parseNum(row.hourlySalary)" />
+ @input="handlePieceSalaryInput(row)" />
</template>
</el-table-column>
<el-table-column label="鍏朵粬鏀跺叆"
minWidth="110">
<template #default="{ row }">
<el-input v-model.number="row.otherIncome"
+ type="number"
+ placeholder="0"
+ size="small"
+ @input="handleSalaryInput(row)" />
+ </template>
+ </el-table-column>
+ <el-table-column label="浜嬪亣"
+ minWidth="90">
+ <template #default="{ row }">
+ <el-input v-model.number="row.personalLeave"
+ type="number"
+ placeholder="0"
+ size="small"
+ @input="handleLeaveInput(row)" />
+ </template>
+ </el-table-column>
+ <el-table-column label="鐥呭亣"
+ minWidth="90">
+ <template #default="{ row }">
+ <el-input v-model.number="row.sickLeave"
+ type="number"
+ placeholder="0"
+ size="small"
+ @input="handleLeaveInput(row)" />
+ </template>
+ </el-table-column>
+ <el-table-column label="涓у亣"
+ minWidth="90">
+ <template #default="{ row }">
+ <el-input v-model.number="row.bereavementLeave"
+ type="number"
+ placeholder="0"
+ size="small"
+ @input="handleLeaveInput(row)" />
+ </template>
+ </el-table-column>
+ <el-table-column label="濠氬亣"
+ minWidth="90">
+ <template #default="{ row }">
+ <el-input v-model.number="row.marriageLeave"
+ type="number"
+ placeholder="0"
+ size="small"
+ @input="handleLeaveInput(row)" />
+ </template>
+ </el-table-column>
+ <el-table-column label="娲ヨ创"
+ minWidth="110">
+ <template #default="{ row }">
+ <el-input v-model.number="row.allowance"
type="number"
placeholder="0"
size="small"
@@ -456,16 +508,20 @@
deptName: "",
basicSalary: 0,
attendanceBonus: 100,
- pieceSalary: 0,
+ entryDate: "",
+ workDays: 0,
+ dailySalary: 0,
hourlySalary: 0,
actualOutput: 0,
standardQuantity: 0,
- conversionFactor: 1,
- convertedWorkHours: 0,
monthTimeTotal: 0,
- standardHours: 0,
conversionRatio: 0,
otherIncome: 0,
+ personalLeave: 0,
+ sickLeave: 0,
+ bereavementLeave: 0,
+ marriageLeave: 0,
+ allowance: 0,
socialPersonal: 0,
fundPersonal: 0,
otherDeduct: 0,
@@ -488,16 +544,20 @@
deptName: source?.deptName ?? fallback.deptName ?? "",
basicSalary: parseNum(source?.basicSalary ?? fallback.basicSalary),
attendanceBonus: parseNum(source?.attendanceBonus ?? fallback.attendanceBonus ?? 100) || 100,
- pieceSalary: parseNum(source?.pieceSalary ?? fallback.pieceSalary),
+ entryDate: source?.entryDate ?? source?.contractStartTime ?? fallback.entryDate ?? "",
+ workDays: parseNum(source?.workDays ?? fallback.workDays),
+ dailySalary: parseNum(source?.dailySalary ?? fallback.dailySalary),
hourlySalary: parseNum(source?.hourlySalary ?? fallback.hourlySalary),
actualOutput: parseNum(source?.actualOutput ?? fallback.actualOutput),
standardQuantity: parseNum(source?.standardQuantity ?? fallback.standardQuantity),
- conversionFactor: parseNum(source?.conversionFactor ?? fallback.conversionFactor) || 1,
- convertedWorkHours: parseNum(source?.convertedWorkHours ?? fallback.convertedWorkHours),
monthTimeTotal: parseNum(source?.monthTimeTotal ?? fallback.monthTimeTotal),
- standardHours: parseNum(source?.standardHours ?? fallback.standardHours),
conversionRatio: parseNum(source?.conversionRatio ?? fallback.conversionRatio),
otherIncome: parseNum(source?.otherIncome ?? fallback.otherIncome),
+ personalLeave: parseNum(source?.personalLeave ?? fallback.personalLeave),
+ sickLeave: parseNum(source?.sickLeave ?? fallback.sickLeave),
+ bereavementLeave: parseNum(source?.bereavementLeave ?? fallback.bereavementLeave),
+ marriageLeave: parseNum(source?.marriageLeave ?? fallback.marriageLeave),
+ allowance: parseNum(source?.allowance ?? fallback.allowance),
socialPersonal: parseNum(source?.socialPersonal ?? fallback.socialPersonal),
fundPersonal: parseNum(source?.fundPersonal ?? fallback.fundPersonal),
otherDeduct: parseNum(source?.otherDeduct ?? fallback.otherDeduct),
@@ -510,8 +570,35 @@
remark: source?.remark ?? fallback.remark ?? "",
});
- const applyBackendRow = (targetRow, sourceRow) => {
+ const recalculateRowByWorkDays = row => {
+ const workDayCount = parseNum(monthWorkDays.value);
+ const monthTimeTotal = parseNum(row.monthTimeTotal);
+ const standardHours = workDayCount > 0 ? workDayCount * 8 : 0;
+ if (workDayCount > 0 && parseNum(row.workDays) > workDayCount) {
+ row.workDays = workDayCount;
+ }
+ if (standardHours > 0) {
+ row.conversionRatio = (monthTimeTotal / standardHours).toFixed(4);
+ } else {
+ row.conversionRatio = 0;
+ }
+ };
+
+ const applyBackendRow = (targetRow, sourceRow, options = {}) => {
+ const preservedConversionRatio = options.preserveConversionRatio
+ ? parseNum(targetRow.conversionRatio)
+ : null;
Object.assign(targetRow, normalizeEmployeeRow(sourceRow, targetRow));
+ if (options.preserveConversionRatio) {
+ targetRow.conversionRatio = preservedConversionRatio;
+ }
+ recalculateRowByWorkDays(targetRow);
+ };
+
+ const recalcRowsByCurrentWorkDays = () => {
+ employeeList.value.forEach(row => {
+ recalculateRowByWorkDays(row);
+ });
};
const clearRowRecalcState = row => {
@@ -528,30 +615,36 @@
recalcVersions.clear();
};
- const requestEmployeeRecalculate = row => {
+ const requestEmployeeRecalculate = (row, options = {}) => {
const key = String(row?.staffOnJobId ?? row?.id ?? "");
if (!key || !form.value.salaryMonth) return;
const version = (recalcVersions.get(key) || 0) + 1;
recalcVersions.set(key, version);
+ const manualWorkDays = parseNum(row.workDays);
clearTimeout(recalcTimers.get(key));
const payload = {
staffOnJobId: row.staffOnJobId ?? row.id,
salaryMonth: form.value.salaryMonth,
+ monthWorkDays: parseNum(monthWorkDays.value),
staffName: row.staffName ?? "",
postName: row.postName ?? "",
deptName: row.deptName ?? "",
+ entryDate: row.entryDate ?? row.contractStartTime ?? "",
basicSalary: parseNum(row.basicSalary),
attendanceBonus: parseNum(row.attendanceBonus),
- pieceSalary: parseNum(row.pieceSalary),
+ workDays: parseNum(row.workDays),
+ dailySalary: parseNum(row.dailySalary),
hourlySalary: parseNum(row.hourlySalary),
actualOutput: parseNum(row.actualOutput),
standardQuantity: parseNum(row.standardQuantity),
- conversionFactor: parseNum(row.conversionFactor) || 1,
- convertedWorkHours: parseNum(row.convertedWorkHours),
monthTimeTotal: parseNum(row.monthTimeTotal),
- standardHours: parseNum(row.standardHours),
conversionRatio: parseNum(row.conversionRatio),
otherIncome: parseNum(row.otherIncome),
+ personalLeave: parseNum(row.personalLeave),
+ sickLeave: parseNum(row.sickLeave),
+ bereavementLeave: parseNum(row.bereavementLeave),
+ marriageLeave: parseNum(row.marriageLeave),
+ allowance: parseNum(row.allowance),
otherDeduct: parseNum(row.otherDeduct),
socialSupplementAmount: parseNullableNum(row.socialSupplementAmount),
remark: row.remark ?? "",
@@ -561,7 +654,12 @@
setTimeout(() => {
staffSalaryMainCalculateByEmployeeId(payload).then(res => {
if (recalcVersions.get(key) !== version) return;
- applyBackendRow(row, res?.data || {});
+ applyBackendRow(row, res?.data || {}, options);
+ if (manualWorkDays > 0) {
+ row.workDays = manualWorkDays;
+ row.dailySalary = manualWorkDays > 0 ? parseNum(row.basicSalary) / manualWorkDays : 0;
+ recalculateRowByWorkDays(row);
+ }
});
}, 250)
);
@@ -572,8 +670,81 @@
row.otherIncome = parseNum(row.otherIncome);
row.actualOutput = parseNum(row.actualOutput);
row.standardQuantity = parseNum(row.standardQuantity);
- row.conversionFactor = parseNum(row.conversionFactor) || 1;
+ row.workDays = parseNum(row.workDays);
+ row.dailySalary = row.workDays > 0
+ ? (parseNum(row.basicSalary) / row.workDays).toFixed(3)
+ : 0;
+ requestEmployeeRecalculate(row, { preserveConversionRatio: true });
+ };
+
+ const handlePieceSalaryInput = row => {
+ row.monthTimeTotal = parseNum(row.monthTimeTotal);
requestEmployeeRecalculate(row);
+ };
+
+ const handleWorkDaysInput = row => {
+ row.workDays = parseNum(row.workDays);
+ const maxWorkDays = parseNum(monthWorkDays.value);
+ if (maxWorkDays > 0 && row.workDays > maxWorkDays) {
+ row.workDays = maxWorkDays;
+ proxy.$modal.msgWarning("鍑哄嫟澶╂暟涓嶈兘澶т簬宸ヤ綔鏃�");
+ }
+ enforceLeaveAndWorkDayLimit(row);
+ row.dailySalary = row.workDays > 0
+ ? (parseNum(row.basicSalary) / row.workDays).toFixed(3)
+ : 0;
+ requestEmployeeRecalculate(row);
+ };
+
+ const handleLeaveInput = row => {
+ row.personalLeave = parseNum(row.personalLeave);
+ row.sickLeave = parseNum(row.sickLeave);
+ row.bereavementLeave = parseNum(row.bereavementLeave);
+ row.marriageLeave = parseNum(row.marriageLeave);
+ enforceLeaveAndWorkDayLimit(row);
+ requestEmployeeRecalculate(row);
+ };
+
+ const enforceLeaveAndWorkDayLimit = row => {
+ const maxWorkDays = parseNum(monthWorkDays.value);
+ if (maxWorkDays <= 0) {
+ return true;
+ }
+ const leaveTotal = parseNum(row.personalLeave)
+ + parseNum(row.sickLeave)
+ + parseNum(row.bereavementLeave)
+ + parseNum(row.marriageLeave)
+ + parseNum(row.workDays);
+ if (leaveTotal > maxWorkDays) {
+ proxy.$modal.msgWarning("璇峰亣鍚堣鍔犲嚭鍕ゅぉ鏁颁笉鑳借秴杩囧伐浣滄棩");
+ const allowedWorkDays = Math.max(0, maxWorkDays
+ - parseNum(row.personalLeave)
+ - parseNum(row.sickLeave)
+ - parseNum(row.bereavementLeave)
+ - parseNum(row.marriageLeave));
+ row.workDays = allowedWorkDays;
+ return false;
+ }
+ return true;
+ };
+
+ const handleMonthWorkDaysInput = () => {
+ monthWorkDays.value = parseNum(monthWorkDays.value);
+ employeeList.value.forEach(row => {
+ const standardHours = monthWorkDays.value > 0 ? monthWorkDays.value * 8 : 0;
+ if (parseNum(row.workDays) > monthWorkDays.value) {
+ row.workDays = monthWorkDays.value;
+ row.dailySalary = monthWorkDays.value > 0
+ ? (parseNum(row.basicSalary) / monthWorkDays.value).toFixed(3)
+ : 0;
+ }
+ if (parseNum(row.monthTimeTotal) > 0 && standardHours > 0) {
+ row.conversionRatio = (parseNum(row.monthTimeTotal) / standardHours).toFixed(4);
+ } else {
+ row.conversionRatio = 0;
+ }
+ requestEmployeeRecalculate(row);
+ });
};
// 鍩虹璧勬枡琛ㄥ崟
@@ -606,6 +777,26 @@
const totalSalary = computed(() => {
return employeeList.value.reduce((sum, e) => sum + parseNum(e.netSalary), 0);
});
+
+ const monthWorkDays = ref(0);
+
+ const calculateMonthWorkDays = salaryMonth => {
+ if (!salaryMonth) return 0;
+ const [yearStr, monthStr] = String(salaryMonth).split("-");
+ const year = Number(yearStr);
+ const month = Number(monthStr);
+ if (!year || !month) return 0;
+ const start = new Date(year, month - 1, 1);
+ const end = new Date(year, month, 0);
+ let workDays = 0;
+ for (let day = new Date(start); day <= end; day.setDate(day.getDate() + 1)) {
+ const weekday = day.getDay();
+ if (weekday !== 0 && weekday !== 6) {
+ workDays += 1;
+ }
+ }
+ return workDays;
+ };
// 鏍规嵁瀹℃牳浜篒D鑾峰彇瀹℃牳浜哄悕绉�
const auditUserName = computed(() => {
@@ -712,6 +903,7 @@
loadUserList();
loadAllDeptOptions();
employeeList.value = [];
+ monthWorkDays.value = 0;
Object.assign(form.value, {
id: undefined,
salaryTitle: "",
@@ -736,10 +928,19 @@
form.value.remark = row.remark ?? "";
form.value.payBank = row.payBank ?? "";
form.value.auditUserId = row.auditUserId ?? undefined;
- // 濡傛灉鏈夊憳宸ユ槑缁嗘暟鎹紝鐩存帴鍙嶆樉
- if (row.staffSalaryDetailList && row.staffSalaryDetailList.length > 0) {
- employeeList.value = row.staffSalaryDetailList.map(e => normalizeEmployeeRow(e));
+ monthWorkDays.value = parseNum(row.monthWorkDays) || calculateMonthWorkDays(form.value.salaryMonth);
+ // 濡傛灉鏈夊憳宸ユ槑缁嗘暟鎹紝鐩存帴鍙嶆樉
+ if (row.staffSalaryDetailList && row.staffSalaryDetailList.length > 0) {
+ employeeList.value = row.staffSalaryDetailList.map(e => {
+ const normalized = normalizeEmployeeRow(e);
+ recalculateRowByWorkDays(normalized);
+ return normalized;
+ });
}
+ recalcRowsByCurrentWorkDays();
+ } else if (form.value.salaryMonth) {
+ monthWorkDays.value = calculateMonthWorkDays(form.value.salaryMonth);
+ recalcRowsByCurrentWorkDays();
}
// 缂栬緫鐘舵�佷笖鏈夋湀浠芥椂锛屽姞杞藉彲鐢ㄩ儴闂ㄥ垪琛�
if (type === "edit" && form.value.salaryMonth) {
@@ -753,6 +954,10 @@
// 鍒囨崲鏈堜唤鏃舵竻绌哄凡閫夋嫨鐨勯儴闂�
if (newMonth !== oldMonth) {
form.value.deptIds = [];
+ }
+ if (!monthWorkDays.value || newMonth !== oldMonth) {
+ monthWorkDays.value = calculateMonthWorkDays(newMonth);
+ recalcRowsByCurrentWorkDays();
}
loadAvailableDepts(newMonth);
});
@@ -786,6 +991,7 @@
staffName: node.label,
postName: node.postName ?? node.post ?? "",
deptName: node.deptName ?? "",
+ entryDate: node.contractStartTime ?? node.entryDate ?? "",
remark: "",
socialSupplementAmount: null,
attendanceBonus: node.attendanceBonus,
@@ -873,16 +1079,30 @@
};
const saveData = status => {
- const payload = {
- id: form.value.id,
- salaryTitle: form.value.salaryTitle,
- deptIds: form.value.deptIds?.length ? form.value.deptIds.join(",") : "",
- salaryMonth: form.value.salaryMonth,
- remark: form.value.remark,
- payBank: form.value.payBank,
- auditUserId: form.value.auditUserId,
- auditUserName: auditUserName.value,
- totalSalary: totalSalary.value,
+ const invalidRow = employeeList.value.find(row => {
+ const maxWorkDays = parseNum(monthWorkDays.value);
+ const leaveTotal = parseNum(row.personalLeave)
+ + parseNum(row.sickLeave)
+ + parseNum(row.bereavementLeave)
+ + parseNum(row.marriageLeave)
+ + parseNum(row.workDays);
+ return maxWorkDays > 0 && leaveTotal > maxWorkDays;
+ });
+ if (invalidRow) {
+ proxy.$modal.msgWarning("璇峰亣鍚堣鍔犲嚭鍕ゅぉ鏁颁笉鑳借秴杩囧伐浣滄棩");
+ return;
+ }
+ const payload = {
+ id: form.value.id,
+ salaryTitle: form.value.salaryTitle,
+ deptIds: form.value.deptIds?.length ? form.value.deptIds.join(",") : "",
+ salaryMonth: form.value.salaryMonth,
+ monthWorkDays: parseNum(monthWorkDays.value),
+ remark: form.value.remark,
+ payBank: form.value.payBank,
+ auditUserId: form.value.auditUserId,
+ auditUserName: auditUserName.value,
+ totalSalary: totalSalary.value,
staffSalaryDetailList: employeeList.value.map(e => ({
staffOnJobId: e.staffOnJobId ?? e.staffId ?? e.id,
staffName: e.staffName,
@@ -890,14 +1110,17 @@
deptName: e.deptName ?? "",
basicSalary: parseNum(e.basicSalary),
attendanceBonus: parseNum(e.attendanceBonus),
- pieceSalary: parseNum(e.pieceSalary),
+ dailySalary: parseNum(e.dailySalary),
+ workDays: parseNum(e.workDays),
+ personalLeave: parseNum(e.personalLeave),
+ sickLeave: parseNum(e.sickLeave),
+ bereavementLeave: parseNum(e.bereavementLeave),
+ marriageLeave: parseNum(e.marriageLeave),
+ allowance: parseNum(e.allowance),
hourlySalary: parseNum(e.hourlySalary),
actualOutput: parseNum(e.actualOutput),
standardQuantity: parseNum(e.standardQuantity),
- conversionFactor: parseNum(e.conversionFactor) || 1,
- convertedWorkHours: parseNum(e.convertedWorkHours),
monthTimeTotal: parseNum(e.monthTimeTotal),
- standardHours: parseNum(e.standardHours),
conversionRatio: parseNum(e.conversionRatio),
otherIncome: parseNum(e.otherIncome),
socialPersonal: parseNum(e.socialPersonal),
diff --git a/src/views/productionManagement/productionCosting/index.vue b/src/views/productionManagement/productionCosting/index.vue
index 53dfcf7..3653368 100644
--- a/src/views/productionManagement/productionCosting/index.vue
+++ b/src/views/productionManagement/productionCosting/index.vue
@@ -216,6 +216,11 @@
minWidth: 100,
},
{
+ label: "鏍囧噯鏁伴噺",
+ prop: "standardQuantity",
+ minWidth: 100,
+ },
+ {
label: "宸ュ崟缂栧彿",
prop: "workOrderNo",
minWidth: 140,
@@ -233,11 +238,6 @@
{
label: "鐢熶骇鏁伴噺",
prop: "quantity",
- minWidth: 100,
- },
- {
- label: "宸ユ椂瀹氶",
- prop: "workHours",
minWidth: 100,
},
{
diff --git a/src/views/productionManagement/productionProcess/Edit.vue b/src/views/productionManagement/productionProcess/Edit.vue
index 28077b6..55be24e 100644
--- a/src/views/productionManagement/productionProcess/Edit.vue
+++ b/src/views/productionManagement/productionProcess/Edit.vue
@@ -31,14 +31,16 @@
:rules="[
{
required: true,
- message: '璇烽�夋嫨宸ュ簭绫诲瀷',
+ message: '宸ュ簭浠呮敮鎸佽浠�',
}
]"
>
- <el-select v-model="formState.type" placeholder="璇烽�夋嫨宸ュ簭绫诲瀷">
- <el-option label="璁℃椂" :value="0" />
+ <el-select v-model="formState.type" placeholder="宸ュ簭浠呮敮鎸佽浠�" disabled>
<el-option label="璁′欢" :value="1" />
</el-select>
+ <div style="margin-top: 6px; color: #909399; font-size: 12px;">
+ 宸ュ簭浠呮敮鎸佽浠�
+ </div>
</el-form-item>
<el-form-item label="宸ヨ祫瀹氶" prop="salaryQuota">
<el-input v-model="formState.salaryQuota" type="number" :step="0.001" />
@@ -88,7 +90,7 @@
const formState = ref({
id: props.record.id,
name: props.record.name,
- type: props.record.type,
+ type: 1,
no: props.record.no,
remark: props.record.remark,
salaryQuota: props.record.salaryQuota,
@@ -113,7 +115,7 @@
id: newRecord.id,
name: newRecord.name || '',
no: newRecord.no || '',
- type: newRecord.type,
+ type: 1,
remark: newRecord.remark || '',
salaryQuota: newRecord.salaryQuota || '',
isQuality: props.record.isQuality,
@@ -130,7 +132,7 @@
id: props.record.id,
name: props.record.name || '',
no: props.record.no || '',
- type: props.record.type,
+ type: 1,
remark: props.record.remark || '',
salaryQuota: props.record.salaryQuota || '',
isQuality: props.record.isQuality,
diff --git a/src/views/productionManagement/productionProcess/index.vue b/src/views/productionManagement/productionProcess/index.vue
index d4c7f9e..9b1ae12 100644
--- a/src/views/productionManagement/productionProcess/index.vue
+++ b/src/views/productionManagement/productionProcess/index.vue
@@ -46,7 +46,7 @@
<div class="process-desc">{{ process.remark || '鏆傛棤鎻忚堪' }}</div>
<div class="process-device">鍏宠仈璁惧: {{ (deviceOptions.find(item => item.id === Number(process.deviceLedgerId))?.deviceName) || '鏈叧鑱�' }}</div>
<div class="process-device">鏍囧噯鏁伴噺: {{ process.standardQuantity || 0 }}</div>
- <div class="process-device">鎶樼畻绯绘暟: {{ process.conversionFactor ?? 1 }}</div>
+ <div class="process-device"></div>
</div>
<div class="card-footer">
<div class="status-tag">
@@ -66,7 +66,7 @@
璁′欢
</el-tag>
</div>
- <span class="param-count">宸ヨ祫瀹氶: 楼{{ process.salaryQuota || 0 }}</span>
+ <span class="param-count"></span>
</div>
</div>
</div>
@@ -120,12 +120,6 @@
<el-input v-model="processForm.name"
placeholder="璇疯緭鍏ュ伐搴忓悕绉�" />
</el-form-item>
- <el-form-item label="宸ヨ祫瀹氶"
- prop="salaryQuota">
- <el-input v-model="processForm.salaryQuota"
- type="number"
- :step="0.001" />
- </el-form-item>
<el-form-item label="鏍囧噯鏁伴噺"
prop="standardQuantity">
<el-input v-model="processForm.standardQuantity"
@@ -133,12 +127,26 @@
:step="0.001"
placeholder="璇疯緭鍏ュ伐搴忔爣鍑嗘暟閲�" />
</el-form-item>
- <el-form-item label="鎶樼畻绯绘暟"
- prop="conversionFactor">
- <el-input v-model="processForm.conversionFactor"
+ <el-form-item label="灏忔彁鐞寸郴鏁�"
+ prop="violinFactor">
+ <el-input v-model="processForm.violinFactor"
type="number"
- :step="0.01"
- placeholder="榛樿 1" />
+ :step="0.001"
+ placeholder="璇疯緭鍏ュ皬鎻愮惔绯绘暟" />
+ </el-form-item>
+ <el-form-item label="澶ф彁鐞寸郴鏁�"
+ prop="violaFactor">
+ <el-input v-model="processForm.violaFactor"
+ type="number"
+ :step="0.001"
+ placeholder="璇疯緭鍏ュぇ鎻愮惔绯绘暟" />
+ </el-form-item>
+ <el-form-item label="璐濇柉绯绘暟"
+ prop="bassFactor">
+ <el-input v-model="processForm.bassFactor"
+ type="number"
+ :step="0.001"
+ placeholder="璇疯緭鍏ヨ礉鏂郴鏁�" />
</el-form-item>
<el-form-item label="鏄惁璐ㄦ"
prop="isQuality">
@@ -359,9 +367,10 @@
id: null,
no: "",
name: "",
- salaryQuota: null,
standardQuantity: null,
- conversionFactor: 1,
+ violinFactor: null,
+ violaFactor: null,
+ bassFactor: null,
isQuality: false,
isProduction: false,
remark: "",
@@ -371,20 +380,6 @@
const processRules = {
no: [{ required: true, message: "璇疯緭鍏ュ伐搴忕紪鐮�", trigger: "blur" }],
name: [{ required: true, message: "璇疯緭鍏ュ伐搴忓悕绉�", trigger: "blur" }],
- salaryQuota: [
- {
- required: false,
- message: "璇疯緭鍏ュ伐璧勫畾棰�",
- trigger: "blur",
- validator: (rule, value, callback) => {
- if (isNaN(value) || value < 0) {
- callback(new Error("宸ヨ祫瀹氶蹇呴』鏄潪璐熸暟瀛�"));
- } else {
- callback();
- }
- },
- },
- ],
standardQuantity: [
{
required: false,
@@ -403,18 +398,54 @@
},
},
],
- conversionFactor: [
+ violinFactor: [
{
required: false,
- message: "璇疯緭鍏ユ姌绠楃郴鏁�",
+ message: "璇疯緭鍏ュ皬鎻愮惔绯绘暟",
trigger: "blur",
validator: (rule, value, callback) => {
if (value == null || value === "") {
callback();
return;
}
- if (isNaN(value) || value <= 0) {
- callback(new Error("鎶樼畻绯绘暟蹇呴』鏄ぇ浜� 0 鐨勬暟瀛�"));
+ if (isNaN(value) || value < 0) {
+ callback(new Error("灏忔彁鐞寸郴鏁板繀椤绘槸闈炶礋鏁板瓧"));
+ } else {
+ callback();
+ }
+ },
+ },
+ ],
+ violaFactor: [
+ {
+ required: false,
+ message: "璇疯緭鍏ュぇ鎻愮惔绯绘暟",
+ trigger: "blur",
+ validator: (rule, value, callback) => {
+ if (value == null || value === "") {
+ callback();
+ return;
+ }
+ if (isNaN(value) || value < 0) {
+ callback(new Error("澶ф彁鐞寸郴鏁板繀椤绘槸闈炶礋鏁板瓧"));
+ } else {
+ callback();
+ }
+ },
+ },
+ ],
+ bassFactor: [
+ {
+ required: false,
+ message: "璇疯緭鍏ヨ礉鏂郴鏁�",
+ trigger: "blur",
+ validator: (rule, value, callback) => {
+ if (value == null || value === "") {
+ callback();
+ return;
+ }
+ if (isNaN(value) || value < 0) {
+ callback(new Error("璐濇柉绯绘暟蹇呴』鏄潪璐熸暟瀛�"));
} else {
callback();
}
@@ -621,9 +652,10 @@
processForm.id = null;
processForm.no = "";
processForm.name = "";
- processForm.salaryQuota = null;
processForm.standardQuantity = null;
- processForm.conversionFactor = 1;
+ processForm.violinFactor = null;
+ processForm.violaFactor = null;
+ processForm.bassFactor = null;
processForm.isQuality = false;
processForm.isProduction = false;
processForm.remark = "";
@@ -637,9 +669,10 @@
processForm.id = process.id;
processForm.no = process.no;
processForm.name = process.name;
- processForm.salaryQuota = process.salaryQuota;
processForm.standardQuantity = process.standardQuantity;
- processForm.conversionFactor = process.conversionFactor ?? 1;
+ processForm.violinFactor = process.violinFactor;
+ processForm.violaFactor = process.violaFactor;
+ processForm.bassFactor = process.bassFactor;
processForm.isQuality = !!process.isQuality;
processForm.isProduction = !!process.isProduction;
processForm.remark = process.remark || "";
--
Gitblit v1.9.3