diff --git a/backend/src/services/risk.service.ts b/backend/src/services/risk.service.ts index 6033fc0..1db0ab4 100644 --- a/backend/src/services/risk.service.ts +++ b/backend/src/services/risk.service.ts @@ -30,7 +30,7 @@ const SOCIAL_AVG_SALARY_3X = 36921 function estimateRiskCost( risk: { type: RiskType; level: RiskLevel; title: string; description: string }, employee?: { hireDate: Date; monthlySalary?: string } | null, -): { estimatedLoss: number; lossRange: [number, number]; deadline?: Date } { +): { estimatedLoss: number; lossRange: [number, number]; deadline?: Date; lossReason?: string } { const today = new Date() const rawSalary = employee ? safeDecryptSalary(employee.monthlySalary || '0') : 0 // 第47条:高收入者月薪封顶为社平3倍 @@ -57,6 +57,7 @@ function estimateRiskCost( estimatedLoss: loss, lossRange: [loss * 0.5, loss], deadline: new Date(today.getTime() + 7 * 86400000), // 7天内处理 + lossReason: `《劳动合同法》第82条:未签书面合同,每月支付2倍工资。${months}个月×月薪${salary.toFixed(0)}元`, } } @@ -68,6 +69,7 @@ function estimateRiskCost( estimatedLoss: loss, lossRange: [loss, loss * 2], // 可能被认定为违法解除 2N deadline: new Date(today.getTime() + 3 * 86400000), // 3天内处理 + lossReason: `《劳动合同法》第47条:经济补偿N×月薪。N=${n}个月×月薪${salary.toFixed(0)}元,违法解除可能2N`, } } @@ -79,6 +81,7 @@ function estimateRiskCost( estimatedLoss: 0, lossRange: [0, salary * n], deadline: new Date(today.getTime() + days * 86400000), + lossReason: `到期未续签可能需支付经济补偿,最高N=${n}个月×月薪${salary.toFixed(0)}元`, } } @@ -89,6 +92,7 @@ function estimateRiskCost( estimatedLoss: loss, lossRange: [loss, loss * 3], deadline: new Date(today.getTime() + 14 * 86400000), // 14天内处理 + lossReason: `试用期工资差额约20%:月薪${salary.toFixed(0)}元×20%`, } } @@ -100,6 +104,7 @@ function estimateRiskCost( estimatedLoss: loss, lossRange: [loss, loss * 2], deadline: new Date(today.getTime() + 1 * 86400000), // 1天内处理 + lossReason: `《劳动合同法》第87条:违法解除按2N赔偿。2N=${(n * 2).toFixed(1)}个月×月薪${salary.toFixed(0)}元`, } } @@ -109,6 +114,7 @@ function estimateRiskCost( estimatedLoss: 500, lossRange: [100, 2000], deadline: new Date(today.getTime() + 3 * 86400000), + lossReason: '逾期缴纳社保/公积金将产生滞纳金,每日万分之五', } } @@ -117,6 +123,7 @@ function estimateRiskCost( estimatedLoss: 1000, lossRange: [500, 5000], deadline: new Date(today.getTime() + 1 * 86400000), + lossReason: '逾期发放工资/申报个税可能面临行政处罚及赔偿,《劳动法》第91条', } } @@ -128,6 +135,7 @@ function estimateRiskCost( estimatedLoss: days > 0 ? salary * (days / 30) : salary, lossRange: [500, salary * 6], deadline: new Date(today.getTime() + (days > 0 ? days : 7) * 86400000), + lossReason: `未及时办理退休可能导致多缴社保公积金,约${(days / 30).toFixed(1)}个月×月薪${salary.toFixed(0)}元`, } } @@ -916,6 +924,8 @@ export async function getDashboardData(orgId: string) { const estimatedLoss = r.estimatedLoss || 0 const priority = calcPriority(r.level, estimatedLoss, r.deadline || undefined) const daysUntilDeadline = r.deadline ? daysBetween(r.deadline, new Date()) : null + // 动态计算损失理由 + const costInfo = estimateRiskCost({ type: r.type, level: r.level, title: r.title, description: r.description }, null) return { id: r.id, type: r.type as 'CONTRACT' | 'SALARY' | 'TERMINATION' | 'MONTHLY' | 'ONBOARDING' | 'RETIREMENT', @@ -926,6 +936,7 @@ export async function getDashboardData(orgId: string) { actionUrl: r.actionUrl || '/', estimatedLoss, lossRange: r.lossRange as [number, number] | null, + lossReason: costInfo.lossReason || null, deadline: r.deadline?.toISOString().slice(0, 10) || null, daysUntilDeadline, employeeName: r.employee?.name || null, diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 0a67df8..6baa76f 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -1193,6 +1193,9 @@ export default function Dashboard() { )} {todo.description} + {todo.estimatedLoss > 0 && todo.lossReason && ( + {todo.lossReason} + )} ) : ( @@ -1220,6 +1223,9 @@ export default function Dashboard() { )} {todo.description} + {todo.estimatedLoss > 0 && todo.lossReason && ( + {todo.lossReason} + )} )}