# 【前端对接·管理后台】派单看板团号与定制师下拉筛选

> Issue: [wx/HL#4876](https://git.1814.love:8443/wx/HL/issues/4876)
> PR: [wx/HL#4877](https://git.1814.love:8443/wx/HL/pulls/4877)
> 服务: `hl-fleet-service` / `hl-order-service-v3` / `hl-user-service`
> 日期: 2026-07-10
> 影响范围: 车务派单看板卡片、团号筛选、定制师筛选下拉

## 1. 结论

- 派单看板仍使用分页接口，不改为一次性全量拉取。
- 卡片新增/补齐 `teamNo`、`consultantId`、`consultantDisplayName`，数据以 order-v3 当前订单为准，不再依赖可能为空的历史派单快照。
- `teamNo` 是包含匹配：输入 `7218` 可以命中完整团号 `26-7218`。
- 定制师筛选改为下拉：先调用 `GET /admin/user/customizers`，选中后向看板传 `consultantId`，后端做 ID 精确筛选。
- 下拉显示 `enterpriseWechatName`。已绑定企微时该字段是企微昵称；未绑定或企微数据缺失时，后端已经回退为 `username`。
- 旧的 `plannerName/consultantName` 文本筛选仍兼容，但新页面不要继续使用自由输入框。

> 本文替代 `53_4871_车务提需求派单看板闭环契约-管理后台.md` 第 5 节中“定制师文本筛选”的前端实现方式；其余状态、分页、操作能力契约继续有效。

## 2. 接口清单

| # | 接口 | 方法 | 路径 | 变更类型 |
|---|------|------|------|----------|
| 1 | 定制师下拉 | GET | `/admin/user/customizers` | 复用既有接口 |
| 2 | 派单看板列表 | GET | `/admin/fleet/board/orders` | 新增 `consultantId`；强化团号与响应字段 |

## 3. 定制师下拉

```http
GET /admin/user/customizers
Authorization: Bearer <fleet-admin-token>
```

请求无参数。车务管理员可直接调用，不需要切换成 admin 或定制师角色。

成功响应示例：

```json
{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": [
    {
      "adminId": "2021059720172838914",
      "username": "wx",
      "enterpriseWechatName": "王骁",
      "avatar": null
    },
    {
      "adminId": "2021059720172838999",
      "username": "designer_test",
      "enterpriseWechatName": "designer_test",
      "avatar": null
    }
  ]
}
```

字段说明：

| 字段 | 类型 | 说明 |
|------|------|------|
| `adminId` | string | 下拉 value；提交给看板的 `consultantId`。 |
| `username` | string | 登录用户名，仅用于兼容或辅助搜索。 |
| `enterpriseWechatName` | string | 下拉 label；企微昵称优先，未绑定企微时后端回退用户名，正常情况下不会空白。 |
| `avatar` | string/null | 头像，可不展示。 |

前端绑定：

```ts
const options = data.map(item => ({
  value: item.adminId,
  label: item.enterpriseWechatName || item.username
}))
```

注意：

- 接口不分页，包含持有 `CUSTOMIZER` 角色的历史定制师；即使账号已锁定/停用仍可能返回，便于筛选历史订单。
- 已软删除账号不返回。
- 前端不要再次按状态过滤下拉，也不要自己请求企微用户接口拼昵称。

## 4. 派单看板查询

```http
GET /admin/fleet/board/orders?page=1&pageSize=10&teamNo=7218&consultantId=2021059720172838914
Authorization: Bearer <fleet-admin-token>
```

查询参数：

| 参数 | 类型 | 必填 | 规则 |
|------|------|------|------|
| `page` | int | 否 | 默认 1。 |
| `pageSize` | int | 否 | 默认 10，最大 100；看板保留分页。 |
| `teamNo` | string | 否 | 团号包含匹配；`7218`、`26-7218` 均可命中 `26-7218`。 |
| `consultantId` | string | 否 | 定制师管理员 ID 精确匹配，值来自下拉 `adminId`。 |
| `plannerName` | string | 否 | 旧定制师姓名模糊筛选，兼容保留。 |
| `consultantName` | string | 否 | `plannerName` 的旧别名，兼容保留。 |

成功响应示例：

```json
{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "page": 1,
    "pageSize": 10,
    "total": 1,
    "records": [
      {
        "id": "HL20260708144557879",
        "orderId": "2074746796763996161",
        "orderNo": "HL20260708144557879",
        "teamNo": "26-7218",
        "consultantId": "2021059720172838914",
        "plannerName": "王骁",
        "consultantName": "王骁",
        "consultantDisplayName": "王骁",
        "assignmentStatus": "unassigned",
        "assignmentStatusLabel": "待派车",
        "startDate": "2026-07-20",
        "endDate": "2026-07-22",
        "headcount": 2,
        "requiredVehicles": [
          {
            "vehicleType": "suv",
            "categoryLabel": "SUV",
            "seats": 5,
            "count": 2
          }
        ],
        "canAssign": true,
        "canRejectRequirement": true
      }
    ]
  }
}
```

空结果响应：

```json
{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "page": 1,
    "pageSize": 10,
    "total": 0,
    "records": []
  }
}
```

字段口径：

| 字段 | 类型 | 说明 |
|------|------|------|
| `teamNo` | string/null | order-v3 当前团号；没有团号时为 null。 |
| `consultantId` | string/null | order-v3 当前负责定制师 ID。 |
| `consultantDisplayName` | string/null | 卡片首选展示名。 |
| `consultantName` | string/null | 兼容字段，与展示名同口径。 |
| `plannerName` | string/null | 旧字段，继续返回。 |

## 5. 前端必须调整

1. 定制师筛选控件改为可搜索、可清空的下拉，不再使用文本输入框。
2. 下拉 `value=item.adminId`，`label=item.enterpriseWechatName || item.username`。
3. 查询看板时传 `consultantId`，不要把下拉文字传到 `consultantName/plannerName`。
4. 卡片展示定制师读 `consultantDisplayName || consultantName || plannerName`。
5. 卡片展示完整团号读 `teamNo`；搜索框可以直接传用户输入的团号片段。
6. 保留分页组件，并按响应 `total/page/pageSize` 驱动。
7. `adminId/consultantId/orderId` 均按字符串处理，禁止转 JavaScript Number。

## 6. 降级与兼容

- order-v3 正常时，团号和当前负责定制师使用 `order_main` 当前值，因此老派单快照缺字段、订单转单后名称过期的问题已消除。
- order-v3 临时不可用且未传 `consultantId` 时，看板会回退 `fleet_assignment` 本地快照，页面仍可打开。
- order-v3 临时不可用且传了 `consultantId` 时，后端无法可靠确认当前负责人，会返回空记录而不是错误匹配。
- 旧前端继续传 `plannerName/consultantName` 不会立即报错，但应尽快切换到 ID 下拉。

## 7. 测试环境验证

验证网关：`https://api.test.1814.love:9443`，真实角色：`fleet_mgr_4760 / VEHICLE_MANAGER`。

```text
GET /admin/fleet/board/orders?page=1&pageSize=100&teamNo=7218
→ 200；命中 HL20260708144557879；teamNo=26-7218 ✓

GET /admin/fleet/board/orders?page=1&pageSize=100&consultantId=2021059720172838914
→ 200；3 条记录全部 consultantId 精确相等，包含目标订单 ✓

GET /admin/fleet/board/orders?page=1&pageSize=100&teamNo=7218&consultantId=2021059720172838914
→ 200；2 条记录同时满足团号片段与定制师 ID，包含目标订单 ✓

GET /admin/user/customizers
→ 200；21 个下拉项；18 个企微昵称与 username 不同；wx 显示为王骁 ✓

目标订单卡片
→ consultantId=2021059720172838914
→ consultantDisplayName=王骁
→ 与下拉 enterpriseWechatName 完全一致 ✓
```

车务完整回归：121/121 通过，覆盖新建订单、补全出行人/大交通、提交用车需求、派单/确认/取消/换司机/驳回、矩阵、车辆、司机、价格、对账、保险与车管模板。

## 8. 不影响范围

- 不修改前端代码。
- 不改变派单看板现有状态枚举、排序与分页上限。
- 不改变订单详情、派单详情及矩阵派单的既有请求结构。
- 不新增数据库字段，不迁移历史数据。

## 9. 前端验收补充（2026-07-10）

> 前端跟进工单：[wx/hl-ui#5](https://git.1814.love:8443/wx/hl-ui/issues/5)

远端 `hl-ui v2.1` 已接入定制师下拉与 `getConsultantDisplayName()`，但列表卡片仍有条件渲染错误：

- `OrderRowList.vue` 将“定制师”放在 `vehicleAdvice` 区块内。
- 只有客户留言、没有车辆建议时，即使接口已返回 `consultantDisplayName`，卡片仍不会显示定制师。
- 定制师展示必须独立于 `vehicleAdvice/customerNote`：只要 `getConsultantDisplayName(o, '')` 非空，就显示“定制师 {昵称}”。
- 密集表格视图已经独立展示定制师，保持现状即可。

复现订单：

```json
{
  "orderNo": "HL20260708144554930",
  "teamNo": "26-0095",
  "consultantId": "2021059720172838914",
  "consultantDisplayName": "王骁",
  "vehicleAdvice": null,
  "customerNote": "Codex 造数：第 1 笔订单出行人资料已补全"
}
```

预期：列表卡片始终显示“定制师 王骁”。当前未显示属于前端渲染问题，后端字段和网关响应已验证正常。
