Files
2026-07-27 16:46:15 +08:00

383 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 车辆数据开放平台 API
在线文档:
- 简洁中文说明:`/open-api/docs/`
- Swagger UI`/open-api/swagger/`
- OpenAPI 3.0`/open-api/openapi.yaml`
Swagger 的认证信息仅保存在当前页面内存中,页面刷新后清除,不会由平台预填或持久化。
## 模块边界
一期向合作方开放经过预统计的车辆单日用氢量、单日里程和指定时刻总里程,并提供:
- 32 位无连字符 UUID `appKey`
- appKey 启停和起止有效期;
- appKey 下的 VIN 白名单和逐车起止有效期;
- 外部调用审计和管理员变更审计。
外部接口与平台后台登录令牌相互独立。appKey 明文只在创建或轮换时返回一次,数据库仅保存 SHA-256 和前 8 位展示前缀。
## 授权规则
```http
Authorization: Bearer <32appKey>
Content-Type: application/json
```
请求需要同时满足:
1. appKey 状态为 `enabled`,当前调用时间在 Key 有效期内;
2. 查询自然日完整落在 Key 有效期内;
3. 每辆车的授权完整覆盖查询自然日;
4. 车牌能映射到授权 VIN。
任一车辆未授权时整批返回 `403 FORBIDDEN`,不会返回部分结果。单日聚合不开放授权首日或结束日的半日数据。
## 单日用氢量
```http
POST /api/v1/vehicles/hydrogen-consumption/query
```
```json
{
"plateNumbers": ["粤A12345", "粤B67890"],
"date": "2026-07-01"
}
```
`plateNumbers` 可选。省略或传空数组时,返回应用在该自然日有效授权的全部车辆;传入时最多 200 个,不允许空字符串或重复值。`date` 固定为 `yyyy-MM-dd`
查询全部授权车辆:
```json
{
"date": "2026-07-01"
}
```
```json
{
"code": "SUCCESS",
"message": "success",
"data": [
{
"vin": "LNB00000000000001",
"plateNumber": "粤A12345",
"date": "2026-07-01",
"hydrogenConsumptionKg": 12.315,
"status": "NORMAL"
},
{
"plateNumber": "粤B67890",
"date": "2026-07-01",
"hydrogenConsumptionKg": null,
"status": "NO_DATA"
}
],
"traceId": "4ccf63c4e51d4d4ab9107d931783a53e"
}
```
## 单日里程
```http
POST /api/v1/vehicles/mileage/query
```
`date` 和可选 `plateNumbers` 外,里程接口支持可选的 `protocolPriority`
```json
{
"plateNumbers": ["粤A12345"],
"date": "2026-07-01",
"protocolPriority": ["GB32960", "MQTT", "JT808"]
}
```
外部协议值只允许 `GB32960``MQTT``JT808`。传入时数组必须非空、不能重复;每辆车独立按数组顺序选择第一个有效协议,未列出的协议被完全禁用,不能兜底。不传该字段时保持现网默认选源行为。
支持的典型模式包括:`["GB32960","MQTT","JT808"]``["JT808","GB32960","MQTT"]``["GB32960","MQTT"]``["JT808"]`
```json
{
"code": "SUCCESS",
"message": "success",
"data": [
{
"plateNumber": "粤A12345",
"date": "2026-07-01",
"dailyMileageKm": 182.437,
"totalMileageKm": 12345.679,
"dataTime": "2026-07-01T23:58:45+08:00",
"updatedAt": "2026-07-02T05:10:00+08:00",
"sourceProtocol": "GB32960",
"status": "NORMAL"
}
],
"traceId": "b7ff5582ab1a4e13bfb4f10943685599"
}
```
`dailyMileageKm` 表示该自然日行驶里程;`totalMileageKm` 表示同一协议统计记录在该日最后有效时刻的累计总里程;`sourceProtocol` 是该行实际选中的协议;`dataTime` 是统计实际采用的最后一条车辆源数据时间;`updatedAt` 是日统计投影最后更新时间。时间均为带 `+08:00` 的 ISO 8601。
`status=NORMAL` 时数据字段均有值;任一关键字段缺失时整车返回 `NO_DATA`,相关数据字段和 `sourceProtocol` 均为 `null`。真实零日里程返回 `NORMAL``dailyMileageKm: 0`
里程与时间字段始终取自 `sourceProtocol` 指定的同一协议统计记录,不跨协议拼接。内部数据源 `YUTONG_MQTT` 对外统一返回 `MQTT`
当查询日没有任何有效日里程和累计总里程,但查询日前存在有效累计里程时,接口执行前向填充:
- `dailyMileageKm` 返回 `0`
- `totalMileageKm` 沿用此前最近的有效累计总里程;
- `sourceProtocol``dataTime` 沿用该历史统计记录;
- `updatedAt` 返回上一个有效统计周期的计算时间,不伪装成查询日计算时间;
- 只有查询日前也不存在有效累计里程时才返回 `NO_DATA`
## 区间日里程
```http
POST /api/v1/vehicles/mileage/range/query
```
最长支持 366 天。`plateNumbers` 可省略,省略时查询整个区间均有效授权的全部车辆;指定时最多 5,000 个。`pageSize` 为 15,000默认 5,000。
首次请求:
```json
{
"startDate": "2026-07-01",
"endDate": "2026-07-23",
"protocolPriority": ["JT808", "GB32960", "MQTT"],
"pageSize": 5000
}
```
响应:
```json
{
"code": "SUCCESS",
"message": "success",
"data": [
{
"vin": "LNB00000000000001",
"plateNumber": "粤A12345",
"date": "2026-07-01",
"dailyMileageKm": 182.437,
"totalMileageKm": 12345.679,
"dataTime": "2026-07-01T23:58:45+08:00",
"updatedAt": "2026-07-02T05:10:00+08:00",
"sourceProtocol": "JT808",
"status": "NORMAL"
}
],
"snapshotId": "9f8a74efbf9846349ae5676f3a5c0de8",
"nextCursor": null,
"traceId": "4ccf63c4e51d4d4ab9107d931783a53e"
}
```
`protocolPriority` 的校验、选源和缺日前向填充规则与单日接口完全一致,并对区间内每辆车、每个自然日独立执行。有下一页时,保持 `startDate``endDate``plateNumbers``protocolPriority``pageSize` 不变,把上一页 `nextCursor` 放入下一次请求。同一次查询的 `snapshotId` 保持不变。快照有效期为 2 小时。
接口只固化授权车辆清单,不预生成“车辆数 × 天数”的明细;每页读取带复合索引的日统计投影,因此大范围查询不会扫描原始时序明细。
## 指定时刻总里程
```http
POST /api/v1/vehicles/total-mileage/query
```
接口返回“不晚于请求时间的最近一条有效总里程记录”。`time` 使用北京时间,格式必须为 `yyyy-MM-dd HH:mm:ss`
```json
{
"vin": "LA9GG68L2PBAF4790",
"time": "2026-07-21 09:30:00",
"protocol": "GB32960"
}
```
`protocol` 可选,只接受车辆数据中台、接收、统计和开放平台共同使用的唯一规范值:`GB32960``YUTONG_MQTT``JT808`。不再接受 `32960``mqtt``808` 等别名。未指定时严格按以下优先级查找首个有数据的协议:
```text
GB32960 > YUTONG_MQTT > JT808
```
协议总里程含义:
| 协议 | 含义 |
|---|---|
| `GB32960` | 车辆仪表盘累计总里程,对应 GB/T 32960 整车数据累计里程 |
| `YUTONG_MQTT` | 车辆仪表盘或车端控制器累计总里程,由 MQTT 平台上报 |
| `JT808` | 定位终端累计里程,由 GPS/终端侧计算,不等同于车辆仪表盘里程 |
三种协议可能使用不同里程源、标定值和重置机制,不能直接拼接成同一条连续里程曲线。响应会返回实际命中的协议和记录时间,调用方应结合时间差判断记录是否足够新。
```json
{
"code": "SUCCESS",
"message": "success",
"data": {
"vin": "LA9GG68L2PBAF4790",
"queryTime": "2026-07-21 09:30:00",
"totalMileageKm": 12345.678,
"protocol": "GB32960",
"protocolInput": "GB32960",
"mileageMeaning": "车辆仪表盘累计总里程GB/T 32960整车数据累计里程",
"recordTime": "2026-07-21 09:29:45",
"timeDifferenceSeconds": 15,
"selectionPolicy": "GB32960 > YUTONG_MQTT > JT808",
"status": "NORMAL"
},
"traceId": "95bddca78133474fa2bf56ecdf758e22"
}
```
字段说明:
- `recordTime`:实际命中的采集记录时间;
- `timeDifferenceSeconds``queryTime - recordTime`,单位秒,正常为非负数;
- `protocol`:实际采用的采集协议,而不是默认优先级描述;
- `NO_DATA`:授权通过,但所有候选协议在请求时间之前都没有有效总里程。
## 错误码
| HTTP | code | 说明 |
|---:|---|---|
| 400 | `INVALID_REQUEST` | 请求结构、车牌或数量不正确 |
| 400 | `INVALID_DATE_FORMAT` | 日期不是 `yyyy-MM-dd` |
| 400 | `INVALID_DATETIME_FORMAT` | 时间不是 `yyyy-MM-dd HH:mm:ss` |
| 401 | `UNAUTHORIZED` | appKey 不存在、停用或过期 |
| 403 | `FORBIDDEN` | Key 或车辆授权未覆盖查询自然日 |
| 500 | `INTERNAL_ERROR` | 服务内部异常 |
## 管理 API
管理 API 使用车辆数据平台后台 Bearer Token`admin` 可调用。
```http
POST /api/v2/open-platform/apps
GET /api/v2/open-platform/apps
PUT /api/v2/open-platform/apps/{id}
POST /api/v2/open-platform/apps/{id}/rotate-key
GET /api/v2/open-platform/apps/{id}/vehicles
PUT /api/v2/open-platform/apps/{id}/vehicles
GET /api/v2/open-platform/users
POST /api/v2/open-platform/users
PUT /api/v2/open-platform/users/{id}
GET /api/v2/open-platform/users/{id}/apps
PUT /api/v2/open-platform/users/{id}/apps
```
创建应用:
```json
{
"name": "示例合作方",
"status": "enabled",
"validFrom": "2026-07-01T00:00:00+08:00",
"validTo": "2027-07-01T00:00:00+08:00"
}
```
创建和轮换响应中的 `data.appKey` 是唯一一次明文交付机会。轮换后旧 Key 立即失效。
车辆授权 `PUT` 使用完整替换语义,单次最多 5000 辆:
```json
{
"vehicles": [
{
"vin": "LTEST32960VIN0001",
"validFrom": "2026-07-01T00:00:00+08:00",
"validTo": "2027-07-01T00:00:00+08:00"
}
]
}
```
VIN 必须已存在于平台身份绑定表。
管理员可以从车辆目录按 VIN、车牌或品牌搜索并勾选也可以批量粘贴 VIN
或车牌自动匹配,或者一次选择当前车辆主数据中的全部车辆。批量匹配会报告
未识别项,不会静默忽略。“全部车辆”是保存时点的车辆快照,不会自动包含
以后新增的车辆。
管理端可通过下列接口读取可授权车辆目录:
```http
GET /portal-api/admin/vehicles
Authorization: Bearer <admin-token>
```
合作伙伴用户可配置账号有效期,并通过 `owner``developer``viewer`
角色绑定一个或多个应用。密码至少 12 位且必须同时包含大小写字母和数字。
连续 5 次登录失败后账号锁定 15 分钟。
内部车辆平台中启用的本地 `admin` 账号可使用同一用户名和密码登录开放平台。
开放平台校验内部密码哈希后签发独立会话,不复制密码,也不共享两个域名的
浏览器 Token。管理员可在“平台管理”中创建开放应用、合作伙伴账号并配置
车辆与授权有效期。
## 合作伙伴门户
独立开放平台默认监听 `20310`,不再与内部平台 `20300` 共用外部 HTTP
入口。门户 API 使用短期会话 Token数据 API 仍使用应用的 32 位 AppKey。
```http
POST /portal-api/auth/login
POST /portal-api/auth/logout
GET /portal-api/session
GET /portal-api/catalog
GET /portal-api/apps
GET /portal-api/apps/{id}/vehicles
GET /portal-api/apps/{id}/audit
POST /portal-api/apps/{id}/rotate-key
PUT /portal-api/account/password
```
只有应用 `owner` 可以在门户轮换 AppKey新 Key 仍只显示一次。门户登录、
密码修改、用户配置和密钥操作均写入审计表。
## 用氢量统计
当天数据由 `vehicle-stat-writer` 直接消费 GB32960 fields Kafka 流,统一采用压力法:
```text
剩余氢量 kg = NIST氢气密度(最高氢压 MPa, 最高氢温 ℃) × 车型氢瓶容量 L / 1000
```
- 不使用广东扩展直接上报的剩余氢量、飞驰剩余百分比或百公里氢耗推算质量;
- `vehicle-stat-writer` 每六小时从 `ln_asset_management.vehicle_info → vehicle_model.tank_capacity` 同步 VIN 容积到本地 `vehicle_hydrogen_tank_capacity`
- 同步完成后一次性加载到进程内存高频帧计算不访问资产库、Redis或MySQL缺少VIN容积时拒绝生成氢量
- 压力法使用 NIST 实氢气密度方程,允许 070 MPa、2201000 K 的输入范围。
每个有效样本在同一个 MySQL 事务中更新
`vehicle_open_hydrogen_stream_state`,并投影到
`vehicle_open_daily_energy`。Kafka offset 只在事务提交成功后提交,因此服务重启或消息重放不会重复累计。状态按
`VIN + 日期 + source_endpoint` 保存,每条消息只做常数次数据库操作,不扫描当天历史数据。
统计规则:
- 先按 VIN 和 `source_endpoint` 分别统计,避免多个采集源的序列交错产生虚假变化;
- 同一 VIN 优先采用质量正常、样本数量更多的数据源,并记录入库;
- 每次加氢之间维护质量低水位,只累计新的有效最低质量,避免压力温度波动反复计量;
- 抖动阈值按该VIN容积对应的 `0.2 MPa` 质量变化动态计算,最小 `0.05 kg`、最大 `1 kg`
- 质量相对本轮低水位上升超过 `max(1 kg, 当前质量×5%)` 时识别为加氢并重置低水位;
- 单次下降超过 `OPEN_STAT_HYDROGEN_MAX_DROP_KG` 时过滤并标记 `SUSPECT`,默认 `20 kg`
- 至少两条有效样本才标记 `OK`
- 对外只返回 `quality_status=OK` 的结果。
当天接口结果是准实时的进行中累计值。乱序、重复和迟到样本不会覆盖更新的状态;跨日迟到数据由
`open-platform-stat` 夜间批处理兜底。批处理默认重算昨天和前天,以修正迟到上报,并作为已结束日期的权威结果。
```bash
/opt/lingniu-vehicle-platform/current/open-platform-stat \
-date 2026-07-01 \
-lookback-days 1
systemctl enable --now lingniu-vehicle-open-stat.timer
```