feat: 20260815 系统优化 - 全部31项问题修复(P0×6+P1×14+P2×9+P3×2)
P0紧急修复(6项): - 草稿保存完整恢复所有字段(含socialAvgWage) - 补偿金批次从compensationBreakdown读取 - 违法解除风险确认UI - 合同结束日期前后校验(前后端双保险) P1高优先级(14项): - 离职日期联动社保/公积金截止月(15号规则) - 合规检查+工作交接改为软阻断(生成待办) - 补偿月数(N/N+1/2N/自定义)+计算基数(近12月/合同/自定义) - 解聘并入花名册操作栏(类型选择跳转向导) - 合同续签开始日期自动推导(原合同结束日+1天) - 年龄合规筛查(童工阻断/未成年工/退休警告) - 编辑入职日期后状态联动(待入职↔在职) - 转正移植到花名册操作栏+薪资回写 - 男职工无法选择三期 P2体验优化(9项): - "劳动合同"调整为"用工关系" - 费用结算新增剩余年假折算(300%日工资) - 身份证号全域改为"证件号码"(前后端18个文件) - 手机号查重 - 开具证明+合同续签移植到花名册操作栏 - 批量转正+批量开具证明 - 去掉用工办理模块 P3规划(2项): - 组织架构+审批流(Department/Position/ApprovalFlow/ApprovalInstance) - 客服工作台(Ticket/ChatSession+SUPPORT角色) 新增模型: Department/Position/ApprovalFlow/ApprovalInstance/Ticket/TicketMessage/ChatSession/ChatMessage 新增字段: Employee.departmentId/supervisorId 新增角色: SUPPORT Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -27,7 +27,7 @@ const REQUIRED_FIELDS: Record<string, string[]> = {
|
||||
// 必填字段中文标签映射
|
||||
const FIELD_LABELS: Record<string, string> = {
|
||||
name: '员工姓名', department: '部门', hireDate: '入职日期', phone: '手机号',
|
||||
idCardNumber: '身份证号', employeeId: '员工ID', contractId: '合同ID',
|
||||
idCardNumber: '证件号码', employeeId: '员工ID', contractId: '合同ID',
|
||||
contractStartDate: '合同开始日期', confirmDate: '转正日期',
|
||||
newEndDate: '新到期日期', newStartDate: '新合同开始日期',
|
||||
suspendDate: '中止日期', employeeName: '员工姓名',
|
||||
@@ -35,11 +35,38 @@ const FIELD_LABELS: Record<string, string> = {
|
||||
leaveDate: '离职日期', agreementStartDate: '协议开始日期',
|
||||
}
|
||||
|
||||
/** 日期字段对配置:各流程类型的开始/结束日期字段对 */
|
||||
const DATE_RANGE_FIELDS: Record<string, Array<{ start: string; end: string; startLabel: string; endLabel: string }>> = {
|
||||
HIRE: [{ start: 'contractStartDate', end: 'contractEndDate', startLabel: '合同开始日期', endLabel: '合同结束日期' }],
|
||||
CUSTOM_CONTRACT: [{ start: 'contractStartDate', end: 'contractEndDate', startLabel: '合同开始日期', endLabel: '合同结束日期' }],
|
||||
RENEW: [{ start: 'newStartDate', end: 'newEndDate', startLabel: '新合同开始日期', endLabel: '新合同结束日期' }],
|
||||
FLEXIBLE: [{ start: 'agreementStartDate', end: 'agreementEndDate', startLabel: '协议开始日期', endLabel: '协议结束日期' }],
|
||||
}
|
||||
|
||||
/** 校验日期前后关系:结束日期不能早于开始日期 */
|
||||
function validateWorkProcessDateRange(type: string, formData: Record<string, any>): string | null {
|
||||
const pairs = DATE_RANGE_FIELDS[type]
|
||||
if (!pairs) return null
|
||||
for (const pair of pairs) {
|
||||
const start = formData[pair.start]
|
||||
const end = formData[pair.end]
|
||||
if (start && end && new Date(end) < new Date(start)) {
|
||||
return `${pair.endLabel}不能早于${pair.startLabel}`
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 创建办理(含草稿)
|
||||
router.post('/', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const data = createWorkProcessSchema.parse(req.body)
|
||||
const { type, title, employeeId, formData, status, remark } = data
|
||||
// 后端日期前后关系校验(双保险)
|
||||
const dateError = validateWorkProcessDateRange(type, formData || {})
|
||||
if (dateError) {
|
||||
return res.status(400).json({ success: false, error: { code: 'INVALID_DATE_RANGE', message: dateError } })
|
||||
}
|
||||
const process = await (prisma as any).workProcess.create({
|
||||
data: {
|
||||
orgId: req.user!.orgId,
|
||||
|
||||
Reference in New Issue
Block a user