fix: 统一风险中心及全应用身份证号显示

后端:
- employee.routes.ts: all-lite 接口加上 idCardNumber 并解密
- special-status.routes.ts: 列表和详情查询加上 idCardNumber 并解密
- esign.routes.ts: 列表/pending/detail/remind 接口加上 idCardNumber 并解密
- risk.service.ts: getMonthlyCalendar 所有事件加上 employeeIdCardNumber
- termination.service.ts: batchTerminatePreview 加上 employeeIdCardNumber
- employee.routes.ts: preview-renew 加上 employeeIdCardNumber

前端:
- Roster.tsx: 批量续签/解聘预检结果加上身份证号
- SpecialStatus.tsx: 列表/下拉/删除确认加上身份证号
- Calendar.tsx: 日历事件姓名后显示身份证号
- ESign.tsx: 签署列表/详情/员工列表/提醒弹窗/下拉加上身份证号
- CommercialInsuranceTab.tsx: 参保选择列表加上身份证号
- OvertimeTab.tsx: 导入预览加上身份证号
This commit is contained in:
freedakgmail
2026-08-18 08:14:26 +08:00
parent 4d78eac5c2
commit eb91c2d8fb
11 changed files with 64 additions and 26 deletions
+20 -9
View File
@@ -20,6 +20,7 @@ import { authMiddleware, AuthRequest } from '../middleware/auth'
import { auditLog } from '../middleware/auditLog'
import { createEvidence, appendEvidence } from '../services/evidence.service'
import { renderTemplate, getTemplateById } from '../services/template.service'
import { decrypt } from '../lib/crypto'
const router = Router()
router.use(authMiddleware)
@@ -69,11 +70,15 @@ router.get('/', async (req: AuthRequest, res: Response, next: NextFunction) => {
...(scene && { scene }),
},
include: {
employee: { select: { id: true, name: true, department: true, phone: true } },
employee: { select: { id: true, name: true, department: true, phone: true, idCardNumber: true } },
},
orderBy: { createdAt: 'desc' },
})
res.json({ success: true, data: records })
const recordsWithIdCard = records.map((r: any) => ({
...r,
employee: r.employee ? { ...r.employee, idCardNumber: (() => { try { const v = r.employee.idCardNumber; return v ? (v.includes(':') ? decrypt(v) : v) : null } catch { return null } })() } : r.employee,
}))
res.json({ success: true, data: recordsWithIdCard })
} catch (err) { next(err) }
})
@@ -98,7 +103,7 @@ router.get('/pending', async (req: AuthRequest, res: Response, next: NextFunctio
status: { in: ['PENDING', 'SIGNING'] },
},
include: {
employee: { select: { id: true, name: true, department: true, phone: true, status: true } },
employee: { select: { id: true, name: true, department: true, phone: true, status: true, idCardNumber: true } },
},
orderBy: { createdAt: 'desc' },
})
@@ -111,7 +116,7 @@ router.get('/pending', async (req: AuthRequest, res: Response, next: NextFunctio
employee: { status: 'ACTIVE' },
},
include: {
employee: { select: { id: true, name: true, department: true, phone: true, status: true } },
employee: { select: { id: true, name: true, department: true, phone: true, status: true, idCardNumber: true } },
},
orderBy: { createdAt: 'desc' },
})
@@ -122,17 +127,19 @@ router.get('/pending', async (req: AuthRequest, res: Response, next: NextFunctio
name: string
department: string | null
phone: string | null
idCardNumber: string | null
pendingItems: any[]
}>()
// 辅助函数:添加员工到 map
const ensureEmployee = (emp: { id: string; name: string; department: string | null; phone: string | null }) => {
const ensureEmployee = (emp: { id: string; name: string; department: string | null; phone: string | null; idCardNumber?: string | null }) => {
if (!employeeMap.has(emp.id)) {
employeeMap.set(emp.id, {
employeeId: emp.id,
name: emp.name,
department: emp.department,
phone: emp.phone,
idCardNumber: (() => { try { const v = emp.idCardNumber; return v ? (v.includes(':') ? decrypt(v) : v) : null } catch { return null } })(),
pendingItems: [],
})
}
@@ -287,7 +294,7 @@ router.post('/remind', async (req: AuthRequest, res: Response, next: NextFunctio
}
const employee = await prisma.employee.findFirst({
where: { id: employeeId, orgId: req.user!.orgId, status: 'ACTIVE' },
select: { id: true, name: true, phone: true, orgId: true },
select: { id: true, name: true, phone: true, orgId: true, idCardNumber: true },
})
if (!employee) {
return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '员工不存在或已离职' } })
@@ -300,7 +307,7 @@ router.post('/remind', async (req: AuthRequest, res: Response, next: NextFunctio
)
const url = `${process.env.PORTAL_BASE_URL || ''}/portal/auto-login?token=${token}&redirect=/portal/esign`
await auditLog(req, 'REMIND', 'ESIGN', employeeId, { employeeName: employee.name })
res.json({ success: true, data: { url, token, employeeName: employee.name, phone: employee.phone } })
res.json({ success: true, data: { url, token, employeeName: employee.name, employeeIdCardNumber: (() => { try { const v = employee.idCardNumber; return v ? (v.includes(':') ? decrypt(v) : v) : null } catch { return null } })(), phone: employee.phone } })
} catch (err) { next(err) }
})
@@ -413,11 +420,15 @@ router.get('/:id', async (req: AuthRequest, res: Response, next: NextFunction) =
const record = await prisma.eSignRecord.findFirst({
where: { id: req.params.id, orgId: req.user!.orgId },
include: {
employee: { select: { id: true, name: true, department: true, phone: true } },
employee: { select: { id: true, name: true, department: true, phone: true, idCardNumber: true } },
},
})
if (!record) return res.status(404).json({ success: false, error: { message: '记录不存在' } })
res.json({ success: true, data: record })
const recordWithIdCard = {
...record,
employee: record.employee ? { ...record.employee, idCardNumber: (() => { try { const v = record.employee.idCardNumber; return v ? (v.includes(':') ? decrypt(v) : v) : null } catch { return null } })() } : record.employee,
}
res.json({ success: true, data: recordWithIdCard })
} catch (err) { next(err) }
})