feat: 工作日历/考勤管理重构/AI人力报告/工作台员工分布/筛选优化/导入导出增强

- 新增工作日历页面(月历视图、事件管理、自定义事件)
- 考勤管理重构为6 Tab模块(班次/排班/每日出勤/月度报表/休假记录)
- AI顾问新增人力报告Tab,支持流式生成+Word导出
- 工作台总览新增员工分布统计(性别/年龄/学历/司龄饼图)+部门成本拆分
- 花名册/合同/解聘补偿新增部门和状态筛选
- 薪税管理新增工资表导入模板下载、银行代发CSV导出
- 社保公积金支持多公积金账户类型显示
- 数据导出新增花名册/解聘记录导出,中文文件名编码修复
- 数据导入新增模板下载(员工/增减员/工资表)+错误日志导出
- 移除工作台日历卡片(已迁移至独立工作日历页面)
- 新增20260728/20260729更新测试指导文档
This commit is contained in:
freedakgmail
2026-07-29 08:35:29 +08:00
parent d020d04a8a
commit fb36b10402
45 changed files with 3756 additions and 169 deletions
@@ -0,0 +1,11 @@
-- P1-9: 多公积金比例账户
-- 给 HousingFundConfig 增加 accountType 字段,支持基本公积金/补充公积金
-- 1. 添加列,默认值 BASIC
ALTER TABLE "HousingFundConfig" ADD COLUMN "accountType" TEXT NOT NULL DEFAULT 'BASIC';
-- 2. 删除旧唯一约束
ALTER TABLE "HousingFundConfig" DROP CONSTRAINT "HousingFundConfig_orgId_city_effectiveFrom_key";
-- 3. 添加新唯一约束(包含 accountType
ALTER TABLE "HousingFundConfig" ADD CONSTRAINT "HousingFundConfig_orgId_city_accountType_effectiveFrom_key" UNIQUE ("orgId", "city", "accountType", "effectiveFrom");
@@ -0,0 +1,27 @@
-- P2-10: 自定义日历事件
CREATE TABLE "CalendarEvent" (
"id" TEXT NOT NULL,
"orgId" TEXT NOT NULL,
"title" TEXT NOT NULL,
"date" TIMESTAMP(3) NOT NULL,
"endDate" TIMESTAMP(3),
"type" TEXT NOT NULL DEFAULT 'CUSTOM',
"priority" TEXT NOT NULL DEFAULT 'medium',
"location" TEXT,
"description" TEXT,
"employeeId" TEXT,
"createdBy" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "CalendarEvent_pkey" PRIMARY KEY ("id")
);
CREATE INDEX "CalendarEvent_orgId_date_idx" ON "CalendarEvent"("orgId", "date");
CREATE INDEX "CalendarEvent_orgId_type_idx" ON "CalendarEvent"("orgId", "type");
ALTER TABLE "CalendarEvent" ADD CONSTRAINT "CalendarEvent_orgId_fkey"
FOREIGN KEY ("orgId") REFERENCES "Organization"("id") ON DELETE CASCADE;
ALTER TABLE "CalendarEvent" ADD CONSTRAINT "CalendarEvent_employeeId_fkey"
FOREIGN KEY ("employeeId") REFERENCES "Employee"("id") ON DELETE SET NULL;
@@ -0,0 +1,25 @@
-- P2-15: 人工咨询服务 Consultation 表
CREATE TABLE "Consultation" (
"id" TEXT NOT NULL,
"orgId" TEXT NOT NULL,
"type" TEXT NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"contactName" TEXT NOT NULL,
"contactPhone" TEXT NOT NULL,
"status" TEXT NOT NULL DEFAULT 'PENDING',
"aiConversationId" TEXT,
"remark" TEXT,
"createdBy" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Consultation_pkey" PRIMARY KEY ("id")
);
CREATE INDEX "Consultation_orgId_status_idx" ON "Consultation"("orgId", "status");
CREATE INDEX "Consultation_orgId_type_idx" ON "Consultation"("orgId", "type");
-- 外键
ALTER TABLE "Consultation" ADD CONSTRAINT "Consultation_orgId_fkey"
FOREIGN KEY ("orgId") REFERENCES "Organization"("id") ON DELETE CASCADE;
+126 -1
View File
@@ -166,6 +166,11 @@ model Organization {
healthCheckReports HealthCheckReport[]
annualValueReports AnnualValueReport[]
specialDeductionRecords SpecialDeductionRecord[]
shifts Shift[]
shiftAssignments ShiftAssignment[]
leaveRecords LeaveRecord[]
calendarEvents CalendarEvent[]
consultations Consultation[]
}
model User {
@@ -216,6 +221,7 @@ model Employee {
specialDeduction Float @default(0) // 专项附加扣除(子女教育、赡养老人等,员工portal端填报)
city String? // 员工社保参保城市
birthDate DateTime? // 出生日期(从身份证号提取)
education String? // 学历(博士/硕士/本科/大专/高中/其他)
femaleWorkerType FemaleWorkerType? // 女性岗位类型(CADRE=干部/WORKER=工人,仅女性需要区分)
retirementDaysLeft Int? // 距退休天数(便捷字段,定期计算)
createdBy String
@@ -242,6 +248,9 @@ model Employee {
attendanceConfirmations AttendanceConfirmation[]
policyReadRecords PolicyReadRecord[]
specialDeductionRecords SpecialDeductionRecord[]
shiftAssignments ShiftAssignment[]
leaveRecords LeaveRecord[]
calendarEvents CalendarEvent[]
@@unique([orgId, idCardHash])
}
@@ -410,6 +419,7 @@ model HousingFundConfig {
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
city String @default("北京")
accountType String @default("BASIC") // BASIC=基本公积金, SUPPLEMENTARY=补充公积金
housingOrg Float @default(12) // 公积金 企业比例 %
housingEmp Float @default(12) // 公积金 个人比例 %
baseMin Float @default(6326) // 公积金缴费基数下限
@@ -422,7 +432,7 @@ model HousingFundConfig {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([orgId, city, effectiveFrom])
@@unique([orgId, city, accountType, effectiveFrom])
@@index([orgId, isCurrent])
}
@@ -668,6 +678,15 @@ model BatchEntry {
allowance Float @default(0)
deduction Float @default(0)
bonus Float @default(0)
// 细化薪资项
positionSalary Float @default(0) // 岗位工资
performanceSalary Float @default(0) // 绩效工资
senioritySalary Float @default(0) // 工龄工资
transportAllowance Float @default(0) // 交通补贴
mealAllowance Float @default(0) // 餐补
housingAllowance Float @default(0) // 住房补贴
communicationAllowance Float @default(0) // 通讯补贴
otherDeduction Float @default(0) // 其他扣款
// 自动计算项
socialEmp Float @default(0)
socialOrg Float @default(0)
@@ -1045,3 +1064,109 @@ model SpecialDeductionRecord {
@@unique([employeeId, month])
@@index([orgId, month])
}
// ========== 班次管理 ==========
model Shift {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
name String // 班次名称,如"早班"、"白班"、"夜班"
startTime String // 上班时间 HH:mm
endTime String // 下班时间 HH:mm
flexibleMinutes Int @default(0) // 弹性时长(分钟)
restMinutes Int @default(0) // 休息时长(分钟)
color String @default("#3b82f6") // 日历显示颜色
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
assignments ShiftAssignment[]
@@index([orgId])
}
// ========== 排班记录 ==========
model ShiftAssignment {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
employeeId String
employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
shiftId String
shift Shift @relation(fields: [shiftId], references: [id], onDelete: Cascade)
date DateTime // 排班日期
createdBy String
createdAt DateTime @default(now())
@@unique([employeeId, date])
@@index([orgId, date])
@@index([orgId, employeeId])
}
// ========== 休假记录(直接记录,无审批流程) ==========
model LeaveRecord {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
employeeId String
employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
leaveType String // SICK=病假 / PERSONAL=事假 / ANNUAL=年假 / MATERNITY=产假 / OTHER=其他
startDate DateTime
endDate DateTime
days Float // 请假天数
reason String?
remark String?
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([orgId, employeeId])
@@index([orgId, startDate])
}
// ========== 自定义日历事件 ==========
model CalendarEvent {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
title String
date DateTime
endDate DateTime?
type String @default("CUSTOM") // CUSTOM=自定义, MEETING=会议, TEAM_BUILDING=团建, TRAINING=培训, INTERVIEW=面试
priority String @default("medium") // high/medium/low
location String?
description String?
employeeId String?
employee Employee? @relation(fields: [employeeId], references: [id], onDelete: SetNull)
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([orgId, date])
@@index([orgId, type])
}
// ========== 人工咨询服务 ==========
model Consultation {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
type String // LEGAL=法律咨询, ARBITRATION=仲裁代理, COURT=出庭服务
title String
description String
contactName String
contactPhone String
status String @default("PENDING") // PENDING=待处理, CONTACTED=已联系, COMPLETED=已完成, CANCELLED=已取消
aiConversationId String? // 关联 AI 会话
remark String?
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([orgId, status])
@@index([orgId, type])
}