# 车辆数据中台一期现状分析与总体方案

> 结论日期：2026-07-14
> 范围：只完成现状分析和方案设计，不进入 V2 功能开发或 ECS 部署。
> 代码依据：`/Users/lingniu/project/ai-coding/ln-bi`、`vehicle-data-platform`、`go/vehicle-gateway`，以及 `docs/architecture`、`docs/ops` 中的生产说明。

## 1. 结论摘要

当前数据接入链路已经具备可用的生产底座：GB32960、JT808、YUTONG_MQTT 经 NATS/Kafka 分流后，分别形成 Redis 当前态、TDengine RAW/位置历史、MySQL 身份/实时/日里程投影；现有平台 BFF 也已提供车辆、实时位置、轨迹点、RAW、里程、质量和运维健康等只读接口。

但现有前端不是可直接扩展的一期产品：生产入口加载的是约 6000 行的 `PrototypeApp.tsx`，仍混有 mock 数据和“接口缺失时展示能力边界”的原型逻辑；另一个模块化 `App.tsx` 并非当前入口。现有地图每次最多创建 500 个普通 Marker，没有聚合、MassMarks/Canvas 图层和视口查询，无法满足 1 万辆级监控。所谓告警接口实际上是质量问题接口的别名，没有规则、事件、处理记录和通知持久化。

建议丢弃现有原型页面的产品实现，但保留经验证的数据适配、领域工具、测试、运行时配置和部署脚手架，建立独立 V2。前端沿用 React + TypeScript + Vite，吸收 `ln-bi` 的视觉语言、壳层、鉴权思想和基础组件，但采用正式路由、查询缓存、虚拟表格和独立地图 SDK 层。后端保留现有接入链路，通过平台 BFF 和新增的告警/导出 worker 补齐业务能力，不让浏览器直接访问 Redis、TDengine 或 MySQL。

## 2. 当前前端技术栈与目录

### 2.1 `ln-bi` 参考项目

| 项目 | 当前实现 | 评价 |
| --- | --- | --- |
| 框架 | React 19、React DOM 19、TypeScript 5.8、Vite 6.2 | 可作为 V2 目标栈参考；不建议仅为对齐版本立刻升级已有平台依赖 |
| 样式 | Tailwind CSS 4、少量 CSS 变量 | 视觉语言清晰，但业务组件 class 较分散，需要提炼 token 和组件配方 |
| 图标/动效 | lucide-react、Motion | 可复用设计语言；监控页面动效应克制并支持 reduced motion |
| 图表 | Recharts 3.8 | 适合常规 BI；百万点、多 Y 轴时序更推荐现平台已有 ECharts 5 |
| 地图 | `@amap/amap-jsapi-loader` + AMap JS API 2.0 | 加载和实例生命周期可借鉴；目前只是热力图业务组件，不是通用地图 SDK |
| API | 原生 `fetch` + JWT 注入 | 可借鉴鉴权流程；错误类型、超时、重试、取消、缓存仍不足 |
| 服务端 | Hono、MySQL/Postgres、JWT、XLSX | 属于 `ln-bi` 自身 BFF，不应直接搬入车辆接入 Go 数据面 |
| 路由 | pathname + hash + `replaceState` 手写 | 适合少量模块，不适合可分享查询、详情层级和权限路由 |
| 状态 | React 本地状态/Context | 未使用全局状态库或服务端查询缓存 |

主要目录：

```text
ln-bi/src/
├── App.tsx                     # 模块注册、权限门禁、懒加载
├── auth/                       # jumpToken -> JWT、fetch token 注入
├── components/
│   ├── Shell.tsx               # 桌面侧栏、移动底栏、模块切换、水印
│   ├── SearchSelect.tsx
│   ├── MultiSearchSelect.tsx
│   └── ui/surface.tsx          # PageFrame、SurfaceCard、MetricTile、状态组件
├── modules/
│   ├── vehicle-heatmap/        # AMap 热力图和筛选/详情面板
│   ├── hydrogen-heatmap/
│   ├── mileage/                # 表格、详情弹窗、XLSX 导出
│   └── ...
├── server/                     # Hono BFF、认证、DB 查询
├── shared/auth/roles.ts        # 角色判断
└── index.css                   # Tailwind、主题变量、地图控件样式
```

