feat: 薪资表格增加最低工资保护和递延扣款的可视化提示

1. 实发列:最低工资保护触发时显示橙色 + ★标记 + tooltip
2. 新增「递延扣款」列:显示递延金额(橙色)或补扣金额(蓝色)
3. 风险列:最低工资保护触发时显示橙色警告图标 + tooltip
4. 工作流步骤从4步改为3步(编辑薪资→归档锁定→发布工资条)

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-16 14:30:08 +08:00
parent 2875965113
commit 904c9c6369
2 changed files with 39 additions and 15 deletions
+25 -3
View File
@@ -948,8 +948,7 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
<Card className="p-4">
<Stepper
steps={[
{ key: 'edit', title: '编辑薪资', description: '填写/导入工资数据', status: isArchived ? 'complete' : 'current' },
{ key: 'review', title: '核对汇总', description: '检查应发/个税/实发', status: isArchived ? 'complete' : 'pending' },
{ key: 'edit', title: '编辑薪资', description: '填写/导入/核对工资数据', status: isArchived ? 'complete' : 'current' },
{ key: 'archive', title: '归档锁定', description: '归档后不可编辑', status: isArchived ? 'complete' : 'pending' },
{ key: 'publish', title: '发布工资条', description: '员工端可见', status: batch.payslipPublished ? 'complete' : 'pending' },
] as Step[]}
@@ -1086,6 +1085,7 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
<th className="py-2 px-2 text-right">()</th>
<th className="py-2 px-2 text-right text-gray-500"></th>
<th className="py-2 px-2 text-right text-gray-500"></th>
<th className="py-2 px-2 text-right text-gray-500"></th>
<th className="py-2 px-2"></th>
{!isArchived && <th className="py-2 px-2"></th>}
</tr>
@@ -1110,12 +1110,34 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
{renderCell(entry, 'socialEmp')}
{renderCell(entry, 'housingEmp')}
<td className="py-2 px-2 text-right text-gray-500 cursor-pointer hover:text-primary hover:underline" onClick={() => handleTaxDetailClick(entry.employeeId, entry.employee.name)} title="点击查看个税计算明细">{fmt(entry.tax)}</td>
<td className="py-2 px-2 text-right font-bold text-safe">{fmt(entry.netPay)}</td>
{/* 实发:最低工资保护触发时高亮显示 */}
<td className={`py-2 px-2 text-right font-bold ${(entry.minWageApplied || 0) > 0 ? 'text-amber-600' : 'text-safe'}`} title={(entry.minWageApplied || 0) > 0 ? `最低工资保护:补齐 ¥${entry.minWageApplied},递延扣款 ¥${(entry.deferredSocialEmp || 0) + (entry.deferredHousingEmp || 0) + (entry.deferredMinWage || 0)} 将在次月补扣` : ''}>
{fmt(entry.netPay)}
{(entry.minWageApplied || 0) > 0 && <span className="text-xs text-amber-500 ml-1"></span>}
</td>
{/* 递延扣款明细 */}
<td className="py-2 px-2 text-right text-xs">
{(() => {
const deferred = (entry.deferredSocialEmp || 0) + (entry.deferredHousingEmp || 0) + (entry.deferredMinWage || 0)
const prevDeferred = (entry.prevDeferredSocialEmp || 0) + (entry.prevDeferredHousingEmp || 0) + (entry.prevDeferredMinWage || 0)
if (deferred > 0) {
return <span className="text-amber-600 cursor-help" title={`递延到次月:社保 ¥${entry.deferredSocialEmp || 0} + 公积金 ¥${entry.deferredHousingEmp || 0} + 最低工资补齐 ¥${entry.deferredMinWage || 0}`}> ¥{fmt(deferred)}</span>
}
if (prevDeferred > 0) {
return <span className="text-blue-600 cursor-help" title={`本月补扣上月递延:社保 ¥${entry.prevDeferredSocialEmp || 0} + 公积金 ¥${entry.prevDeferredHousingEmp || 0} + 最低工资补齐 ¥${entry.prevDeferredMinWage || 0}`}> ¥{fmt(prevDeferred)}</span>
}
return <span className="text-gray-300"></span>
})()}
</td>
<td className="py-2 px-2">
{entry.riskWarnings && entry.riskWarnings.length > 0 ? (
<span className="text-danger cursor-help" title={entry.riskWarnings.join('\n')}>
<AlertTriangle className="w-4 h-4" />
</span>
) : (entry.minWageApplied || 0) > 0 ? (
<span className="text-amber-500 cursor-help" title={`最低工资保护已触发:实发补齐到 ¥${entry.minWage},递延 ¥${(entry.deferredSocialEmp || 0) + (entry.deferredHousingEmp || 0) + (entry.deferredMinWage || 0)} 次月补扣`}>
<AlertTriangle className="w-4 h-4" />
</span>
) : (
<span className="text-gray-300"></span>
)}