覆盖架构、API 端点、前端组件、数据映射, 1:1 复刻原型的实时监控和统计报表。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8.5 KiB
8.5 KiB
里程管理模块设计
背景
在模块化重构的基础上,实现里程管理 BI 模块,1:1 复刻原型 /Users/kkfluous/Projects/ai-coding/ln-yuanxing/lnoneos-1 中的里程管理部分。包含 3 个子 Tab:实时监控、统计报表、每日汇报(占位)。
目标
- 1:1 复刻原型 UI(样式、动画、交互细节完全一致)
- 接入真实数据源(两个数据库)
- 每日汇报 Tab 暂做占位
数据源
数据库 1:lingniu_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— 车辆关联客户名、部门、经理
数据库 2:hydrogen_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 辆车的今日里程 + 关联信息。
查询逻辑:
- 从
v_vehicle_daily_stats取最新日期的所有车辆数据(plate, daily_km, total_km, source) - 从
lingniu_prod取车辆关联信息(客户名、部门、经理),使用现有的MAIN_SQL关联链 - 内存按 plate 合并
返回:
{
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
考核项目列表 + 每个项目的汇总统计。
查询逻辑:
- 从
tab_mileage_assessment_target取全部未删除项目 - 从
tab_mileage_assessment_vehicle按 target_id 聚合统计
返回:
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
返回:
Array<{
plateNumber: string;
todayMileage: number;
totalMileage: number;
completionRate: number;
isQualified: boolean;
currentYearIsQualified: boolean;
dailyRequiredMileage: number;
}>
GET /api/mileage/trend?targetId=...&days=7
7天里程趋势,按考核项目筛选。
查询逻辑:
- 若有 targetId:从
tab_mileage_assessment_vehicle取该项目的所有 plate_number - 从
v_vehicle_daily_statsWHERE plate IN (...) AND stat_date >= (today - days) GROUP BY stat_date
返回:
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 结构:
- 看板头部(标题 + 全屏按钮 + 排序切换)
- 快捷筛选栏(3 个 SearchableSelect + 高级筛选图标)
- 可展开高级筛选面板
- KPI 卡片网格(4列:总里程深色卡、平均单车、监控台数)
- 车辆详情清单(motion.div 列表)
- 全屏叠加层(AnimatePresence)
SearchableSelect 组件: 在 MonitoringView 内部定义(原型中的实现与公共 SearchSelect 不同,它使用 motion 动画、"无限制"默认选项、不同样式)。
StatisticsView.tsx
1:1 复刻原型统计报表视图。
状态:
- selectedProject, chartType ('bar' | 'line' | 'area')
- isTableFullscreen, expandedModel, viewAllModel, viewAllSearch, viewAllSort
UI 结构:
- 项目选择器(横向滚动按钮组)
- 左侧:7天趋势图(Recharts BarChart/LineChart/AreaChart 切换)+ landscape KPI 卡片
- 右侧:车型考核里程汇总卡片列表(可展开详情 + 车辆明细前5台)
- 全屏表格叠加层(15列明细表)
- 查看全部侧滑面板(搜索 + 排序 + 车辆列表)
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: 前缀样式,照搬即可但不做额外适配工作)
- 后端缓存
- 新增依赖