2968484d2d
- Money.tsx (2260行→54行): 拆分为 money/ 子目录4个组件, React.lazy二级分割 - AIAssistant.tsx (2038行→63行): 拆分为 ai-assistant/ 子目录6个组件, React.lazy二级分割 - xlsx改为动态导入, OvertimeTab从345KB降至12.7KB - api-services.ts: 请求参数 any→Record<string,unknown> - 移除前端3处console.log残留 - 后端console替换为pino logger - 前后端未使用import/变量清理 - Zod schema验证: termination/platform/special-status/work-process - 新增 leave.routes.ts, acceptance-test.routes.ts - UI组件: PageGuide, QueryError, Stepper
134 lines
7.1 KiB
TypeScript
134 lines
7.1 KiB
TypeScript
import Card from "../../components/ui/Card"
|
||
import { UserX, DollarSign, Building2 } from "lucide-react"
|
||
import { fmt, terminateReasonMap } from "./shared"
|
||
import { CityHistoryTab } from "./PayslipSocialInfo"
|
||
|
||
/** 变更历史Tab:分组显示各类变更记录 */
|
||
export default function ChangeHistoryTab({ profile }: { profile: any }) {
|
||
const salaryChanges = profile.salaryChanges || []
|
||
const departmentRecords = profile.departmentRecords || []
|
||
const socialInsRecords = profile.socialInsRecords || []
|
||
const housingFundRecords = profile.housingFundRecords || []
|
||
const terminations = profile.terminations || []
|
||
|
||
const changeTypeMap: Record<string, string> = { ONBOARDING: '入职', REHIRE: '重新入职', ADJUST: '调基', TERMINATION: '离职/解聘', SALARY_CHANGE: '调薪', TRANSFER: '调部门', CITY_CHANGE: '城市变更' }
|
||
const changeTypeColor: Record<string, string> = { ONBOARDING: 'bg-green-50 text-safe', REHIRE: 'bg-blue-50 text-blue-600', ADJUST: 'bg-amber-50 text-amber-600', TERMINATION: 'bg-red-50 text-danger', SALARY_CHANGE: 'bg-indigo-50 text-indigo-600', TRANSFER: 'bg-purple-50 text-purple-600', CITY_CHANGE: 'bg-cyan-50 text-cyan-600' }
|
||
|
||
const totalChanges = salaryChanges.length + departmentRecords.length + socialInsRecords.length + housingFundRecords.length + terminations.length
|
||
|
||
if (totalChanges === 0) {
|
||
return <Card><div className="text-center py-8 text-gray-400">暂无变更记录</div></Card>
|
||
}
|
||
|
||
return (
|
||
<div className="space-y-4">
|
||
{/* 薪资变更 */}
|
||
{salaryChanges.length > 0 && (
|
||
<Card>
|
||
<h3 className="text-sm font-medium mb-3 flex items-center gap-2">
|
||
<DollarSign className="w-4 h-4 text-indigo-600" />
|
||
薪资变更历史({salaryChanges.length}条)
|
||
</h3>
|
||
<table className="w-full text-sm">
|
||
<thead>
|
||
<tr className="border-b text-xs text-gray-500">
|
||
<th className="py-2 text-left">生效日期</th>
|
||
<th className="py-2 text-right">原薪资</th>
|
||
<th className="py-2 text-right">新薪资</th>
|
||
<th className="py-2 text-right">变动额</th>
|
||
<th className="py-2 text-center">类型</th>
|
||
<th className="py-2 text-left">原因</th>
|
||
<th className="py-2 text-left">失效年月</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{salaryChanges.map((r: any, idx: number) => (
|
||
<tr key={idx} className="border-b last:border-0 hover:bg-gray-50">
|
||
<td className="py-2 font-medium">{new Date(r.effectiveDate).toLocaleDateString('zh-CN')}</td>
|
||
<td className="py-2 text-right text-gray-600">¥{fmt(r.oldSalary)}</td>
|
||
<td className="py-2 text-right text-gray-600">¥{fmt(r.newSalary)}</td>
|
||
<td className="py-2 text-right font-medium text-primary">{r.newSalary >= r.oldSalary ? '+' : ''}¥{fmt(r.newSalary - r.oldSalary)}</td>
|
||
<td className="py-2 text-center"><span className={`px-2 py-0.5 rounded text-xs ${changeTypeColor[r.changeType] || 'bg-gray-100 text-gray-500'}`}>{changeTypeMap[r.changeType] || r.changeType}</span></td>
|
||
<td className="py-2 text-gray-400 text-xs">{r.reason || '-'}</td>
|
||
<td className="py-2 text-gray-400 text-xs">{r.endMonth || '至今'}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</Card>
|
||
)}
|
||
|
||
{/* 部门变更 */}
|
||
{departmentRecords.length > 0 && (
|
||
<Card>
|
||
<h3 className="text-sm font-medium mb-3 flex items-center gap-2">
|
||
<Building2 className="w-4 h-4 text-purple-600" />
|
||
部门变更历史({departmentRecords.length}条)
|
||
</h3>
|
||
<table className="w-full text-sm">
|
||
<thead>
|
||
<tr className="border-b text-xs text-gray-500">
|
||
<th className="py-2 text-left">生效年月</th>
|
||
<th className="py-2 text-left">原部门</th>
|
||
<th className="py-2 text-left">新部门</th>
|
||
<th className="py-2 text-center">类型</th>
|
||
<th className="py-2 text-left">原因</th>
|
||
<th className="py-2 text-left">失效年月</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{departmentRecords.map((r: any, idx: number) => (
|
||
<tr key={idx} className="border-b last:border-0 hover:bg-gray-50">
|
||
<td className="py-2 font-medium">{r.effectiveMonth}</td>
|
||
<td className="py-2 text-gray-600">{r.oldDepartment || '无'}</td>
|
||
<td className="py-2 font-medium">{r.newDepartment}</td>
|
||
<td className="py-2 text-center"><span className={`px-2 py-0.5 rounded text-xs ${changeTypeColor[r.changeType] || 'bg-gray-100 text-gray-500'}`}>{changeTypeMap[r.changeType] || r.changeType}</span></td>
|
||
<td className="py-2 text-gray-400 text-xs">{r.reason || '-'}</td>
|
||
<td className="py-2 text-gray-400 text-xs">{r.endMonth || '至今'}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</Card>
|
||
)}
|
||
|
||
{/* 参保城市变更(社保+公积金合并) */}
|
||
{(socialInsRecords.length > 0 || housingFundRecords.length > 0) && (
|
||
<CityHistoryTab socialInsRecords={socialInsRecords} housingFundRecords={housingFundRecords} changeTypeMap={changeTypeMap} changeTypeColor={changeTypeColor} />
|
||
)}
|
||
|
||
{/* 离职/解聘记录 */}
|
||
{terminations.length > 0 && (
|
||
<Card>
|
||
<h3 className="text-sm font-medium mb-3 flex items-center gap-2">
|
||
<UserX className="w-4 h-4 text-danger" />
|
||
离职/解聘记录({terminations.length}条)
|
||
</h3>
|
||
<table className="w-full text-sm">
|
||
<thead>
|
||
<tr className="border-b text-xs text-gray-500">
|
||
<th className="py-2 text-left">离职日期</th>
|
||
<th className="py-2 text-center">离职类型</th>
|
||
<th className="py-2 text-left">原因</th>
|
||
<th className="py-2 text-left">备注</th>
|
||
<th className="py-2 text-left">创建时间</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{terminations.map((r: any, idx: number) => (
|
||
<tr key={idx} className="border-b last:border-0 hover:bg-gray-50">
|
||
<td className="py-2 font-medium">{new Date(r.terminationDate).toLocaleDateString('zh-CN')}</td>
|
||
<td className="py-2 text-center"><span className="px-2 py-0.5 rounded text-xs bg-red-50 text-danger">{terminateReasonMap[r.terminationType] || r.terminationType}</span></td>
|
||
<td className="py-2 text-gray-600 text-xs">{r.reason || '-'}</td>
|
||
<td className="py-2 text-gray-400 text-xs">{r.remark || '-'}</td>
|
||
<td className="py-2 text-gray-400 text-xs">{new Date(r.createdAt).toLocaleString('zh-CN')}</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</Card>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|