### 2.2 当前车辆平台前端

目录为 `vehicle-data-platform/apps/web`，使用 React 18.3、TypeScript 5.7、Vite 6、Semi UI 2.71、ECharts 5.6。当前入口 `src/main.tsx` 加载 `PrototypeApp`，不是 `src/App.tsx`。

```text
vehicle-data-platform/apps/web/src/
├── main.tsx                    # 当前生产入口 -> PrototypeApp
├── PrototypeApp.tsx            # 大型原型单体，真实接口与 mock 逻辑混合
├── App.tsx                     # 未作为入口的模块化旧实现
├── api/                        # 统一响应信封、类型和调用方法
├── components/                 # VehicleMap、状态标签、空状态等
├── config/                     # API/高德运行时配置
├── domain/                     # 路由、导出、车辆查询等纯函数
├── integrations/amap.ts        # AMap loader、坐标校验、逆地理编码
├── layout/AppShell.tsx
├── pages/                      # 旧模块化页面
├── prototype/                  # mock、真实数据适配、view model、字段映射
└── styles/                     # token、全局样式、原型样式
```

V2 的原则是“页面重建、能力甄别复用”：不复制 `PrototypeApp.tsx` 和 `prototype.css`；保留可独立测试的 `api`、`domain`、`integrations`、真实数据归一化逻辑及其测试，再按新接口契约重构。

## 3. 可复用能力清单

| 能力 | 来源 | 复用决策 | 说明 |
| --- | --- | --- | --- |
| 80px 深色侧栏、顶部面包屑、水印、移动底栏 | `ln-bi/components/Shell.tsx` | 设计复用、代码重构 | V2 桌面优先，应改为正式路由和可折叠侧栏 |
| PageFrame、SurfaceCard、MetricTile、SegmentedNav | `ln-bi/components/ui/surface.tsx` | 可迁移后组件化 | 统一 token、尺寸和可访问性后复用 |
| SearchSelect、MultiSearchSelect | `ln-bi/components` | 交互参考 | 当前仅接收字符串数组，缺少远程搜索、虚拟列表、label/value 和键盘完整性 |
| 加载、空、错误状态 | 两项目 | 合并重构 | 建立统一 `AsyncState`，禁止页面各自拼接 |
| JWT/jumpToken 门禁、角色判断 | `ln-bi/auth`、`shared/auth` | 复用认证协议思想 | token 仍应保存在 session；权限改为路由/操作级声明，后端必须二次校验 |
| AMap loader、实例销毁、运行时密钥 | 两项目 | 合并为通用 SDK | 统一 loader promise、插件注册、安全代理和错误状态 |
| 热力图数据归一化 | `ln-bi/vehicle-heatmap` | 可复用算法 | `log1p/sqrt` 强度变换适合密度层，不等于车辆状态点图层 |
| 表格/详情弹窗/XLSX | `ln-bi/mileage` | 交互与导出格式参考 | 一期大数据导出必须后端异步，不能沿用浏览器全量 XLSX |
| ECharts | 当前车辆平台 | 保留 | 更适合多 Y 轴、dataZoom、断点、阶梯线和大数据采样 |
| `api/client.ts` 响应信封和 traceId | 当前车辆平台 | 扩展复用 | 增加鉴权、AbortSignal、超时、错误码、幂等键和查询缓存 |
| 车辆 lookup、字段归一化、CSV 纯函数及测试 | 当前车辆平台 | 审核后复用 | 去掉 mock fallback，统一到 V2 DTO/领域模型 |
| Semi UI 页面组件 | 当前车辆平台 | 暂不作为 V2 默认 | 与 `ln-bi` Tailwind 视觉体系并存会形成双设计系统；V2 启动前只选一套基础组件策略 |

不存在可直接复用的“通用图表组件”或“通用高性能表格组件”。`ln-bi` 的 Recharts 与页面耦合，当前平台的 ECharts 也需要建立 `TimeSeriesChart`、轴/单位/空值策略和采样契约；表格需新增服务端分页、列配置、固定列和虚拟滚动封装。

