Files
ln-bi/docs/superpowers/specs/2026-04-01-mileage-module-design.md
kkfluous 7cf7bc945a docs: 添加里程管理模块设计文档
覆盖架构、API 端点、前端组件、数据映射,
1:1 复刻原型的实时监控和统计报表。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:55:45 +08:00

243 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 里程管理模块设计
## 背景
在模块化重构的基础上,实现里程管理 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: 前缀样式,照搬即可但不做额外适配工作)
- 后端缓存
- 新增依赖