diff --git a/backend/src/routes/commercial-insurance.routes.ts b/backend/src/routes/commercial-insurance.routes.ts index b3e1ed0..fd94d69 100644 --- a/backend/src/routes/commercial-insurance.routes.ts +++ b/backend/src/routes/commercial-insurance.routes.ts @@ -2,6 +2,7 @@ import { Router, Response, NextFunction } from 'express' import { z } from 'zod' import prisma from '../lib/prisma' import { authMiddleware, AuthRequest } from '../middleware/auth' +import { decrypt } from '../lib/crypto' const router = Router() router.use(authMiddleware) @@ -45,7 +46,7 @@ router.get('/plans/:planId/enrollments', async (req: AuthRequest, res: Response, employeeId: e.employeeId, name: e.employee.name, department: e.employee.department, - idCardMasked: e.employee.idCardNumber ? e.employee.idCardNumber.slice(0, 3) + '****' + e.employee.idCardNumber.slice(-4) : null, + idCardNumber: e.employee.idCardNumber ? (() => { try { return e.employee.idCardNumber.includes(':') ? decrypt(e.employee.idCardNumber) : e.employee.idCardNumber } catch { return null } })() : null, premium: e.premium, effectiveFrom: e.effectiveFrom, effectiveTo: e.effectiveTo, diff --git a/backend/src/routes/roster.routes.ts b/backend/src/routes/roster.routes.ts index 441779d..d61cc61 100644 --- a/backend/src/routes/roster.routes.ts +++ b/backend/src/routes/roster.routes.ts @@ -190,18 +190,6 @@ router.get('/', authMiddleware, async (req: AuthRequest, res, next) => { const isResigned = e.terminations.some((t) => t.status === 'COMPLETED' && t.terminationDate <= today) const isPreHire = !isResigned && e.hireDate > todayEnd const dynamicStatus = isResigned ? 'RESIGNED' : (isPreHire ? 'PRE_HIRE' : 'ACTIVE') - // 证件号码脱敏显示 - let idCardMasked: string | null = null - if (e.idCardNumber) { - try { - const idCard = decrypt(e.idCardNumber) - if (idCard.length >= 11) { - idCardMasked = idCard.slice(0, 3) + '****' + idCard.slice(-4) - } else { - idCardMasked = '****' - } - } catch {} - } return { id: e.id, name: e.name, @@ -217,7 +205,6 @@ router.get('/', authMiddleware, async (req: AuthRequest, res, next) => { hireDate: e.hireDate, gender: e.gender, phone: e.phone, - idCardMasked, idCardNumber: safeDecryptStr(e.idCardNumber), monthlySalary: safeDecrypt(e.monthlySalary), baseSalary: e.baseSalary ? safeDecrypt(e.baseSalary) : null, diff --git a/backend/src/routes/social.routes.ts b/backend/src/routes/social.routes.ts index dc70436..9974b6a 100644 --- a/backend/src/routes/social.routes.ts +++ b/backend/src/routes/social.routes.ts @@ -5,6 +5,14 @@ import { decrypt } from '../lib/crypto' import { z } from 'zod' import OpenAI from 'openai' +function decryptIdCard(encrypted: string | null): string | null { + if (!encrypted) return null + try { + if (!encrypted.includes(':')) return encrypted + return decrypt(encrypted) + } catch { return null } +} + const router = Router() router.use(authMiddleware) @@ -1305,6 +1313,7 @@ router.get('/monthly-changes', async (req: AuthRequest, res: Response, next: Nex recordId: r.id, employeeId: r.employeeId, name: r.employee.name, + idCardNumber: decryptIdCard(r.employee.idCardNumber), department: r.employee.department, city: r.city, base: r.base, @@ -1376,6 +1385,7 @@ router.get('/housing/monthly-changes', async (req: AuthRequest, res: Response, n recordId: r.id, employeeId: r.employeeId, name: r.employee.name, + idCardNumber: decryptIdCard(r.employee.idCardNumber), department: r.employee.department, city: r.city, base: r.base, @@ -1442,7 +1452,8 @@ router.get('/active-declaration', async (req: AuthRequest, res: Response, next: recordId: r.id, employeeId: r.employeeId, name: r.employee.name, - department: r.employee.department, + idCardNumber: decryptIdCard((r as any).employee.idCardNumber), + department: (r as any).employee.department, city: r.city, base: r.base, startMonth: r.startMonth, @@ -1505,7 +1516,8 @@ router.get('/housing/active-declaration', async (req: AuthRequest, res: Response recordId: r.id, employeeId: r.employeeId, name: r.employee.name, - department: r.employee.department, + idCardNumber: decryptIdCard((r as any).employee.idCardNumber), + department: (r as any).employee.department, city: r.city, base: r.base, startMonth: r.startMonth, diff --git a/frontend/src/pages/Roster.tsx b/frontend/src/pages/Roster.tsx index b41544c..00e0bbb 100644 --- a/frontend/src/pages/Roster.tsx +++ b/frontend/src/pages/Roster.tsx @@ -475,7 +475,7 @@ export default function Roster() { formData: { employeeId: id, employeeName: emp.name, - idCardNumber: emp.idCardMasked || '', + idCardNumber: emp.idCardNumber || '', position: emp.position || '', monthlyIncome: emp.monthlySalary ? `¥${emp.monthlySalary}` : '', purpose: '批量开具', @@ -564,7 +564,7 @@ export default function Roster() { const [showColSettings, setShowColSettings] = useState(false) const filtered = employees?.filter((e: any) => - !search || e.name.includes(search) || e.department.includes(search) || (e.idCardMasked && e.idCardMasked.includes(search)) + !search || e.name.includes(search) || e.department.includes(search) || (e.idCardNumber && e.idCardNumber.includes(search)) ) || [] // 通讯录视图数据 @@ -800,7 +800,7 @@ export default function Roster() { if (e.idCardNumber) { copyToClipboard(e.idCardNumber, '已复制证件号码') } - }}>{e.idCardMasked || '—'} + }}>{e.idCardNumber || '—'} {colVisible('department') && {e.department}} @@ -1213,7 +1213,7 @@ export default function Roster() { formData: { employeeId: certEmployee.id, employeeName: certEmployee.name, - idCardNumber: certEmployee.idCardMasked || '', + idCardNumber: certEmployee.idCardNumber || '', position: certEmployee.position || '', monthlyIncome: certEmployee.monthlySalary ? `¥${certEmployee.monthlySalary}` : '', purpose: certPurpose || '通用', diff --git a/frontend/src/pages/roster/EmployeeProfileShell.tsx b/frontend/src/pages/roster/EmployeeProfileShell.tsx index 734188c..0f70b52 100644 --- a/frontend/src/pages/roster/EmployeeProfileShell.tsx +++ b/frontend/src/pages/roster/EmployeeProfileShell.tsx @@ -18,7 +18,7 @@ interface EmployeeSummary { phone?: string email?: string city?: string - idCardMasked?: string + idCardNumber?: string probationInfo?: { isProbation: boolean isExpiring: boolean @@ -175,8 +175,8 @@ export default function EmployeeProfileShell({ {profile.city} )} - {profile.idCardMasked && ( - {profile.idCardMasked} + {profile.idCardNumber && ( + {profile.idCardNumber} )} diff --git a/frontend/src/pages/social-insurance/CommercialInsuranceTab.tsx b/frontend/src/pages/social-insurance/CommercialInsuranceTab.tsx index 242658c..51174fb 100644 --- a/frontend/src/pages/social-insurance/CommercialInsuranceTab.tsx +++ b/frontend/src/pages/social-insurance/CommercialInsuranceTab.tsx @@ -210,7 +210,7 @@ export default function CommercialInsuranceTab() { {e.name} {e.department} - {e.idCardMasked || '—'} + {e.idCardNumber || '—'} ¥{fmt(e.premium || 0)} {e.effectiveFrom || '—'} diff --git a/frontend/src/pages/social-insurance/MonthlyRows.tsx b/frontend/src/pages/social-insurance/MonthlyRows.tsx index 664f00f..cbb8af4 100644 --- a/frontend/src/pages/social-insurance/MonthlyRows.tsx +++ b/frontend/src/pages/social-insurance/MonthlyRows.tsx @@ -34,7 +34,12 @@ export function MonthlyRow({ item: i, type, onCorrected }: { item: any; type: 'a return ( <> setExpanded(!expanded)}> - {i.name} {d && {expanded ? '▾' : '▸'}} + +
+ {i.name} {d && {expanded ? '▾' : '▸'}} + {i.idCardNumber && {i.idCardNumber}} +
+ {i.department} {typeLabel} @@ -121,7 +126,12 @@ export function MonthlyHousingRow({ item: i, type, onCorrected }: { item: any; t return ( - {i.name} + +
+ {i.name} + {i.idCardNumber && {i.idCardNumber}} +
+ {i.department} {typeLabel}