## 4. 高德地图当前封装方式

### 4.1 `ln-bi`

`AmapHeatmapCanvas.tsx` 动态导入 `@amap/amap-jsapi-loader`，写入 `_AMapSecurityConfig.securityJsCode`，加载 AMap 2.0 的 HeatMap、ToolBar、Scale 插件；创建白色地图和 HeatMap，点击地图回传经纬度，数据变化时调用 `setDataSet`，焦点变化时计算 bounds，卸载时销毁实例。

优点是 loader 官方、生命周期完整、地图与侧面板分屏清楚。限制是车辆和加氢模块各有近似实现，密钥直接下发前端，未封装 Marker/聚合/信息窗/轨迹/播放，也没有实例共享和视口事件节流。

### 4.2 当前车辆平台

`integrations/amap.ts` 自行加载 `https://webapi.amap.com/loader.js`，按插件集合缓存 Promise，支持 Scale、Geocoder、坐标合法性检查、URI Marker 链接和浏览器逆地理编码；`appConfig.ts` 从 `window.__LINGNIU_APP_CONFIG__` 或 Vite 环境变量读取 Web JS key、安全代码/代理和 API base URL。

`VehicleMap.tsx` 在组件内创建 Map、Marker、Polyline，重绘时清除 overlay，最多截取 500 个点，并在未配置地图时提供坐标预览。它适合验证和小规模页面，不适合一期：每点 HTML button、没有聚合、状态图层、InfoWindow 管理、车辆朝向、轨迹抽稀/播放或视口查询。

### 4.3 V2 建议封装

建立 `features/map-sdk`，分为：

- `AMapProvider/useAMap`：唯一 loader、插件按需加载、实例注册、resize/destroy。
- `BaseMap`：纯地图容器，只接收中心、缩放、样式和事件。
- `VehiclePointLayer`：小规模用 Marker，规模化优先 MarkerCluster/LabelsLayer/MassMarks 或 Canvas/WebGL 能力；详情卡只保留一个 InfoWindow。
- `TrackLayer`：Polyline、起终点、停车/告警节点和移动标记；播放状态在业务 hook，不绑入地图实例。
- `HeatmapLayer`、`GeocoderService`、`MapControls`：独立能力。
- 视口查询使用 `bounds + zoom + filterHash`；移动结束后防抖请求服务器聚合结果，前端不一次拉取全量 1 万点 DOM。

高德 Web JS key 可由运行时配置下发，但安全密钥优先使用服务端安全代理；逆地理编码优先走现有 `/api/map/reverse-geocode`，避免泄露 REST key并便于限流/缓存。

## 5. 当前车辆相关接口

现有平台 BFF 的有效能力如下；详细缺口见 `vehicle-data-platform-api-gap.md`。

| 领域 | 接口 | 当前用途 |
| --- | --- | --- |
| 总览 | `GET /api/dashboard/summary` | 在线、今日活跃、帧数、问题数、协议/服务/链路统计 |
| 车辆 | `GET /api/vehicles`、`/api/vehicles/resolve`、`/api/vehicles/coverage`、`/summary` | 车辆列表、VIN/车牌/手机号解析、来源覆盖 |
| 单车 | `GET /api/vehicle-service`、`/summary`、`/overview`；`POST /overviews` | 聚合身份、实时、历史、RAW、里程、质量证据 |
| 实时 | `GET /api/realtime/vehicles`、`/api/realtime/locations` | VIN 聚合实时状态和每协议最新位置 |
| 历史 | `GET /api/history/locations`、`GET/POST /api/history/raw-frames` | TDengine 位置点和 RAW 证据分页 |
| 里程 | `GET /api/mileage/summary`、`/api/mileage/daily` | MySQL 日里程统计 |
| 在线 | `GET /api/statistics/online-summary`、`/online-vehicles` | 当前固定口径的在线统计和车辆状态 |
| 数据质量 | `GET /api/quality/summary`、`/issues`、`/notification-plan` | 由当前数据推导的质量信号和静态通知方案 |
| 告警兼容 | `GET /api/alert-events/summary`、`/alert-events`、`/notification-plan` | 实际是上述质量接口别名，不是业务告警事件 |
| 地图 | `GET /api/map/reverse-geocode` | 服务端高德逆地理编码 |
| 运维 | `GET /api/ops/health`、`/source-readiness` | 数据源可写性、Kafka lag、连接/Redis key、发布版本和接入准备度 |

