fix(scheduling): fix vehicle type classification and algorithm candidate matching

- classifyVehicleType now parses dic_type.dic_name (e.g. "4.5吨冷链车") instead of raw model code
- Remove overly strict completionRate >= 0.8 filter for hopeless candidates
- Use vehicle's yearTarget as fallback when inventory has no assessment target
- Filter out suggestions with no candidates (not actionable)
- estimatedGain counts rescue_hopeless suggestions as potential gains

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-16 20:31:44 +08:00
parent db5ca2e686
commit 253cc2f2c0
13 changed files with 2110 additions and 28 deletions

View File

@@ -0,0 +1,153 @@
# 三大运营统计模块设计
从 lnoneos 原型迁移到 ln-bi 生产项目,使用真实 MySQL 数据。
## 架构决策
- **数据源**:复用现有 `getVehicles()` 缓存(~1000 辆,内存聚合无性能问题)
- **跳过**出勤率、日均里程无数据源QR Code
- **新增图标**`Search`, `Filter`, `ArrowRightLeft` (lucide-react已安装)
## 模块 1部门运营统计
### 后端 API
**`GET /api/vehicles/dept-stats`** — 返回 `DeptGroup[]`
聚合逻辑:按 `Vehicle.departmentName` 分组,每个部门下按 `Vehicle.customerManager` 分组。每个业务员统计车型分布:
| 车型类别 | 过滤条件 |
|---|---|
| t4_5 | type=4.5T 且 model 不含"冷链" |
| t4_5c | type=4.5T 且 model 含"冷链" |
| t18 | type=18T |
| t49 | type=49T |
| trailer | model 含"挂车" |
| other | 以上都不是 |
部门级别额外字段:`totalAssets`(运营中的)、`operatingCount`status=Operating`idleCount`status=Inventory 或 Abnormal
### 后端:扩展 `/api/vehicles/list`
新增查询参数:
- `manager` — 按客户经理筛选
- `customer` — 按客户名称筛选
- `isColdChain` — true/false筛选冷链/非冷链
- `isTrailer` — true/false筛选挂车/非挂车
### 前端类型
```typescript
interface ManagerStats {
manager: string;
department: string;
t4_5: number;
t4_5c: number;
t18: number;
t49: number;
trailer: number;
other: number;
total: number;
}
interface DeptGroup {
department: string;
totalAssets: number;
operatingCount: number;
idleCount: number;
managers: ManagerStats[];
}
```
### 前端 UI
参照 lnoneos 1362-1880 行:
- 顶部深色汇总条(总资产/运营中/闲置中,跳过平均出勤)
- 按部门/按业务员切换
- 桌面表格 + 移动端卡片
- 展开部门显示业务员卡片,展开业务员显示 6 个车型格子(可点击下钻到车牌列表)
## 模块 2区域运营统计
### 后端 API
**`GET /api/vehicles/region-stats`** — 返回 `RegionGroup[]`
新增大区映射函数province/city → 华东/华南/华北/华中/西南/西北/其他)。按大区分组,每个区域下统计:
- 按车型4.5T/18T/49T的资产/运营/库存数
- 列出区域内的客户列表
```typescript
interface RegionGroup {
region: string; // 华东、华南等
totalAssets: number;
operatingCount: number;
inventoryCount: number;
customers: string[];
typeBreakdown: { type: string; total: number; operating: number; inventory: number; customers: string[] }[];
}
```
### 前端 UI
参照 lnoneos 1882-2174 行:
- 筛选弹出框(客户搜索/区域/城市下拉)
- 可展开区域行,展开后显示车型子行
- 桌面表格 + 移动端卡片
## 模块 3客户运营统计
### 后端 API
**`GET /api/vehicles/customer-stats`** — 返回 `CustomerStats[]`
`Vehicle.customerName` 分组(只统计 status=Operating 的车辆),每个客户统计:
- 关联业务员customerManager、品牌brandLabel、部门departmentName
- 大区(从 province/city 映射)、城市
- 6 个车型分列计数 + 合计
```typescript
interface CustomerStats {
customer: string;
manager: string;
brand: string;
department: string;
region: string;
city: string;
t4_5: number;
t4_5c: number;
t18: number;
t49: number;
trailer: number;
other: number;
total: number;
}
```
### 前端 UI
参照 lnoneos 2176-2496 行:
- 筛选弹出框(客户名/业务员搜索,品牌/部门/区域下拉)
- 翡翠绿色主题表头
- 客户表格,各车型列可点击下钻
- 展开后显示 4 个详情卡片(客户详情/主要车型/运营状态/资产占比)
- 桌面表格 + 移动端卡片
## 文件变更清单
| 文件 | 变更 |
|---|---|
| `src/server/routes/vehicles.ts` | 新增 3 个 API 端点 + 扩展 `/list` 的过滤参数 + 大区映射函数 |
| `src/types.ts` | 新增 `DeptGroup`, `ManagerStats`, `CustomerStats`, `RegionGroup` 接口 |
| `src/server/types.ts` | 同步新增后端类型 |
| `src/api.ts` | 新增 `fetchDeptStats`, `fetchRegionStats`, `fetchCustomerStats` |
| `src/App.tsx` | 新增 3 个 section + 相关 state/toggle/filter 逻辑 + 扩展 showPlateNumbers 类型 |
## 实现顺序
1. 后端:大区映射 + 3 个 API + 扩展 list 过滤
2. 前端类型 + API 客户端
3. 部门运营统计 UI
4. 区域运营统计 UI
5. 客户运营统计 UI
6. 验证构建通过