diff --git a/docs/superpowers/specs/2026-04-01-mileage-module-design.md b/docs/superpowers/specs/2026-04-01-mileage-module-design.md new file mode 100644 index 0000000..160065b --- /dev/null +++ b/docs/superpowers/specs/2026-04-01-mileage-module-design.md @@ -0,0 +1,242 @@ +# 里程管理模块设计 + +## 背景 + +在模块化重构的基础上,实现里程管理 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 辆车的今日里程 + 关联信息。 + +**查询逻辑:** +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: 前缀样式,照搬即可但不做额外适配工作) +- 后端缓存 +- 新增依赖