feat: 解聘Step3合规检查增强 — 系统自动预填+建议

后端:
- getChecklistForReason 接收 employee 数据,支持自动检查
- 医疗期是否届满:根据 isInMedicalPeriod 自动判断
- 是否经过培训/调岗:根据 trainingRecords 自动判断
- 经济补偿金/代通知金:系统给建议(suggestion + suggestionType)
- checklist 接口改为 async,获取员工 profile 传入

前端:
- checklist 查询传入 employeeId
- useEffect 自动预填系统判断结果到 checklist state
- Step 3 UI 重写:显示系统判断标签、来源说明、建议提示
- 建议按类型显示不同颜色(warning/required/info)
This commit is contained in:
freedakgmail
2026-07-23 16:56:28 +08:00
parent fa7aa01c48
commit 1b05facc92
3 changed files with 175 additions and 39 deletions
+25 -3
View File
@@ -19,9 +19,31 @@ router.get('/', authMiddleware, async (req: AuthRequest, res, next) => {
}
})
router.get('/checklist/:reason', authMiddleware, (req: AuthRequest, res) => {
const checklist = getChecklistForReason(req.params.reason)
res.json({ success: true, data: checklist })
router.get('/checklist/:reason', authMiddleware, async (req: AuthRequest, res, next) => {
try {
const employeeId = req.query.employeeId as string
let employee: any = undefined
if (employeeId) {
const emp = await prisma.employee.findFirst({
where: { id: employeeId, orgId: req.user!.orgId },
include: {
trainingRecords: true,
},
})
if (emp) {
employee = {
isInMedicalPeriod: emp.isInMedicalPeriod,
trainingRecords: emp.trainingRecords,
}
}
}
const checklist = getChecklistForReason(req.params.reason, employee)
res.json({ success: true, data: checklist })
} catch (err) {
next(err)
}
})
router.get('/assess/:employeeId', authMiddleware, async (req: AuthRequest, res, next) => {
+90 -21
View File
@@ -6,39 +6,108 @@ function daysBetween(a: Date, b: Date): number {
return Math.floor((a.getTime() - b.getTime()) / (1000 * 60 * 60 * 24))
}
export function getChecklistForReason(reason: string): { key: string; label: string }[] {
export interface ChecklistItem {
key: string
label: string
autoChecked?: boolean | null // null=无法自动判断,true/false=系统判断结果
autoSource?: string // 系统判断依据说明
suggestion?: string // 系统建议说明
suggestionType?: 'info' | 'warning' | 'required'
}
export function getChecklistForReason(reason: string, employee?: any): ChecklistItem[] {
switch (reason) {
case 'NEGOTIATED':
return [
{ key: 'compensation_paid', label: '是否已支付经济补偿金' },
{ key: 'agreement_signed', label: '是否签署协商解除协议' },
{ key: 'final_pay_ready', label: '是否结清最后工资' },
{
key: 'compensation_paid', label: '是否已支付经济补偿金',
autoChecked: null,
suggestion: '协商解除需支付经济补偿金(N),建议在协商协议中明确金额',
suggestionType: 'required',
},
{ key: 'agreement_signed', label: '是否签署协商解除协议', autoChecked: null },
{ key: 'final_pay_ready', label: '是否结清最后工资', autoChecked: null },
]
case 'FAULT':
return [
{ key: 'has_rules', label: '是否有规章制度依据' },
{ key: 'has_evidence', label: '是否有违纪证据' },
{ key: 'notify_union', label: '是否事先通知工会' },
{ key: 'written_notice', label: '是否出具书面解除通知' },
]
case 'NONFAULT':
return [
{ key: 'medical_period_end', label: '医疗期是否已届满' },
{ key: 'training_given', label: '是否经过培训或调岗' },
{ key: 'compensation_paid', label: '是否支付经济补偿金' },
{ key: 'advance_notice', label: '是否提前30天通知或支付代通知金' },
{ key: 'has_rules', label: '是否有规章制度依据', autoChecked: null },
{ key: 'has_evidence', label: '是否有违纪证据', autoChecked: null },
{ key: 'notify_union', label: '是否事先通知工会', autoChecked: null },
{ key: 'written_notice', label: '是否出具书面解除通知', autoChecked: null },
]
case 'NONFAULT': {
const items: ChecklistItem[] = []
// 医疗期是否已届满 — 系统自动判断
if (employee?.isInMedicalPeriod) {
items.push({
key: 'medical_period_end', label: '医疗期是否已届满',
autoChecked: false,
autoSource: '系统记录显示该员工正处于医疗期内,医疗期未届满',
suggestion: '医疗期内不得以非过错理由解除,需等待医疗期届满',
suggestionType: 'warning',
})
} else {
items.push({
key: 'medical_period_end', label: '医疗期是否已届满',
autoChecked: null,
autoSource: '系统未记录该员工处于医疗期,如实际已届满请勾选确认',
})
}
// 是否经过培训或调岗 — 系统自动判断
const hasTraining = employee?.trainingRecords?.length > 0
items.push({
key: 'training_given', label: '是否经过培训或调岗',
autoChecked: hasTraining ? true : null,
autoSource: hasTraining
? `系统记录显示该员工有${employee.trainingRecords.length}条培训记录`
: '系统未找到培训或调岗记录,请人工确认',
suggestion: hasTraining
? '已有培训记录,满足"不胜任工作经培训或调岗"的前提条件'
: '以不胜任工作为由解除前,必须先经过培训或调岗,否则违法解除风险极高',
suggestionType: hasTraining ? 'info' : 'warning',
})
// 是否支付经济补偿金 — 系统建议
items.push({
key: 'compensation_paid', label: '是否支付经济补偿金',
autoChecked: null,
suggestion: '非过错解除需支付经济补偿金(N),并在Step 4费用结算中确认金额',
suggestionType: 'required',
})
// 是否提前30天通知或支付代通知金 — 系统建议
items.push({
key: 'advance_notice', label: '是否提前30天通知或支付代通知金',
autoChecked: null,
suggestion: '非过错解除需提前30天书面通知,或额外支付1个月工资作为代通知金(N+1)',
suggestionType: 'required',
})
return items
}
case 'LAYOFF':
return [
{ key: 'advance_notice_30', label: '是否提前30天向工会或全体职工说明' },
{ key: 'listen_opinions', label: '是否听取工会或职工意见' },
{ key: 'report_labor_dept', label: '是否向劳动行政部门报告' },
{ key: 'compensation_paid', label: '是否支付经济补偿金' },
{ key: 'advance_notice_30', label: '是否提前30天向工会或全体职工说明', autoChecked: null },
{ key: 'listen_opinions', label: '是否听取工会或职工意见', autoChecked: null },
{ key: 'report_labor_dept', label: '是否向劳动行政部门报告', autoChecked: null },
{
key: 'compensation_paid', label: '是否支付经济补偿金',
autoChecked: null,
suggestion: '裁员需支付经济补偿金(N)',
suggestionType: 'required',
},
]
case 'EXPIRED':
return [
{ key: 'compensation_paid', label: '是否支付经济补偿金(如需)' },
{ key: 'written_notice', label: '是否提前通知员工不续签' },
{
key: 'compensation_paid', label: '是否支付经济补偿金(如需)',
autoChecked: null,
suggestion: '公司提出不续签需支付经济补偿金(N);员工主动提出不续签则无需支付',
suggestionType: 'info',
},
{ key: 'written_notice', label: '是否提前通知员工不续签', autoChecked: null },
]
default:
return []