feat(assets): add dimension analysis and authorized user previews
ci/woodpecker/push/woodpecker Pipeline was successful

Refactor asset drilldowns with combined dimension filters, parent summaries and progressive loading. Add the hidden /who read-only permission preview with scoped authorization, identity mapping and audit logging. Refine inventory counts and AI问数 presentation.
This commit is contained in:
shishengliang
2026-09-28 12:29:51 +08:00
parent 6de77adb47
commit f1b3f8d3da
69 changed files with 3871 additions and 536 deletions
@@ -12,6 +12,19 @@ import { fetchVehicleList } from '../../api';
const filters = { region: '华东', city: '上海', brand: '品牌甲', type: '18T', model: '批次一' };
test('abnormal inventory drill preserves exact row keys and intersects the abnormal category and company', () => {
const rows = [{ ...filters, batch: '', quantity: 10, abnormal: 1 }];
const selection = inventorySubtotalSelection(rows, rows[0].model, 'Abnormal');
const request = buildVehicleModalRequest(selection, '公司甲');
assert.equal(request.kind, 'vehicles');
if (request.kind !== 'vehicles') throw new Error('wrong endpoint');
assert.deepEqual(request.params.inventoryKeys, rows.map(inventoryKey));
assert.equal(request.params.category, 'Abnormal');
assert.equal(request.params.subject, '公司甲');
assert.match(selection.scopeLabel!, /异动 1 台$/);
assert.ok(selection.scopeLabel!.includes('批次一'));
});
test('mobile region navigation shows only cities then types, preserving totals and exact leaf scope', () => {
const rows = [
{ ...filters, batch: '', quantity: 9 },
@@ -115,10 +128,10 @@ test('mobile pages cover every record once and clamp after a filter reduces the
test('inventory status hints show nonzero subset counts and hide zeros', () => {
const row = { ...filters, batch: '', quantity: 9, pending: 2, abnormal: 1 };
const html = renderToStaticMarkup(createElement(InventoryStatusCounts, { rows: [row] }));
assert.match(html, /其中待交车 <strong>2<\/strong> 台/);
assert.match(html, /其中异动 <strong>1<\/strong> 台/);
assert.equal(renderToStaticMarkup(createElement(InventoryStatusCounts, { rows: [{ ...row, pending: 0, abnormal: 0 }] })), '');
const html = renderToStaticMarkup(createElement(InventoryStatusCounts, { onSelect: () => {}, rows: [row] }));
assert.match(html, /待交车 <strong>2<\/strong> 台/);
assert.match(html, /异动 <strong>1<\/strong> 台/);
assert.equal(renderToStaticMarkup(createElement(InventoryStatusCounts, { onSelect: () => {}, rows: [{ ...row, pending: 0, abnormal: 0 }] })), '');
});
test('filtered inventory totals retain all filters in the vehicle request', () => {