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:
@@ -20,6 +20,7 @@ enum Role {
|
||||
ADMIN
|
||||
HR
|
||||
VIEWER
|
||||
SUPPORT
|
||||
}
|
||||
|
||||
enum EmployeeStatus {
|
||||
@@ -197,6 +198,14 @@ model Organization {
|
||||
benefitEnrollments EmployeeBenefitEnrollment[]
|
||||
eSignRecords ESignRecord[]
|
||||
medicalPeriodPolicies MedicalPeriodPolicy[]
|
||||
// 组织架构 + 审批流
|
||||
departments Department[]
|
||||
positions Position[]
|
||||
approvalFlows ApprovalFlow[]
|
||||
approvalInstances ApprovalInstance[]
|
||||
// 客服工作台
|
||||
tickets Ticket[]
|
||||
chatSessions ChatSession[]
|
||||
}
|
||||
|
||||
model User {
|
||||
@@ -224,6 +233,9 @@ model Employee {
|
||||
department String
|
||||
position String? // 岗位
|
||||
hireDate DateTime
|
||||
// 组织架构扩展
|
||||
departmentId String? // 关联 Department 表(兼容旧 department 字符串)
|
||||
supervisorId String? // 直属上级员工ID
|
||||
monthlySalary String // AES-256 加密存储
|
||||
status EmployeeStatus @default(ACTIVE)
|
||||
gender String?
|
||||
@@ -285,6 +297,11 @@ model Employee {
|
||||
commercialInsEnrollments CommercialInsuranceEnrollment[]
|
||||
benefitEnrollments EmployeeBenefitEnrollment[]
|
||||
eSignRecords ESignRecord[]
|
||||
// 组织架构关联
|
||||
dept Department? @relation("DeptEmployees", fields: [departmentId], references: [id])
|
||||
supervisor Employee? @relation("SupervisorSubordinates", fields: [supervisorId], references: [id])
|
||||
subordinates Employee[] @relation("SupervisorSubordinates")
|
||||
approvalInstances ApprovalInstance[]
|
||||
|
||||
@@unique([orgId, idCardHash])
|
||||
}
|
||||
@@ -1528,3 +1545,161 @@ model ESignRecord {
|
||||
@@index([employeeId])
|
||||
@@index([contractId])
|
||||
}
|
||||
|
||||
// ==================== 组织架构 + 审批流 ====================
|
||||
|
||||
/// 部门(树形结构,自引用 parent)
|
||||
model Department {
|
||||
id String @id @default(cuid())
|
||||
orgId String
|
||||
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
parentId String?
|
||||
parent Department? @relation("DeptChildren", fields: [parentId], references: [id], onDelete: SetNull)
|
||||
children Department[] @relation("DeptChildren")
|
||||
level Int @default(0) // 层级(0=根)
|
||||
sortOrder Int @default(0) // 同级排序
|
||||
description String?
|
||||
createdBy String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
employees Employee[] @relation("DeptEmployees")
|
||||
positions Position[]
|
||||
|
||||
@@unique([orgId, name, parentId])
|
||||
@@index([orgId, parentId])
|
||||
}
|
||||
|
||||
/// 岗位字典
|
||||
model Position {
|
||||
id String @id @default(cuid())
|
||||
orgId String
|
||||
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
departmentId String?
|
||||
department Department? @relation(fields: [departmentId], references: [id], onDelete: SetNull)
|
||||
headcount Int @default(0) // 编制人数
|
||||
level String? // 职级(如 P1/P2/M1)
|
||||
description String?
|
||||
createdBy String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([orgId, name, departmentId])
|
||||
@@index([orgId, departmentId])
|
||||
}
|
||||
|
||||
/// 审批流配置
|
||||
model ApprovalFlow {
|
||||
id String @id @default(cuid())
|
||||
orgId String
|
||||
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
||||
type String // LEAVE / TERMINATION / SALARY_CHANGE / OTHER
|
||||
name String
|
||||
enabled Boolean @default(true)
|
||||
// 步骤配置 JSON: [{ step: 1, approverType: 'SUPERVISOR' | 'PERSON', approverId?: string, name: string }]
|
||||
steps Json
|
||||
createdBy String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
instances ApprovalInstance[]
|
||||
|
||||
@@unique([orgId, type])
|
||||
@@index([orgId])
|
||||
}
|
||||
|
||||
/// 审批实例
|
||||
model ApprovalInstance {
|
||||
id String @id @default(cuid())
|
||||
orgId String
|
||||
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
||||
flowId String
|
||||
flow ApprovalFlow @relation(fields: [flowId], references: [id], onDelete: Cascade)
|
||||
type String // 冗余 flow.type,便于查询
|
||||
bizId String? // 关联业务记录ID(如 LeaveRequest.id)
|
||||
bizType String? // 业务类型
|
||||
status String @default("PENDING") // PENDING / APPROVED / REJECTED / CANCELLED
|
||||
currentStep Int @default(1)
|
||||
// 审批记录 JSON: [{ step, approverId, approverName, result, comment, timestamp }]
|
||||
approvals Json @default("[]")
|
||||
employeeId String?
|
||||
employee Employee? @relation(fields: [employeeId], references: [id], onDelete: SetNull)
|
||||
createdBy String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([orgId, status])
|
||||
@@index([employeeId])
|
||||
@@index([bizId])
|
||||
}
|
||||
|
||||
// ==================== 客服工作台 ====================
|
||||
|
||||
/// 工单
|
||||
model Ticket {
|
||||
id String @id @default(cuid())
|
||||
orgId String // 提交方租户
|
||||
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
||||
title String
|
||||
content String
|
||||
category String? // 分类(如:系统bug/功能咨询/数据问题)
|
||||
priority String @default("NORMAL") // LOW / NORMAL / HIGH / URGENT
|
||||
status String @default("OPEN") // OPEN / IN_PROGRESS / RESOLVED / CLOSED
|
||||
assigneeId String? // 客服处理人 userId
|
||||
createdBy String // 提交人 userId
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
messages TicketMessage[]
|
||||
|
||||
@@index([orgId, status])
|
||||
@@index([assigneeId])
|
||||
}
|
||||
|
||||
/// 工单回复
|
||||
model TicketMessage {
|
||||
id String @id @default(cuid())
|
||||
ticketId String
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
content String
|
||||
senderId String
|
||||
senderRole String // USER / SUPPORT
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([ticketId])
|
||||
}
|
||||
|
||||
/// 客服-客户会话
|
||||
model ChatSession {
|
||||
id String @id @default(cuid())
|
||||
orgId String // 客户租户
|
||||
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
||||
supportUserId String // 客服 userId
|
||||
lastMessage String?
|
||||
lastMessageAt DateTime?
|
||||
unreadByUser Int @default(0)
|
||||
unreadBySupport Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
messages ChatMessage[]
|
||||
|
||||
@@unique([orgId, supportUserId])
|
||||
@@index([supportUserId])
|
||||
}
|
||||
|
||||
/// 会话消息
|
||||
model ChatMessage {
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
session ChatSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
content String
|
||||
senderId String
|
||||
senderRole String // USER / SUPPORT
|
||||
read Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([sessionId])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user