docs: 添加里程管理模块设计文档

覆盖架构、API 端点、前端组件、数据映射,
1:1 复刻原型的实时监控和统计报表。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-01 20:55:45 +08:00
parent 968e9369a0
commit 7cf7bc945a

View File

@@ -0,0 +1,242 @@
# 里程管理模块设计
## 背景
在模块化重构的基础上,实现里程管理 BI 模块1:1 复刻原型 `/Users/kkfluous/Projects/ai-coding/ln-yuanxing/lnoneos-1` 中的里程管理部分。包含 3 个子 Tab实时监控、统计报表、每日汇报占位
## 目标
- 1:1 复刻原型 UI样式、动画、交互细节完全一致
- 接入真实数据源(两个数据库)
- 每日汇报 Tab 暂做占位
## 数据源
### 数据库 1lingniu_prod已有连接
- `tab_mileage_assessment_target` — 5 个考核项目定义(目标名称、车辆数、年考核里程、考核年限等)
- `tab_mileage_assessment_vehicle` — 492 辆考核车辆(今日里程、累计里程、完成率、达标状态等)
- `tab_truck``tab_truck_status_info``tab_contract``tab_customer` / `tab_user``tab_department` — 车辆关联客户名、部门、经理
### 数据库 2hydrogen_energy新增连接
- 连接信息:`101.133.130.65:3306`,用户 `bi_reader_02`,密码 `bi_reader_02_Pass`,库名 `hydrogen_energy`
- `v_vehicle_daily_stats` — 1004 辆车的每日里程明细plate, vin, stat_date, daily_km, total_km, day_hydrogen, daily_run_secs, source
## 架构
### 后端
新增 `src/server/mileage-db.ts` — hydrogen_energy 数据库连接池。
新增 `src/server/routes/mileage.ts` — 里程管理 API 路由。
修改 `src/server/index.ts` — 注册新路由 `/api/mileage`
### 前端
```
src/modules/mileage/
├── MileageModule.tsx # 主组件3个子Tab切换实时监控/统计报表/每日汇报)
├── MonitoringView.tsx # 实时监控视图
├── StatisticsView.tsx # 统计报表视图
├── DailyReportView.tsx # 每日汇报(占位)
├── api.ts # API 客户端
└── types.ts # 类型定义
```
### 数据流
```
前端 MileageModule → fetch /api/mileage/*
后端 mileage.ts 路由
├── lingniu_prod 池:考核目标/车辆、车辆关联信息(客户/部门/经理)
└── hydrogen_energy 池v_vehicle_daily_stats日里程/趋势)
↓ 内存合并
前端渲染Recharts 图表 + 列表)
```
## API 端点
### `GET /api/mileage/monitoring`
实时监控数据:全部 1004 辆车的今日里程 + 关联信息。
**查询逻辑:**
1.`v_vehicle_daily_stats` 取最新日期的所有车辆数据plate, daily_km, total_km, source
2.`lingniu_prod` 取车辆关联信息(客户名、部门、经理),使用现有的 `MAIN_SQL` 关联链
3. 内存按 plate 合并
**返回:**
```ts
{
vehicles: Array<{
plate: string;
vin: string;
dailyKm: number;
totalKm: number | null;
source: string; // TBOX / G7S / NONE
isOnline: boolean; // source !== 'NONE' && dailyKm > 0
isDataSynced: boolean; // source !== 'NONE'
customer: string | null;
department: string | null;
manager: string | null;
}>;
updatedAt: string;
}
```
### `GET /api/mileage/targets`
考核项目列表 + 每个项目的汇总统计。
**查询逻辑:**
1.`tab_mileage_assessment_target` 取全部未删除项目
2.`tab_mileage_assessment_vehicle` 按 target_id 聚合统计
**返回:**
```ts
Array<{
id: number;
targetName: string;
vehicleCount: number;
totalMileagePerVehicle: number;
annualMileagePerVehicle: number;
assessmentYears: number;
period: string; // "YYYY-MM-DD ~ YYYY-MM-DD"
todayTotal: number; // SUM(today_mileage)
cumulativeTotal: number; // SUM(current_mileage)
avgCompletion: number; // AVG(completion_rate) * 100
qualifiedCount: number; // SUM(is_qualified)
yearQualifiedCount: number; // SUM(current_year_is_qualified)
halfQualifiedCount: number; // completion_rate >= 0.5 的车辆数
currentYearTarget: number; // SUM(current_year_mileage_task)
currentYearCompleted: number; // SUM(current_year_mileage)
remaining: number; // currentYearTarget - currentYearCompleted
daysLeft: number; // current_year_assessment_end_date - today
dailyTarget: number; // remaining / daysLeft
}>
```
### `GET /api/mileage/target/:id/vehicles`
某考核项目的车辆明细列表。
**查询逻辑:**
`tab_mileage_assessment_vehicle` WHERE target_id = :id AND is_deleted = 0
**返回:**
```ts
Array<{
plateNumber: string;
todayMileage: number;
totalMileage: number;
completionRate: number;
isQualified: boolean;
currentYearIsQualified: boolean;
dailyRequiredMileage: number;
}>
```
### `GET /api/mileage/trend?targetId=...&days=7`
7天里程趋势按考核项目筛选。
**查询逻辑:**
1. 若有 targetId`tab_mileage_assessment_vehicle` 取该项目的所有 plate_number
2.`v_vehicle_daily_stats` WHERE plate IN (...) AND stat_date >= (today - days) GROUP BY stat_date
**返回:**
```ts
Array<{
date: string; // "MM-DD"
mileage: number; // SUM(daily_km)
}>
```
## 前端组件设计
### MileageModule.tsx
主组件,管理子 Tab 切换monitoring / statistics / report包含
- 子导航栏(实时监控/统计报表/每日汇报),带 motion layoutId 动画下划线
- 条件渲染对应 View 组件
### MonitoringView.tsx
1:1 复刻原型实时监控视图。
**状态:**
- activeSubTab 由父组件管理
- searchTerm, filterDept, filterPlate, filterProject, filterEntity, filterRegionCode, filterYear, filterDate, filterDateRange, filterMileageRange
- sortBy ('today' | 'total'), sortOrder ('asc' | 'desc')
- isFilterOpen, isFullscreen
**UI 结构:**
1. 看板头部(标题 + 全屏按钮 + 排序切换)
2. 快捷筛选栏3 个 SearchableSelect + 高级筛选图标)
3. 可展开高级筛选面板
4. KPI 卡片网格4列总里程深色卡、平均单车、监控台数
5. 车辆详情清单motion.div 列表)
6. 全屏叠加层AnimatePresence
**SearchableSelect 组件:** 在 MonitoringView 内部定义(原型中的实现与公共 SearchSelect 不同,它使用 motion 动画、"无限制"默认选项、不同样式)。
### StatisticsView.tsx
1:1 复刻原型统计报表视图。
**状态:**
- selectedProject, chartType ('bar' | 'line' | 'area')
- isTableFullscreen, expandedModel, viewAllModel, viewAllSearch, viewAllSort
**UI 结构:**
1. 项目选择器(横向滚动按钮组)
2. 左侧7天趋势图Recharts BarChart/LineChart/AreaChart 切换)+ landscape KPI 卡片
3. 右侧:车型考核里程汇总卡片列表(可展开详情 + 车辆明细前5台
4. 全屏表格叠加层15列明细表
5. 查看全部侧滑面板(搜索 + 排序 + 车辆列表)
### DailyReportView.tsx
占位组件,显示"每日汇报 - 开发中"。
## 数据映射
### 实时监控
| UI 字段 | 数据来源 |
|---------|---------|
| 车牌号 | `v_vehicle_daily_stats.plate` |
| 今日里程 | `daily_km`(最新日期) |
| 累计里程 | `total_km`(最近非空值,用用户提供的变量填充 SQL |
| 在线状态 | `source !== 'NONE' && daily_km > 0` |
| 数据同步 | `source !== 'NONE'` |
| 客户名 | `lingniu_prod`: tab_truck → tab_truck_status_info → tab_contract → tab_customer.customer_name |
| 部门 | `lingniu_prod`: → tab_user → tab_department.dep_name |
### 统计报表
| UI 字段 | 数据来源 |
|---------|---------|
| 项目列表 | `tab_mileage_assessment_target`target_name, vehicle_count 等) |
| 今日总里程 | `SUM(tab_mileage_assessment_vehicle.today_mileage)` by target_id |
| 累计总里程 | `SUM(current_mileage)` by target_id |
| 平均完成率 | `AVG(completion_rate) * 100` by target_id |
| 达标车辆数 | `SUM(current_year_is_qualified)` by target_id |
| 50%达标数 | `COUNT(completion_rate >= 0.5)` by target_id |
| 考核区间 | `default_start_date ~ default_end_date` |
| 年考核任务/辆 | `annual_mileage_per_vehicle` |
| 本年需完成 | `SUM(current_year_mileage_task)` |
| 已完成 | `SUM(current_year_mileage)` |
| 未完成总数 | 本年需完成 - 已完成 |
| 剩余天数 | `current_year_assessment_end_date - today`(取 vehicle 中的值) |
| 日均需完成 | 未完成 / 剩余天数 |
| 7天趋势 | `v_vehicle_daily_stats` 按项目车牌过滤聚合 |
| 车辆明细 | `tab_mileage_assessment_vehicle` 的 plate_number, today_mileage, total_mileage 等 |
## 不在范围内
- 每日汇报 Tab 具体实现(占位)
- landscape 适配(原型中有 landscape: 前缀样式,照搬即可但不做额外适配工作)
- 后端缓存
- 新增依赖