docs: 智能调度模块设计规格
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
224
docs/superpowers/specs/2026-04-16-smart-scheduling-design.md
Normal file
224
docs/superpowers/specs/2026-04-16-smart-scheduling-design.md
Normal file
@@ -0,0 +1,224 @@
|
||||
# 智能调度模块设计
|
||||
|
||||
基于里程考核数据,通过贪心优先级匹配算法,生成车辆替换建议,帮助调度员优化车队里程分布,最大化达标车辆数。
|
||||
|
||||
## 业务背景
|
||||
|
||||
公司有多批次考核车辆(40台普货、190台冷藏车等),每批次有年度里程考核目标。车辆租赁给不同客户,客户实际使用强度差异大。考核的是**车辆本身的里程**,因此需要通过替换车辆来均衡里程:
|
||||
- 高里程客户的已达标车换下来,换上里程缺口大的车(让新车追赶)
|
||||
- 低里程客户的无望达标车换下来给高里程客户(抢救),给低里程客户换上已达标的车
|
||||
|
||||
## 核心算法
|
||||
|
||||
### 车辆分类
|
||||
|
||||
从 `tab_mileage_assessment_vehicle` 获取所有考核车辆,按客户聚合计算**客户日均里程**(客户下所有车辆近 30 天日均里程的平均值),然后对每辆车计算:
|
||||
|
||||
```
|
||||
预测年终里程 = 当前累计里程 + 客户日均里程 × 剩余天数
|
||||
达标概率 = 预测年终里程 / 年度目标里程
|
||||
```
|
||||
|
||||
分为三类:
|
||||
|
||||
| 类型 | 条件 | 含义 |
|
||||
|------|------|------|
|
||||
| qualified | `currentYearIsQualified = true` 或 达标概率 ≥ 120% | 已完成或铁定完成 |
|
||||
| hopeless | 达标概率 < 60% | 按当前客户使用强度,年底肯定完不成 |
|
||||
| normal | 60% ≤ 达标概率 < 120% | 有希望但不确定,暂不干预 |
|
||||
|
||||
### 替换建议生成
|
||||
|
||||
**场景 A:replace_qualified(高里程客户的已达标车辆)**
|
||||
- 目标:把已达标的车换下来,换上里程缺口大的库存车
|
||||
- 候选池:库存车(rent_status='在库')+ 同车型 + 同区域
|
||||
- 排序:优先选剩余缺口最大但换后仍可达标的车
|
||||
- 校验:`候选车当前累计 + 客户日均 × 剩余天数 ≥ 年度目标` 才推荐
|
||||
|
||||
**场景 B:rescue_hopeless(低里程客户的无望达标车辆)**
|
||||
- 目标:把无望车换给高里程客户抢救,给低里程客户换上已达标/库存车
|
||||
- 候选池:库存中已达标或将达标的同车型同区域车辆
|
||||
- 排序:优先选已达标且里程最高的车(对低里程客户无影响)
|
||||
|
||||
### 车型匹配规则
|
||||
|
||||
| 源车型 | 可替换为 | 说明 |
|
||||
|--------|---------|------|
|
||||
| 4.5T冷链 | 4.5T冷链、4.5T普货 | 冷链不开空调可当普货用 |
|
||||
| 4.5T普货 | 4.5T普货 | 不能反向替换冷链 |
|
||||
| 18T | 18T | 同型号互换 |
|
||||
| 49T | 49T | 同型号互换 |
|
||||
| 挂车 | 挂车 | 同型号互换 |
|
||||
|
||||
### 区域匹配规则
|
||||
|
||||
复用已有 `mapRegion()` 函数,将 province/city 映射到大区(嘉兴/广东/北京/新疆/其他)。同一大区内可替换,跨大区不推荐。
|
||||
|
||||
### 优先级排序
|
||||
|
||||
干预清单排序:
|
||||
1. **hopeless + 有可行替换方案** → priority: high(最紧急,还能抢救)
|
||||
2. **qualified + 高里程客户 + 有库存可换** → priority: medium(释放达标车,让新车追赶)
|
||||
|
||||
## 后端 API
|
||||
|
||||
### GET /api/scheduling/suggestions
|
||||
|
||||
获取调度建议列表。每次请求实时计算(不使用定时缓存),因为用户操作后需要立即看到最新结果。
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| targetId | number (可选) | 按批次筛选,不传则全部 |
|
||||
|
||||
**响应**:
|
||||
|
||||
```typescript
|
||||
{
|
||||
summary: {
|
||||
qualifiedCount: number; // 已达标车辆数
|
||||
hopelessCount: number; // 无望达标车辆数
|
||||
suggestionCount: number; // 可干预建议数
|
||||
estimatedGain: number; // 预计干预后可新增达标数
|
||||
};
|
||||
suggestions: SchedulingSuggestion[];
|
||||
targets: { id: number; name: string; vehicleCount: number }[];
|
||||
}
|
||||
```
|
||||
|
||||
`SchedulingSuggestion` 结构:
|
||||
|
||||
```typescript
|
||||
{
|
||||
id: string; // 建议唯一ID(如 "s-{plate}-{timestamp}")
|
||||
priority: 'high' | 'medium';
|
||||
type: 'replace_qualified' | 'rescue_hopeless';
|
||||
|
||||
currentVehicle: {
|
||||
plateNumber: string;
|
||||
targetId: number;
|
||||
targetName: string; // 所属批次
|
||||
vehicleType: string; // "4.5T冷链" / "18T" 等
|
||||
totalMileage: number;
|
||||
completionRate: number; // 0-1
|
||||
yearTarget: number; // 年度目标里程
|
||||
region: string; // 大区(嘉兴/广东等)
|
||||
province: string; // 原始省份
|
||||
customer: string;
|
||||
customerAvgDaily: number; // 客户日均里程
|
||||
predictedYearEnd: number; // 预测年终里程
|
||||
daysLeft: number;
|
||||
};
|
||||
|
||||
candidates: {
|
||||
plateNumber: string;
|
||||
targetId: number | null; // 库存车可能无批次
|
||||
targetName: string | null;
|
||||
vehicleType: string;
|
||||
totalMileage: number;
|
||||
completionRate: number;
|
||||
yearTarget: number | null;
|
||||
region: string;
|
||||
province: string;
|
||||
mileageGap: number; // 剩余缺口
|
||||
predictedAfterSwap: number; // 换到该客户后预测年终里程
|
||||
canQualifyAfterSwap: boolean;
|
||||
}[];
|
||||
|
||||
reason: string; // 建议原因文案
|
||||
}
|
||||
```
|
||||
|
||||
### POST /api/scheduling/notify
|
||||
|
||||
发送替换通知。成功后前端立即重新拉取 suggestions。
|
||||
|
||||
**请求体**:
|
||||
|
||||
```typescript
|
||||
{
|
||||
suggestionId: string;
|
||||
currentPlate: string;
|
||||
candidatePlate: string;
|
||||
}
|
||||
```
|
||||
|
||||
操作人从 JWT auth 中获取。
|
||||
|
||||
**响应**:`{ success: boolean; message: string }`
|
||||
|
||||
**行为**:调用外部回调接口发送通知(具体回调 URL 后续配置)。成功后在本地记录已操作状态,后续 GET suggestions 时排除已操作的建议。
|
||||
|
||||
### 数据查询流程
|
||||
|
||||
后端一次请求聚合以下数据:
|
||||
1. 所有考核车辆 — `tab_mileage_assessment_vehicle`(里程进度、达标状态)
|
||||
2. 所有考核目标 — `tab_mileage_assessment_target`(批次名称、年度目标)
|
||||
3. 库存车辆 — `tab_truck WHERE truck_rent_status = 0`(在库)+ 同表获取车型
|
||||
4. 车辆实时位置 — `tab_truck_remote_sync_realtime_info`(province, city)
|
||||
5. 合同/客户信息 — 复用 `vehicle-info.ts` 已有的 JOIN 查询
|
||||
6. 客户日均里程 — 按客户聚合 `v_vehicle_daily_stats` 近 30 天均值
|
||||
|
||||
## 前端结构
|
||||
|
||||
### 文件组织
|
||||
|
||||
```
|
||||
src/modules/scheduling/
|
||||
├── SchedulingModule.tsx // 主入口,状态管理和数据加载
|
||||
├── SuggestionList.tsx // 干预建议清单列表
|
||||
├── SuggestionDetail.tsx // 单条建议展开详情(含替换车辆对比)
|
||||
├── api.ts // fetchSuggestions(), sendNotify()
|
||||
└── types.ts // SchedulingSuggestion 等类型定义
|
||||
```
|
||||
|
||||
后端:
|
||||
```
|
||||
src/server/routes/scheduling/
|
||||
├── index.ts // 路由注册
|
||||
├── suggestions.ts // GET /suggestions 算法核心
|
||||
└── notify.ts // POST /notify 回调通知
|
||||
```
|
||||
|
||||
### 页面层级
|
||||
|
||||
```
|
||||
智能调度 Tab
|
||||
├── 顶部:批次选择器(复用里程统计的批次 tabs,默认"全部")
|
||||
├── 统计卡片区(3 个)
|
||||
│ ├── 已达标车辆数(绿色)
|
||||
│ ├── 无望达标车辆数(红色)
|
||||
│ └── 可干预建议数 + 预计可新增达标数(蓝色)
|
||||
├── 干预建议清单(主列表,按优先级排序)
|
||||
│ ├── 每条:车牌、批次、客户、客户日均、完成率、区域、类型标签(已达标/无望)
|
||||
│ └── 点击 → 展开干预详情
|
||||
└── 干预详情(弹窗)
|
||||
├── 当前车辆信息卡片
|
||||
├── 推荐替换车辆列表(最多 5 辆)
|
||||
│ └── 每辆显示对比:替换前后的区域、车型、里程、预测达标
|
||||
├── 建议原因说明
|
||||
└── 「发送替换通知」按钮 → notify 接口 → 成功后刷新列表
|
||||
```
|
||||
|
||||
### UI 设计要求
|
||||
|
||||
- 以原型 `SmartSchedulingView` 组件为基础风格
|
||||
- 使用 ui-ux-pro-max 优化视觉质量
|
||||
- 适配移动端(竖屏卡片流)和 Web 端(landscape 横屏大表格)
|
||||
- 干预详情弹窗需截图友好:完整卡片布局、替换前后对比一屏可见、关键数据醒目
|
||||
- 统计卡片区保持与原型一致的三列 grid 布局
|
||||
- 批次选择器横向滚动 pill 按钮样式
|
||||
|
||||
### 技术栈
|
||||
|
||||
复用项目已有:React 19 + Tailwind CSS + motion/react(动画)+ recharts(图表)+ lucide-react(图标)
|
||||
|
||||
## 约束与边界
|
||||
|
||||
- 替换仅为建议,不直接操作数据库修改车辆归属
|
||||
- 不能推荐已租赁给其他客户的车辆,只从库存(在库)中推荐
|
||||
- 跨批次可替换,但车型必须匹配(含冷链→普货单向规则)
|
||||
- 同大区内替换,不跨大区
|
||||
- notify 操作后数据立即更新(不使用定时缓存)
|
||||
- 客户名称展示需使用已有的脱敏/Blur 组件
|
||||
Reference in New Issue
Block a user