feat: 员工特殊状态台账(三期/工伤/医疗期)完整实现

This commit is contained in:
selfrelease
2026-07-30 15:04:34 +08:00
parent 5a5ce7186b
commit 826c8fda65
11 changed files with 1275 additions and 6 deletions
+201
View File
@@ -0,0 +1,201 @@
/**
* 员工特殊状态台账路由
* 管理三期/工伤/医疗期等特殊状态的 CRUD 和提醒
*/
import { Router, Response, NextFunction } from 'express'
import { authMiddleware, AuthRequest } from '../middleware/auth'
import prisma from '../lib/prisma'
import {
createSpecialStatus,
updateSpecialStatus,
deleteSpecialStatus,
getPendingReminders,
STATUS_TYPES,
getAlertLevel,
} from '../services/special-status.service'
const router = Router()
/**
* 获取特殊状态列表(分页 + 筛选)
*/
router.get('/', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const orgId = req.user!.orgId
const page = parseInt(req.query.page as string) || 1
const pageSize = parseInt(req.query.pageSize as string) || 20
const type = (req.query.type as string) || ''
const status = (req.query.status as string) || ''
const search = (req.query.search as string) || ''
const where: any = { orgId }
if (type) where.type = type
if (status) where.status = status
if (search) {
where.employee = {
OR: [
{ name: { contains: search, mode: 'insensitive' } },
{ phone: { contains: search } },
],
}
}
const [list, total] = await Promise.all([
(prisma as any).employeeSpecialStatus.findMany({
where,
orderBy: { createdAt: 'desc' },
skip: (page - 1) * pageSize,
take: pageSize,
include: {
employee: {
select: { id: true, name: true, department: true, phone: true, gender: true, status: true },
},
},
}),
(prisma as any).employeeSpecialStatus.count({ where }),
])
// 附加预警级别
const listWithAlert = list.map((item: any) => ({
...item,
alertLevel: getAlertLevel(item.reminderDate, item.status),
}))
res.json({
success: true,
data: { list: listWithAlert, total, page, pageSize },
})
} catch (err) {
next(err)
}
})
/**
* 获取单条详情
*/
router.get('/:id', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const record = await (prisma as any).employeeSpecialStatus.findFirst({
where: { id: req.params.id, orgId: req.user!.orgId },
include: {
employee: {
select: { id: true, name: true, department: true, phone: true, gender: true, hireDate: true },
},
},
})
if (!record) {
return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '记录不存在' } })
}
res.json({ success: true, data: record })
} catch (err) {
next(err)
}
})
/**
* 创建特殊状态
*/
router.post('/', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const record = await createSpecialStatus(req.user!.orgId, req.user!.id, req.body)
res.json({ success: true, data: record })
} catch (err: any) {
if (err.code) {
return res.status(400).json({ success: false, error: { code: err.code, message: err.message } })
}
next(err)
}
})
/**
* 更新特殊状态
*/
router.put('/:id', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const record = await updateSpecialStatus(req.user!.orgId, req.user!.id, req.params.id, req.body)
res.json({ success: true, data: record })
} catch (err: any) {
if (err.code) {
return res.status(400).json({ success: false, error: { code: err.code, message: err.message } })
}
next(err)
}
})
/**
* 删除特殊状态
*/
router.delete('/:id', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
await deleteSpecialStatus(req.user!.orgId, req.params.id)
res.json({ success: true, data: { message: '已删除' } })
} catch (err: any) {
if (err.code) {
return res.status(400).json({ success: false, error: { code: err.code, message: err.message } })
}
next(err)
}
})
/**
* 获取待提醒列表
*/
router.get('/reminders/pending', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const reminders = await getPendingReminders(req.user!.orgId)
res.json({ success: true, data: reminders })
} catch (err) {
next(err)
}
})
/**
* 获取统计概览
*/
router.get('/stats/overview', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const orgId = req.user!.orgId
const [total, active, pending, byType] = await Promise.all([
(prisma as any).employeeSpecialStatus.count({ where: { orgId } }),
(prisma as any).employeeSpecialStatus.count({ where: { orgId, status: 'ACTIVE' } }),
(prisma as any).employeeSpecialStatus.count({ where: { orgId, status: 'PENDING' } }),
(prisma as any).employeeSpecialStatus.groupBy({
by: ['type'],
where: { orgId, status: 'ACTIVE' },
_count: true,
}),
])
// 预警统计
const now = new Date()
const soon7 = new Date()
soon7.setDate(soon7.getDate() + 7)
const soon30 = new Date()
soon30.setDate(soon30.getDate() + 30)
const [redCount, yellowCount] = await Promise.all([
(prisma as any).employeeSpecialStatus.count({
where: { orgId, status: 'ACTIVE', reminderDate: { lte: soon7 } },
}),
(prisma as any).employeeSpecialStatus.count({
where: { orgId, status: 'ACTIVE', reminderDate: { gt: soon7, lte: soon30 } },
}),
])
res.json({
success: true,
data: {
total,
active,
pending,
redAlert: redCount,
yellowAlert: yellowCount,
byType: byType.map((t: any) => ({ type: t.type, label: STATUS_TYPES[t.type]?.label || t.type, count: t._count })),
},
})
} catch (err) {
next(err)
}
})
export default router