diff --git a/backend/src/routes/leave.routes.ts b/backend/src/routes/leave.routes.ts index 32ac011..734befe 100644 --- a/backend/src/routes/leave.routes.ts +++ b/backend/src/routes/leave.routes.ts @@ -2,9 +2,18 @@ import { Router, Response, NextFunction } from 'express' import { authMiddleware, AuthRequest } from '../middleware/auth' import prisma from '../lib/prisma' import { parsePagination } from '../lib/pagination' +import { decrypt } from '../lib/crypto' const router = Router() +function safeDecryptStr(encrypted: string | null): string | null { + if (!encrypted) return null + try { + if (!encrypted.includes(':')) return encrypted + return decrypt(encrypted) + } catch { return null } +} + // 休假申请列表 router.get('/', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => { try { @@ -21,14 +30,18 @@ router.get('/', authMiddleware, async (req: AuthRequest, res: Response, next: Ne const list = await prisma.leaveRequest.findMany({ where, include: { - employee: { select: { id: true, name: true, department: true, position: true } }, + employee: { select: { id: true, name: true, department: true, position: true, idCardNumber: true } }, }, orderBy: { createdAt: 'desc' }, skip: (page - 1) * pageSize, take: pageSize, }) - res.json({ success: true, data: { list, total, page, pageSize } }) + const data = list.map((r: any) => ({ + ...r, + employee: r.employee ? { ...r.employee, idCardNumber: safeDecryptStr(r.employee.idCardNumber) } : r.employee, + })) + res.json({ success: true, data: { list: data, total, page, pageSize } }) } catch (err) { next(err) } diff --git a/backend/src/routes/payroll.routes.ts b/backend/src/routes/payroll.routes.ts index e38ed35..bcdaf43 100644 --- a/backend/src/routes/payroll.routes.ts +++ b/backend/src/routes/payroll.routes.ts @@ -8,6 +8,14 @@ import { isInProbation } from '../services/contract.service' const router = Router() router.use(authMiddleware) +function safeDecryptStr(encrypted: string | null): string | null { + if (!encrypted) return null + try { + if (!encrypted.includes(':')) return encrypted + return decrypt(encrypted) + } catch { return null } +} + // ========== 加班费记录 ========== const overtimeSchema = z.object({ @@ -29,10 +37,14 @@ router.get('/overtime', async (req: AuthRequest, res: Response, next: NextFuncti ...(employeeId ? { employeeId: String(employeeId) } : {}), ...(month ? { month: String(month) } : {}), }, - include: { employee: { select: { id: true, name: true, department: true } } }, + include: { employee: { select: { id: true, name: true, department: true, idCardNumber: true } } }, orderBy: { createdAt: 'desc' }, }) - res.json({ success: true, data: records }) + const data = records.map((r: any) => ({ + ...r, + employee: r.employee ? { ...r.employee, idCardNumber: safeDecryptStr(r.employee.idCardNumber) } : r.employee, + })) + res.json({ success: true, data }) } catch (err) { next(err) } @@ -236,10 +248,14 @@ router.get('/payslip', async (req: AuthRequest, res: Response, next: NextFunctio ...(month ? { month: String(month) } : {}), ...(employeeId ? { employeeId: String(employeeId) } : {}), }, - include: { employee: { select: { id: true, name: true, department: true } } }, + include: { employee: { select: { id: true, name: true, department: true, idCardNumber: true } } }, orderBy: [{ month: 'desc' }, { employee: { name: 'asc' } }], }) - res.json({ success: true, data: payslips }) + const data = payslips.map((p: any) => ({ + ...p, + employee: p.employee ? { ...p.employee, idCardNumber: safeDecryptStr(p.employee.idCardNumber) } : p.employee, + })) + res.json({ success: true, data }) } catch (err) { next(err) } diff --git a/backend/src/routes/payroll2.routes.ts b/backend/src/routes/payroll2.routes.ts index 00c8817..d4a12bf 100644 --- a/backend/src/routes/payroll2.routes.ts +++ b/backend/src/routes/payroll2.routes.ts @@ -13,6 +13,14 @@ import { import { isInProbation } from '../services/contract.service' import { getBonusByMonthAndEmployeeIds } from '../services/commission-bonus.service' +function safeDecryptStr(encrypted: string | null): string | null { + if (!encrypted) return null + try { + if (!encrypted.includes(':')) return encrypted + return decrypt(encrypted) + } catch { return null } +} + /** * 查询上月递延扣款数据(上月已归档批次中该员工的递延金额) * 用于本月创建批次时补扣上月未扣完的社保/公积金/最低工资补齐 @@ -209,18 +217,25 @@ router.get('/batches', async (req: AuthRequest, res: Response, next: NextFunctio // 获取批次详情 router.get('/batches/:id', async (req: AuthRequest, res: Response, next: NextFunction) => { try { - const batch = await prisma.payrollBatch.findFirst({ + const rawBatch = await prisma.payrollBatch.findFirst({ where: { id: req.params.id, orgId: req.user!.orgId }, include: { entries: { include: { - employee: { select: { id: true, name: true, department: true, status: true, bankAccount: true, bankName: true } }, + employee: { select: { id: true, name: true, department: true, status: true, bankAccount: true, bankName: true, idCardNumber: true } }, }, orderBy: { employee: { name: 'asc' } }, }, }, }) - if (!batch) return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '批次不存在' } }) + if (!rawBatch) return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '批次不存在' } }) + const batch = { + ...rawBatch, + entries: rawBatch.entries.map((e: any) => ({ + ...e, + employee: e.employee ? { ...e.employee, idCardNumber: safeDecryptStr(e.employee.idCardNumber) } : e.employee, + })), + } res.json({ success: true, data: batch }) } catch (err) { next(err) diff --git a/backend/src/routes/roster.routes.ts b/backend/src/routes/roster.routes.ts index d61cc61..8792a21 100644 --- a/backend/src/routes/roster.routes.ts +++ b/backend/src/routes/roster.routes.ts @@ -850,16 +850,20 @@ router.get('/training/list', authMiddleware, async (req: AuthRequest, res, next) }) where.employeeId = { in: employees.map(e => e.id) } } - const [records, total] = await Promise.all([ + const [rawRecords, total] = await Promise.all([ prisma.trainingRecord.findMany({ where, - include: { employee: { select: { id: true, name: true, department: true } } }, + include: { employee: { select: { id: true, name: true, department: true, idCardNumber: true } } }, orderBy: { trainingDate: 'desc' }, skip: (page - 1) * pageSize, take: pageSize, }), prisma.trainingRecord.count({ where }), ]) + const records = rawRecords.map((r: any) => ({ + ...r, + employee: r.employee ? { ...r.employee, idCardNumber: safeDecryptStr(r.employee.idCardNumber) } : r.employee, + })) res.json({ success: true, data: { records, total, page, pageSize } }) } catch (err) { next(err) } }) @@ -908,16 +912,20 @@ router.get('/performance/list', authMiddleware, async (req: AuthRequest, res, ne }) where.employeeId = { in: employees.map(e => e.id) } } - const [records, total] = await Promise.all([ + const [rawRecords, total] = await Promise.all([ prisma.performanceRecord.findMany({ where, - include: { employee: { select: { id: true, name: true, department: true } } }, + include: { employee: { select: { id: true, name: true, department: true, idCardNumber: true } } }, orderBy: { period: 'desc' }, skip: (page - 1) * pageSize, take: pageSize, }), prisma.performanceRecord.count({ where }), ]) + const records = rawRecords.map((r: any) => ({ + ...r, + employee: r.employee ? { ...r.employee, idCardNumber: safeDecryptStr(r.employee.idCardNumber) } : r.employee, + })) res.json({ success: true, data: { records, total, page, pageSize } }) } catch (err) { next(err) } }) @@ -937,16 +945,20 @@ router.get('/disciplinary/list', authMiddleware, async (req: AuthRequest, res, n }) where.employeeId = { in: employees.map(e => e.id) } } - const [records, total] = await Promise.all([ + const [rawRecords, total] = await Promise.all([ prisma.disciplinaryRecord.findMany({ where, - include: { employee: { select: { id: true, name: true, department: true } } }, + include: { employee: { select: { id: true, name: true, department: true, idCardNumber: true } } }, orderBy: { violationDate: 'desc' }, skip: (page - 1) * pageSize, take: pageSize, }), prisma.disciplinaryRecord.count({ where }), ]) + const records = rawRecords.map((r: any) => ({ + ...r, + employee: r.employee ? { ...r.employee, idCardNumber: safeDecryptStr(r.employee.idCardNumber) } : r.employee, + })) res.json({ success: true, data: { records, total, page, pageSize } }) } catch (err) { next(err) } }) diff --git a/backend/src/routes/social.routes.ts b/backend/src/routes/social.routes.ts index 9974b6a..d3e496f 100644 --- a/backend/src/routes/social.routes.ts +++ b/backend/src/routes/social.routes.ts @@ -1744,10 +1744,14 @@ router.get('/special-deduction/batch', async (req: AuthRequest, res: Response, n try { const { month } = req.query if (!month) return res.status(400).json({ success: false, message: '缺少 month' }) - const records = await prisma.specialDeductionRecord.findMany({ + const rawRecords = await prisma.specialDeductionRecord.findMany({ where: { orgId: req.user!.orgId, month: month as string }, - include: { employee: { select: { name: true, department: true } } }, + include: { employee: { select: { name: true, department: true, idCardNumber: true } } }, }) + const records = rawRecords.map((r: any) => ({ + ...r, + employee: r.employee ? { ...r.employee, idCardNumber: decryptIdCard(r.employee.idCardNumber) } : r.employee, + })) res.json({ success: true, data: records }) } catch (err) { next(err) diff --git a/frontend/src/pages/LeaveApproval.tsx b/frontend/src/pages/LeaveApproval.tsx index 9f4e88b..4cf8612 100644 --- a/frontend/src/pages/LeaveApproval.tsx +++ b/frontend/src/pages/LeaveApproval.tsx @@ -167,8 +167,11 @@ export default function LeaveApproval() { return ( -
{item.employee?.name}
-
{item.employee?.department}
+
+ {item.employee?.name} + {item.employee?.idCardNumber && {item.employee.idCardNumber}} + {item.employee?.department} +
{LEAVE_TYPE_MAP[item.leaveType] || item.leaveType} diff --git a/frontend/src/pages/money/BatchTab.tsx b/frontend/src/pages/money/BatchTab.tsx index 7f424e2..98f34a4 100644 --- a/frontend/src/pages/money/BatchTab.tsx +++ b/frontend/src/pages/money/BatchTab.tsx @@ -1194,11 +1194,14 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void {batch.entries.slice((page - 1) * pageSize, page * pageSize).map((entry: any) => ( -
{entry.employee.name}
-
{entry.employee.department}
- {entry.employee.status === 'RESIGNED' && ( - 已离职 - )} +
+
{entry.employee.name}
+ {entry.employee.idCardNumber && {entry.employee.idCardNumber}} +
{entry.employee.department}
+ {entry.employee.status === 'RESIGNED' && ( + 已离职 + )} +
{renderCell(entry, 'baseSalary')} {renderCell(entry, 'overtimePay')} diff --git a/frontend/src/pages/money/OvertimeTab.tsx b/frontend/src/pages/money/OvertimeTab.tsx index cb6c617..f6d5658 100644 --- a/frontend/src/pages/money/OvertimeTab.tsx +++ b/frontend/src/pages/money/OvertimeTab.tsx @@ -425,7 +425,12 @@ export function OvertimeCalculator() { {overtimeRecords.map((r: any) => ( - {r.employee?.name} + +
+ {r.employee?.name} + {r.employee?.idCardNumber && {r.employee.idCardNumber}} +
+ {r.employee?.department} {editingId === r.id ? ( <> diff --git a/frontend/src/pages/money/PayslipTab.tsx b/frontend/src/pages/money/PayslipTab.tsx index f2b061e..a40e22f 100644 --- a/frontend/src/pages/money/PayslipTab.tsx +++ b/frontend/src/pages/money/PayslipTab.tsx @@ -194,7 +194,12 @@ export function PayslipManager({ filterEmployeeId }: { filterEmployeeId?: string {payslips.slice((page - 1) * pageSize, page * pageSize).map((p: any) => ( - {p.employee?.name} + +
+ {p.employee?.name} + {p.employee?.idCardNumber && {p.employee.idCardNumber}} +
+ {p.employee?.department} ¥{fmt(p.baseSalary)} ¥{fmt(p.overtimePay)} diff --git a/frontend/src/pages/roster/DisciplinaryRecords.tsx b/frontend/src/pages/roster/DisciplinaryRecords.tsx index 8299da3..68cbb54 100644 --- a/frontend/src/pages/roster/DisciplinaryRecords.tsx +++ b/frontend/src/pages/roster/DisciplinaryRecords.tsx @@ -121,7 +121,10 @@ export default function DisciplinaryRecords() { ) : records.map((r: any) => ( - {r.employee?.name} +
+ {r.employee?.name} + {r.employee?.idCardNumber && {r.employee.idCardNumber}} +
{r.employee?.department || '-'} {fmtDate(r.violationDate)} diff --git a/frontend/src/pages/roster/PerformanceRecords.tsx b/frontend/src/pages/roster/PerformanceRecords.tsx index acaf1bc..f0df5e9 100644 --- a/frontend/src/pages/roster/PerformanceRecords.tsx +++ b/frontend/src/pages/roster/PerformanceRecords.tsx @@ -124,7 +124,10 @@ export default function PerformanceRecords() { ) : records.map((r: any) => ( - {r.employee?.name} +
+ {r.employee?.name} + {r.employee?.idCardNumber && {r.employee.idCardNumber}} +
{r.employee?.department || '-'} {r.period} diff --git a/frontend/src/pages/roster/TrainingRecords.tsx b/frontend/src/pages/roster/TrainingRecords.tsx index d9af5a1..098d274 100644 --- a/frontend/src/pages/roster/TrainingRecords.tsx +++ b/frontend/src/pages/roster/TrainingRecords.tsx @@ -156,7 +156,10 @@ export default function TrainingRecords() { ) : records.map((r: any) => ( - {r.employee?.name} +
+ {r.employee?.name} + {r.employee?.idCardNumber && {r.employee.idCardNumber}} +
{r.employee?.department || '-'} {fmtDate(r.trainingDate)} diff --git a/frontend/src/pages/social-insurance/SpecialDeductionTab.tsx b/frontend/src/pages/social-insurance/SpecialDeductionTab.tsx index 610ce3e..acc7456 100644 --- a/frontend/src/pages/social-insurance/SpecialDeductionTab.tsx +++ b/frontend/src/pages/social-insurance/SpecialDeductionTab.tsx @@ -172,7 +172,12 @@ export default function SpecialDeductionTab({ month, setMonth }: { month: string {editing === r.employeeId ? ( <> - {r.employee?.name} + +
+ {r.employee?.name} + {r.employee?.idCardNumber && {r.employee.idCardNumber}} +
+ {r.employee?.department} setEditForm({ ...editForm, children: Number(e.target.value) })} /> setEditForm({ ...editForm, elderly: Number(e.target.value) })} /> @@ -190,7 +195,12 @@ export default function SpecialDeductionTab({ month, setMonth }: { month: string ) : ( <> - {r.employee?.name} + +
+ {r.employee?.name} + {r.employee?.idCardNumber && {r.employee.idCardNumber}} +
+ {r.employee?.department} {r.children > 0 ? `¥${fmt(r.children)}` : '-'} {r.elderly > 0 ? `¥${fmt(r.elderly)}` : '-'}