同时，Go `realtime-api` 还提供面向底层表的查询接口和 OpenAPI，但 V2 浏览器应统一访问平台 BFF，避免前端绑定多个端口与底层存储模型。

## 6. 数据职责概览

- TDengine `lingniu_vehicle_ts`：`raw_frames` 是原始接收与扁平解析证据，`raw_frame_payload_chunks` 保存超长 payload，`vehicle_locations` 保存 VIN 级位置、速度、方向、告警标志和总里程历史。它不是车辆档案或告警业务库。
- Redis DB 50：`vehicle:latest:*`、`vehicle:realtime-raw:*`、`vehicle:rt-kv:*`、`vehicle:online:*`、`vehicle:protocols:*`、`vehicle:last_seen` 提供可过期、可重建的当前态。它不能作为历史、告警或导出任务事实源。
- MySQL `lingniu_vehicle_data`：保存 `vehicle`、多标识映射、JT808 注册鉴权、每协议实时快照/位置、来源配置和日里程事实/结果。现有 `vehicle` 档案很轻，只含 VIN、车牌、OEM、启用状态，尚不足以支撑车型、公司、车辆类型等产品字段。

统一模型及新增模型详见 `vehicle-data-platform-data-model.md`。

## 7. 一期缺口结论

必须新增或升级的核心能力：

1. 完整车辆档案、组织/车型/协议/接入厂家字典与首次接入事实。
2. 地图聚合查询、组合筛选、状态统计和可配置在线口径。
3. 包含方向、SOC、告警标志、停车点、异常点过滤和抽稀元数据的轨迹接口。
4. 动态指标目录，以及多车、多指标、聚合/抽稀、分页的通用时序查询。
5. MySQL 持久化告警规则、告警事件、处理记录、站内通知和告警计算 worker。
6. MySQL 异步导出任务、对象/本地文件存储、worker、进度与下载授权。
7. 接入状态字段：首次/最近上报、事件时间与接收时间延迟、最近消息类型、最近错误、动态在线阈值。
8. 真正的认证、菜单/操作权限审计；现车辆平台 BFF 尚未呈现完整权限体系。

## 8. 推荐一期路由与菜单

```text
/
├── /monitor                         全局监控（默认首页）
├── /vehicles                        车辆查询
│   └── /vehicles/:vin               单车数字档案
├── /tracks                          轨迹查询与回放
├── /history                         历史数据分析
│   └── /history/exports             导出任务
├── /alerts
│   ├── /alerts/events               告警事件
│   ├── /alerts/rules                告警规则
│   └── /alerts/inbox                站内通知
├── /access                          车辆接入状态
└── /operations                      运维质量（管理员）
```

侧栏一级菜单保持 6 个业务入口：全局监控、车辆中心、轨迹回放、历史分析、告警中心、接入管理；导出任务挂在历史分析二级菜单，运维质量按权限置底。详情、告警、轨迹之间用带 `returnTo` 的上下文跳转，查询条件同步 URL，浏览器返回可恢复筛选、时间和选中车辆。

## 9. 推荐前后端整体架构

```mermaid
flowchart LR
  UI["V2 React Web"] --> BFF["Platform API / BFF"]
  BFF --> RT["Redis 当前态"]
  BFF --> TS["TDengine 时序与 RAW"]
  BFF --> DB["MySQL 业务事实"]
  BFF --> MAP["高德 REST / 安全代理"]
  ING["Gateway + NATS + Kafka Writers"] --> RT
  ING --> TS
  ING --> DB
  K["Kafka fields/raw"] --> AW["Alert evaluator"]
  AW --> DB
  BFF --> EQ["Export queue"]
  EQ --> EW["Export worker"]
  EW --> TS
  EW --> DB
  EW --> FS["文件/对象存储"]
```

