feat: 员工特殊状态台账(三期/工伤/医疗期)完整实现
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user