import { Router, Response, NextFunction } from 'express' import { authMiddleware, AuthRequest } from '../middleware/auth' import { requireAdmin } from '../middleware/rbac' import { z } from 'zod' import prisma from '../lib/prisma' import { createPolicy, getPolicies, getPolicyDetail, updatePolicy, advanceDemocracyStep, deletePolicy, } from '../services/policy.service' const router = Router() /** 获取制度列表 */ router.get('/', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => { try { const status = req.query.status as string | undefined const page = parseInt(req.query.page as string) || 1 const pageSize = Math.min(parseInt(req.query.pageSize as string) || 20, 200) const result = await getPolicies(req.user!.orgId, status, page, pageSize) res.json({ success: true, data: result }) } catch (err) { next(err) } }) /** 获取制度详情 */ router.get('/:id', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => { try { const policy = await getPolicyDetail(req.user!.orgId, req.params.id) res.json({ success: true, data: policy }) } catch (err) { next(err) } }) /** 创建制度 */ router.post('/', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => { try { const schema = z.object({ title: z.string().min(1), content: z.string().min(1), type: z.string().optional(), }) const data = schema.parse(req.body) const policy = await createPolicy(req.user!.orgId, req.user!.id, data) res.json({ success: true, data: { id: policy.id } }) } catch (err) { next(err) } }) /** 更新制度 */ router.put('/:id', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => { try { const schema = z.object({ title: z.string().optional(), content: z.string().optional(), type: z.string().optional(), }) const data = schema.parse(req.body) await updatePolicy(req.user!.orgId, req.params.id, data) res.json({ success: true }) } catch (err) { next(err) } }) /** 推进民主程序步骤 */ router.post('/:id/advance-step', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => { try { const schema = z.object({ step: z.number().int().min(1).max(4), note: z.string().optional() }) const { step, note } = schema.parse(req.body) await advanceDemocracyStep(req.user!.orgId, req.params.id, step, note) res.json({ success: true }) } catch (err) { next(err) } }) /** 删除制度 */ router.delete('/:id', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => { try { await deletePolicy(req.user!.orgId, req.params.id) res.json({ success: true }) } catch (err) { next(err) } }) /** 获取制度的阅读签收统计 */ router.get('/:id/read-stats', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => { try { const orgId = req.user!.orgId const policy = await prisma.policyDocument.findFirst({ where: { id: req.params.id, orgId }, select: { id: true, title: true } }) if (!policy) { return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '制度不存在' } }) } const [allEmployees, readRecords] = await Promise.all([ prisma.employee.findMany({ where: { orgId, status: 'ACTIVE' }, select: { id: true, name: true, department: true }, orderBy: { name: 'asc' } }), prisma.policyReadRecord.findMany({ where: { policyId: req.params.id, orgId }, include: { employee: { select: { id: true, name: true, department: true } } }, orderBy: { readAt: 'desc' }, }), ]) const readEmpIds = new Set(readRecords.map(r => r.employeeId)) const unreadEmployees = allEmployees.filter(e => !readEmpIds.has(e.id)) res.json({ success: true, data: { total: allEmployees.length, readCount: readRecords.length, unreadCount: unreadEmployees.length, records: readRecords.map(r => ({ employeeId: r.employeeId, employeeName: r.employee.name, department: r.employee.department, readAt: r.readAt.toISOString(), ip: r.ip, })), unreadEmployees: unreadEmployees.map(e => ({ employeeId: e.id, employeeName: e.name, department: e.department, })), }, }) } catch (err) { next(err) } }) /** 催办未签收员工 */ router.post('/:id/remind', authMiddleware, requireAdmin, async (req: AuthRequest, res: Response, next: NextFunction) => { try { const orgId = req.user!.orgId const policy = await prisma.policyDocument.findFirst({ where: { id: req.params.id, orgId }, select: { id: true, title: true } }) if (!policy) { return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '制度不存在' } }) } const { employeeIds } = req.body as { employeeIds?: string[] } const readRecords = await prisma.policyReadRecord.findMany({ where: { policyId: req.params.id, orgId }, select: { employeeId: true } }) const readEmpIds = new Set(readRecords.map(r => r.employeeId)) const targetEmployees = await prisma.employee.findMany({ where: { orgId, status: 'ACTIVE', id: employeeIds && employeeIds.length > 0 ? { in: employeeIds } : undefined, }, select: { id: true, name: true }, }) const unreadEmployees = targetEmployees.filter(e => !readEmpIds.has(e.id)) // 创建催办通知 for (const emp of unreadEmployees) { await prisma.notificationLog.create({ data: { orgId, employeeId: emp.id, type: 'POLICY_REMIND', title: `制度签收提醒:${policy.title}`, content: `您有一项制度「${policy.title}」尚未签收,请尽快完成阅读确认。`, channel: 'IN_APP', status: 'SENT', }, }).catch(() => {}) } res.json({ success: true, data: { reminded: unreadEmployees.length } }) } catch (err) { next(err) } }) export default router