feat(assets): refine compact inventory drilldowns and exact subtotal scopes
This commit is contained in:
@@ -2,8 +2,8 @@ import { Fragment, type Dispatch, type SetStateAction } from 'react';
|
||||
import { ArrowUpRight, ChevronRight } from 'lucide-react';
|
||||
import { InventoryStatusCounts } from './InventoryStatusCounts';
|
||||
import { InventoryModelTags } from './InventoryModelTags';
|
||||
import { inventoryBrandGroups, inventorySelection, type InventoryDisplayGroup } from './inventory-presentation';
|
||||
import type { InventoryFilters, VehicleModalSelection } from '../../model';
|
||||
import { inventoryBrandGroups, inventoryRegionRows, inventorySelection, inventorySubtotalSelection, inventoryTotal, type InventoryDisplayGroup } from './inventory-presentation';
|
||||
import { inventoryTypeLabel, type InventoryFilters, type VehicleModalSelection } from '../../model';
|
||||
import type { RegionalInventoryStats } from '../../types';
|
||||
|
||||
export interface InventoryListProps {
|
||||
@@ -23,13 +23,13 @@ export function InventoryQuantity({ quantity, label, onClick }: { quantity: numb
|
||||
}
|
||||
|
||||
export function selectInventoryRow(row: RegionalInventoryStats, select: InventoryListProps['select']) {
|
||||
select(inventorySelection(row, `库存统计 · ${row.city} · ${row.model}`));
|
||||
select(inventorySelection(row, `库存统计 · ${row.city} · ${row.model}`, { vehicleType: row.type }));
|
||||
}
|
||||
|
||||
export function selectInventoryGroup(group: InventoryDisplayGroup, { tab, filters, select }: Pick<InventoryListProps, 'tab' | 'filters' | 'select'>) {
|
||||
select(inventorySelection(filters, `库存统计 · ${group.name}`, tab === 'region'
|
||||
select(inventorySelection(tab === 'model' ? { ...filters, type: group.name } : filters, `库存统计 · ${group.name}`, tab === 'region'
|
||||
? { location: filters.city || group.name }
|
||||
: { vehicleType: group.name }));
|
||||
: {}));
|
||||
}
|
||||
|
||||
export function InventoryShare({ quantity, total }: { quantity: number; total: number }) {
|
||||
@@ -37,16 +37,26 @@ export function InventoryShare({ quantity, total }: { quantity: number; total: n
|
||||
return <div className="inventory-share"><span className="inventory-share-track" aria-hidden="true"><span style={{ width: `${percent}%` }} /></span><span>{percent.toFixed(1)}%</span></div>;
|
||||
}
|
||||
|
||||
function InventorySubtotal({ rows, label, select }: { rows: RegionalInventoryStats[]; label: string; select: InventoryListProps['select'] }) {
|
||||
return <div className={`inventory-subtotal${rows.length === 1 ? ' inventory-subtotal-inline' : ''}`} aria-label={`${label}合计 ${inventoryTotal(rows)} 台`}>
|
||||
<button className="inventory-subtotal-button" disabled={!inventoryTotal(rows)} aria-label={`${label}合计 ${inventoryTotal(rows)} 台,查看车辆明细`} onClick={() => select(inventorySubtotalSelection(rows, label))}>合计 <strong>{inventoryTotal(rows).toLocaleString()}</strong> 台<ArrowUpRight size={12} aria-hidden="true" /></button>
|
||||
<InventoryStatusCounts rows={rows} />
|
||||
</div>;
|
||||
}
|
||||
|
||||
function InventoryDetailRows({ rows, city, tab, total, select }: Pick<InventoryListProps, 'tab' | 'total' | 'select'> & { rows: RegionalInventoryStats[]; city?: string }) {
|
||||
const brands = inventoryBrandGroups(rows, tab === 'region' ? 'type' : 'model');
|
||||
return brands.map((brand, brandIndex) => brand.variants.map((variants, variantIndex) => variants.map((row, index) =>
|
||||
return brands.map((brand, brandIndex) => brand.variants.map((variants, variantIndex) =>
|
||||
(tab === 'model' ? inventoryRegionRows(variants) : variants.map(row => ({ row, regionSpan: 0 }))).map(({ row, regionSpan }, index) =>
|
||||
<tr className="inventory-detail-row" key={`${brandIndex}-${variantIndex}-${index}`}>
|
||||
{tab === 'region' && brandIndex === 0 && variantIndex === 0 && index === 0 && <th rowSpan={rows.length} scope="rowgroup" className="inventory-merged-cell inventory-city-cell">{city || '未分配'}</th>}
|
||||
{variantIndex === 0 && index === 0 && <td rowSpan={brand.rows.length} className="inventory-merged-cell">{brand.brand || '—'}</td>}
|
||||
{tab === 'region' && brandIndex === 0 && variantIndex === 0 && index === 0 && <th rowSpan={rows.length} scope="rowgroup" className="inventory-merged-cell inventory-city-cell">{city || '未分配'}<InventorySubtotal select={select} rows={rows} label={city || '未分配'} /></th>}
|
||||
{variantIndex === 0 && index === 0 && <td rowSpan={brand.rows.length} className="inventory-merged-cell">{brand.brand || '—'}<InventorySubtotal select={select} rows={brand.rows} label={brand.brand || '未分配品牌'} /></td>}
|
||||
{index === 0 && <td rowSpan={variants.length} className="inventory-merged-cell">
|
||||
{tab === 'region' ? <span className="inventory-tag inventory-tag-type">{row.type || '未分类'}</span> : <InventoryModelTags row={row} hideType />}
|
||||
{tab === 'region' ? <span className="inventory-tag inventory-tag-type">{inventoryTypeLabel(row.type) || '未分类'}</span> : <InventoryModelTags row={row} hideType />}
|
||||
<InventorySubtotal select={select} rows={variants} label={tab === 'region' ? inventoryTypeLabel(row.type) : row.model} />
|
||||
</td>}
|
||||
<td>{tab === 'region' ? <InventoryModelTags row={row} hideType /> : <><span className="inventory-place-region">{row.region}</span><span>{row.city}</span></>}</td>
|
||||
{tab === 'model' && regionSpan > 0 && <td rowSpan={regionSpan} className="inventory-merged-cell inventory-region-cell">{row.region || '未分配'}<InventorySubtotal select={select} rows={variants.filter(item => item.region === row.region)} label={row.region || '未分配'} /></td>}
|
||||
<td>{tab === 'region' ? <InventoryModelTags row={row} hideType /> : row.city || '未分配'}</td>
|
||||
<td className="inventory-number-column"><InventoryQuantity quantity={row.quantity} label={`${row.city} · ${row.brand} · ${row.model}`} onClick={() => selectInventoryRow(row, select)} /><InventoryStatusCounts rows={[row]} /></td>
|
||||
<td><InventoryShare quantity={row.quantity} total={total} /></td>
|
||||
</tr>
|
||||
@@ -62,14 +72,14 @@ export function InventoryDesktopTable(props: InventoryListProps) {
|
||||
{tab === 'region' && <th scope="col">区域 / 城市</th>}
|
||||
<th scope="col">品牌</th>
|
||||
{tab === 'region' && <th scope="col">车型</th>}
|
||||
<th scope="col">类别 / 颜色 / 归属方</th>
|
||||
{tab === 'model' && <th scope="col">区域 / 城市</th>}
|
||||
<th scope="col">类别</th>
|
||||
{tab === 'model' && <><th scope="col">区域</th><th scope="col">城市</th></>}
|
||||
<th scope="col" className="inventory-number-column">库存数量</th>
|
||||
<th scope="col" className="inventory-share-column">库存占比</th>
|
||||
</tr></thead>
|
||||
{groups.map(group => <Fragment key={group.name}><tbody>
|
||||
<tr className="inventory-group-row">
|
||||
<th scope="row" colSpan={tab === 'region' ? 4 : 3}>
|
||||
<tr className="inventory-group-row" data-expanded={expanded.has(group.name)}>
|
||||
<th scope="row" colSpan={4}>
|
||||
<div className="inventory-group-heading">
|
||||
<button className="inventory-expand" aria-expanded={expanded.has(group.name)} onClick={() => toggle(group.name)}>
|
||||
<ChevronRight size={16} aria-hidden="true" /><strong>{group.name || '未分配'}</strong><span>{group.sections.length} 个{tab === 'region' ? '城市' : '型号'}</span>
|
||||
|
||||
Reference in New Issue
Block a user