refactor(stage5): 合并重复实现,移除失效的演示能力

Excel 导出(原先 4 份各自拼装 workbook)
- 新增 src/shared/xlsx.ts 作为唯一实现:文件名统一 .xlsx、sheet 名截断到 31 字符,
  对外提供 buildAoaSheet / buildJsonSheet / writeWorkbook / exportAoaSheet / exportJsonSheet。
  只收敛"组装与写出"这一层,各调用方仍自行决定列宽、冻结与数字格式,导出样式不变。
- 迁移 assets(内联 json_to_sheet + writeFile)、mileage/xlsx-export、
  hydrogen 的两份 helper(prototype-download.ts 与 download-xls.js,均已删除)。

高德地图(原先 2 份近乎逐行复制)
- 新增 src/shared/amap.ts:SDK 版本、插件列表、安全码注入、底图参数、
  控件位置与热力图色带只在此处定义;两个画布只保留各自的半径/透明度。
- 图例渐变条原先把同一组色值又写了一遍,改为复用 shared 的常量,图例与地图不会漂移。

数值格式化
- 两个下钻视图各自复制了同样的 formatNumber/format(共 42 处调用),
  统一到 hydrogen/model/display-format.ts 的 formatFixed;默认路径与既有行为逐字一致。
- 原 display-format.ts 里的 finiteNumber/formatNumber/formatScaled 无任何生产调用方,
  只被自己的测试引用;改为 formatFixed + blankForMissing 显式选项,
  既保留了"真零 vs 不可用"的区分能力,也不再留无人使用的导出。测试同步重写。

失效的演示能力
- Blur / DemoModeProvider 恒为 enabled=false,等于永久 no-op:
  移除 13 个文件里 50 处 <Blur> 包裹(渲染结果不变)、删除 components/Blur.tsx
  与 Shell 中的 Provider,调用方直接渲染原表达式。

未做(刻意)
- src/lib/cn.ts 不引入 tailwind-merge:全仓只有 2 处调用,不值得新增传递依赖。已在文档说明。

架构守护新增 2 条:只有 shared/amap.ts 可加载高德 SDK;
modules/** 不得再出现 book_new / book_append_sheet / writeFile(。

lint / test(137) / build 全绿,可达性仍为 0 未引用文件。
This commit is contained in:
dsh-agent
2026-09-11 10:28:32 +08:00
parent 5d14a28b0f
commit 507bc90ed2
33 changed files with 334 additions and 318 deletions
@@ -21,7 +21,6 @@ import {
XAxis,
YAxis,
} from 'recharts';
import Blur from '../../../components/Blur';
import type { MileageReportGroup } from '../api';
import {
filterAndSortVehicles,
@@ -167,7 +166,7 @@ export default function VehicleTable({ group }: { group: MileageReportGroup }) {
<div className="min-w-0">
<div className="flex items-center gap-2 text-xs font-black text-slate-900">
<BarChart3 size={15} className="text-blue-600" />
<Blur>{trendVehicle.plate}</Blur>
{trendVehicle.plate}
<span className="font-bold text-slate-400">近7日里程</span>
</div>
<div className="mt-2 flex flex-wrap gap-x-5 gap-y-1 text-[10px] font-bold text-slate-500">
@@ -249,12 +248,12 @@ export default function VehicleTable({ group }: { group: MileageReportGroup }) {
className={`grid cursor-pointer grid-cols-[112px_88px_minmax(140px,1fr)_82px_90px_80px_28px] items-center gap-3 px-3 py-2.5 text-[11px] font-bold outline-none transition-colors hover:bg-slate-50 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-blue-500 md:grid-cols-[110px_72px_100px_minmax(160px,1fr)_90px_100px_88px_32px] ${selected ? 'bg-blue-50/60' : ''}`}
>
<span className={`sticky left-3 z-10 -my-2.5 flex self-stretch flex-col justify-center font-mono font-black text-slate-800 shadow-[8px_0_12px_-12px_rgba(15,23,42,0.45)] md:flex-row md:items-center md:shadow-none ${frozenCellClass}`}>
<Blur>{vehicle.plate}</Blur>
{vehicle.plate}
<span className={`mt-0.5 font-sans text-[9px] md:hidden ${vehicle.mileageBand === 'INVENTORY' ? 'text-amber-600' : 'text-emerald-600'}`}>{vehicle.status}</span>
</span>
<span className={`sticky left-[110px] z-10 -my-2.5 hidden self-stretch items-center shadow-[8px_0_12px_-12px_rgba(15,23,42,0.45)] md:flex ${frozenCellClass} ${vehicle.mileageBand === 'INVENTORY' ? 'text-amber-600' : 'text-emerald-600'}`}>{vehicle.status}</span>
<span className="truncate text-slate-500">{vehicle.department || vehicle.inventoryRegion || '未标注'}</span>
<span className="truncate text-slate-500"><Blur>{vehicle.customer || '未绑定客户'}</Blur></span>
<span className="truncate text-slate-500">{vehicle.customer || '未绑定客户'}</span>
<span className={`text-right tabular-nums ${vehicle.mileageBand === 'HIGH' ? 'text-blue-600' : vehicle.mileageBand === 'INVENTORY' && vehicle.dailyMileage > 0 ? 'text-rose-600' : 'text-slate-700'}`}>
{fmtKm(vehicle.dailyMileage)} km
</span>