Add monitoring metrics, numeric sorting, report-time display, vehicle number labels, and map layout fixes. Include accumulated mileage, hydrogen, OneOS authentication, open platform, ingestion, deployment, and UI updates. Exclude temporary files, generated reports, and credentials. Validate frontend 632 tests and production build, API packages, vehicle-map tests, and release installer tests. Gateway suite has one pre-existing date-sensitive identity throttling test failure reproduced on the parent commit.
521 lines
102 KiB
HTML
521 lines
102 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>羚牛 · 车辆数据开放平台</title>
|
||
<style>
|
||
:root{color-scheme:light;--page:#f5f5f7;--surface:#fff;--ink:#1d1d1f;--muted:#6e6e73;--line:rgba(0,0,0,.10);--blue:#0071e3;--blue-soft:#e8f2ff;--green:#007a46;--code:#1d1d1f;--radius:18px;--sidebar:264px}
|
||
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;font:15px/1.58 -apple-system,BlinkMacSystemFont,"SF Pro Text","PingFang SC","Microsoft YaHei",sans-serif;color:var(--ink);background:var(--page);-webkit-font-smoothing:antialiased}
|
||
a{color:inherit;text-decoration:none}.layout{min-height:100vh;display:grid;grid-template-columns:var(--sidebar) minmax(0,1fr)}
|
||
.sidebar{position:sticky;top:0;height:100vh;padding:26px 14px 20px;border-right:1px solid var(--line);background:rgba(255,255,255,.84);backdrop-filter:blur(18px);overflow-y:auto}.brand{display:block;padding:7px 11px 27px}.brand-name{display:block;font-size:17px;font-weight:650;letter-spacing:-.02em}.brand-subtitle{display:block;margin-top:3px;color:var(--muted);font-size:12px}
|
||
.nav-group{padding:15px 0 5px;border-top:1px solid var(--line)}.nav-group:first-of-type{border-top:0;padding-top:0}.nav-title{display:block;padding:0 11px 7px;color:var(--muted);font-size:12px;font-weight:600}.nav-link{display:flex;align-items:center;gap:10px;margin:2px 0;padding:8px 11px;border-radius:9px;color:#424245;font-size:14px}.nav-link:hover{color:var(--blue);background:#f3f7fc}.nav-link::before{content:"";width:5px;height:5px;border-radius:50%;background:#c7c7cc;flex:0 0 auto}.nav-link.primary::before{background:var(--blue)}.nav-link.station::before{background:var(--green)}.nav-link.docs::before{width:6px;height:6px;border-radius:2px;background:#8e8e93}.external{display:inline-flex;align-items:center;gap:8px;margin:22px 11px 0;padding:9px 10px;color:var(--blue);font-size:13px;font-weight:550}.external svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:1.8}
|
||
.content{max-width:1200px;width:100%;padding:48px 56px 96px}.intro{padding:0 0 34px;border-bottom:1px solid var(--line)}h1{margin:0;letter-spacing:-.04em;font-size:40px;line-height:1.15;font-weight:680}.intro p{max-width:720px;margin:13px 0 0;color:var(--muted);font-size:16px}.base-url{display:inline-flex;gap:8px;align-items:center;margin-top:21px;padding:8px 11px;border:1px solid var(--line);border-radius:9px;background:var(--surface);font:12px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--muted)}.base-url code{color:var(--blue)}
|
||
.section{scroll-margin-top:26px;padding:36px 0;border-bottom:1px solid var(--line)}.section:target{margin:0 -18px;padding-right:18px;padding-left:18px;border-radius:var(--radius);background:rgba(0,113,227,.035);border-bottom-color:transparent}.section:last-child{border-bottom:0}.section-head{display:flex;align-items:flex-start;justify-content:space-between;gap:20px}.section h2{margin:0;font-size:24px;letter-spacing:-.025em;line-height:1.25}.section p{margin:8px 0 0;color:var(--muted)}.endpoint{display:inline-flex;align-items:center;gap:8px;margin-top:15px;font:13px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;color:#38383a}.method{padding:4px 7px;border-radius:6px;background:#e4f5eb;color:var(--green);font:700 11px/1 -apple-system,BlinkMacSystemFont,"SF Pro Text",sans-serif;letter-spacing:.04em}.anchor{margin-top:4px;color:#8e8e93;font-size:12px}.anchor:hover{color:var(--blue)}
|
||
.grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(300px,.92fr);gap:34px;margin-top:23px}.subhead{margin:0 0 9px;font-size:13px;font-weight:650;color:#3a3a3c}.param-table{width:100%;border-collapse:collapse;font-size:13px}.param-table th,.param-table td{padding:10px 8px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}.param-table th{color:var(--muted);font-weight:500}.param-table td:first-child{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:#303033}.required{color:var(--green);font-size:12px}.optional{color:var(--muted);font-size:12px}.code{margin:0;overflow:auto;padding:15px;border-radius:12px;background:var(--code);color:#f5f5f7;font:12px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;white-space:pre}.code .key{color:#82b9ff}.code .number{color:#a8d5a2}.code .string{color:#f5cc88}.note{margin:14px 0 0;padding:11px 12px;border-left:2px solid var(--blue);background:#f4f8fd;color:#59595d;font-size:13px}.note strong{color:#303033}.errors{margin:14px 0 0;padding:0;color:#59595d;font-size:13px;list-style:none}.errors li{position:relative;padding:3px 0 3px 13px}.errors li::before{content:"";position:absolute;top:11px;left:0;width:4px;height:4px;border-radius:50%;background:#ff9f0a}.empty{margin-top:16px;color:var(--muted);font-size:13px}.field-tabs{display:flex;gap:4px;margin:0 0 14px;padding:3px;width:max-content;border-radius:9px;background:#ececf1}.field-tab{appearance:none;border:0;border-radius:7px;padding:7px 10px;background:transparent;color:#6e6e73;font:600 12px/1 -apple-system,BlinkMacSystemFont,"SF Pro Text",sans-serif;cursor:pointer}.field-tab[aria-selected="true"]{background:#fff;color:#1d1d1f;box-shadow:0 1px 3px rgba(0,0,0,.12)}.response-panel{display:none}.response-panel.active{display:block}.response-caption{margin:0 0 9px;color:var(--muted);font-size:12px}.response-table th:nth-child(1){width:31%}.response-table th:nth-child(2){width:17%}.response-table td:nth-child(2){color:#6e6e73;font:12px ui-monospace,SFMono-Regular,Menlo,monospace}.response-table td:nth-child(3){color:#4b4b4f}.tree-field{display:flex;align-items:center;gap:6px;min-height:20px;white-space:nowrap}.tree-field.depth-1{padding-left:14px}.tree-field.depth-2{padding-left:31px}.tree-field.depth-3{padding-left:48px}.tree-branch{width:9px;height:16px;border-left:1px solid #c7c7cc;border-bottom:1px solid #c7c7cc;border-radius:0 0 0 3px}.tree-root{display:inline-flex;align-items:center;gap:5px;font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text",sans-serif;font-size:12px;font-weight:650;color:#303033}.tree-root::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--blue)}.tree-node{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:#303033}.tree-kind{display:inline-block;margin-left:5px;padding:1px 5px;border-radius:5px;background:#f0f1f4;color:#6e6e73;font:10px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace}.enum-value{display:inline-block;margin:2px 3px 2px 0;padding:2px 5px;border-radius:5px;background:#f1f6fd;color:#1665b5;font:11px ui-monospace,SFMono-Regular,Menlo,monospace}
|
||
.auth{margin-top:20px;padding:17px 18px;border:1px solid var(--line);border-radius:14px;background:var(--surface)}.auth code{display:block;margin-top:8px;color:#38383a;font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace}.protocol-table{width:100%;margin-top:18px;border-collapse:collapse}.protocol-table th,.protocol-table td{padding:12px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}.protocol-table th{color:var(--muted);font-size:13px;font-weight:500}.protocol-table td:first-child{width:170px;font:12px ui-monospace,SFMono-Regular,Menlo,monospace}.error-table{margin-top:18px}.request-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;margin-top:21px}.request-sample{padding:15px;border:1px solid var(--line);border-radius:14px;background:var(--surface)}.request-sample h3{margin:0 0 6px;font-size:13px;font-weight:650}.request-sample .endpoint{margin:0 0 11px;font-size:11px}.request-sample .code{padding:12px;border-radius:9px;font-size:11px}@media(max-width:680px){.request-grid{grid-template-columns:1fr}.request-sample{padding:13px}}
|
||
@media(max-width:900px){:root{--sidebar:218px}.content{padding:42px 34px 76px}.grid{grid-template-columns:1fr;gap:22px}}
|
||
@media(max-width:680px){body{background:var(--surface)}.layout{display:block}.sidebar{z-index:3;display:flex;align-items:center;gap:0;position:sticky;width:100%;height:auto;padding:0 12px;border-right:0;border-bottom:1px solid var(--line);overflow-x:auto;overflow-y:hidden;white-space:nowrap;background:rgba(255,255,255,.92)}.brand{padding:13px 10px 13px 0}.brand-name{font-size:14px}.brand-subtitle,.nav-title{display:none}.nav-group{display:contents;border:0;padding:0}.nav-link{margin:0;padding:13px 9px;font-size:13px}.nav-link::before{display:none}.external{display:none}.content{padding:31px 20px 64px}.intro{padding-bottom:27px}h1{font-size:31px}.intro p{font-size:15px}.section{padding:31px 0;scroll-margin-top:54px}.section:target{margin:0 -8px;padding-right:8px;padding-left:8px}.section-head{gap:9px}.section h2{font-size:21px}.anchor{display:none}.grid{margin-top:19px}.param-table th,.param-table td{padding:9px 5px}.param-table th:nth-child(2),.param-table td:nth-child(2){width:47px}.base-url{max-width:100%;overflow:auto}.code{font-size:11px}}
|
||
|
||
.content{min-width:0}.operating-subsection{margin-top:28px}.operating-subsection h3{margin:0 0 12px;font-size:18px}.operating-subsection h4{margin:20px 0 10px;font-size:14px}.operating-subsection .code{margin:12px 0}.operating-table-scroll{overflow-x:auto;margin:14px 0}.operating-table-scroll .param-table{min-width:620px}.operating-subsection .param-table td:first-child{overflow-wrap:anywhere;max-width:270px}.operating-list{padding-left:22px;color:#59595d}.operating-list li{margin:9px 0}.operating-subsection details{margin:14px 0}.operating-subsection summary{cursor:pointer;font-size:14px;font-weight:600;color:var(--blue);padding:8px 0}.operating-endpoint{display:block;line-height:1.8;overflow-wrap:anywhere;word-break:break-word}.operating-status{display:block;padding:12px 14px;border-left:3px solid var(--blue);background:var(--blue-soft);color:#34506e;font-size:13px;margin-top:18px}
|
||
@media print{body{background:#fff;font-size:10pt}.layout{display:block}.sidebar{display:none}.content{padding:0;max-width:none}.section{border:0;padding:12px 0}.operating-table-scroll{overflow:visible}.operating-table-scroll .param-table{min-width:0;font-size:8pt}.operating-subsection h3{break-after:avoid}tr{break-inside:avoid}.code{white-space:pre-wrap;overflow-wrap:anywhere;background:#f2f3f5;color:#1d1d1f;font-size:8pt}.operating-list{color:#303033}details:not([open]){display:none}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="layout">
|
||
<aside class="sidebar" aria-label="接口导航">
|
||
<a class="brand" href="#overview"><span class="brand-name">羚牛 · 数据开放平台</span><span class="brand-subtitle">车辆数据 API Reference</span></a>
|
||
<nav>
|
||
<div class="nav-group"><span class="nav-title">开始使用</span><a class="nav-link docs" href="#overview">平台简介</a><a class="nav-link docs" href="#authentication">认证与授权</a><a class="nav-link docs" href="#request-examples">请求体样例</a></div>
|
||
<div class="nav-group"><span class="nav-title">车辆数据</span><a class="nav-link primary" href="#operating-data">综合运营数据</a><a class="nav-link primary" href="#daily-hydrogen">车辆单日用氢量</a><a class="nav-link primary" href="#historical-hydrogen">历史剩余氢质量</a><a class="nav-link primary" href="#daily-mileage">车辆单日里程</a><a class="nav-link primary" href="#mileage-range">车辆区间日里程</a><a class="nav-link primary" href="#total-mileage">指定时刻总里程</a><a class="nav-link primary" href="#realtime">实时位置与状态</a></div>
|
||
<div class="nav-group"><span class="nav-title">加氢服务</span><a class="nav-link station" href="#stationary">加氢车辆停留核验</a><a class="nav-link station" href="#stations">加氢站地图点位</a></div>
|
||
<div class="nav-group"><span class="nav-title">通用说明</span><a class="nav-link docs" href="#response-fields">返回字段与枚举</a><a class="nav-link docs" href="#protocols">总里程协议口径</a><a class="nav-link docs" href="#errors">异常与状态码</a></div>
|
||
</nav>
|
||
<a class="external" href="/open-api/swagger/">Swagger 在线调试 <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M6 3h7v7M13 3 6.5 9.5M12 9.5V13H3V4h3.5"/></svg></a>
|
||
</aside>
|
||
<main class="content">
|
||
<header class="intro" id="overview">
|
||
<h1>接口文档</h1>
|
||
<p>面向合作方开放车辆用氢量、里程、实时状态及加氢车辆停留核验数据。每个接口独立说明请求参数、成功返回与异常情况。</p>
|
||
<span class="base-url">Base URL <code>https://open.d.lnoneos.com</code></span>
|
||
</header>
|
||
|
||
<section class="section" id="authentication"><div class="section-head"><div><h2>认证与授权</h2><p>所有接口均使用平台管理员签发的 32 位 appKey。appKey 有效期及车辆授权期必须完整覆盖查询时间。</p></div><a class="anchor" href="#authentication">#</a></div><div class="auth"><strong>请求头</strong><code>Authorization: Bearer <YOUR_APP_KEY><br>Content-Type: application/json</code></div><div class="note"><strong>授权边界:</strong>车牌是否可省略以各接口参数表为准;综合运营查询车牌可选,省略或空数组返回所选时间范围内均有效授权的全部车辆,不受 200 辆限制;显式指定车牌最多 200 项。日统计授权覆盖查询自然日,实时授权覆盖请求时点,综合查询先校验全部所选范围。综合查询返回紧凑 JSON;下方示例已格式化。</div></section>
|
||
|
||
<section class="section" id="request-examples"><div class="section-head"><div><h2>请求体样例</h2><p>所有接口使用 <code>Content-Type: application/json</code>。以下 JSON 可直接复制;未列出的可选字段可省略。</p></div><a class="anchor" href="#request-examples">#</a></div><div class="request-grid"><article class="request-sample"><h3>综合运营数据</h3><div class="endpoint">/vehicles/operating-data/query</div><pre class="code" data-language="json">{
|
||
"dailyDate": "2026-10-23",
|
||
"plateNumbers": [
|
||
"粤A09635F"
|
||
],
|
||
"dataTypes": [
|
||
"REALTIME",
|
||
"DAILY_MILEAGE",
|
||
"DAILY_HYDROGEN"
|
||
],
|
||
"protocolPriority": [
|
||
"GB32960",
|
||
"MQTT",
|
||
"JT808"
|
||
]
|
||
}</pre></article><article class="request-sample"><h3>车辆单日用氢量</h3><div class="endpoint">/vehicles/hydrogen-consumption/query</div><pre class="code">{
|
||
"date": "2026-08-06",
|
||
"plateNumbers": ["浙F06618F"]
|
||
}</pre></article><article class="request-sample"><h3>车辆单日里程</h3><div class="endpoint">/vehicles/mileage/query</div><pre class="code">{
|
||
"date": "2026-08-06",
|
||
"plateNumbers": ["浙F06618F"],
|
||
"protocolPriority": ["GB32960", "MQTT", "JT808"]
|
||
}</pre></article><article class="request-sample"><h3>车辆区间日里程</h3><div class="endpoint">/vehicles/mileage/range/query</div><pre class="code">{
|
||
"startDate": "2026-08-01",
|
||
"endDate": "2026-08-06",
|
||
"pageSize": 100
|
||
}</pre></article><article class="request-sample"><h3>指定时刻总里程</h3><div class="endpoint">/vehicles/total-mileage/query</div><pre class="code">{
|
||
"vin": "LA9GG68L2PBAF4790",
|
||
"time": "2026-08-06 10:30:00",
|
||
"protocol": "GB32960"
|
||
}</pre></article><article class="request-sample"><h3>实时位置与状态</h3><div class="endpoint">/vehicles/realtime/query</div><pre class="code">{
|
||
"plateNumbers": ["浙F06618F"]
|
||
}</pre></article><article class="request-sample"><h3>加氢车辆停留核验</h3><div class="endpoint">/vehicles/stationary/query</div><pre class="code">{
|
||
"startTime": "2026-08-06 10:00:00",
|
||
"endTime": "2026-08-06 12:00:00",
|
||
"longitude": 120.752312,
|
||
"latitude": 30.746281,
|
||
"coordinateSystem": "GCJ02",
|
||
"radiusMeters": 8
|
||
}</pre></article><article class="request-sample"><h3>加氢站地图点位</h3><div class="endpoint">/hydrogen-stations/query</div><pre class="code">{
|
||
"province": "浙江省",
|
||
"city": "嘉兴市",
|
||
"cooperateOnly": true
|
||
}</pre></article></div></section>
|
||
|
||
<section class="section" id="historical-hydrogen"><div class="section-head"><div><h2>历史时刻剩余氢质量 · 1.10.0</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/hydrogen-remaining/history/query</div><p>仅查询2026-08-01起的真实历史 event_time,不使用未来采样、实时值或日用氢量填补。最近氢相关帧异常或字段不全时显式返回,不跳过它找旧正常值。</p></div><a class="anchor" href="#historical-hydrogen">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>queries</td><td>是</td><td>1–200项</td></tr><tr><td>queries[].requestId</td><td>是</td><td>本批唯一非空,最多128字节,原样回显</td></tr><tr><td>queries[].vin / time</td><td>是</td><td>VIN规范化大写17位且不含I/O/Q;北京时间yyyy-MM-dd HH:mm:ss,不可未来或早于2026-08-01</td></tr><tr><td>queries[].protocol</td><td>否</td><td>GB32960 / YUTONG_MQTT / JT808;省略固定GB32960,后两者当前UNSUPPORTED,不跨协议回退</td></tr><tr><td>maxTimeDifferenceSeconds</td><td>否</td><td>整数0–300,默认300;0要求精确命中</td></tr></table><div class="note">应用与逐车授权需同时覆盖查询时刻和采样时刻(结束时间不含端点);FORBIDDEN不泄露采样元数据。当前appKey无效/过期为401,非法结构400。</div></div><div><h3 class="subhead">请求示例(非真实读数)</h3><pre class="code">{
|
||
"queries": [{
|
||
"requestId": "job-start",
|
||
"vin": "LA9GG68L2PBAF4773",
|
||
"time": "2026-08-03 16:02:43",
|
||
"protocol": "GB32960"
|
||
}],
|
||
"maxTimeDifferenceSeconds": 300
|
||
}</pre><p>合法批量HTTP200/SUCCESS,逐项状态判断:NORMAL、NO_DATA、MISSING、STALE、UNSUPPORTED、INVALID、FORBIDDEN、ERROR。非NORMAL质量null,不丢项,不补零。</p><p>每app每实例30批/60秒,最多2个并发批;429读取Retry-After秒后重试。整批9秒预算、4个工作协程,超时项ERROR而不是NO_DATA。200项是结构上限,不保证200个不同点均能按时完成;建议从20个不同点开始,超时缩小批量并退避重试。</p></div></div><div class="note">历史容量需要历史适用版本;当前表不能回套历史。当前只有REPORTED质量可用,缺历史容量版本时不估算,返回MISSING。同批按规范化VIN+time+protocol去重,同点共享单次查询/授权结果和来源版本,所有requestId独立回显;不同点仍是非原子快照,保留各项版本和原始证据。质量保留原精度,Seeker自行计算两端净减少量并在负差值时归零。</div></section>
|
||
|
||
<section class="section" id="operating-data"><div class="section-head"><div><h2>车辆综合运营数据批量查询</h2><div class="endpoint operating-endpoint"><span class="method">POST</span> /api/v1/vehicles/operating-data/query</div><p>文档 V1.5 · OpenAPI 1.12.2 · 2026-10-26 · 随当前服务版本发布</p></div><a class="anchor" href="#operating-data">#</a></div><p>一次请求按需返回实时、单日里程及单日用氢。SIMPLE模式固定9字段;默认FULL保留完整来源、质量及时间。两种模式共用授权和批量查询,不增加数据库查询,不表示共同快照。</p><article class="operating-subsection" id="operating-data-simple"><h3>精简模式 SIMPLE · 固定 9 字段</h3><p>请求显式增加 <code>responseMode: "SIMPLE"</code>。省略或传 FULL 保留已上线完整响应。外层字段保持一致,data 每辆车仅返回下表9项,未知或未选字段显式 null。</p><pre class="code" data-language="json">{
|
||
"responseMode": "SIMPLE",
|
||
"dailyDate": "2026-10-23",
|
||
"plateNumbers": [
|
||
"沪A01933F"
|
||
]
|
||
}</pre><div class="operating-table-scroll"><table class="param-table"><tr><th>字段</th><th>类型</th><th>返回规则</th></tr><tr><td>plateNumber</td><td>string</td><td>规范化后的请求车牌,保持请求顺序。</td></tr><tr><td>reportTime</td><td>string | null</td><td>实时选中主记录的event_time,真实源采集/上报时刻;缺失为null,不使用平台接收、投影更新或请求时间替代。FULL recordTime保持原兼容口径。</td></tr><tr><td>offline</td><td>boolean | null</td><td>主实时记录可用且online已知时取反;无记录或查询失败为null,不能当成离线。</td></tr><tr><td>remainingHydrogenKg</td><td>number | null</td><td>剩余氢量kg。仅kg字段NORMAL、数值有效且有可信采集时间,响应时不超过300秒并不晚于服务时点1分钟时展示;陈旧/缺失/异常为null,真实0保留。</td></tr><tr><td>socPercent</td><td>number | null</td><td>动力电池SOC百分比;实时主记录有效且数值在0–100内,未知为null。</td></tr><tr><td>totalMileageKm</td><td>number | null</td><td>实时主记录累计里程km;不使用日统计累计值兜底。</td></tr><tr><td>dailyHydrogenConsumptionKg</td><td>number | null</td><td>queryDate用氢量kg;子查询成功、status=NORMAL、qualityStatus=OK时返回有效非负数值,否则null。日内值可为PRELIMINARY,不保证终报。</td></tr><tr><td>dailyMileageKm</td><td>number | null</td><td>queryDate里程km;执行成功、业务NORMAL且非CARRIED_FORWARD时返回有效非负数值;实测零保留,结转补零和异常为null。</td></tr><tr><td>hydrogenConsumptionPer100KmKg</td><td>number | null</td><td>kg/100km预留字段;当前缺少可比区间完整证据,固定null,不参与summary计数。禁止调用方以同日日指标直接相除。</td></tr></table></div><h4>精简响应示例(合成数据)</h4><pre class="code" data-language="json">{
|
||
"code": "SUCCESS",
|
||
"message": "success",
|
||
"traceId": "f924a83d8a93475bac26b054305fc427",
|
||
"queryDate": "2026-10-23",
|
||
"timezone": "Asia/Shanghai",
|
||
"requestAt": "2026-10-23T12:00:00+08:00",
|
||
"generatedAt": "2026-10-23T12:00:01+08:00",
|
||
"data": [
|
||
{
|
||
"plateNumber": "沪A01933F",
|
||
"reportTime": "2026-10-23T11:59:30+08:00",
|
||
"offline": false,
|
||
"remainingHydrogenKg": 16,
|
||
"socPercent": 78.8,
|
||
"totalMileageKm": 80707,
|
||
"dailyHydrogenConsumptionKg": 4.003,
|
||
"dailyMileageKm": 128,
|
||
"hydrogenConsumptionPer100KmKg": null
|
||
}
|
||
],
|
||
"summary": {
|
||
"requestedCount": 1,
|
||
"returnedCount": 1,
|
||
"successCount": 1,
|
||
"partialSuccessCount": 0,
|
||
"failedCount": 0
|
||
}
|
||
}</pre><div class="note"><strong>summary:</strong>仅统计所选类型的展示字段:实时5项、日里程1项、日用氢1项。全部有值计入successCount;部分有值计入partialSuccessCount;全部为空计入failedCount。车牌与预留百公里氢耗不参与;未选类型也不参与。真实0、offline=false均为有效值。null及failedCount不能直接作为自动重试依据。FULL模式原有执行统计不变。</div><p>离线不触发缓存或历史兜底;最新主记录自带reportTime,在线状态不决定SOC和总里程是否存在。剩余氢量额外执行300秒时效门槛。任何源失败只影响对应字段,不能把offline未知写成true。</p><p>当前没有可证明可比区间的正式百公里氢耗算法,因此hydrogenConsumptionPer100KmKg固定null。不能因为同一天有氢量和里程就自行相除。日内用氢可能是初步统计,正式对账继续使用FULL查询质量、阶段和来源。</p></article><article class="operating-subsection" id="operating-data-request"><h3>请求参数</h3><pre class="code" data-language="json">{
|
||
"dailyDate": "2026-10-23",
|
||
"plateNumbers": [
|
||
"粤A09635F"
|
||
],
|
||
"dataTypes": [
|
||
"REALTIME",
|
||
"DAILY_MILEAGE",
|
||
"DAILY_HYDROGEN"
|
||
],
|
||
"protocolPriority": [
|
||
"GB32960",
|
||
"MQTT",
|
||
"JT808"
|
||
]
|
||
}</pre><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>参数</th><th>必填</th><th>规则</th></tr></thead><tbody><tr><td>responseMode</td><td>否</td><td>FULL / SIMPLE;省略默认FULL,显式空字符串或null不合法。SIMPLE返回固定9字段,未选类型字段也为null。</td></tr><tr><td>plateNumbers</td><td>否</td><td>省略或传空数组时查询所选时间范围内均有效授权的全部车辆,按车牌排序;无有效授权车辆返回空数组。省略或空数组不受 200 辆限制,不分页、不截断;显式指定最多 200 项,超出返回 HTTP 400 / BATCH_SIZE_EXCEEDED。指定时每项为字符串,去首尾空白、转大写后非空、最多 32 个 Unicode 字符;不允许重复。</td></tr><tr><td>dailyDate</td><td>条件必填</td><td>选择任一日统计时必填,严格 yyyy-MM-dd,不晚于北京时间当日。仅实时可省略;若提供仍校验,但不影响实时选源或实时授权,queryDate 仍为 null。</td></tr><tr><td>dataTypes</td><td>否</td><td>省略默认 REALTIME、DAILY_MILEAGE、DAILY_HYDROGEN 全部;显式数组非空、不重复、不接受未知枚举。未选数据块从响应中省略。</td></tr><tr><td>protocolPriority</td><td>否</td><td>仅选择 DAILY_MILEAGE 时可提供。非空、不重复,仅 GB32960、MQTT、JT808。未列出的协议不兜底;省略沿用原里程选源。对实时及用氢不生效。</td></tr></tbody></table></div><div class="note">请求体最大 64 KiB。拒绝未知字段、显式 null、非法类型、多个 JSON 根对象,以及规范化后重复车牌。无新增固定历史下界;可查询日期不代表保留了完整历史统计。</div><h4>仅查询实时</h4><pre class="code" data-language="json">{
|
||
"plateNumbers": [
|
||
"粤A09635F"
|
||
],
|
||
"dataTypes": [
|
||
"REALTIME"
|
||
]
|
||
}</pre><p>不查询日统计,仅返回 realtime,queryDate=null。appKey 与所查车辆须在当前请求时点有效。</p><h4>调用示例</h4><pre class="code" data-language="shell">curl --request POST \
|
||
--url https://open.d.lnoneos.com/api/v1/vehicles/operating-data/query \
|
||
--header 'Authorization: Bearer YOUR_APP_KEY' \
|
||
--header 'Content-Type: application/json' \
|
||
--data '{"plateNumbers":["粤A09635F"],"dailyDate":"2026-10-23"}'</pre></article><article class="operating-subsection" id="operating-data-auth"><h3>认证、授权与车辆关联</h3><pre class="code" data-language="http">Authorization: Bearer <32位appKey>
|
||
Content-Type: application/json</pre><ul class="operating-list"><li>appKey 当前启用且在有效期内。实时查询校验 appKey 与车辆授权覆盖 requestAt;车辆授权的结束时点不包含在有效区间中。</li><li>日统计要求 appKey 和逐车授权完整覆盖 dailyDate 的北京时间自然日。授权不满一整天时,不开放半日统计。</li><li>同时选择实时和历史统计时,两套授权都须通过;历史授权不能用于取得当前实时位置,当前授权也不能替代历史授权。</li><li>先完成全部范围校验,再查询业务数据。任一车辆越权整批 403,不返回其他车辆或已成功块;授权依赖故障按 500 失败关闭。</li><li>按 VIN 关联并复用固定的车牌/VIN 映射,保持请求顺序;映射冲突按内部错误处理,不猜测匹配。</li><li>appKey 由调用方后端持有,不嵌入公开前端或小程序。日志不记录明文 appKey。</li></ul></article><article class="operating-subsection" id="operating-data-response"><h3>返回结构与汇总</h3><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>字段</th><th>类型</th><th>含义与空值规则</th></tr></thead><tbody><tr><td>code</td><td>string</td><td>固定 SUCCESS;不保证每个数据块均执行成功。</td></tr><tr><td>message</td><td>string</td><td>顶层处理说明。</td></tr><tr><td>traceId</td><td>string</td><td>服务端生成的唯一请求标识。</td></tr><tr><td>queryDate</td><td>date | null</td><td>包含日统计时为dailyDate;仅实时为null。</td></tr><tr><td>timezone</td><td>string</td><td>枚举:Asia/Shanghai。</td></tr><tr><td>requestAt</td><td>date-time</td><td>固定请求基准时点,用于实时授权与记录年龄判断。</td></tr><tr><td>generatedAt</td><td>date-time</td><td>响应生成时点,不是任何业务数据的更新时间。</td></tr><tr><td>data</td><td>array</td><td>车辆数组,顺序与规范化后的请求名单一致。</td></tr><tr><td>summary</td><td>object</td><td>按车辆统计所选块的执行情况,详见下节。</td></tr></tbody></table></div><p>以下完整结构和字段表适用于FULL。每辆车外层包含 vin、plateNumber,以及所选择的 realtime、dailyMileage、dailyHydrogen。成功块保留完整业务字段;源可选字段缺失统一为 null,真实 0 和 false 保留。块内不重复 vin 和 plateNumber。所有本接口时间戳输出为带 +08:00 的 RFC3339,可含小数秒。</p><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>summary 字段</th><th>定义</th></tr></thead><tbody><tr><td>requestedCount</td><td>校验通过的请求车辆数。</td></tr><tr><td>returnedCount</td><td>data 条数;HTTP 200 时等于 requestedCount。</td></tr><tr><td>successCount</td><td>所有所选块 queryStatus 均为 SUCCESS 的车辆数。</td></tr><tr><td>partialSuccessCount</td><td>至少一个所选块 SUCCESS、至少一个 FAILED 的车辆数。</td></tr><tr><td>failedCount</td><td>所有所选块均 FAILED 的车辆数。</td></tr></tbody></table></div><div class="note">FULL模式中 successCount + partialSuccessCount + failedCount = returnedCount。NO_DATA、DATA_ANOMALY、STALE 和 CARRIED_FORWARD 不影响执行成功计数。仅选择一种数据时 partialSuccessCount 恒为 0。顶层 SUCCESS / HTTP 200 不能代替逐块检查。</div></article><article class="operating-subsection" id="operating-data-examples"><h3>完整响应示例</h3><p>以下为合成示例,仅用于说明结构。单车请求对应单条 data。示例包含部分储氢字段缺失和当天初步用氢结果,并不代表已取得真实联调数据。</p><details open><summary>完整成功响应 · 200(可展开 / 收起)</summary><pre class="code" data-language="json">{
|
||
"code": "SUCCESS",
|
||
"message": "success",
|
||
"traceId": "f924a83d8a93475bac26b054305fc427",
|
||
"queryDate": "2026-10-23",
|
||
"timezone": "Asia/Shanghai",
|
||
"requestAt": "2026-10-23T09:30:15+08:00",
|
||
"generatedAt": "2026-10-23T09:30:16+08:00",
|
||
"data": [
|
||
{
|
||
"vin": "LTEST000000000001",
|
||
"plateNumber": "粤A09635F",
|
||
"realtime": {
|
||
"gpsFixStatus": "FIXED",
|
||
"locationRecordTime": "2026-10-23T09:29:56+08:00",
|
||
"coordinateSystem": "GCJ02",
|
||
"protocol": "GB32960",
|
||
"longitude": 113.264385,
|
||
"latitude": 23.129112,
|
||
"speedKmh": 35.6,
|
||
"socPercent": 68.0,
|
||
"totalMileageKm": 43968.2,
|
||
"recordTime": "2026-10-23T09:29:56+08:00",
|
||
"timeDifferenceSeconds": 19,
|
||
"online": true,
|
||
"activeToday": true,
|
||
"motionStatus": "driving",
|
||
"locationAvailable": true,
|
||
"status": "NORMAL",
|
||
"hydrogenPressureTemperatureSource": null,
|
||
"remainingHydrogenPercentSource": null,
|
||
"hydrogenFullCapacityKg": null,
|
||
"hydrogenTankCapacityL": null,
|
||
"hydrogenFullPressureMPa": null,
|
||
"hydrogenReferenceTemperatureC": null,
|
||
"hydrogenEstimatePressureMPa": null,
|
||
"hydrogenEstimateTemperatureC": null,
|
||
"hydrogenCalculationVersion": null,
|
||
"hydrogenCapacitySource": null,
|
||
"hydrogenPercentReason": "MISSING_TANK_CAPACITY",
|
||
"remainingHydrogenKg": 16.0,
|
||
"remainingHydrogenPercent": null,
|
||
"hydrogenRecordTime": "2026-10-23T09:29:56+08:00",
|
||
"hydrogenDataStatus": "PARTIAL",
|
||
"remainingHydrogenKgStatus": "NORMAL",
|
||
"remainingHydrogenPercentStatus": "MISSING",
|
||
"hydrogenValueSource": "REPORTED",
|
||
"hydrogenSourceProtocol": "GB32960",
|
||
"hydrogenStaleAfterSeconds": 300,
|
||
"hydrogenExpectedIntervalSeconds": null,
|
||
"queryStatus": "SUCCESS",
|
||
"errorCode": null,
|
||
"errorMessage": null
|
||
},
|
||
"dailyMileage": {
|
||
"queryStatus": "SUCCESS",
|
||
"errorCode": null,
|
||
"errorMessage": null,
|
||
"status": "NORMAL",
|
||
"date": "2026-10-23",
|
||
"dailyMileageKm": 38.9,
|
||
"totalMileageKm": 43968.2,
|
||
"sourceProtocol": "GB32960",
|
||
"dataQuality": null,
|
||
"dataTime": "2026-10-23T09:29:50+08:00",
|
||
"updatedAt": "2026-10-23T09:30:02+08:00",
|
||
"statisticsStartTime": "2026-10-22T23:59:40+08:00",
|
||
"statisticsEndTime": "2026-10-23T09:29:50+08:00"
|
||
},
|
||
"dailyHydrogen": {
|
||
"queryStatus": "SUCCESS",
|
||
"errorCode": null,
|
||
"errorMessage": null,
|
||
"status": "NORMAL",
|
||
"date": "2026-10-23",
|
||
"hydrogenConsumptionKg": 3.573,
|
||
"qualityStatus": "OK",
|
||
"qualityReason": null,
|
||
"calculationPhase": "PRELIMINARY",
|
||
"algorithmVersion": "PRESSURE_NIST_VALID_BOUNDARY_CHARGE_CYCLE_V3_5",
|
||
"statisticsStartTime": null,
|
||
"statisticsEndTime": "2026-10-23T09:29:56+08:00",
|
||
"updatedAt": "2026-10-23T09:30:03+08:00"
|
||
}
|
||
}
|
||
],
|
||
"summary": {
|
||
"requestedCount": 1,
|
||
"returnedCount": 1,
|
||
"successCount": 1,
|
||
"partialSuccessCount": 0,
|
||
"failedCount": 0
|
||
}
|
||
}</pre></details><div class="note">示例实时 kg 可用、百分比为 MISSING;日用氢为 PRELIMINARY,且两类日统计边界不一致。应展示各自指标,不能直接计算百公里氢耗。</div><details><summary>完整部分失败响应 · 200</summary><pre class="code" data-language="json">{
|
||
"code": "SUCCESS",
|
||
"message": "success",
|
||
"traceId": "be2ed2362ee44c7098fd3d347c41f2f9",
|
||
"queryDate": "2026-10-23",
|
||
"timezone": "Asia/Shanghai",
|
||
"requestAt": "2026-10-23T09:30:15+08:00",
|
||
"generatedAt": "2026-10-23T09:30:16+08:00",
|
||
"data": [
|
||
{
|
||
"vin": "LTEST000000000001",
|
||
"plateNumber": "粤A09635F",
|
||
"realtime": {
|
||
"gpsFixStatus": "FIXED",
|
||
"locationRecordTime": "2026-10-23T09:29:56+08:00",
|
||
"coordinateSystem": "GCJ02",
|
||
"protocol": "GB32960",
|
||
"longitude": 113.264385,
|
||
"latitude": 23.129112,
|
||
"speedKmh": 35.6,
|
||
"socPercent": 68.0,
|
||
"totalMileageKm": 43968.2,
|
||
"recordTime": "2026-10-23T09:29:56+08:00",
|
||
"timeDifferenceSeconds": 19,
|
||
"online": true,
|
||
"activeToday": true,
|
||
"motionStatus": "driving",
|
||
"locationAvailable": true,
|
||
"status": "NORMAL",
|
||
"hydrogenPressureTemperatureSource": null,
|
||
"remainingHydrogenPercentSource": null,
|
||
"hydrogenFullCapacityKg": null,
|
||
"hydrogenTankCapacityL": null,
|
||
"hydrogenFullPressureMPa": null,
|
||
"hydrogenReferenceTemperatureC": null,
|
||
"hydrogenEstimatePressureMPa": null,
|
||
"hydrogenEstimateTemperatureC": null,
|
||
"hydrogenCalculationVersion": null,
|
||
"hydrogenCapacitySource": null,
|
||
"hydrogenPercentReason": "MISSING_TANK_CAPACITY",
|
||
"remainingHydrogenKg": 16.0,
|
||
"remainingHydrogenPercent": null,
|
||
"hydrogenRecordTime": "2026-10-23T09:29:56+08:00",
|
||
"hydrogenDataStatus": "PARTIAL",
|
||
"remainingHydrogenKgStatus": "NORMAL",
|
||
"remainingHydrogenPercentStatus": "MISSING",
|
||
"hydrogenValueSource": "REPORTED",
|
||
"hydrogenSourceProtocol": "GB32960",
|
||
"hydrogenStaleAfterSeconds": 300,
|
||
"hydrogenExpectedIntervalSeconds": null,
|
||
"queryStatus": "SUCCESS",
|
||
"errorCode": null,
|
||
"errorMessage": null
|
||
},
|
||
"dailyMileage": {
|
||
"queryStatus": "SUCCESS",
|
||
"errorCode": null,
|
||
"errorMessage": null,
|
||
"status": "NORMAL",
|
||
"date": "2026-10-23",
|
||
"dailyMileageKm": 38.9,
|
||
"totalMileageKm": 43968.2,
|
||
"sourceProtocol": "GB32960",
|
||
"dataQuality": null,
|
||
"dataTime": "2026-10-23T09:29:50+08:00",
|
||
"updatedAt": "2026-10-23T09:30:02+08:00",
|
||
"statisticsStartTime": "2026-10-22T23:59:40+08:00",
|
||
"statisticsEndTime": "2026-10-23T09:29:50+08:00"
|
||
},
|
||
"dailyHydrogen": {
|
||
"queryStatus": "FAILED",
|
||
"status": null,
|
||
"errorCode": "HYDROGEN_QUERY_TIMEOUT",
|
||
"errorMessage": "daily hydrogen query timeout"
|
||
}
|
||
}
|
||
],
|
||
"summary": {
|
||
"requestedCount": 1,
|
||
"returnedCount": 1,
|
||
"successCount": 0,
|
||
"partialSuccessCount": 1,
|
||
"failedCount": 0
|
||
}
|
||
}</pre></details><p>失败块只包含 queryStatus、status:null、errorCode、errorMessage;不附带旧业务数值。实时和里程成功时,用氢失败不丢弃其他结果。全部子查询失败仍可返回 200,此时 failedCount=returnedCount。</p></article><article class="operating-subsection" id="operating-data-realtime"><h3>realtime 全部字段</h3><p>以下为 queryStatus=SUCCESS 的完整字段集合;vin、plateNumber 取车辆外层身份。</p><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>字段</th><th>类型</th><th>含义与空值规则</th></tr></thead><tbody><tr><td>queryStatus</td><td>string</td><td>SUCCESS 表示该子服务可见查询执行完成;仍需检查业务状态和逐字段质量。</td></tr><tr><td>errorCode</td><td>string | null</td><td>成功块固定为 null。</td></tr><tr><td>errorMessage</td><td>string | null</td><td>成功块固定为 null。</td></tr><tr><td>gpsFixStatus</td><td>string</td><td>实际位置报文定位位;GB32960 bit0=0、JT808 bit1=1 表示 FIXED;MQTT 或缺少可信定位位为 UNKNOWN。不以在线或数据年龄推断;枚举:FIXED, NO_FIX, UNKNOWN。</td></tr><tr><td>locationRecordTime</td><td>date-time | null</td><td>位置行对应实际采集时间,独立于主记录 recordTime;历史 FIXED 不因车辆离线改变 未知时为 null。</td></tr><tr><td>coordinateSystem</td><td>string</td><td>仅 GB2025 显式坐标类型 1=WGS84、2=GCJ02,其余 UNKNOWN;GB2016/JT808/MQTT 当前无确证为 UNKNOWN,未知坐标系不得直接当高德坐标使用;枚举:WGS84, GCJ02, UNKNOWN。</td></tr><tr><td>protocol</td><td>string | null</td><td>本条实时位置、速度、里程及记录时间实际采用的采集协议;GB32960=车辆协议,MQTT=MQTT车端来源,JT808=定位终端来源 未知时为 null。</td></tr><tr><td>longitude</td><td>number | null</td><td>所选来源的最新有效经度;无位置时为 null</td></tr><tr><td>latitude</td><td>number | null</td><td>所选来源的最新有效纬度;无位置时为 null</td></tr><tr><td>speedKmh</td><td>number | null</td><td>所选来源瞬时速度,单位 km/h 未知时为 null。</td></tr><tr><td>socPercent</td><td>number | null</td><td>动力电池 SOC(%);未知为 null,不能替代储氢百分比。</td></tr><tr><td>totalMileageKm</td><td>number | null</td><td>所选来源累计总里程,单位 km 未知时为 null。</td></tr><tr><td>recordTime</td><td>date-time | null</td><td>实时主记录的实际采集时间,统一输出带 +08:00 的 RFC3339。 未知时为 null。</td></tr><tr><td>timeDifferenceSeconds</td><td>integer | null</td><td>requestAt 与主记录的时间差(秒),沿用源服务非负处理;表示记录年龄,不表示实际离线时长。未知为 null。</td></tr><tr><td>online</td><td>boolean</td><td>任一采集协议是否在最近60秒内上报</td></tr><tr><td>activeToday</td><td>boolean</td><td>任一采集协议在当前自然日(Asia/Shanghai)内上报过</td></tr><tr><td>motionStatus</td><td>string</td><td>driving=在线且速度大于3km/h;idle=在线且速度不大于3km/h;offline=当前不在线或无实时记录;枚举:driving, idle, offline。</td></tr><tr><td>locationAvailable</td><td>boolean</td><td>true=longitude/latitude 有效;false=当前无有效位置</td></tr><tr><td>status</td><td>string</td><td>当前实时主记录状态为 NORMAL / NO_DATA;不代表所有位置或储氢字段可用。</td></tr><tr><td>hydrogenPressureTemperatureSource</td><td>string | null</td><td>最大氢压/最大氢温聚合读数近似;两者不保证来自同一瓶,不是逐瓶质量求和或全瓶完整性证明 未知时为 null。;枚举:MAX_SENSOR_AGGREGATE。</td></tr><tr><td>remainingHydrogenPercentSource</td><td>string | null</td><td>百分比始终为模型满充容量推算;与 kg 来源独立,计算前缺条件时为 null;枚举:ESTIMATED。</td></tr><tr><td>hydrogenFullCapacityKg</td><td>number | null</td><td>实际用于比例分母的未舍入满充质量,kg;PressureHydrogenMassKg(35,15,VIN水容积),不是扣除残余后的可用容量 未知时为 null。</td></tr><tr><td>hydrogenTankCapacityL</td><td>number | null</td><td>VIN 配置的全车储氢水容积,L;必须 active 且大于0、不超过10000,不根据车型臆造默认值 未知时为 null。</td></tr><tr><td>hydrogenFullPressureMPa</td><td>number | null</td><td>本次业务确认的满充参考压力,MPa;不代表自动核验每辆车铭牌额定压力 未知时为 null。;枚举:35。</td></tr><tr><td>hydrogenReferenceTemperatureC</td><td>number | null</td><td>满充参考温度,摄氏度 未知时为 null。;枚举:15。</td></tr><tr><td>hydrogenEstimatePressureMPa</td><td>number | null</td><td>仅平台估算 kg 时使用的同帧最大氢压,MPa;支持0,不补默认值 未知时为 null。</td></tr><tr><td>hydrogenEstimateTemperatureC</td><td>number | null</td><td>仅平台估算 kg 时使用的同帧最大氢温,摄氏度;模型输入范围−40–726.85°C,不是车辆安全温度阈值;缺失不补默认温度 未知时为 null。</td></tr><tr><td>hydrogenCalculationVersion</td><td>string | null</td><td>实时储氢模型版本;不修改日用氢算法 未知时为 null。;枚举:REAL_GAS_35MPA_15C_V1。</td></tr><tr><td>hydrogenCapacitySource</td><td>string | null</td><td>满充容量采用的 VIN 配置数据表 未知时为 null。;枚举:vehicle_hydrogen_tank_capacity。</td></tr><tr><td>hydrogenPercentReason</td><td>string | null</td><td>缺少或拒绝百分比的原因;超出业务满充参考仅拒绝百分比,不伪装为100,也不据此判断车辆安全状态 未知时为 null。;枚举:MISSING_HYDROGEN_MEASUREMENT, INVALID_MASS_READING, INVALID_PRESSURE_TEMPERATURE, INCOMPLETE_PRESSURE_TEMPERATURE, MISSING_TANK_CAPACITY, MASS_CALCULATION_FAILED, EXCEEDS_NOMINAL_FULL_CAPACITY。</td></tr><tr><td>remainingHydrogenKg</td><td>number | null</td><td>全车氢质量 kg;优先 GB32960 广东扩展终端上报(0–200 kg),缺质量时以同帧最大氢压/氢温和 VIN 全车水容积作实气估算(0–500 kg)。真实零保留,缺失/异常为 null,陈旧值保留并标 STALE</td></tr><tr><td>remainingHydrogenPercent</td><td>number | null</td><td>剩余质量除以 VIN 水容积在 35 MPa、15°C 的实气模型满充质量乘100,属于 ESTIMATED;缺容量为 null/MISSING。超过100返回 null/INVALID,不截断为100,kg独立保留;不以动力电池SOC替代</td></tr><tr><td>hydrogenRecordTime</td><td>date-time | null</td><td>氢质量对应原始同帧实际采集时间,RFC 3339 带时区;不是请求时间或缓存更新时间 未知时为 null。</td></tr><tr><td>hydrogenDataStatus</td><td>string</td><td>NORMAL 两项有效(可包含估算,见来源);PARTIAL 部分字段有效;STALE 数据陈旧;MISSING 缺少数据或容量;UNSUPPORTED 不支持;INVALID 异常。数值和字段级状态独立判断;枚举:NORMAL, PARTIAL, STALE, MISSING, UNSUPPORTED, INVALID。</td></tr><tr><td>remainingHydrogenKgStatus</td><td>string</td><td>枚举:NORMAL, STALE, MISSING, UNSUPPORTED, INVALID。</td></tr><tr><td>remainingHydrogenPercentStatus</td><td>string</td><td>独立于 kg 状态;容量缺失 MISSING,比例超100 INVALID;有值时继承 kg 的 NORMAL 或 STALE;枚举:NORMAL, STALE, MISSING, UNSUPPORTED, INVALID。</td></tr><tr><td>hydrogenValueSource</td><td>string | null</td><td>kg 来源;REPORTED 仅确认终端上报,无法判断终端内部测量或估算;ESTIMATED 为平台压力/温度/容积实气模型估算 未知时为 null。;枚举:REPORTED, ESTIMATED。</td></tr><tr><td>hydrogenSourceProtocol</td><td>string | null</td><td>储氢数据采用的协议,独立于位置的 protocol 未知时为 null。;枚举:GB32960, MQTT, JT808。</td></tr><tr><td>hydrogenStaleAfterSeconds</td><td>integer | null</td><td>GB32960 服务时效策略为 300 秒;不是协议采样周期承诺 未知时为 null。</td></tr><tr><td>hydrogenExpectedIntervalSeconds</td><td>integer | null</td><td>当前无已确认上报周期,固定 null</td></tr></tbody></table></div><div class="note">主 status=NORMAL 不保证位置或每个储氢字段可用,必须结合 GPS、坐标系、采集时间和逐字段储氢质量判断。实时主 protocol、储氢协议和采集时点可以不同。离线不等于 GPS 异常;UNKNOWN 坐标系不能直接按 GCJ02 上图。</div><p>聚合层不新增旧值兜底。原实时服务已有的有界原始帧回补仍保留,必须带实际 hydrogenRecordTime、来源和 STALE 状态。现有补充查询共享 3 秒预算,补充存储错误可降级为 MISSING/UNKNOWN,主查询仍 SUCCESS;queryStatus 不承诺区分所有被源服务吸收的底层失败。</p></article><article class="operating-subsection" id="operating-data-mileage"><h3>dailyMileage 全部字段</h3><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>字段</th><th>类型</th><th>含义与空值规则</th></tr></thead><tbody><tr><td>queryStatus</td><td>string</td><td>SUCCESS 表示该子服务可见查询执行完成;仍需检查业务状态和逐字段质量。</td></tr><tr><td>errorCode</td><td>string | null</td><td>成功块固定为 null。</td></tr><tr><td>errorMessage</td><td>string | null</td><td>成功块固定为 null。</td></tr><tr><td>statisticsStartTime</td><td>date-time | null</td><td>日里程起点累计读数的时间;可跨越多个缺报日;历史结转补零或无数据时为 null</td></tr><tr><td>statisticsEndTime</td><td>date-time | null</td><td>当日所选来源最晚 latest_event_time,等于 dataTime;历史结转补零或无数据时为 null。与用氢接口无共同快照保证</td></tr><tr><td>date</td><td>date</td><td>查询自然日(Asia/Shanghai),与顶层 queryDate 一致,格式 yyyy-MM-dd。</td></tr><tr><td>dailyMileageKm</td><td>number | null</td><td>日里程(km),复用原服务:优先已核验终端日统计,否则进行同来源累计读数对账;结转为 0,异常可为 null,GPS 估算不参与。</td></tr><tr><td>totalMileageKm</td><td>number | null</td><td>当日所选协议最后有效终端累计总里程,km;GPS 日里程估算不会作为累计总里程。status=NORMAL 时必定有值,NO_DATA 时为 null</td></tr><tr><td>dataTime</td><td>date-time | null</td><td>本次统计实际采用的最后一条车辆源数据时间;status=NO_DATA 时为 null</td></tr><tr><td>updatedAt</td><td>date-time | null</td><td>本行所依据统计周期的计算时间;前向填充时为上一统计周期计算时间,status=NO_DATA 时为 null</td></tr><tr><td>sourceProtocol</td><td>string | null</td><td>本行实际选中的来源协议;status=NO_DATA 时为 null;枚举:GB32960, MQTT, JT808。</td></tr><tr><td>dataQuality</td><td>string | null</td><td>CARRIED_FORWARD 表示缺报结转;其他值表示无法连续对账的原因,此时 dailyMileageKm 为 null,保留累计读数及来源证据</td></tr><tr><td>status</td><td>string</td><td>NORMAL=存在可用数据;NO_DATA=授权范围内无可用数据;DATA_ANOMALY=检测到数据异常,详情见 dataQuality;枚举:NORMAL, NO_DATA, DATA_ANOMALY。</td></tr></tbody></table></div><div class="note">CARRIED_FORWARD 是 dataQuality 的值,status 仍为 NORMAL。日里程补 0、累计值与来源/时间沿用历史记录,不代表当日实测零里程;统计边界沿用源结果。不得隐式合并 realtime.totalMileageKm 与 dailyMileage.totalMileageKm。</div></article><article class="operating-subsection" id="operating-data-hydrogen"><h3>dailyHydrogen 全部字段</h3><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>字段</th><th>类型</th><th>含义与空值规则</th></tr></thead><tbody><tr><td>queryStatus</td><td>string</td><td>SUCCESS 表示该子服务可见查询执行完成;仍需检查业务状态和逐字段质量。</td></tr><tr><td>errorCode</td><td>string | null</td><td>成功块固定为 null。</td></tr><tr><td>errorMessage</td><td>string | null</td><td>成功块固定为 null。</td></tr><tr><td>statisticsStartTime</td><td>date-time | null</td><td>FINAL 证据区间最早开始时间;PRELIMINARY 仅有结束水位故为 null;缺失或异常证据为 null。边界是证据包络,不承诺连续覆盖</td></tr><tr><td>statisticsEndTime</td><td>date-time | null</td><td>FINAL 证据区间最晚结束时间,PRELIMINARY 为真实 lastEventTime 水位;缺失或异常证据为 null;不是 API 查询时间</td></tr><tr><td>updatedAt</td><td>date-time | null</td><td>同一用氢统计行的数据库更新时间,RFC 3339 带时区;无统计行时为 null</td></tr><tr><td>date</td><td>date</td><td>查询自然日(Asia/Shanghai),与顶层 queryDate 一致,格式 yyyy-MM-dd。</td></tr><tr><td>hydrogenConsumptionKg</td><td>number | null</td><td>单日用氢量,kg;OK 和 SUSPECT 计算结果均返回数值,无数据时为 null</td></tr><tr><td>calculationPhase</td><td>string | null</td><td>PRELIMINARY 仅供标注为初步的日内监控;FINAL 表示批量重算已完成,补传或算法调整仍可能再次重算,不保证固定结算时刻 未知时为 null。</td></tr><tr><td>algorithmVersion</td><td>string | null</td><td>氢耗计算算法版本 未知时为 null。</td></tr><tr><td>qualityStatus</td><td>string | null</td><td>OK 对应 NORMAL;SUSPECT 对应 DATA_ANOMALY 并保留数值供审计,不得用于正常百公里氢耗;NO_DATA 对应无可用统计 未知时为 null。</td></tr><tr><td>qualityReason</td><td>string | null</td><td>质量判定原因;SUSPECT 或 NO_DATA 时供调用方解释和审计 未知时为 null。</td></tr><tr><td>status</td><td>string</td><td>NORMAL 对应有效质量 OK;DATA_ANOMALY 对应可疑质量 SUSPECT;NO_DATA 为无可用统计。</td></tr></tbody></table></div><p>PRELIMINARY 仅用于明确标注为初步的日内监控;FINAL 表示完成相应批量重算,仍可被补传或算法修订回修。日期本身不决定阶段。DATA_ANOMALY 可保留数值供审计,不能当作正常用氢结果。没有统计行时值为 null,不填 0。</p></article><article class="operating-subsection" id="operating-data-errors"><h3>执行状态与错误码</h3><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>情况</th><th>queryStatus</th><th>业务结果</th></tr></thead><tbody><tr><td>子服务完成并有数据</td><td>SUCCESS</td><td>保留源 status、质量和逐字段状态。</td></tr><tr><td>子服务完成但无可用记录</td><td>SUCCESS</td><td>status=NO_DATA;数值按源定义为空,实时布尔/状态字段按原规则保留。</td></tr><tr><td>源业务数据异常</td><td>SUCCESS</td><td>status=DATA_ANOMALY;保留允许返回的审计字段。</td></tr><tr><td>子服务错误 / 超时</td><td>FAILED</td><td>status=null;仅返回执行错误字段。</td></tr><tr><td>源可选补充已降级</td><td>SUCCESS</td><td>保留 MISSING / UNKNOWN 等源状态,不能断言设备没有记录。</td></tr></tbody></table></div><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>字段</th><th>类型</th><th>含义与空值规则</th></tr></thead><tbody><tr><td>queryStatus</td><td>string</td><td>FAILED:该块查询错误、超时或结果转换失败。</td></tr><tr><td>status</td><td>string | null</td><td>枚举:null。</td></tr><tr><td>errorCode</td><td>string</td><td>枚举:REALTIME_QUERY_FAILED, REALTIME_QUERY_TIMEOUT, MILEAGE_QUERY_FAILED, MILEAGE_QUERY_TIMEOUT, HYDROGEN_QUERY_FAILED, HYDROGEN_QUERY_TIMEOUT, SOURCE_DATA_INVALID。</td></tr><tr><td>errorMessage</td><td>string</td><td></td></tr></tbody></table></div><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>HTTP</th><th>顶层 code</th><th>说明</th></tr></thead><tbody><tr><td>200</td><td>SUCCESS</td><td>聚合流程完成,含部分或全部子查询失败;逐块判断。</td></tr><tr><td>400</td><td>INVALID_REQUEST</td><td>结构、类型、车牌、枚举、协议或批量数量不合法。</td></tr><tr><td>400</td><td>INVALID_DATE_FORMAT</td><td>缺少必需日期或日期格式不正确。</td></tr><tr><td>400</td><td>INVALID_DATE_RANGE</td><td>查询日期晚于北京时间当日。</td></tr><tr><td>401</td><td>UNAUTHORIZED</td><td>appKey 缺失、无效、停用或当前过期。</td></tr><tr><td>403</td><td>FORBIDDEN</td><td>车辆或查询时段未授权;整批拒绝。</td></tr><tr><td>413</td><td>PAYLOAD_TOO_LARGE</td><td>请求体超过 64 KiB。</td></tr><tr><td>429</td><td>RATE_LIMIT_EXCEEDED</td><td>应用或全局限额超限;读取 Retry-After 秒数后退避重试。</td></tr><tr><td>500</td><td>INTERNAL_ERROR</td><td>授权依赖故障、身份冲突或无法完成聚合的内部异常。</td></tr></tbody></table></div><pre class="code" data-language="json">{
|
||
"code": "FORBIDDEN",
|
||
"message": "无数据访问权限",
|
||
"traceId": "ee030dc62c1b4c9aa9b43cc9fa6b4b23"
|
||
}</pre><p>非 200 响应不返回 data 或 summary。块错误码为 REALTIME_QUERY_FAILED/TIMEOUT、MILEAGE_QUERY_FAILED/TIMEOUT、HYDROGEN_QUERY_FAILED/TIMEOUT;这里的 TIMEOUT 表示完整代码后缀 _QUERY_TIMEOUT。源字段无法安全序列化或转换时间时为 SOURCE_DATA_INVALID。单个类型批量查询整体失败时,该类型对全部车辆均标 FAILED;单车结果转换异常可仅影响该车该块。</p></article><article class="operating-subsection" id="operating-data-performance"><h3>容量、超时与调用建议</h3><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>项目</th><th>当前实现</th></tr></thead><tbody><tr><td>车辆批量</td><td>显式车牌最多 200 项,超出返回 BATCH_SIZE_EXCEEDED;省略或空数组返回所选授权范围交集的全部车辆,不受 200 辆限制。按类型对 VIN 集合批量查询。</td></tr><tr><td>内部执行</td><td>所选三类最多三个任务并行,共享授权结果与固定映射;不逐车 HTTP 回调原接口。</td></tr><tr><td>总预算</td><td>6 秒,受更短的上游请求截止时间约束。</td></tr><tr><td>子查询预算</td><td>所选数据查询共享最多 4.5 秒;只把尚未完成的类型标记超时,保留已经完成的块。</td></tr><tr><td>应用限额</td><td>每应用、每服务实例 30 批/60 秒,最多 2 批并发;与历史剩余氢量接口配额独立。</td></tr><tr><td>端点总并发</td><td>每个服务实例最多 16 批;超限立即 429。</td></tr><tr><td>多实例与网关</td><td>统一配额由网关协调;网关预算须长于应用总预算并留传输余量。</td></tr><tr><td>响应格式</td><td>本端点返回紧凑 JSON;本文示例为便于阅读进行了格式化。</td></tr><tr><td>性能证据</td><td>已有本地测试与 Mock 基准,不包含线上数据库、网络或生产压测;不承诺未经验证的 P95。</td></tr></tbody></table></div><p>只需某一类数据时显式传 dataTypes。收到部分失败后优先仅重试失败类型,遵循 Retry-After 并退避;不要把 NO_DATA 当成网络失败反复重试。当前没有新增聚合缓存、统计表或数据库迁移。</p></article><article class="operating-subsection" id="operating-data-quality"><h3>统计可比性与版本说明</h3><div class="note">FULL不返回百公里氢耗,SIMPLE预留该字段并固定null。相同 VIN、相同日期、NORMAL、相近更新时间,均不足以证明分子分母的统计区间可比。</div><ul class="operating-list"><li>调用方计算前至少检查:两块执行成功、业务正常,用氢质量 OK,里程为正且不是结转或异常;VIN 与日期一致。</li><li>还需有可核查的区间、证据覆盖及来源口径。statisticsStartTime/statisticsEndTime 只是证据包络;即使边界相等也不能单独证明连续覆盖。证据不足时只展示独立指标。</li><li>正式报表要求适用结果为 FINAL 并保留算法版本、查询时刻和结果快照;初步监控另标 PRELIMINARY。</li></ul><div class="operating-table-scroll"><table class="param-table"><thead><tr><th>版本 / 状态</th><th>说明</th></tr></thead><tbody><tr><td>文档 V1.5 · 2026-10-26</td><td>按当前开发实现同步。对应 OpenAPI 1.12.2。</td></tr><tr><td>实现状态</td><td>已完成接口实现及测试;本文随开放平台服务发布,版本与实际状态可通过 /healthz 核对。</td></tr><tr><td>与 V1.1 评审稿的变化</td><td>限额与超时已明确;保留现有业务字段,失败块结构固定;补齐完整字段、示例和已知源降级边界。</td></tr><tr><td>旧接口</td><td>继续保留;本端点不修改其返回字段、统计或选源口径。瞬时车辆授权到期边界按结束时点不包含处理。</td></tr></tbody></table></div></article></section>
|
||
<section class="section" id="daily-hydrogen"><div class="section-head"><div><h2>车辆单日用氢量</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/hydrogen-consumption/query</div><p>查询车辆单日用氢量,单位 kg。NORMAL + OK + PRELIMINARY 仅供初步监控;正式报表要求 FINAL 并核对证据与版本。两个日统计接口没有共同快照,区间缺失或不同不能直接计算百公里氢耗。</p></div><a class="anchor" href="#daily-hydrogen">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>date</td><td class="required">是</td><td>日期,格式 yyyy-MM-dd</td></tr><tr><td>plateNumbers</td><td class="optional">否</td><td>车牌数组;省略或 [] 时查询全部授权车辆</td></tr></table></div><div><h3 class="subhead">成功返回 · 200</h3><pre class="code">{<br> <span class="key">"code"</span>: <span class="string">"SUCCESS"</span>,<br> <span class="key">"data"</span>: [{<br> <span class="key">"plateNumber"</span>: <span class="string">"浙F06618F"</span>,<br> <span class="key">"hydrogenConsumptionKg"</span>: <span class="number">12.315</span>,<br> <span class="key">"status"</span>: <span class="string">"NORMAL"</span><br> }]<br>}</pre><ul class="errors"><li>400:日期或车牌格式不正确</li><li>401:appKey 无效、停用或过期</li><li>403:指定车辆未授权</li></ul></div></div></section>
|
||
|
||
<section class="section" id="daily-mileage"><div class="section-head"><div><h2>车辆单日里程</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/mileage/query</div><p>返回当日行驶里程、当日累计总里程和实际选用的数据协议,单位 km。</p></div><a class="anchor" href="#daily-mileage">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>date</td><td class="required">是</td><td>日期,格式 yyyy-MM-dd</td></tr><tr><td>plateNumbers</td><td class="optional">否</td><td>省略时查询全部授权车辆</td></tr><tr><td>protocolPriority</td><td class="optional">否</td><td>协议选源顺序,例如 ["GB32960","MQTT","JT808"]</td></tr></table><div class="note"><strong>缺数规则:</strong>日里程优先采用中台已选中且质量通过的终端日统计及其同来源基线,来源切换不单独触发异常;缺报日沿用累计值、日里程补 0(CARRIED_FORWARD),跨缺报期增量计入恢复日。没有已验证日统计时才按相邻日累计差计算;无法验证的首次基线、来源切换或累计回退返回 DATA_ANOMALY,日里程为 null。GPS 估算不参与本接口。</div></div><div><h3 class="subhead">成功返回 · 200</h3><pre class="code">{<br> <span class="key">"code"</span>: <span class="string">"SUCCESS"</span>,<br> <span class="key">"data"</span>: [{<br> <span class="key">"dailyMileageKm"</span>: <span class="number">182.437</span>,<br> <span class="key">"totalMileageKm"</span>: <span class="number">12345.679</span>,<br> <span class="key">"sourceProtocol"</span>: <span class="string">"GB32960"</span>,<br> <span class="key">"status"</span>: <span class="string">"NORMAL"</span><br> }]<br>}</pre><ul class="errors"><li>400:日期、车牌或协议参数错误</li><li>403:授权期未覆盖查询日</li><li>无统计:单车以 NO_DATA 返回</li></ul></div></div></section>
|
||
|
||
<section class="section" id="mileage-range"><div class="section-head"><div><h2>车辆区间日里程</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/mileage/range/query</div><p>按车辆、日期分页返回区间日里程,最长查询区间为 3 年(1096 天)。</p></div><a class="anchor" href="#mileage-range">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>startDate / endDate</td><td class="required">是</td><td>日期区间,yyyy-MM-dd</td></tr><tr><td>plateNumbers</td><td class="optional">否</td><td>车牌数组,最多 5000 辆</td></tr><tr><td>protocolPriority</td><td class="optional">否</td><td>协议选源顺序</td></tr><tr><td>pageSize / cursor</td><td class="optional">否</td><td>分页大小及下一页游标</td></tr></table></div><div><h3 class="subhead">成功返回 · 200</h3><pre class="code">{<br> <span class="key">"code"</span>: <span class="string">"SUCCESS"</span>,<br> <span class="key">"data"</span>: [{<br> <span class="key">"date"</span>: <span class="string">"2026-08-06"</span>,<br> <span class="key">"dailyMileageKm"</span>: <span class="number">182.437</span>,<br> <span class="key">"totalMileageKm"</span>: <span class="number">12345.679</span><br> }],<br> <span class="key">"nextCursor"</span>: <span class="string">null</span><br>}</pre><ul class="errors"><li>400:区间超限或游标与原参数不一致</li><li>403:授权未完整覆盖查询区间</li></ul></div></div></section>
|
||
|
||
<section class="section" id="total-mileage"><div class="section-head"><div><h2>指定时刻总里程</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/total-mileage/query</div><p>按 VIN 返回不晚于指定时刻的最近一条总里程及实际采集协议。</p></div><a class="anchor" href="#total-mileage">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>vin</td><td class="required">是</td><td>17 位已授权 VIN</td></tr><tr><td>time</td><td class="required">是</td><td>北京时间 yyyy-MM-dd HH:mm:ss</td></tr><tr><td>protocol</td><td class="optional">否</td><td>GB32960、MQTT 或 JT808;省略时按默认顺序选取</td></tr></table></div><div><h3 class="subhead">成功返回 · 200</h3><pre class="code">{<br> <span class="key">"code"</span>: <span class="string">"SUCCESS"</span>,<br> <span class="key">"data"</span>: {<br> <span class="key">"totalMileageKm"</span>: <span class="number">12345.678</span>,<br> <span class="key">"protocol"</span>: <span class="string">"GB32960"</span>,<br> <span class="key">"recordTime"</span>: <span class="string">"2026-08-06 10:29:45"</span>,<br> <span class="key">"timeDifferenceSeconds"</span>: <span class="number">15</span><br> }<br>}</pre><ul class="errors"><li>400:VIN、时间或协议不合法</li><li>403:VIN 未授权</li><li>无记录:返回 NO_DATA</li></ul></div></div></section>
|
||
|
||
<section class="section" id="realtime"><div class="section-head"><div><h2>车辆实时位置与状态</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/realtime/query</div><p>返回位置、在线状态、速度、总里程、储氢及独立 GPS 状态。储氢优先终端上报质量,缺质量可按同帧温压和 VIN 容积估算;百分比采用35 MPa、15°C满充参考,来源和质量分别说明。</p><p>比例 = 剩余质量 / PressureHydrogenMassKg(35,15,VIN容积) × 100。参考温度与密度比定义见 <a href="https://unece.org/sites/default/files/2024-07/ECE_TRANS_WP.29_2023_110E.pdf">UNECE 定义文件</a>;35 MPa 为本次业务参数,非所有车型额定压力的自动认证。</p></div><a class="anchor" href="#realtime">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>plateNumbers</td><td class="optional">否</td><td>省略或 [] 时返回全部当前有效授权车辆</td></tr></table></div><div><h3 class="subhead">成功返回 · 200</h3><pre class="code">{<br> <span class="key">"data"</span>: [{<br> <span class="key">"vin"</span>: <span class="string">"LA9GG68L2PBAF4790"</span>,<br> <span class="key">"plateNumber"</span>: <span class="string">"浙F06618F"</span>,<br> <span class="key">"protocol"</span>: <span class="string">"GB32960"</span>,<br> <span class="key">"longitude"</span>: <span class="number">120.75</span>,<br> <span class="key">"latitude"</span>: <span class="number">30.74</span>,<br> <span class="key">"speedKmh"</span>: <span class="number">0</span>,<br> <span class="key">"totalMileageKm"</span>: <span class="number">12345.678</span>,<br> <span class="key">"recordTime"</span>: <span class="string">"2026-08-17 17:40:12"</span>,<br> <span class="key">"timeDifferenceSeconds"</span>: <span class="number">8</span>,<br> <span class="key">"online"</span>: <span class="number">true</span>,<br> <span class="key">"activeToday"</span>: <span class="number">true</span>,<br> <span class="key">"motionStatus"</span>: <span class="string">"idle"</span>,<br> <span class="key">"locationAvailable"</span>: <span class="number">true</span>,<br> <span class="key">"status"</span>: <span class="string">"NORMAL"</span><br> }]<br>}</pre><ul class="errors"><li>400:车牌格式错误</li><li>403:指定车牌未授权</li><li>无实时记录:返回 NO_DATA</li></ul></div></div></section>
|
||
|
||
<section class="section" id="stationary"><div class="section-head"><div><h2>加氢车辆停留核验</h2><div class="endpoint"><span class="method">POST</span>/api/v1/vehicles/stationary/query</div><p>按站点坐标、坐标系、时间段和半径,核验速度接近 0 的车辆停留记录,并按匹配度降序返回。</p></div><a class="anchor" href="#stationary">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>startTime / endTime</td><td class="required">是</td><td>北京时间;查询区间最长 24 小时</td></tr><tr><td>longitude / latitude</td><td class="required">是</td><td>加氢站经纬度;由 coordinateSystem 说明坐标系</td></tr><tr><td>coordinateSystem</td><td class="optional">否</td><td>WGS84(默认)或 GCJ02(高德);GCJ02 自动转换后核验</td></tr><tr><td>radiusMeters</td><td class="optional">否</td><td>核验半径,单位 m;1–100,默认 5</td></tr><tr><td>plateNumbers</td><td class="optional">否</td><td>省略时核验全部有效授权车辆</td></tr></table><div class="note"><strong>匹配规则:</strong>速度 ≤ 3 km/h,至少 2 个样本且停留 ≥ 60 秒;相邻定位点间隔超过 10 分钟时拆分停留区间。</div></div><div><h3 class="subhead">成功返回 · 200</h3><pre class="code">{<br> <span class="key">"data"</span>: [{<br> <span class="key">"plateNumber"</span>: <span class="string">"浙F06618F"</span>,<br> <span class="key">"stayStartTime"</span>: <span class="string">"2026-08-06 10:16:02"</span>,<br> <span class="key">"stayEndTime"</span>: <span class="string">"2026-08-06 10:42:18"</span>,<br> <span class="key">"stayDurationSeconds"</span>: <span class="number">1576</span>,<br> <span class="key">"matchScore"</span>: <span class="number">93.842</span><br> }]<br>}</pre><ul class="errors"><li>400:时间、坐标、坐标系或半径不合法</li><li>403:授权期未覆盖整个时间段</li><li>无匹配:data 为空数组</li></ul></div></div></section>
|
||
|
||
<section class="section" id="stations"><div class="section-head"><div><h2>加氢站地图点位</h2><div class="endpoint"><span class="method">POST</span>/api/v1/hydrogen-stations/query</div><p>只读查询有有效坐标的加氢站,可按行政区划和合作属性筛选。</p></div><a class="anchor" href="#stations">#</a></div><div class="grid"><div><h3 class="subhead">请求参数</h3><table class="param-table"><tr><th>字段</th><th>必填</th><th>说明</th></tr><tr><td>province / city</td><td class="optional">否</td><td>行政区划筛选</td></tr><tr><td>cooperateOnly</td><td class="optional">否</td><td>true 仅合作站;false 仅外部站</td></tr></table></div><div><h3 class="subhead">成功返回 · 200</h3><pre class="code">{<br> <span class="key">"data"</span>: [{<br> <span class="key">"id"</span>: <span class="string">"1"</span>,<br> <span class="key">"name"</span>: <span class="string">"示例加氢站"</span>,<br> <span class="key">"longitude"</span>: <span class="number">120.752312</span>,<br> <span class="key">"latitude"</span>: <span class="number">30.746281</span>,<br> <span class="key">"cooperative"</span>: <span class="number">true</span><br> }]<br>}</pre><ul class="errors"><li>400:行政区划参数过长</li><li>401:appKey 无效</li><li>无符合站点:data 为空数组</li></ul></div></div></section>
|
||
|
||
<section class="section" id="response-fields"><div class="section-head"><div><h2>返回字段与枚举说明</h2><p>所有成功响应外层固定包含 code、message、data 和 traceId;以下为 data 内的字段。无数据时按对应接口返回 null、NO_DATA 或空数组。</p></div><a class="anchor" href="#response-fields">#</a></div><h3 class="subhead" style="margin-top:22px">通用响应与状态</h3><table class="protocol-table"><tr><th>字段/枚举</th><th>说明</th></tr><tr><td>code = SUCCESS</td><td>请求已成功处理。业务数据是否存在由每条数据的 status 判断。</td></tr><tr><td>message</td><td>成功时固定为 success。</td></tr><tr><td>traceId</td><td>本次请求唯一追踪标识;异常排查时请完整提供。</td></tr><tr><td>status = NORMAL</td><td>存在可用数据,相关数值、协议和时间字段有效。</td></tr><tr><td>status = NO_DATA</td><td>在授权范围内未找到可用数据;可选数值、位置、时间字段为 null 或省略。</td></tr><tr><td>status = DATA_ANOMALY</td><td>检测到数据异常,里程异常不返回可能错误的里程;用氢 SUSPECT 保留审计数值。原因分别见 dataQuality / qualityReason。</td></tr><tr><td>dataQuality = TOTAL_MILEAGE_ROLLBACK</td><td>终端累计里程明显回退,已阻止其作为正常累计里程返回。</td></tr></table><h3 class="subhead" style="margin-top:28px">车辆单日用氢量</h3><table class="protocol-table"><tr><th>字段</th><th>说明</th></tr><tr><td>vin / plateNumber / date</td><td>授权车辆 VIN、车牌与查询自然日(Asia/Shanghai)。</td></tr><tr><td>hydrogenConsumptionKg</td><td>当日用氢量,单位 kg;无有效数据时为 null。</td></tr><tr><td>status / qualityStatus</td><td>NORMAL / OK 为可用;DATA_ANOMALY / SUSPECT 保留数值供审计,不参与正常百公里氢耗;NO_DATA 不可用。</td></tr><tr><td>calculationPhase / algorithmVersion</td><td>PRELIMINARY 为初步监控结果,FINAL 为批量重算结果;历史结果仍可能再重算,保留实际版本。</td></tr><tr><td>statisticsStartTime / statisticsEndTime / updatedAt</td><td>证据包络起止和统计行更新时间;PRELIMINARY 开始时间为 null,结束为数据水位。与里程无共同快照保证。</td></tr></table><h3 class="subhead" style="margin-top:28px">车辆单日里程与区间日里程</h3><table class="protocol-table"><tr><th>字段</th><th>说明</th></tr><tr><td>vin / plateNumber / date</td><td>车辆唯一 VIN、车牌和统计自然日。</td></tr><tr><td>dailyMileageKm</td><td>当日行驶里程,单位 km。缺少当日记录且可前向补齐时为 0。</td></tr><tr><td>totalMileageKm</td><td>所选协议的日末累计总里程,单位 km;不会用 GPS 日里程估算值替代。</td></tr><tr><td>sourceProtocol</td><td>实际采用的协议:GB32960、MQTT 或 JT808。</td></tr><tr><td>dataTime</td><td>实际采用的最后一条车辆源数据时间。</td></tr><tr><td>updatedAt</td><td>该统计周期的计算时间;前向补齐时保持上一有效统计周期时间。</td></tr><tr><td>snapshotId / nextCursor</td><td>仅区间接口返回;snapshotId 固定本次分页车辆范围,nextCursor 为下一页游标,最后一页为 null。</td></tr></table><h3 class="subhead" style="margin-top:28px">指定时刻总里程</h3><table class="protocol-table"><tr><th>字段</th><th>说明</th></tr><tr><td>vin / queryTime</td><td>查询车辆 VIN 与请求的北京时间。</td></tr><tr><td>totalMileageKm</td><td>不晚于请求时间的最近一条累计总里程,单位 km。</td></tr><tr><td>protocol / protocolInput</td><td>protocol 为实际命中协议;protocolInput 为请求显式传入的协议,未传则省略。</td></tr><tr><td>recordTime / timeDifferenceSeconds</td><td>实际命中记录时间,以及请求时间与记录时间的差值,单位秒。</td></tr><tr><td>mileageMeaning</td><td>该协议累计里程的业务口径;JT808 为定位终端/GPS侧累计值。</td></tr></table><h3 class="subhead" style="margin-top:28px">车辆实时位置与状态</h3><table class="protocol-table"><tr><th>字段/枚举</th><th>说明</th></tr><tr><td>protocol</td><td>本条位置、速度、累计里程和记录时间实际采用的协议:GB32960、MQTT 或 JT808。</td></tr><tr><td>remainingHydrogenKg / remainingHydrogenPercent</td><td>全车储氢 kg / %,真实零保留。质量优先终端上报,缺值可用同帧温压和 VIN 容积估算;百分比按35 MPa、15°C满充质量计算,缺条件独立返回 null。</td></tr><tr><td>hydrogenRecordTime / hydrogenDataStatus</td><td>同帧采集时间和聚合状态 NORMAL / PARTIAL / STALE / MISSING / UNSUPPORTED / INVALID;必须同时检查两个字段级状态。</td></tr><tr><td>gpsFixStatus / locationRecordTime / coordinateSystem</td><td>真实定位位、位置采集时间和 WGS84 / GCJ02 / UNKNOWN。离线不清除历史 FIXED,陈旧不证明无定位。</td></tr><tr><td>longitude / latitude</td><td>无有效位置或 NO_FIX 时为 null,locationAvailable 为 false;UNKNOWN 坐标系需由调用方确认后上图。</td></tr><tr><td>speedKmh / totalMileageKm</td><td>所选来源的瞬时速度(km/h)和累计总里程(km)。</td></tr><tr><td>recordTime / timeDifferenceSeconds</td><td>所选来源的记录时间,以及与当前查询时间的差值,单位秒。</td></tr><tr><td>online</td><td>true:任一协议最近 60 秒内上报;false:没有任一协议满足该实时阈值。</td></tr><tr><td>activeToday</td><td>true:任一协议在当前自然日曾上报;不等同于实时 online。</td></tr><tr><td>motionStatus = driving</td><td>在线且所选来源速度大于 3 km/h。</td></tr><tr><td>motionStatus = idle</td><td>在线且所选来源速度不大于 3 km/h。</td></tr><tr><td>motionStatus = offline</td><td>当前不在线,或没有实时记录。</td></tr></table><h3 class="subhead" style="margin-top:28px">加氢车辆停留核验</h3><table class="protocol-table"><tr><th>字段</th><th>说明</th></tr><tr><td>stayStartTime / stayEndTime</td><td>满足核验条件的连续停留开始、结束时间。</td></tr><tr><td>stayDurationSeconds / stayDurationMinutes</td><td>停留时长,分别以秒、分钟表示。</td></tr><tr><td>matchScore</td><td>0–100;位置越接近、速度越低、停留越久、样本越充分,分数越高。</td></tr><tr><td>averageDistanceMeters / maxDistanceMeters</td><td>定位点相对输入站点坐标的平均/最大距离,单位 m。</td></tr><tr><td>averageSpeedKmh / maxSpeedKmh / matchedSamples</td><td>核验区间内速度统计与匹配定位样本数。</td></tr><tr><td>sourceProtocols</td><td>本停留片段采用过的协议数组,枚举值为 GB32960、MQTT、JT808。</td></tr></table><h3 class="subhead" style="margin-top:28px">加氢站地图点位</h3><table class="protocol-table"><tr><th>字段</th><th>说明</th></tr><tr><td>id / name / shortName</td><td>站点唯一标识、标准名称和简称;id 为字符串以避免 JavaScript 精度丢失。</td></tr><tr><td>address / province / city / district</td><td>站点地址及行政区划。</td></tr><tr><td>longitude / latitude</td><td>站点坐标。</td></tr><tr><td>cooperative</td><td>true:合作站(内部站或已导入合作名录);false:外部站。</td></tr></table></section>
|
||
|
||
<section class="section" id="protocols"><div class="section-head"><div><h2>总里程协议口径</h2><p>未指定 protocol 时,按 GB32960 > MQTT > JT808 选择第一个有数据的协议;不会跨协议拼接里程。</p></div><a class="anchor" href="#protocols">#</a></div><table class="protocol-table"><tr><th>规范值</th><th>总里程含义</th></tr><tr><td>GB32960</td><td>车辆仪表盘累计总里程,对应 GB/T 32960 整车数据累计里程。</td></tr><tr><td>MQTT</td><td>车辆仪表盘或车端控制器累计总里程,由 MQTT 平台上报。</td></tr><tr><td>JT808</td><td>定位终端累计里程,由 GPS/终端侧计算,不等同于车辆仪表盘里程。</td></tr></table></section>
|
||
|
||
<section class="section" id="errors"><div class="section-head"><div><h2>异常与状态码</h2><p>所有响应均包含 <code>code</code>、<code>message</code> 和 <code>traceId</code>;请在工单中提供 traceId 以便排查。</p></div><a class="anchor" href="#errors">#</a></div><table class="protocol-table error-table"><tr><th>HTTP</th><th>code</th><th>说明</th></tr><tr><td>200</td><td>SUCCESS</td><td>查询成功;无统计数据时,数据行的 status 为 NO_DATA。</td></tr><tr><td>400</td><td>INVALID_REQUEST</td><td>请求格式、数量、日期、时间、坐标或协议不正确。</td></tr><tr><td>401</td><td>UNAUTHORIZED</td><td>appKey 不存在、停用或已过期。</td></tr><tr><td>403</td><td>FORBIDDEN</td><td>车辆或 appKey 授权期未覆盖请求时间。</td></tr><tr><td>500</td><td>INTERNAL_ERROR</td><td>服务内部异常;请提供 traceId。</td></tr></table></section>
|
||
</main>
|
||
</div>
|
||
<script>
|
||
(() => {
|
||
const common = [
|
||
["code", "string", "固定为 SUCCESS,表示 HTTP 请求处理成功;请结合 data 内每条 status 判断是否有业务数据。"],
|
||
["message", "string", "成功时固定为 success。"],
|
||
["traceId", "string", "本次请求的唯一追踪标识;出现问题时请完整提供给羚牛技术支持。"]
|
||
];
|
||
const fields = {
|
||
"historical-hydrogen": [
|
||
["data[].requestId / vin / queryTime", "string", "逐项对应请求;不得只依赖数组位置配对作业起终点。"],
|
||
["data[].plateNumber", "string | null", "当前缺少历史车牌证据,为null,不把当前车牌冒充历史车牌。"],
|
||
["data[].remainingHydrogenKg / remainingHydrogenKgStatus", "number | null / enum", "仅NORMAL给原始精度kg;其他状态null。有效质量超过容差STALE;最新INVALID/MISSING保留原状态。无历史氢相关帧NO_DATA;分块重组失败或扫描预算耗尽ERROR,不得回退。"],
|
||
["data[].hydrogenRecordTime / timeDifferenceSeconds", "datetime | null / number | null", "真实event_time(RFC3339带时区)与查询采样偏差秒数,绝不使用查询之后的帧。"],
|
||
["data[].hydrogenValueSource / hydrogenSourceProtocol", "string | null", "当前REPORTED表示终端上报(不等同直接测量),GB32960为实际氢协议。ESTIMATED保留但缺历史容积版本时不输出估算值。"],
|
||
["data[].sourceRecordId", "string | null", "raw-sha256采样身份指纹,便于识别同一采样命中;内容版本另看sourceDataVersion,不是批次快照。"],
|
||
["data[].sourceDataVersion", "string | null", "sha256原始JSON与解析状态内容指纹,识别同采样修订;不同起终点内容不同是正常的,不要求两端此字段相等。"],
|
||
["data[].hydrogenCalculationVersion / hydrogenCapacityVersion", "string | null", "REPORTED_HYDROGEN_KG_V1解码转换版本;历史容量版本缺证据为null,不能用当前值回套。"],
|
||
["data[].updatedAt", "datetime | null", "原始记录接收时间,不代替采集时间;即使时间不变,内容修订仍会改变sourceDataVersion。"],
|
||
["data[].reasonCode / message", "string | null", "可程序识别原因与中文说明;ERROR应重试,不能当NO_DATA;FORBIDDEN不返回采样证据。"],
|
||
["data[].hydrogenEstimatePressureMPa / hydrogenEstimateTemperatureC / hydrogenTankCapacityL / hydrogenPressureTemperatureSource", "number | null / string | null", "有同帧温压可返回诊断证据;MAX_SENSOR_AGGREGATE不保证同瓶。没有历史容量证据仍MISSING,容积null。"]
|
||
],
|
||
"daily-hydrogen": [
|
||
["data[]", "array", "按请求车牌顺序返回的车辆数据数组。"],
|
||
["data[].vin", "string", "授权车辆 VIN,必须与实时、里程记录共同核对。"],
|
||
["data[].plateNumber", "string", "车辆车牌号。"],
|
||
["data[].date", "date", "查询自然日,格式 yyyy-MM-dd,时区 Asia/Shanghai。"],
|
||
["data[].hydrogenConsumptionKg", "number | null", "当日用氢量,单位 kg;无有效统计时为 null。"],
|
||
["data[].statisticsStartTime / statisticsEndTime", "datetime | null", "FINAL 取证据区间最早开始/最晚结束,是证据包络,不保证连续覆盖;PRELIMINARY 仅结束水位,开始为 null;异常或缺失证据为 null。"],
|
||
["data[].updatedAt", "datetime | null", "同一用氢统计行的数据库更新时间,RFC 3339 带时区。"],
|
||
["data[].calculationPhase", "enum (optional)", "PRELIMINARY:初步监控值;FINAL:已批量重算,仍可因补传或算法变更再次重算。"],
|
||
["data[].algorithmVersion", "string (optional)", "实际计算算法版本;压力/温度/容积模型估算,特殊能量积分兜底由质量原因说明。"],
|
||
["data[].qualityStatus / qualityReason", "string (optional)", "OK:可用;SUSPECT:异常/估算兜底,保留数值供审计;NO_DATA:不可用。qualityReason 解释原因。"],
|
||
["data[].status", "enum", "NORMAL 对应 OK;DATA_ANOMALY 对应 SUSPECT,禁止参与正常百公里氢耗;NO_DATA 为无可用统计。"]
|
||
],
|
||
"daily-mileage": [
|
||
["data[]", "array", "按请求车牌顺序返回的车辆数据数组。"],
|
||
["data[].vin", "string", "车辆唯一 VIN。"], ["data[].plateNumber", "string", "车辆车牌号。"], ["data[].date", "date", "查询自然日,yyyy-MM-dd,Asia/Shanghai。"],
|
||
["data[].dailyMileageKm", "number | null", "当日行驶里程,单位 km;若当日无记录但存在此前有效累计里程,则返回 0。"],
|
||
["data[].totalMileageKm", "number | null", "日末累计总里程,单位 km;仅采用终端累计里程,不以 GPS 日里程估算替代。"],
|
||
["data[].sourceProtocol", "enum | null", "<span class='enum-value'>GB32960</span> GB/T 32960 车辆仪表累计里程;<span class='enum-value'>MQTT</span> 车端/MQTT 平台累计里程;<span class='enum-value'>JT808</span> 定位终端/GPS侧累计里程。"],
|
||
["data[].statisticsStartTime / statisticsEndTime", "datetime | null", "当日统计所选来源首末采集时间,跨日基线开始可早于当日零点,不是自然日起始;历史结转补零时均为 null。与用氢无共同快照,不可仅凭同日直接相除。"],
|
||
["data[].dataTime", "datetime | null", "本条统计实际采用的最后一条车辆源数据时间。"], ["data[].updatedAt", "datetime | null", "本行统计计算时间;前向补齐时为上一个有效统计周期的计算时间。"],
|
||
["data[].status", "enum", "<span class='enum-value'>NORMAL</span> 有效;<span class='enum-value'>NO_DATA</span> 无数据;<span class='enum-value'>DATA_ANOMALY</span> 发现异常,里程不返回。"],
|
||
["data[].dataQuality", "enum | null", "仅 DATA_ANOMALY 时返回。<span class='enum-value'>TOTAL_MILEAGE_ROLLBACK</span> 表示终端累计里程明显回退,已拦截。"]
|
||
],
|
||
"mileage-range": [
|
||
["data[]", "array", "当前页的车辆×日期数据,按请求区间与授权车辆快照排序。字段说明见下表;statisticsStartTime / statisticsEndTime 仅单日接口新增。"],
|
||
["data[].vin / plateNumber / date", "string / date", "车辆 VIN、车牌和该行统计自然日。"], ["data[].dailyMileageKm", "number | null", "当日里程,单位 km。"], ["data[].totalMileageKm", "number | null", "该日累计总里程,单位 km。"],
|
||
["data[].sourceProtocol", "enum | null", "<span class='enum-value'>GB32960</span> / <span class='enum-value'>MQTT</span> / <span class='enum-value'>JT808</span>;含义见单日里程接口。"],
|
||
["data[].dataTime / updatedAt", "datetime | null", "采用源数据时间 / 统计计算时间。"], ["data[].status / dataQuality", "enum | null", "NORMAL、NO_DATA、DATA_ANOMALY;异常原因目前为 TOTAL_MILEAGE_ROLLBACK。"],
|
||
["snapshotId", "string", "本次分页授权车辆快照标识;后续翻页必须保持原参数并继续使用。"], ["nextCursor", "string | null", "下一页游标;为 null 表示已到最后一页。"]
|
||
],
|
||
"total-mileage": [
|
||
["data.vin", "string", "查询车辆 VIN。"], ["data.queryTime", "datetime", "请求指定的北京时间。"], ["data.totalMileageKm", "number | null", "不晚于 queryTime 的最近一条累计总里程,单位 km;无记录时为 null。"],
|
||
["data.protocol", "enum | null", "实际命中协议。<span class='enum-value'>GB32960</span> 仪表累计;<span class='enum-value'>MQTT</span> 车端累计;<span class='enum-value'>JT808</span> 定位/GPS累计。"],
|
||
["data.protocolInput", "string | null", "请求中传入的协议原值;未指定时为 null/省略。"], ["data.mileageMeaning", "string | null", "当前 protocol 的累计里程业务口径说明。"],
|
||
["data.recordTime", "datetime | null", "实际命中的源数据记录时间,北京时间。"], ["data.timeDifferenceSeconds", "integer | null", "queryTime 减 recordTime 的秒数。"],
|
||
["data.selectionPolicy", "string", "未指定协议时使用的默认选源顺序。"], ["data.status", "enum", "<span class='enum-value'>NORMAL</span> 找到记录;<span class='enum-value'>NO_DATA</span> 未找到不晚于请求时间的记录。"]
|
||
],
|
||
"realtime": [
|
||
["data[]", "array", "按请求车牌顺序返回;省略车牌时返回当前授权范围内全部车辆。"], ["data[].vin / plateNumber", "string", "车辆唯一 VIN / 车牌。"],
|
||
["data[].remainingHydrogenKg / remainingHydrogenPercent", "number | null", "全车质量 kg / 比例 %;优先 GB32960 广东扩展终端上报 kg(0–200),缺kg可由同帧最大氢压/氢温与VIN容积估算(0–500)。比例按35 MPa、15°C满充质量计算;真实0保留,不以动力电池SOC替代。"],
|
||
["data[].hydrogenRecordTime", "datetime | null", "氢量原始同帧的实际采集时间,RFC 3339 带时区;不是查询/缓存时间。仅 GB 最新快照有引用且精确帧氢量 MISSING 时,回查快照 received_at 向前 5 分钟的候选,按采集时间优先检查最近5条;不完整温压可取次新完整帧,INVALID 不回退,离线回补保留真实 STALE。"],
|
||
["data[].hydrogenDataStatus", "enum", "NORMAL 全部有效;PARTIAL 部分字段支持;STALE 陈旧;MISSING 缺记录或本次未取得可信证据(补充查询失败/3 秒超时会降级);UNSUPPORTED 不支持;INVALID 异常。两项有效时 NORMAL(是否估算看来源);仅一项有效时 PARTIAL。"],
|
||
["data[].remainingHydrogenKgStatus / remainingHydrogenPercentStatus", "enum", "逐字段 NORMAL / STALE / MISSING / UNSUPPORTED / INVALID;独立判断两个数值,聚合状态不代表两者都有效。"],
|
||
["data[].hydrogenValueSource / hydrogenSourceProtocol", "string | null", "kg 来源 REPORTED 仅确认终端上报,ESTIMATED 为平台温压/容积实气估算;储氢协议独立于位置 protocol。"],
|
||
["data[].remainingHydrogenPercentSource", "enum | null", "ESTIMATED:比例按模型满充质量计算,与kg来源独立;计算缺条件时null。超过100比例null/INVALID,kg独立保留,不截断成100。"],
|
||
["data[].hydrogenFullCapacityKg / hydrogenTankCapacityL", "number | null", "未舍入满充质量分母kg / 已启用VIN全车水容积L(0<V≤10000)。无默认车型容积;缺容量百分比MISSING。"],
|
||
["data[].hydrogenFullPressureMPa / hydrogenReferenceTemperatureC", "number | null", "35 MPa / 15°C;业务满充参考,不是自动核验每车铭牌额定压力,也不是可用容量扣除残余后的分母。"],
|
||
["data[].hydrogenEstimatePressureMPa / hydrogenEstimateTemperatureC", "number | null", "仅估算kg时采用的同帧最大氢压/氢温;压力0–70 MPa,温度−40–726.85°C,不补默认温度。"],
|
||
["data[].hydrogenPressureTemperatureSource", "enum | null", "MAX_SENSOR_AGGREGATE:最大温压聚合值,不保证来自同一瓶,不能当逐瓶质量求和或完整性证明。"],
|
||
["data[].hydrogenCalculationVersion / hydrogenCapacitySource", "string | null", "REAL_GAS_35MPA_15C_V1 / vehicle_hydrogen_tank_capacity。复用实气模型与VIN配置,不改变日用氢算法。"],
|
||
["data[].hydrogenPercentReason", "enum | null", "MISSING_HYDROGEN_MEASUREMENT、INVALID_MASS_READING、INVALID_PRESSURE_TEMPERATURE、INCOMPLETE_PRESSURE_TEMPERATURE、MISSING_TANK_CAPACITY、MASS_CALCULATION_FAILED、EXCEEDS_NOMINAL_FULL_CAPACITY;超满充参考拒绝百分比,不据此判断车辆安全状态。"],
|
||
["data[].hydrogenStaleAfterSeconds / hydrogenExpectedIntervalSeconds", "integer | null", "GB32960 服务陈旧阈值 300 秒;协议期望上报周期未约定为 null,阈值不是采样周期承诺。"],
|
||
["data[].gpsFixStatus", "enum", "FIXED / NO_FIX / UNKNOWN:实际位置报文定位位,独立于在线和数据年龄;MQTT 无可信定位位为 UNKNOWN。"],
|
||
["data[].locationRecordTime / coordinateSystem", "datetime | null / enum", "位置实际采集时间。坐标系 WGS84 / GCJ02 / UNKNOWN;仅 GB2025 显式类型 1/2 确定 WGS84/GCJ02,GB2016/JT808/MQTT 无确证为 UNKNOWN。不能默认 GCJ02。"],
|
||
["data[].protocol", "enum | null", "本条位置、速度、累计里程和记录时间实际采用的唯一协议字段。<span class='enum-value'>GB32960</span> 车辆协议;<span class='enum-value'>MQTT</span> MQTT 车端来源;<span class='enum-value'>JT808</span> 定位终端来源。"],
|
||
["data[].longitude / latitude", "number | null", "所选来源的最新有效经度/纬度;无位置时为 null。"], ["data[].speedKmh", "number | null", "所选来源瞬时速度,单位 km/h。"], ["data[].socPercent", "number", "所选来源的动力电池荷电状态,单位 %;仅在采集值为 0–100 时返回,无值或无效值时字段省略。"], ["data[].totalMileageKm", "number | null", "所选来源累计总里程,单位 km。"],
|
||
["data[].recordTime", "datetime | null", "所选来源实际记录时间,北京时间。"], ["data[].timeDifferenceSeconds", "integer | null", "当前查询时间减 recordTime,单位秒。"],
|
||
["data[].online", "boolean", "true:任一采集协议在最近 60 秒内上报;false:没有协议满足实时阈值。"], ["data[].activeToday", "boolean", "true:任一采集协议在当前自然日曾上报;它不等同于 online。"],
|
||
["data[].motionStatus", "enum", "<span class='enum-value'>driving</span> 在线且所选速度 > 3 km/h;<span class='enum-value'>idle</span> 在线且速度 ≤ 3 km/h;<span class='enum-value'>offline</span> 当前不在线或无实时记录。"],
|
||
["data[].locationAvailable", "boolean", "true:longitude 与 latitude 有效;false:当前无有效位置。"], ["data[].status", "enum", "<span class='enum-value'>NORMAL</span> 找到实时记录;<span class='enum-value'>NO_DATA</span> 无实时记录。"]
|
||
],
|
||
"stationary": [
|
||
["data[]", "array", "满足站点停留匹配条件的车辆片段;无匹配时为空数组。"], ["data[].vin / plateNumber", "string", "车辆唯一 VIN / 车牌。"],
|
||
["data[].stayStartTime / stayEndTime", "datetime", "连续停留片段的起止定位时间,北京时间。"], ["data[].stayDurationSeconds / stayDurationMinutes", "integer / number", "停留时长,分别以秒/分钟表示。"],
|
||
["data[].matchScore", "number", "0–100;位置越接近、速度越低、停留越久、样本越充分,分数越高。"], ["data[].averageDistanceMeters / maxDistanceMeters", "number", "定位点相对输入站点坐标的平均/最大距离,单位 m。"],
|
||
["data[].averageSpeedKmh / maxSpeedKmh", "number", "停留片段内平均/最大速度,单位 km/h。"], ["data[].matchedSamples", "integer", "用于该停留片段的定位样本数,至少为 2。"],
|
||
["data[].sourceProtocols", "array<enum>", "片段中实际采用过的协议数组:GB32960、MQTT、JT808。"]
|
||
],
|
||
"stations": [
|
||
["data[]", "array", "符合行政区划与合作属性筛选条件的站点数组;无符合项时为空数组。"], ["data[].id", "string", "站点 ID 使用字符串,避免 JavaScript 大整数精度丢失。"], ["data[].name / shortName", "string", "站点标准名称 / 简称。"],
|
||
["data[].address", "string", "站点地址。"], ["data[].longitude / latitude", "number", "站点经纬度。"], ["data[].province / city / district", "string", "站点省、市、区县行政区划。"],
|
||
["data[].cooperative", "boolean", "true:合作站(内部站或已导入合作名录);false:外部站。"]
|
||
]
|
||
};
|
||
const sectionIds = Object.keys(fields);
|
||
const esc = value => String(value).replace(/[&<>\"]/g, char => ({"&":"&","<":"<",">":">","\"":"""}[char]));
|
||
const expandFields = rows => rows.flatMap(([path, type, description]) => {
|
||
if (path === "data[]") return [[path, type, description]];
|
||
const prefix = path.startsWith("data[].") ? "data[]." : (path.startsWith("data.") ? "data." : "");
|
||
const names = path.slice(prefix.length).split(" / ");
|
||
const types = type.split(" / ");
|
||
return names.map((name, index) => [prefix + name, types[index] || type, description]);
|
||
});
|
||
const treeCell = (depth, name, kind, root) => {
|
||
const branch = root ? "" : "<span class='tree-branch' aria-hidden='true'></span>";
|
||
const label = root ? "<span class='tree-root'>" + esc(name) + "</span>" : "<span class='tree-node'>" + esc(name) + "</span>";
|
||
return "<div class='tree-field depth-" + depth + "'>" + branch + label + (kind ? "<span class='tree-kind'>" + esc(kind) + "</span>" : "") + "</div>";
|
||
};
|
||
const renderResponseTree = rows => {
|
||
const expanded = expandFields(rows);
|
||
const dataArray = expanded.find(row => row[0] === "data[]");
|
||
const dataObject = expanded.some(row => row[0].startsWith("data."));
|
||
const regular = expanded.filter(row => row[0] !== "data[]");
|
||
const outer = regular.filter(row => !row[0].startsWith("data.") && !row[0].startsWith("data[]."));
|
||
const nested = regular.filter(row => row[0].startsWith("data.") || row[0].startsWith("data[]."));
|
||
let html = "<tr class='tree-root-row'><td>" + treeCell(0, "响应对象", "object", true) + "</td><td>object</td><td>本接口成功响应的 JSON 根对象。</td></tr>";
|
||
html += common.map(row => "<tr><td>" + treeCell(1, row[0], "", false) + "</td><td>" + esc(row[1]) + "</td><td>" + row[2] + "</td></tr>").join("");
|
||
if (dataArray) {
|
||
html += "<tr><td>" + treeCell(1, "data", "array", false) + "</td><td>array</td><td>" + dataArray[2] + "</td></tr>";
|
||
html += "<tr><td>" + treeCell(2, "[]", "object", false) + "</td><td>object</td><td>data 数组中的一条车辆/站点数据。</td></tr>";
|
||
} else if (dataObject) {
|
||
html += "<tr><td>" + treeCell(1, "data", "object", false) + "</td><td>object</td><td>本次查询对应的一条业务数据。</td></tr>";
|
||
}
|
||
html += nested.map(row => {
|
||
const name = row[0].replace(/^data(?:\[\])?\./, "");
|
||
return "<tr><td>" + treeCell(dataArray ? 3 : 2, name, "", false) + "</td><td>" + esc(row[1]) + "</td><td>" + row[2] + "</td></tr>";
|
||
}).join("");
|
||
html += outer.map(row => "<tr><td>" + treeCell(1, row[0], "", false) + "</td><td>" + esc(row[1]) + "</td><td>" + row[2] + "</td></tr>").join("");
|
||
return html;
|
||
};
|
||
sectionIds.forEach(id => {
|
||
const section = document.getElementById(id);
|
||
const left = section && section.querySelector(".grid > div:first-child");
|
||
if (!left) return;
|
||
const requestTitle = left.querySelector(".subhead");
|
||
const requestTable = left.querySelector("table");
|
||
if (!requestTitle || !requestTable) return;
|
||
requestTitle.remove();
|
||
const tabs = document.createElement("div"); tabs.className = "field-tabs";
|
||
const requestButton = document.createElement("button"); requestButton.className = "field-tab"; requestButton.type = "button"; requestButton.textContent = "请求参数"; requestButton.setAttribute("aria-selected", "true");
|
||
const responseButton = document.createElement("button"); responseButton.className = "field-tab"; responseButton.type = "button"; responseButton.textContent = "返回字段"; responseButton.setAttribute("aria-selected", "false");
|
||
tabs.append(requestButton, responseButton);
|
||
const requestPanel = document.createElement("div"); requestPanel.className = "request-panel"; requestPanel.append(requestTitle, requestTable);
|
||
const responsePanel = document.createElement("div"); responsePanel.className = "response-panel";
|
||
responsePanel.innerHTML = "<h3 class='subhead'>返回字段</h3><p class='response-caption'>按响应 JSON 的对象层级展示;数组元素以 <code>[]</code> 标记,枚举与空值规则已逐项说明。</p><table class='param-table response-table'><tr><th>响应结构</th><th>类型</th><th>说明/枚举</th></tr>" + renderResponseTree(fields[id]) + "</table>";
|
||
left.replaceChildren(tabs, requestPanel, responsePanel);
|
||
requestButton.addEventListener("click", () => { requestButton.setAttribute("aria-selected", "true"); responseButton.setAttribute("aria-selected", "false"); requestPanel.style.display = "block"; responsePanel.classList.remove("active"); });
|
||
responseButton.addEventListener("click", () => { responseButton.setAttribute("aria-selected", "true"); requestButton.setAttribute("aria-selected", "false"); requestPanel.style.display = "none"; responsePanel.classList.add("active"); });
|
||
});
|
||
const realtimeSample = document.querySelector("#realtime .code");
|
||
if (realtimeSample) realtimeSample.innerHTML = realtimeSample.innerHTML.replace("sourceProtocol", "protocol").replace('<span class="key">"speedKmh"</span>:', '<span class="key">"socPercent"</span>: <span class="number">78.5</span>,<br> <span class="key">"speedKmh"</span>:');
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|