import { Router, Response, NextFunction } from 'express' import { z } from 'zod' import prisma from '../lib/prisma' import { authMiddleware, AuthRequest } from '../middleware/auth' const router = Router() router.use(authMiddleware) const planSchema = z.object({ name: z.string().min(1), category: z.string(), amount: z.number().default(0), frequency: z.string().default('MONTHLY'), taxDeductible: z.boolean().default(false), description: z.string().optional(), }) const BENEFIT_CATEGORIES: Record = { TRANSPORT: '交通补贴', MEAL: '餐补', HOUSING: '住房补贴', COMMUNICATION: '通讯补贴', HEALTH_CHECK: '体检', HOLIDAY: '节日福利', BIRTHDAY: '生日福利', OTHER: '其他', } // 福利方案列表 router.get('/plans', async (req: AuthRequest, res: Response, next: NextFunction) => { try { const plans = await prisma.employeeBenefitPlan.findMany({ where: { orgId: req.user!.orgId }, orderBy: { createdAt: 'desc' }, include: { _count: { select: { enrollments: { where: { status: 'ACTIVE' } } } } }, }) res.json({ success: true, data: plans }) } catch (err) { next(err) } }) // 创建福利方案 router.post('/plans', async (req: AuthRequest, res: Response, next: NextFunction) => { try { const data = planSchema.parse(req.body) const plan = await prisma.employeeBenefitPlan.create({ data: { ...data, orgId: req.user!.orgId, createdBy: req.user!.id }, }) res.json({ success: true, data: plan }) } catch (err) { next(err) } }) // 更新福利方案 router.put('/plans/:planId', async (req: AuthRequest, res: Response, next: NextFunction) => { try { const data = planSchema.partial().parse(req.body) const plan = await prisma.employeeBenefitPlan.update({ where: { id: req.params.planId, orgId: req.user!.orgId }, data, }) res.json({ success: true, data: plan }) } catch (err) { next(err) } }) // 删除福利方案 router.delete('/plans/:planId', async (req: AuthRequest, res: Response, next: NextFunction) => { try { await prisma.employeeBenefitPlan.delete({ where: { id: req.params.planId, orgId: req.user!.orgId }, }) res.json({ success: true }) } catch (err) { next(err) } }) // 方案参保人员 router.get('/plans/:planId/enrollments', async (req: AuthRequest, res: Response, next: NextFunction) => { try { const enrollments = await prisma.employeeBenefitEnrollment.findMany({ where: { orgId: req.user!.orgId, planId: req.params.planId }, include: { employee: { select: { id: true, name: true, department: true } } }, orderBy: { createdAt: 'desc' }, }) const data = enrollments.map((e: any) => ({ id: e.id, employeeId: e.employeeId, name: e.employee.name, department: e.employee.department, effectiveFrom: e.effectiveFrom, effectiveTo: e.effectiveTo, amount: e.amount, status: e.status, })) res.json({ success: true, data }) } catch (err) { next(err) } }) // 批量参保 router.post('/plans/:planId/enroll', async (req: AuthRequest, res: Response, next: NextFunction) => { try { const { employeeIds, effectiveFrom } = req.body as { employeeIds: string[]; effectiveFrom: string } const plan = await prisma.employeeBenefitPlan.findFirst({ where: { id: req.params.planId, orgId: req.user!.orgId } }) if (!plan) return res.status(404).json({ success: false, error: { message: '方案不存在' } }) const existing = await prisma.employeeBenefitEnrollment.findMany({ where: { planId: plan.id, employeeId: { in: employeeIds }, status: 'ACTIVE' }, select: { employeeId: true }, }) const existingIds = new Set(existing.map((e: any) => e.employeeId)) const newIds = employeeIds.filter((id) => !existingIds.has(id)) if (newIds.length > 0) { await prisma.employeeBenefitEnrollment.createMany({ data: newIds.map((empId) => ({ orgId: req.user!.orgId, planId: plan.id, employeeId: empId, effectiveFrom: effectiveFrom || new Date().toISOString().slice(0, 7), })), }) } res.json({ success: true, data: { enrolled: newIds.length, skipped: existingIds.size } }) } catch (err) { next(err) } }) // 退福利 router.post('/enrollments/:enrollmentId/terminate', async (req: AuthRequest, res: Response, next: NextFunction) => { try { const { effectiveTo } = req.body as { effectiveTo: string } const enrollment = await prisma.employeeBenefitEnrollment.update({ where: { id: req.params.enrollmentId, orgId: req.user!.orgId }, data: { status: 'TERMINATED', effectiveTo: effectiveTo || new Date().toISOString().slice(0, 7) }, }) res.json({ success: true, data: enrollment }) } catch (err) { next(err) } }) // 员工福利汇总(按员工维度) router.get('/employee-summary', async (req: AuthRequest, res: Response, next: NextFunction) => { try { const enrollments = await prisma.employeeBenefitEnrollment.findMany({ where: { orgId: req.user!.orgId, status: 'ACTIVE' }, include: { employee: { select: { id: true, name: true, department: true } }, plan: { select: { id: true, name: true, category: true, amount: true, frequency: true } }, }, }) const summary: Record = {} for (const e of enrollments) { if (!summary[e.employeeId]) { summary[e.employeeId] = { employeeId: e.employeeId, name: e.employee.name, department: e.employee.department, benefits: [], totalMonthly: 0, } } const amount = e.amount ?? e.plan.amount summary[e.employeeId].benefits.push({ planId: e.planId, planName: e.plan.name, category: e.plan.category, categoryLabel: BENEFIT_CATEGORIES[e.plan.category] || e.plan.category, amount, }) if (e.plan.frequency === 'MONTHLY') { summary[e.employeeId].totalMonthly += amount } } res.json({ success: true, data: Object.values(summary) }) } catch (err) { next(err) } }) export default router