fix(assets): expose full inventory for scoped users and stabilize previews
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
shishengliang
2026-09-28 13:16:12 +08:00
parent f1b3f8d3da
commit 48cf429468
17 changed files with 191 additions and 57 deletions
+20 -10
View File
@@ -9,7 +9,7 @@ import type {
BatchGroup,
InventoryTypeSummary,
} from '../types.js';
import { filterByPermission, maskCustomerNames, maskCustomerName } from '../auth/permissions.js';
import { filterAssetVehiclesByPermission, filterByPermission, maskCustomerNames, maskCustomerName } from '../auth/permissions.js';
import type { AuthUser } from '../auth/types.js';
import type { Context } from 'hono';
import {
@@ -46,12 +46,12 @@ import {
export { mapRegion } from './vehicles/model.js';
const app = new Hono();
const app = new Hono<{ Variables: { user: AuthUser } }>();
async function getVehiclesForUser(c: Context): Promise<Vehicle[]> {
async function getVehiclesForUser(c: Context, includePublicInventory = true): Promise<Vehicle[]> {
const all = await vehicleRepository.getVehicles();
const user = ((c as any).get?.('user') || (c as any).var?.user) as AuthUser | undefined;
let list = user ? filterByPermission(all, user) : all;
let list = user ? (includePublicInventory ? filterAssetVehiclesByPermission(all, user) : filterByPermission(all, user)) : all;
list = applySubjectFilter(c, list);
return maskCustomerNames(list);
}
@@ -71,7 +71,8 @@ function applySubjectFilter(c: Context, vehicles: Vehicle[]): Vehicle[] {
// GET /api/vehicles/summary
app.get('/summary', async (c) => {
const [vehicles, weeklyIds] = await Promise.all([getVehiclesForUser(c), vehicleRepository.getWeeklyTruckIds()]);
const vehicleIds = new Set(vehicles.map(v => String(v.id)));
const user = c.get('user') as AuthUser | undefined;
const vehicleIds = new Set((user ? filterByPermission(vehicles, user) : vehicles).map(v => String(v.id)));
const summary: SummaryData = {
totalAssets: vehicles.length,
operating: {
@@ -98,7 +99,15 @@ app.get('/summary', async (c) => {
// GET /api/vehicles/by-type
app.get('/by-type', async (c) => {
const [vehicles, weeklyIds] = await Promise.all([getVehiclesForUser(c), vehicleRepository.getWeeklyTruckIds()]);
const [vehicles, allWeeklyIds] = await Promise.all([getVehiclesForUser(c), vehicleRepository.getWeeklyTruckIds()]);
const user = c.get('user') as AuthUser | undefined;
const historyIds = new Set((user ? filterByPermission(vehicles, user) : vehicles).map(v => String(v.id)));
const weeklyIds = {
...allWeeklyIds,
delivered: new Set([...allWeeklyIds.delivered].filter(id => historyIds.has(id))),
returned: new Set([...allWeeklyIds.returned].filter(id => historyIds.has(id))),
replaced: new Set([...allWeeklyIds.replaced].filter(id => historyIds.has(id))),
};
const result: TypeSummary[] = SUMMARY_TYPE_FILTERS.map((t) => {
const typeVehicles = vehicles.filter(t.filter);
@@ -587,8 +596,9 @@ app.get('/weekly-detail', async (c) => {
const hasModelFilter = model && model !== 'All';
const hasBatchFilter = batch && batch !== 'All';
const hasLocationFilter = location && location !== 'All';
if (hasModelFilter || hasBatchFilter || hasLocationFilter || getSubjectParam(c)) {
const vehicles = await getVehiclesForUser(c);
{
// Public current inventory does not grant access to historical delivery/return events.
const vehicles = await getVehiclesForUser(c, type === 'pending');
let pool2 = vehicles;
if (hasModelFilter) pool2 = pool2.filter((v) => v.model === model);
if (hasBatchFilter) pool2 = pool2.filter((v) => (v.contractNo || '未知') === batch);
@@ -605,7 +615,7 @@ app.get('/weekly-detail', async (c) => {
// 资产流转日报:按运维签章时间统计业务车次;交车包含关联替换单的记录,替换作为其中的子项,同车多笔业务分别累计。
app.get('/flow-stats', async (c) => {
const { start, end } = normalizeDateRange(c.req.query('start'), c.req.query('end'));
const allowedVehicles = await getVehiclesForUser(c);
const allowedVehicles = await getVehiclesForUser(c, false);
const allowedTruckIds = new Set(allowedVehicles.map((v) => String(v.id)));
const rows = await vehicleRepository.getFlowDetailRows(start, end);
@@ -654,7 +664,7 @@ app.get('/flow-stats', async (c) => {
app.get('/subjects', async (c) => {
const all = await vehicleRepository.getVehicles();
const user = ((c as any).get?.('user') || (c as any).var?.user) as AuthUser | undefined;
const visible = user ? filterByPermission(all, user) : all;
const visible = user ? filterAssetVehiclesByPermission(all, user) : all;
const map = new Map<string, { total: number; inventory: number; operating: number }>();
for (const v of visible) {