前端按 `app/router`、`shared`、`entities/vehicle`、`features`、`pages` 分层。服务端状态使用查询缓存库统一取消、去重、失效和后台刷新；少量 UI 状态用 React Context/局部 store。地图、图表、表格均只接收领域 DTO，不直接处理协议字段名。

平台 BFF 负责统一鉴权、参数校验、分页、在线状态计算、跨源聚合、字段目录、限流、traceId 和 DTO；禁止让前端分别拼 Redis/MySQL/TDengine。已有接入 writer 保持不变，新告警 worker 消费可重放 fields/raw 流，异步导出 worker 读取 TDengine/MySQL 并把任务状态写 MySQL。

## 10. 运维与最终 ECS 部署边界

已查阅 `docs/ops/vehicle-ingest-runbook.md`、`docs/ops/go-vehicle-ingest-memory.md`、`docs/architecture/production-data-plane-inventory.md` 和 `vehicle-data-platform/docs/deployment.md`。当前接入数据面采用 systemd 裸机 release 目录与 `current` 软链，平台使用 `/opt/lingniu-vehicle-platform/{releases,current,env}`，HTTP 端口 20300；部署后应验证 `/api/ops/health`、车辆查询和运行时配置。

V2 最终仍部署到当前 ECS，但不应在分析阶段执行。实施完成后的发布顺序应是：数据库向前兼容迁移 -> 新 worker（默认禁用规则）-> BFF -> 静态 Web -> 小流量健康验证 -> 启用告警/导出 worker。每一步保留旧 release 和可回滚软链；密钥只进 ECS 环境文件，不进仓库或构建产物。完整发布验收纳入路线图最后阶段。

## 11. 风险与待确认事项

| 优先级 | 风险/待确认 | 影响与建议 |
| --- | --- | --- |
| P0 | `vehicle` 档案缺车型、类型、公司、接入厂家等 | 先确定主数据来源和维护责任，不要从实时 JSON 猜档案 |
| P0 | 现有告警接口名与真实语义不符 | V2 使用 `/api/v2/alerts/*` 新契约，旧别名标记 deprecated，避免误把质量信号当已处理事件 |
| P0 | 动态指标没有目录、单位、类型和协议映射 | 先落指标元数据；否则图表、规则和导出会各自硬编码 |
| P0 | 用户/角色来源尚未确认 | 明确复用 `ln-bi` jumpToken/JWT，还是接入统一 SSO；后端权限不可只靠菜单隐藏 |
| P1 | 在线阈值是全局、协议级还是车辆级 | 建议全局默认 + 协议覆盖；一期暂不做单车覆盖 |
| P1 | 轨迹异常过滤可能隐藏原始证据 | API 同时返回 raw/filtered 计数和算法版本，允许关闭过滤 |
| P1 | TDengine `raw_frames.parsed_json` 是动态字段唯一历史来源 | 通用指标查询先从 JSON 提取会有成本；高频稳定指标应按使用量逐步物化，而非一期全列化 |
| P1 | 单 ECS 同时承担接入、查询、告警和导出 | 导出/重查询必须有并发、时间范围、行数和资源配额；压测后再定 worker 并发 |
| P1 | 地图 1 万辆的插件/授权与浏览器性能 | 先完成 1k/10k 基准，确定 MarkerCluster、MassMarks 或 Canvas 方案和高德配额 |
| P1 | 站内通知实时方式 | 一期可 SSE + 轮询降级；若 ECS 反代不适合长连接，先使用增量轮询 |
| P2 | Semi UI 与 Tailwind 双设计系统 | V2 启动前确认唯一基础组件策略；建议 Tailwind token + 无样式/轻量基础组件，ECharts 保留 |
| P2 | 导出文件存储位置与保留期 | 确认 OSS 或 ECS 本地盘；推荐 OSS/兼容对象存储，任务和文件设过期清理策略 |

## 12. 本阶段完成定义

本阶段仅交付本分析、路线图、API 缺口和数据模型四份文档。V2 代码、数据库迁移、告警/导出 worker、ECS 发布均须在确认 P0 项后按路线图进入下一阶段。
