feat: 待办事项显示损失金额理由
后端 estimateRiskCost 返回 lossReason 字段,说明法律依据和计算方式 前端在损失金额下方显示理由,如'逾期缴纳社保/公积金将产生滞纳金,每日万分之五'
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -1193,6 +1193,9 @@ export default function Dashboard() {
|
||||
)}
|
||||
</div>
|
||||
<span className="text-xs text-gray-500 flex items-center gap-1"><Clock className="w-3 h-3" />{todo.description}</span>
|
||||
{todo.estimatedLoss > 0 && todo.lossReason && (
|
||||
<span className="text-[11px] text-gray-400">{todo.lossReason}</span>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
@@ -1220,6 +1223,9 @@ export default function Dashboard() {
|
||||
)}
|
||||
</div>
|
||||
<span className="text-xs text-gray-500 flex items-center gap-1"><Clock className="w-3 h-3" />{todo.description}</span>
|
||||
{todo.estimatedLoss > 0 && todo.lossReason && (
|
||||
<span className="text-[11px] text-gray-400">{todo.lossReason}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user