diff --git a/src/server/auth/permissions.ts b/src/server/auth/permissions.ts index dc14642..76120e7 100644 --- a/src/server/auth/permissions.ts +++ b/src/server/auth/permissions.ts @@ -1,5 +1,26 @@ import type { AuthUser } from './types.js'; +/** 客户名称脱敏 */ +export function maskCustomerName(name: string | null): string | null { + if (!name) return name; + const len = name.length; + if (len <= 1) return '*'; + if (len <= 3) return name[0] + '***'; + if (len <= 6) return name.slice(0, 2) + '***' + name.slice(-1); + return name.slice(0, 4) + '***' + name.slice(-2); +} + +/** 对数据列表中的客户名称进行脱敏 */ +export function maskCustomerNames(items: T[]): T[] { + return items.map(v => { + const obj = v as any; + const copy = { ...obj }; + if ('customer' in copy && copy.customer) copy.customer = maskCustomerName(copy.customer); + if ('customerName' in copy && copy.customerName) copy.customerName = maskCustomerName(copy.customerName); + return copy as T; + }); +} + /** * 通用权限过滤函数 * 适配 CachedVehicle(department, manager, managerId)和 Vehicle(departmentName, customerManager, managerId) diff --git a/src/server/routes/mileage/monitoring.ts b/src/server/routes/mileage/monitoring.ts index f173b08..08c4ea1 100644 --- a/src/server/routes/mileage/monitoring.ts +++ b/src/server/routes/mileage/monitoring.ts @@ -1,6 +1,6 @@ import { Hono } from 'hono'; import { getCache, queryDateMileage, buildDateFilters } from './cache.js'; -import { filterByPermission } from '../../auth/permissions.js'; +import { filterByPermission, maskCustomerNames } from '../../auth/permissions.js'; import type { AuthUser } from '../../auth/types.js'; import type { CachedVehicle, MonitoringFilters, MonitoringResponse } from './types.js'; @@ -115,7 +115,7 @@ app.get('/', async (c) => { const total = filtered.length; return c.json({ - vehicles: paged, + vehicles: maskCustomerNames(paged), stats, filters, total, diff --git a/src/server/routes/mileage/targets.ts b/src/server/routes/mileage/targets.ts index 7301e32..f6bb3b3 100644 --- a/src/server/routes/mileage/targets.ts +++ b/src/server/routes/mileage/targets.ts @@ -3,7 +3,7 @@ import pool from '../../db.js'; import mileagePool from '../../mileage-db.js'; import { getCache } from './cache.js'; import { fetchVehicleInfoByPlates } from './vehicle-info.js'; -import { filterByPermission } from '../../auth/permissions.js'; +import { filterByPermission, maskCustomerNames } from '../../auth/permissions.js'; const app = new Hono(); @@ -173,7 +173,7 @@ app.get('/:id/vehicles', async (c) => { const user = (c as any).get('user') as import('../../auth/types.js').AuthUser | undefined; const filtered = user ? filterByPermission(result, user) : result; - return c.json(filtered); + return c.json(maskCustomerNames(filtered)); } catch (e: unknown) { console.error('target vehicles error:', e); return c.json([], 500); diff --git a/src/server/routes/vehicles.ts b/src/server/routes/vehicles.ts index 30d02d9..56d8ca5 100644 --- a/src/server/routes/vehicles.ts +++ b/src/server/routes/vehicles.ts @@ -10,7 +10,7 @@ import type { BatchGroup, InventoryTypeSummary, } from '../types.js'; -import { filterByPermission } from '../auth/permissions.js'; +import { filterByPermission, maskCustomerNames, maskCustomerName } from '../auth/permissions.js'; import type { AuthUser } from '../auth/types.js'; import type { Context } from 'hono'; @@ -312,15 +312,12 @@ async function getVehicles(): Promise { async function getVehiclesForUser(c: Context): Promise { const all = await getVehicles(); - // Hono 子路由 context 可能丢失变量,尝试多种方式获取 const user = ((c as any).get?.('user') || (c as any).var?.user) as AuthUser | undefined; if (user) { const filtered = filterByPermission(all, user); - console.log(`[vehicles] permission: ${user.permissionLevel}, user: ${user.userName}, before: ${all.length}, after: ${filtered.length}`); - return filtered; + return maskCustomerNames(filtered); } - console.log('[vehicles] WARNING: no user in context, returning all'); - return all; + return maskCustomerNames(all); } function getRegionCounts(vehicles: Vehicle[], regions: readonly string[]): Record { @@ -1009,7 +1006,8 @@ app.get('/weekly-detail', async (c) => { return c.json([]); } const [rows] = await pool.query(sql); - return c.json(rows); + const masked = (rows as any[]).map(r => ({ ...r, customer_name: maskCustomerName(r.customer_name) })); + return c.json(masked); }); // GET /api/vehicles/refresh — force cache refresh