feat: 社保公积金版本管理 + 员工基数调整 + 加班费计算优化 + UI组件改进
- SocialInsuranceConfig 版本化(effectiveFrom/effectiveTo/isCurrent/adjustmentDone) - 社保配置版本管理接口(列表/新建/按月获取/当前版本) - 员工基数调整:预览全部在职员工、上年月均工资计算建议基数、可编辑表格、确认后批量保存 - payroll.service 按批次月份匹配对应版本社保配置 - risk.service / seed.ts 同步更新 - 前端社保tab重构为版本管理+调整+试算 - 加班费计算三步流程、CSV导入、批次导入 - UI组件、Dashboard、合同、薪酬等页面优化
This commit is contained in:
@@ -61,15 +61,15 @@ export default function Compensation() {
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-lg font-semibold">补偿计算</h1>
|
||||
<div className="space-y-3">
|
||||
<h1 className="text-xs font-medium">补偿计算</h1>
|
||||
|
||||
<div className="flex gap-1 border-b">
|
||||
{tabs.map((t) => (
|
||||
<button
|
||||
key={t.key}
|
||||
onClick={() => setTab(t.key)}
|
||||
className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
|
||||
className={`px-3 py-1.5 text-xs font-medium border-b-2 transition-colors ${
|
||||
tab === t.key ? 'border-primary text-primary' : 'border-transparent text-gray-500 hover:text-gray-700'
|
||||
}`}
|
||||
>
|
||||
@@ -150,7 +150,7 @@ function SeveranceCalculator() {
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
<Card>
|
||||
<h2 className="font-medium mb-4">填写信息</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-3">
|
||||
<EmployeeSelector employees={employees} selectedId={selectedEmpId} onSelect={handleSelectEmp} />
|
||||
<div>
|
||||
<Label>入职日期</Label>
|
||||
@@ -189,19 +189,19 @@ function SeveranceCalculator() {
|
||||
<h2 className="font-medium mb-4 flex items-center gap-2"><Calculator className="w-5 h-5" />计算结果</h2>
|
||||
{result ? (
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm text-gray-500">离职原因:<span className="text-gray-900">{result.reason}</span></div>
|
||||
<div className="text-sm text-gray-500">工作年限:<span className="text-gray-900">{result.years}年{result.remainingMonths}个月</span></div>
|
||||
<div className="text-xs text-gray-500">离职原因:<span className="text-gray-900">{result.reason}</span></div>
|
||||
<div className="text-xs text-gray-500">工作年限:<span className="text-gray-900">{result.years}年{result.remainingMonths}个月</span></div>
|
||||
{result.noComp ? (
|
||||
<div className="px-3 py-2 rounded-md bg-gray-50 text-gray-700 text-sm">
|
||||
<div className="px-3 py-2 rounded-md bg-gray-50 text-gray-700 text-xs">
|
||||
{result.reasonNote}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="text-sm text-gray-500">补偿月数:<span className="text-gray-900">{result.compMonths}个月</span></div>
|
||||
<div className="text-xs text-gray-500">补偿月数:<span className="text-gray-900">{result.compMonths}个月</span></div>
|
||||
{result.capped && (
|
||||
<div className="text-sm text-warning">⚠️ 工资超过社平3倍,已按三倍封顶且最多补偿12个月</div>
|
||||
<div className="text-xs text-warning">⚠️ 工资超过社平3倍,已按三倍封顶且最多补偿12个月</div>
|
||||
)}
|
||||
<div className="text-sm text-gray-500">计算基数:<span className="text-gray-900">¥{fmt(result.wage)}/月</span></div>
|
||||
<div className="text-xs text-gray-500">计算基数:<span className="text-gray-900">¥{fmt(result.wage)}/月</span></div>
|
||||
<div className="border-t pt-3 space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="font-medium">{result.isIllegal ? '经济补偿金' : '应付金额'}</span>
|
||||
@@ -211,7 +211,7 @@ function SeveranceCalculator() {
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="font-medium text-danger">违法解除赔偿金(×2)</span>
|
||||
<span className="text-xl font-bold text-danger">¥{fmt(result.totalPay)}</span>
|
||||
<span className="text-lg font-bold text-danger">¥{fmt(result.totalPay)}</span>
|
||||
</div>
|
||||
<div className="text-xs text-gray-400">({result.compMonths}个月 × ¥{fmt(result.wage)} × 2)</div>
|
||||
</>
|
||||
@@ -219,7 +219,7 @@ function SeveranceCalculator() {
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="font-medium">{result.reason}</span>
|
||||
<span className="text-xl font-bold text-primary">¥{fmt(result.totalPay)}</span>
|
||||
<span className="text-lg font-bold text-primary">¥{fmt(result.totalPay)}</span>
|
||||
</div>
|
||||
<div className="text-xs text-gray-400">({result.compMonths}个月 × ¥{fmt(result.wage)})
|
||||
{result.noticePay > 0 && <span className="block">含代通知金 ¥{fmt(result.noticePay)}</span>}
|
||||
@@ -228,12 +228,12 @@ function SeveranceCalculator() {
|
||||
)}
|
||||
</div>
|
||||
{result.reasonNote && (
|
||||
<div className={`flex items-start gap-2 px-3 py-2 rounded-md text-sm ${result.isIllegal ? 'bg-red-50 text-red-700' : 'bg-blue-50 text-blue-700'}`}>
|
||||
<div className={`flex items-start gap-2 px-3 py-2 rounded-md text-xs ${result.isIllegal ? 'bg-red-50 text-red-700' : 'bg-blue-50 text-blue-700'}`}>
|
||||
<Info className="w-4 h-4 mt-0.5 shrink-0" />
|
||||
<span>{result.reasonNote}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-start gap-2 px-3 py-2 rounded-md bg-blue-50 text-blue-700 text-sm">
|
||||
<div className="flex items-start gap-2 px-3 py-2 rounded-md bg-blue-50 text-blue-700 text-xs">
|
||||
<Info className="w-4 h-4 mt-0.5 shrink-0" />
|
||||
<span>满1年补1个月,满6个月不满1年按1年算,不满6个月补半个月</span>
|
||||
</div>
|
||||
@@ -241,7 +241,7 @@ function SeveranceCalculator() {
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-gray-400 text-sm">填写信息后点击「计算」按钮</div>
|
||||
<div className="text-gray-400 text-xs">填写信息后点击「计算」按钮</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
@@ -303,7 +303,7 @@ function DoubleSalaryCalculator() {
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
<Card>
|
||||
<h2 className="font-medium mb-4">填写信息</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-3">
|
||||
<EmployeeSelector employees={employees} selectedId={selectedEmpId} onSelect={handleSelectEmp} />
|
||||
<div>
|
||||
<Label>月工资(元)</Label>
|
||||
@@ -333,24 +333,24 @@ function DoubleSalaryCalculator() {
|
||||
<h2 className="font-medium mb-4 flex items-center gap-2"><AlertCircle className="w-5 h-5 text-warning" />计算结果</h2>
|
||||
{result ? (
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm text-gray-500">入职日期:<span className="text-gray-900">{hireDate}</span></div>
|
||||
<div className="text-sm text-gray-500">合同签订:<span className="text-gray-900">{hasContract ? contractDate || '未填写' : '未签订'}</span></div>
|
||||
<div className="text-sm text-gray-500">双倍工资起算:<span className="text-gray-900">{result.startDate.toISOString().slice(0, 10)}</span></div>
|
||||
<div className="text-sm text-gray-500">双倍工资截止:<span className="text-gray-900">{result.endDate.toISOString().slice(0, 10)}</span></div>
|
||||
<div className="text-xs text-gray-500">入职日期:<span className="text-gray-900">{hireDate}</span></div>
|
||||
<div className="text-xs text-gray-500">合同签订:<span className="text-gray-900">{hasContract ? contractDate || '未填写' : '未签订'}</span></div>
|
||||
<div className="text-xs text-gray-500">双倍工资起算:<span className="text-gray-900">{result.startDate.toISOString().slice(0, 10)}</span></div>
|
||||
<div className="text-xs text-gray-500">双倍工资截止:<span className="text-gray-900">{result.endDate.toISOString().slice(0, 10)}</span></div>
|
||||
<div className="border-t pt-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="font-medium">需赔</span>
|
||||
<span className="text-xl font-bold text-danger">¥{fmt(result.totalPay)}</span>
|
||||
<span className="text-lg font-bold text-danger">¥{fmt(result.totalPay)}</span>
|
||||
</div>
|
||||
<div className="text-xs text-gray-400 mt-1">({result.months}个月 × ¥{fmt(monthlyWage)})</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-2 px-3 py-2 rounded-md bg-blue-50 text-blue-700 text-sm">
|
||||
<div className="flex items-start gap-2 px-3 py-2 rounded-md bg-blue-50 text-blue-700 text-xs">
|
||||
<Info className="w-4 h-4 mt-0.5 shrink-0" />
|
||||
<span>法律规定:入职1个月没签合同,从第2个月起要付双倍工资,最多11个月</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-gray-400 text-sm">请填写入职日期</div>
|
||||
<div className="text-gray-400 text-xs">请填写入职日期</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user