# 【接口新增·管理后台】车管「证件到期看板」上线（GET /admin/fleet/board/expiry）

> 服务：hl-fleet-service ｜ 分支：dev-v3 ｜ PR：#4160 ｜ 工单：#4159
> 已部署测试服 + 9443 真 token API 实测全通过（基础调用 + kinds/buckets/keyword 筛选 + counts 全量不随筛选变，含真实数据，2026-06-21）

## ⚠️ 关键说明

1. **用途**：车管控制台「证件到期 / 到期提醒中心」聚合页（原型 `page_expiry`）数据源——一次查询聚合**四类证件到期**，按剩余天数分桶，供 KPI 卡 + 列表渲染。**纯查询、零写、无业务错误码。**
2. 路径 `GET /admin/fleet/board/expiry`，需 admin 登录（网关 `/admin/fleet/**` 已覆盖，无新增路由）。
3. **四类到期 kind**：`inspect`（车辆年检）/ `vehInsure`（车辆保险）/ `license`（司机驾照）/ `driverInsure`（司机年度保险，仅年保司机有）。
4. **司机赛季 gate**：司机两类（license / driverInsure）仅纳入在岗司机（season=active/pending），已离队 / 黑名单司机排除；车辆两类无此限制（软删车自然排除）。

## 1. 入参（query · 均可选）

| 参数 | 类型 | 说明 |
|---|---|---|
| kinds | string[] | 类型多选 `inspect`/`vehInsure`/`license`/`driverInsure`，任一命中即返；空=四类全返 |
| buckets | string[] | 桶多选 `expired`/`urgent`/`soon`/`watch`/`ok`，任一命中即返；空=全部桶。**建议默认取 expired+urgent+soon+watch（不含 ok），需正常项再传 ok** |
| keyword | string | 模糊搜车牌 / 司机姓名（匹配 title 或 sub，大小写不敏感）|

> 多选参数传法：`?kinds=license&kinds=driverInsure` 或 `?buckets=expired&buckets=urgent`。

## 2. 出参

- `data.counts`：各桶计数 `{expired, urgent, soon, watch, ok, total}`，**全量·不随 kinds/buckets/keyword 筛选变化**（供 KPI 卡固定展示，total=各桶之和=四类到期项总数）。
- `data.list`：筛选后明细数组，**排序固定**=桶优先级 `expired→urgent→soon→watch→ok` 升序、组内 `daysLeft` 升序（最紧急 / 过期最久在最前）。无数据 counts 全 0、list 返空数组。

`list` 项字段：

| 字段 | 说明 |
|---|---|
| id | 列表 key，`{targetId}::{kind}`（如 `蒙A-20221::vehInsure`）|
| kind | 到期类型（见上 4 值）|
| target | 实体域：`vehicle` / `driver` |
| targetId | 车=车牌 plate / 司机=driverId |
| title | 车=车牌 / 司机=姓名 |
| sub | 车=`车型 · 车队`；司机驾照=`脱敏手机 · 准驾车型 驾照`；司机年险=`脱敏手机 · ¥年保费/年`（手机脱敏）|
| expiryField | 到期字段名（inspect_due / insure_due / license_expire / insurance_annual_end）|
| expiryDate | 到期日 `YYYY-MM-DD` |
| daysLeft | 剩余天数（负=已过期 N 天）|
| bucket | 所属桶（见下分桶口径）|

## 3. 分桶口径

`daysLeft = 到期日 − 今天`：`expired`(<0 已过期) / `urgent`(0-30) / `soon`(31-60) / `watch`(61-90) / `ok`(>90)。颜色 / 桶标签由前端渲染，后端只给 `bucket` + `daysLeft`。

## 4. 真实请求 / 响应（测试服实测节选）

```bash
curl -k "https://api.test.1814.love:9443/admin/fleet/board/expiry" \
  -H "Authorization: Bearer <admin token>"
```

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "counts": {"expired": 3, "urgent": 4, "soon": 1, "watch": 1, "ok": 48, "total": 57},
    "list": [
      {"id":"2067084362829979650::license","kind":"license","target":"driver",
       "targetId":"2067084362829979650","title":"王信","sub":"185****2756 · C1 驾照",
       "expiryField":"license_expire","expiryDate":"2022-02-05","daysLeft":-1597,"bucket":"expired"},
      {"id":"2065272148229865473::driverInsure","kind":"driverInsure","target":"driver",
       "targetId":"2065272148229865473","title":"恩克","sub":"135****5010 · ¥2/年",
       "expiryField":"insurance_annual_end","expiryDate":"2026-06-20","daysLeft":-1,"bucket":"expired"}
    ]
  }
}
```

筛选示例（counts 恒为全量 57，仅 list 变化）：

```bash
# 仅驾照类
curl -k ".../admin/fleet/board/expiry?kinds=license" -H "Authorization: Bearer <token>"
# 仅已过期桶（list=3，=counts.expired）
curl -k ".../admin/fleet/board/expiry?buckets=expired" -H "Authorization: Bearer <token>"
# 关键词搜司机姓名（中文需 URL 编码）
curl -k ".../admin/fleet/board/expiry?keyword=%E7%8E%8B" -H "Authorization: Bearer <token>"
```

## 前端动作（车管控制台）

1. 「证件到期 / 到期提醒中心」页对接本接口：KPI 卡读 `data.counts`（5 桶固定计数），列表读 `data.list`（已排好序，前端按 bucket 上色即可）。
2. 顶部筛选：类型多选传 `kinds`、紧急度多选传 `buckets`、搜索框传 `keyword`；**`counts` 是全量固定值不随筛选变，别用 list 长度反推 KPI**。
3. 列表项颜色 / 「已过期 N 天」「N 天后到期」文案前端按 `bucket` + `daysLeft` 渲染。
