feat: 工作日历/考勤管理重构/AI人力报告/工作台员工分布/筛选优化/导入导出增强
- 新增工作日历页面(月历视图、事件管理、自定义事件) - 考勤管理重构为6 Tab模块(班次/排班/每日出勤/月度报表/休假记录) - AI顾问新增人力报告Tab,支持流式生成+Word导出 - 工作台总览新增员工分布统计(性别/年龄/学历/司龄饼图)+部门成本拆分 - 花名册/合同/解聘补偿新增部门和状态筛选 - 薪税管理新增工资表导入模板下载、银行代发CSV导出 - 社保公积金支持多公积金账户类型显示 - 数据导出新增花名册/解聘记录导出,中文文件名编码修复 - 数据导入新增模板下载(员工/增减员/工资表)+错误日志导出 - 移除工作台日历卡片(已迁移至独立工作日历页面) - 新增20260728/20260729更新测试指导文档
This commit is contained in:
@@ -906,6 +906,25 @@ export async function getMonthlyCalendar(orgId: string, month: string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 自定义日历事件
|
||||
const customEvents = await prisma.calendarEvent.findMany({
|
||||
where: {
|
||||
orgId,
|
||||
date: { gte: monthStart, lte: monthEnd },
|
||||
},
|
||||
include: { employee: { select: { name: true } } },
|
||||
})
|
||||
for (const ev of customEvents) {
|
||||
events.push({
|
||||
date: ev.date.toISOString().slice(0, 10),
|
||||
type: ev.type,
|
||||
title: ev.title + (ev.employee ? ` — ${ev.employee.name}` : ''),
|
||||
employeeName: ev.employee?.name,
|
||||
actionUrl: '/dashboard',
|
||||
priority: ev.priority as 'high' | 'medium' | 'low',
|
||||
})
|
||||
}
|
||||
|
||||
// 按日期排序
|
||||
events.sort((a, b) => a.date.localeCompare(b.date))
|
||||
|
||||
@@ -1000,6 +1019,35 @@ export async function getCostAnalysis(orgId: string, month: string) {
|
||||
})
|
||||
}
|
||||
|
||||
// 按部门拆分成本
|
||||
const deptEntries = await prisma.batchEntry.findMany({
|
||||
where: {
|
||||
orgId,
|
||||
batch: { month, status: 'ARCHIVED' },
|
||||
},
|
||||
include: { employee: { select: { department: true } } },
|
||||
})
|
||||
const deptMap: Record<string, { totalPay: number; socialOrg: number; housingOrg: number; headcount: number }> = {}
|
||||
for (const e of deptEntries) {
|
||||
const dept = e.employee?.department || '未分配'
|
||||
if (!deptMap[dept]) deptMap[dept] = { totalPay: 0, socialOrg: 0, housingOrg: 0, headcount: 0 }
|
||||
deptMap[dept].totalPay += e.totalPay
|
||||
deptMap[dept].socialOrg += e.socialOrg
|
||||
deptMap[dept].housingOrg += e.housingOrg
|
||||
deptMap[dept].headcount += 1
|
||||
}
|
||||
const departmentCost = Object.entries(deptMap)
|
||||
.map(([dept, v]) => ({
|
||||
department: dept,
|
||||
totalCost: v.totalPay + v.socialOrg + v.housingOrg,
|
||||
totalPay: v.totalPay,
|
||||
socialOrg: v.socialOrg,
|
||||
housingOrg: v.housingOrg,
|
||||
headcount: v.headcount,
|
||||
perCapita: v.headcount > 0 ? (v.totalPay + v.socialOrg + v.housingOrg) / v.headcount : 0,
|
||||
}))
|
||||
.sort((a, b) => b.totalCost - a.totalCost)
|
||||
|
||||
return {
|
||||
month,
|
||||
current: {
|
||||
@@ -1026,6 +1074,7 @@ export async function getCostAnalysis(orgId: string, month: string) {
|
||||
changePercent: yoyChange,
|
||||
},
|
||||
factors,
|
||||
departmentCost,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user