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

8.5 KiB
Raw Blame History

里程管理模块设计

背景

在模块化重构的基础上,实现里程管理 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_trucktab_truck_status_infotab_contracttab_customer / tab_usertab_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 合并

返回:

{
  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 聚合统计

返回:

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天里程趋势按考核项目筛选。

查询逻辑:

  1. 若有 targetIdtab_mileage_assessment_vehicle 取该项目的所有 plate_number
  2. v_vehicle_daily_stats WHERE 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 结构:

  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_targettarget_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: 前缀样式,照搬即可但不做额外适配工作)
  • 后端缓存
  • 新增依赖