feat: 绩效工资改为手动获取+按考核系数着色
后端: - 建立批次时绩效工资填0,不自动带出 - 获取绩效工资接口返回 details(grade/coefficient/performanceSalary) - 无考核记录时系数为1.0(绩效工资=基数全额) 前端: - 存储获取绩效工资返回的 details 到 perfDetails state - 绩效工资列按系数着色:A级(1.2)绿色/C级(0.8)橙色/D级(0.6)红色 - B级(1.0)和无考核正常色,0值灰色 - hover显示考核等级和系数
This commit is contained in:
@@ -493,11 +493,11 @@ router.post('/batches', async (req: AuthRequest, res: Response, next: NextFuncti
|
||||
} else if (prevPayslip) {
|
||||
// 非试用期:优先用上月工资条的基本工资(保持薪资连续性)
|
||||
baseSalary = prevPayslip.baseSalary
|
||||
performanceSalary = prevPayslip.performanceSalary || 0
|
||||
// 绩效工资不自动带出,需手动点"获取绩效工资"按钮
|
||||
} else if (empBaseSalary > 0 || empPerformanceSalary > 0) {
|
||||
// 新数据:有工资结构
|
||||
baseSalary = empBaseSalary
|
||||
performanceSalary = empPerformanceSalary
|
||||
// 绩效工资不自动带出,需手动点"获取绩效工资"按钮
|
||||
} else if (emp.monthlySalary) {
|
||||
// 旧数据兼容:回退到 monthlySalary
|
||||
try { baseSalary = Number(decrypt(emp.monthlySalary)) || 0 } catch { baseSalary = Number(emp.monthlySalary) || 0 }
|
||||
@@ -515,7 +515,7 @@ router.post('/batches', async (req: AuthRequest, res: Response, next: NextFuncti
|
||||
performanceSalary = 0
|
||||
} else if (empBaseSalary > 0 || empPerformanceSalary > 0) {
|
||||
baseSalary = empBaseSalary
|
||||
performanceSalary = empPerformanceSalary
|
||||
// 绩效工资不自动带出,需手动点"获取绩效工资"按钮
|
||||
} else if (emp.monthlySalary && mode === 'custom') {
|
||||
// custom 模式旧数据兼容
|
||||
try { baseSalary = Number(decrypt(emp.monthlySalary)) || 0 } catch { baseSalary = Number(emp.monthlySalary) || 0 }
|
||||
@@ -840,11 +840,13 @@ router.post('/batches/:batchId/fetch-performance', async (req: AuthRequest, res:
|
||||
|
||||
let filled = 0
|
||||
let totalAmount = 0
|
||||
const details: { employeeId: string; grade: string | null; coefficient: number; performanceSalary: number }[] = []
|
||||
for (const entry of entries) {
|
||||
const basePerfSalary = empPerfSalaryMap.get(entry.employeeId) || 0
|
||||
if (basePerfSalary <= 0) continue // 绩效工资基数为0则跳过
|
||||
|
||||
const perfRecord = perfMap.get(entry.employeeId)
|
||||
const grade = perfRecord?.grade || null
|
||||
const coefficient = perfRecord ? (gradeCoefficients[perfRecord.grade] || 1.0) : 1.0
|
||||
const calculatedPerfSalary = Math.round(basePerfSalary * coefficient * 100) / 100
|
||||
|
||||
@@ -853,6 +855,7 @@ router.post('/batches/:batchId/fetch-performance', async (req: AuthRequest, res:
|
||||
data: { performanceSalary: calculatedPerfSalary },
|
||||
})
|
||||
await recalcEntry(orgId, batchId, batch.month, batch.type, entry.id, entry.employeeId)
|
||||
details.push({ employeeId: entry.employeeId, grade, coefficient, performanceSalary: calculatedPerfSalary })
|
||||
filled++
|
||||
totalAmount += calculatedPerfSalary
|
||||
}
|
||||
@@ -865,6 +868,7 @@ router.post('/batches/:batchId/fetch-performance', async (req: AuthRequest, res:
|
||||
data: {
|
||||
filled,
|
||||
totalAmount: Math.round(totalAmount * 100) / 100,
|
||||
details,
|
||||
message: filled > 0
|
||||
? `已填充 ${filled} 人绩效工资,合计 ¥${Math.round(totalAmount * 100) / 100}${performanceRecords.length > 0 ? `(${performanceRecords.length} 人有考核记录)` : '(无考核记录,按系数1.0计算)'}`
|
||||
: '无绩效工资数据(员工未设置绩效工资基数)',
|
||||
|
||||
Reference in New Issue
Block a user