3 天以前 2a69f1a4365fb7daa8d00c07ac859a0d45780eb7
docs(mes): 添加设备数采API调试文档

- 新增设备数采API调试记录文档,包含模块与数据流概述
- 详细说明数采接口的调试前置条件、数采服务地址配置和外部接口约定
- 提供6个核心接口的详细说明,包括拉取、分页查询、最新数据、设备列表、校验明细和统计接口
- 添加遥测记录公共字段说明和调试注意事项排查清单
- 提供数据自查SQL语句便于调试辅助验证
已添加1个文件
403 ■■■■■ 文件已修改
docs/dv_telemetry_api_debug.md 403 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/dv_telemetry_api_debug.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,403 @@
# è®¾å¤‡æ•°é‡‡ Â· API è°ƒè¯•记录
> è¯´æ˜Žï¼šæœ¬æ–‡æ¡£åŸºäºŽåŽç«¯ä»£ç ï¼ˆ`yudao-module-mes` çš„ `controller/admin/dv/telemetry`)静态整理,供联调、回归、排查使用。示例报文字段对齐当前数据库真实样本(截至 2026-09-09)。
## ä¸€ã€æ¨¡å—与数据流概述
- æ‰€å±žæ¨¡å—:**MES è®¾å¤‡ç®¡ç† â†’ è®¾å¤‡æ•°é‡‡**(前端 `views/mes/dv/telemetry/`)。
- ä¸šåŠ¡æ•°æ®å…¨éƒ¨æ¥è‡ª**外部数采服务**(近 5 åˆ†é’Ÿçª—口),由后端拉取后落库到本地 `mes_dv_telemetry`,页面只读查询。
- æ•°é‡‡æŽ¥å£å‡æ— æ–°å¢ž/修改/删除/导出操作,仅有 **1 ä¸ªæ‹‰å–** + **5 ä¸ªæŸ¥è¯¢** æŽ¥å£ï¼Œç»Ÿä¸€æƒé™ `mes:dv-telemetry:query`。
- è½åº“表 `mes_dv_telemetry` çŽ°çŠ¶ï¼š**296 æ¡ / 4 å°è®¾å¤‡**。
| è®¾å¤‡åç§° | tbDeviceId | è®°å½•æ•° | é¥æµ‹æ—¶é—´èŒƒå›´ |
|----------|------------|-------|--------------|
| å•轴高低压-3 | 773544054188146757 | 64 | 2026-08-28 10:59:10 |
| å•轴高低压-4 | 773543983287631941 | 128 | 2026-08-28 10:59:09 ~ 2026-09-09 10:59:20 |
| å•轴高低压-5-改造 | 773543911229489221 | 64 | 2026-08-28 11:00:02 |
| çœŸç©ºæµ‡ç­‘机 | 773543828480065605 | 40 | 2026-08-28 10:59:53 ~ 2026-09-09 10:59:38 |
> æ³¨ï¼šå•轴高低压-3、-5-改造 æ•°æ®åœç•™åœ¨ 08-28,说明近几天数采服务仅对部分设备持续产出数据,属外部数据侧现状。
### æ•°æ®æµ
```
[外部数采服务] --GET è¿‘5分钟--> MesDvTelemetryPullJob(定时/手动) --convert+insertBatch--> mes_dv_telemetry
                                                                        |
                        é¡µé¢ latest / page / check / check-summary <----┘ (只读)
```
## äºŒã€è°ƒè¯•前置条件
| é¡¹ | å€¼ | è¯´æ˜Ž |
|----|----|------|
| æŽ¥å£å‰ç¼€ | `http://<服务器IP>:<端口>/admin-api` | åŽç«¯æœåŠ¡åœ°å€ |
| é‰´æƒ | `Authorization: Bearer <token>` | å…ˆç™»å½•获取 token |
| ç™»å½•接口 | `POST /admin-api/system/auth/login` | Body `{ "username": "…", "password": "…" }`,响应 `data.accessToken` |
| æƒé™ | `mes:dv-telemetry:query` | å½“前用户需拥有该权限,否则返回 403 |
| æ•°æ®è¡¨ | `mes_dv_telemetry`(库 `mom-xgdl`) | æ— å†™åº“场景,仅拉取写入 |
**通用请求头示例**
```http
GET /admin-api/mes/dv/telemetry/latest HTTP/1.1
Host: <服务器IP>:<端口>
Authorization: Bearer <token>
```
**通用响应壳**(所有接口):
```json
{ "code": 0, "msg": "", "data": â€¦ }
```
`code = 0` æˆåŠŸï¼›éž 0 ä¸ºä¸šåŠ¡/系统错误,见 `msg`。
### æ•°é‡‡æœåŠ¡åœ°å€é…ç½®ï¼ˆæ‹‰å– /pull ä¾èµ–)
配置项 `yudao.mes.telemetry`(`MesTelemetryProperties`):
| é¡¹ | å½“前值(application-local.yaml) | è¯´æ˜Ž |
|----|-------------------------------|------|
| `base-url` | `http://106.227.91.252:3100` | æ•°é‡‡æœåŠ¡åŸºç¡€åœ°å€ï¼Œæœªé…ç½®æ—¶ /pull æŠ¥é”™ |
| `path` | `/api/jxjs/mesTb/getDeviceDetails` | è¿”回近 5 åˆ†é’Ÿè®¾å¤‡æ•°æ® |
> è‹¥åˆ‡æ¢å…¶å®ƒè¿è¡Œ profile,请同步对应 yaml(local / test ç­‰å¤š profile ä¿æŒä¸€è‡´ï¼‰ã€‚
## ä¸‰ã€å¤–部数采接口约定(/pull åŽç«¯ä»£è°ƒï¼‰
后端 `/pull` ä¼šä»¥ HTTP GET è°ƒç”¨ï¼š
```
GET {base-url}{path}   (无参,返回近 5 åˆ†é’Ÿè®¾å¤‡æ•°æ®)
```
**期望响应结构:**
```json
{
  "code": "200",
  "data": [
    {
      "tbDeviceId": "773543983287631941",
      "deviceName": "单轴高低压-4",
      "paramName": "Slave1@油变_总匝数设定",
      "paramKeyName": "Slave1@油变_总匝数设定",
      "standardValue": null,
      "timelyValue": "500",
      "avgValue": "500.00",
      "maxValue": "500",
      "minValue": "500",
      "whetherAnomaly": false,
      "telemetryDataTime": "2026-09-09 10:59:20",
      "billNo": null,
      "shiftName": "早班"
    }
  ]
}
```
**字段 â†’ è¡¨åˆ—映射:**
| å¤–部字段 | è¡¨åˆ— | ç±»åž‹(库) | è¯´æ˜Ž |
|----------|------|----------|------|
| tbDeviceId | tb_device_id | varchar(100) | æ•°é‡‡è®¾å¤‡ID,与设备台账 `tb_device_id` å¯¹åº” |
| deviceName | device_name | varchar(100) | è®¾å¤‡åç§° |
| paramName | param_name | varchar(100) | ä¿¡å·åç§°ï¼ˆå±•示名) |
| paramKeyName | param_key_name | varchar(100) | è®¾å¤‡ KEY åç§°ï¼ˆåŽ»é‡é”®ï¼‰ |
| standardValue | standard_value | varchar(64) | æ ‡å‡†å€¼ |
| timelyValue | timely_value | varchar(64) | ä¿¡å·å€¼ï¼ˆå®žæ—¶ï¼‰ |
| avgValue | avg_value | varchar(64) | å‡å€¼ |
| maxValue | max_value | varchar(64) | æœ€å¤§å€¼ |
| minValue | min_value | varchar(64) | æœ€å°å€¼ |
| whetherAnomaly | whether_anomaly | bit(1) | æ˜¯å¦å¼‚常;接受 `1/0/true/false/Y/N` å­—符串 |
| telemetryDataTime | telemetry_data_time | datetime | é¥æµ‹æ—¶é—´ï¼ŒåŽç«¯æŒ‰é€šç”¨æ—¥æœŸæ ¼å¼è§£æž |
| billNo | bill_no | varchar(64) | å•据号 |
| shiftName | shift_name | varchar(64) | ç­æ¬¡ |
**容错规则(/pull ä¾§ï¼‰ï¼š**
- å¤–部 `code != "200"` â†’ æŠ¥é”™ã€Œæ•°é‡‡æ•°æ®æ‹‰å–失败:数采接口返回异常」。
- å¤–部返回 `data` ä¸ºç©ºæ•°ç»„ â†’ æ­£å¸¸è¿”回 `recordCount=0, deviceCount=0`(不报错)。
- `data` å†…某行不是 JSON å¯¹è±¡ â†’ è¯¥è¡Œè·³è¿‡ã€‚
## å››ã€æŽ¥å£æ˜Žç»†
> ç»Ÿä¸€è·¯å¾„前缀 `/admin-api/mes/dv/telemetry`,下同;以下均需 `Authorization: Bearer`,权限均 `mes:dv-telemetry:query`。
### 1. æ‹‰å–数采数据 `GET /pull`
无请求参数。后端调用外部数采接口并批量入库,返回本次统计。
**请求:**
```bash
curl "http://<服务器IP>:<端口>/admin-api/mes/dv/telemetry/pull" -H "Authorization: Bearer <token>"
```
**正常响应(有数据):**
```json
{
  "code": 0,
  "data": {
    "recordCount": 40,
    "deviceCount": 2,
    "pullTime": "2026-09-09 11:02:29"
  }
}
```
**正常响应(近 5 åˆ†é’Ÿæ— æ•°æ®ï¼‰ï¼š**
```json
{ "code": 0, "data": { "recordCount": 0, "deviceCount": 0, "pullTime": "2026-09-09 11:02:29" } }
```
| data å­—段 | ç±»åž‹ | è¯´æ˜Ž |
|----------|------|------|
| recordCount | Integer | æœ¬æ¬¡å…¥åº“条数 |
| deviceCount | Integer | æœ¬æ¬¡æ¶‰åŠè®¾å¤‡æ•°ï¼ˆæŒ‰ tbDeviceId åŽ»é‡ï¼‰ |
| pullTime | LocalDateTime | æ‹‰å–时间(入库批量共用) |
**异常场景:**
| code | è§¦å‘条件 |
|------|----------|
| 1_040_308_001(数采数据拉取失败:xxx) | æœªé…ç½® base-url / å¤–部调用异常 / è¿”回为空 / code≠200 |
> æŽ’查:外部服务地址是否可达(当前 base-url ä¸ºå…¬ç½‘/内网地址,网络不通时即报错);外部 `code` æ˜¯å¦å­—符串 `"200"`。
### 2. åŽ†å²è®°å½•åˆ†é¡µ `GET /page`
| å‚æ•° | ç±»åž‹ | å¿…å¡« | è¯´æ˜Ž |
|------|------|------|------|
| pageNo | Integer | æ˜¯ | é¡µç ï¼Œä»Ž 1 å¼€å§‹ |
| pageSize | Integer | æ˜¯ | æ¯é¡µæ¡æ•° |
| tbDeviceId | String | å¦ | æ•°é‡‡è®¾å¤‡ID(精确) |
| deviceName | String | å¦ | è®¾å¤‡åç§°ï¼ˆæ¨¡ç³Š like) |
| paramName | String | å¦ | ä¿¡å·åç§°ï¼ˆæ¨¡ç³Š like) |
| whetherAnomaly | Boolean | å¦ | true=异常 / false=正常 |
| shiftName | String | å¦ | ç­æ¬¡ï¼ˆç²¾ç¡®ï¼‰ |
| telemetryDataTime | String[] | å¦ | é¥æµ‹æ—¶é—´åŒºé—´ `[èµ·,æ­¢]`,格式 `yyyy-MM-dd HH:mm:ss` |
**请求:**
```bash
curl "http://<服务器IP>:<端口>/admin-api/mes/dv/telemetry/page?pageNo=1&pageSize=10&shiftName=%E6%97%A9%E7%8F%AD&whetherAnomaly=false" -H "Authorization: Bearer <token>"
```
**正常响应:**
```json
{
  "code": 0,
  "data": {
    "total": 128,
    "list": [
      {
        "id": 410,
        "tbDeviceId": "773543983287631941",
        "deviceName": "单轴高低压-4",
        "paramName": "Slave1@六段出头一设定",
        "paramKeyName": "Slave1@六段出头一设定",
        "standardValue": null,
        "timelyValue": "0",
        "avgValue": "0",
        "maxValue": "0",
        "minValue": "0",
        "whetherAnomaly": false,
        "telemetryDataTime": "2026-09-09 10:59:20",
        "billNo": null,
        "shiftName": "早班",
        "pullTime": "2026-09-09 11:02:29",
        "createTime": "2026-09-09 11:02:29"
      }
    ]
  }
}
```
**分页返回结构:** é¡¶å±‚ `data.total`(Long)+ `data.list`(数组)——注意是 **`list`**,不是 `records`,前端按 `{ total, list }` è§£æžã€‚
> æŽ’序:`telemetry_data_time` å€’序,再按 `id` å€’序。历史表为“每次拉取全量追加”,同信号会重复多行,联调注意用时间区间过滤。
### 3. å„设备最新遥测(实时监控)`GET /latest`
| å‚æ•° | ç±»åž‹ | å¿…å¡« | è¯´æ˜Ž |
|------|------|------|------|
| tbDeviceId | String | å¦ | ç²¾ç¡®è¿‡æ»¤å•台设备(设备台账「数采数据」Tab ç”¨ï¼‰ |
| deviceName | String | å¦ | è®¾å¤‡åç§°æ¨¡ç³Šè¿‡æ»¤ |
**实现要点:** å– `mes_dv_telemetry` æœ€è¿‘ **5000 æ¡**(按遥测时间倒序),内存按 `tbDeviceId + paramKeyName` åŽ»é‡ä¿ç•™æœ€æ–°ï¼Œè¿”å›ž**裸数组**。
**请求:**
```bash
curl "http://<服务器IP>:<端口>/admin-api/mes/dv/telemetry/latest" -H "Authorization: Bearer <token>"
curl "http://<服务器IP>:<端口>/admin-api/mes/dv/telemetry/latest?tbDeviceId=773543828480065605" -H "Authorization: Bearer <token>"
```
**正常响应(裸数组):**
```json
{
  "code": 0,
  "data": [
    {
      "id": 380,
      "tbDeviceId": "773543828480065605",
      "deviceName": "真空浇筑机",
      "paramName": "信号名称示例",
      "paramKeyName": "key@示例",
      "standardValue": null,
      "timelyValue": "0",
      "avgValue": "0",
      "maxValue": "0",
      "minValue": "0",
      "whetherAnomaly": false,
      "telemetryDataTime": "2026-09-09 10:59:38",
      "billNo": null,
      "shiftName": "早班",
      "pullTime": "2026-09-09 11:02:29",
      "createTime": "2026-09-09 11:02:29"
    }
  ]
}
```
**边界提醒:**
- è¿”回是数组,不是分页对象,前端需关闭分页组件解析,否则空展示。
- æ— æ•°æ®æ—¶è¿”回 `[]`(code ä»ä¸º 0)。
- åŽ»é‡ä¸Šé™ 5000 æ¡ï¼Œè‹¥åŽ†å²æ•°æ®é‡å·¨å¤§å¯¼è‡´ä¸€æ‰¹å†…æŸè®¾å¤‡æ—©äºŽ 5000 æ¡ä¹‹å¤–,该设备可能缺项。
### 4. æ•°é‡‡è®¾å¤‡ä¸‹æ‹‰ `GET /device-list`
无参数。从遥测表按 `tb_device_id + device_name` åˆ†ç»„去重返回。
```bash
curl "http://<服务器IP>:<端口>/admin-api/mes/dv/telemetry/device-list" -H "Authorization: Bearer <token>"
```
**正常响应:**
```json
{
  "code": 0,
  "data": [
    { "tbDeviceId": "773543911229489221", "deviceName": "单轴高低压-5-改造" },
    { "tbDeviceId": "773543828480065605", "deviceName": "真空浇筑机" },
    { "tbDeviceId": "773544054188146757", "deviceName": "单轴高低压-3" },
    { "tbDeviceId": "773543983287631941", "deviceName": "单轴高低压-4" }
  ]
}
```
> è¯¥ä¸‹æ‹‰ä»…列出**已出现在遥测表**的设备;若某台账设备从未被拉取过,不会出现在此。
### 5. ä¾›ç”µå‚数比对校验明细 `GET /check`
**当前实现与 `/latest` å®Œå…¨ä¸€è‡´**(同一 service æ–¹æ³•),仅前端展示口径不同(明细逐行对比 `timelyValue` ä¸Ž `standardValue`)。
| å‚æ•° | ç±»åž‹ | å¿…å¡« | è¯´æ˜Ž |
|------|------|------|------|
| tbDeviceId | String | å¦ | è®¾å¤‡è¿‡æ»¤ |
| deviceName | String | å¦ | è®¾å¤‡åç§°æ¨¡ç³Šè¿‡æ»¤ |
请求/响应结构与 `/latest` ç›¸åŒï¼ˆè¿”回裸数组)。
**响应字段比对含义:**
| å­—段 | åœ¨æ¯”对页的用途 |
|------|----------------|
| timelyValue | å®žæ—¶é‡‡é›†å€¼ |
| standardValue | ä¾›ç”µæ ‡å‡†å€¼ |
| whetherAnomaly | true=偏离标准(异常) |
> æ³¨æ„ï¼šå½“前后端仅**透传**外部数据的 `standardValue` / `whetherAnomaly`,未在内部做阈值计算。若外部未上报标准值(现库中 `standard_value` ä¸ºç©ºï¼‰ï¼Œæ¯”对结论主要依赖 `whetherAnomaly`。
### 6. ä¾›ç”µå‚数比对校验统计 `GET /check-summary`
基于 `/latest`(同上去重后的每设备最新参数行)按设备聚合统计。
| å‚æ•° | ç±»åž‹ | å¿…å¡« | è¯´æ˜Ž |
|------|------|------|------|
| tbDeviceId | String | å¦ | æŒ‡å®šè®¾å¤‡ï¼›ä¸ä¼ åˆ™æ±‡æ€»å…¨éƒ¨è®¾å¤‡ |
| deviceName | String | å¦ | è®¾å¤‡åç§°æ¨¡ç³Šè¿‡æ»¤ |
```bash
curl "http://<服务器IP>:<端口>/admin-api/mes/dv/telemetry/check-summary?tbDeviceId=773543983287631941" -H "Authorization: Bearer <token>"
```
**正常响应:**
```json
{
  "code": 0,
  "data": [
    {
      "tbDeviceId": "773543983287631941",
      "deviceName": "单轴高低压-4",
      "totalCount": 64,
      "normalCount": 64,
      "anomalyCount": 0,
      "anomalyRate": 0.0
    }
  ]
}
```
| data å­—段 | ç±»åž‹ | è¯´æ˜Ž |
|----------|------|------|
| tbDeviceId / deviceName | String | è®¾å¤‡ |
| totalCount | Integer | è¯¥è®¾å¤‡æœ€æ–°å‚数行数 |
| normalCount | Integer | æ­£å¸¸ï¼ˆwhetherAnomaly=false)数 |
| anomalyCount | Integer | å¼‚常(whetherAnomaly=true)数 |
| anomalyRate | BigDecimal | å¼‚常率%,保留 1 ä½å°æ•°ï¼ˆå››èˆäº”入);无参数时为 0 |
**统计口径:** totalCount = è®¾å¤‡åœ¨â€œæœ€è¿‘ 5000 æ¡åŽ»é‡åŽâ€çš„ä¿¡å·æ•°ï¼›`anomalyRate = anomalyCount * 100.0 / totalCount`(异常率百分比)。当前库中 4 å°è®¾å¤‡å¼‚常率均为 0(无异常行)。
## äº”、遥测记录公共字段(page / latest / check é€šç”¨ï¼‰
| å­—段 | ç±»åž‹ | è¯´æ˜Ž |
|------|------|------|
| id | Long | ç¼–号 |
| tbDeviceId | String | æ•°é‡‡è®¾å¤‡ID |
| deviceName | String | è®¾å¤‡åç§° |
| paramName | String | ä¿¡å·åç§° |
| paramKeyName | String | è®¾å¤‡KEY名称(去重键) |
| standardValue | String | æ ‡å‡†å€¼ï¼ˆå¯èƒ½ä¸ºç©ºï¼‰ |
| timelyValue | String | ä¿¡å·å€¼ï¼ˆå®žæ—¶ï¼‰ |
| avgValue / maxValue / minValue | String | å‡å€¼/最大/最小 |
| whetherAnomaly | Boolean | true=异常,false=正常 |
| telemetryDataTime | LocalDateTime | é¥æµ‹æ•°æ®æ—¶é—´ |
| billNo | String | å•据号(可能为空) |
| shiftName | String | ç­æ¬¡ï¼ˆå­—典类文本直存) |
| pullTime | LocalDateTime | æœ¬æ¬¡æ‹‰å–入库时间 |
| createTime | LocalDateTime | åˆ›å»ºæ—¶é—´ |
## å…­ã€è°ƒè¯•注意事项与排查清单
1. **鉴权/权限**:401 æ£€æŸ¥ token æ˜¯å¦è¿‡æœŸï¼›403 æ£€æŸ¥æ˜¯å¦ç¼º `mes:dv-telemetry:query`。
2. **/pull ä¾èµ–外网/内网数采服务**:当前 base-url `http://106.227.91.252:3100` éžæœ¬æœºï¼Œç½‘络不可达时直接报「数采数据拉取失败」。可在服务器侧 `curl http://106.227.91.252:3100/api/jxjs/mesTb/getDeviceDetails` å‰ç½®éªŒè¯ã€‚
3. **5 åˆ†é’Ÿçª—口**:外部接口仅保留近 5 åˆ†é’Ÿæ•°æ®ï¼Œè¶…过即丢。系统默认由定时任务(`MesDvTelemetryPullJob`,建议每 5 åˆ†é’Ÿï¼‰å…œåº•;页面手动 `/pull` ä»…用于实时补拉。
4. **分页字段**:`/page` è¿”回 `{ total, list }`,不是 `records`;`/latest`、`/check`、`/check-summary`、`/device-list` è¿”回裸数组,前端不可开启分页组件解析。
5. **whetherAnomaly å¸ƒå°”**:库列为 `bit(1)`,响应为 Boolean;布尔过滤传 `true/false`。
6. **去重上限**:`/latest` ç³»åˆ—仅取最近 5000 æ¡åšåŽ»é‡ï¼Œæ•°æ®é‡å¢žé•¿åŽæ³¨æ„è®¾å¤‡æ˜¯å¦ç¼ºé¡¹ã€‚
7. **standardValue ç¼ºå¤±**:现库中标准值全为空,`/check` æ¯”对主要看 `whetherAnomaly`,联调时注意界面空值展示。
8. **时间过滤**:`telemetryDataTime` ä¼  `yyyy-MM-dd HH:mm:ss` æ•°ç»„;历史表持续增长,查询建议必带时间区间。
## ä¸ƒã€æ•°æ®è‡ªæŸ¥ SQL(调试辅助)
```sql
-- æ‹‰å–落库是否成功:最近一次拉取
SELECT pull_time, COUNT(*) FROM `mom-xgdl`.`mes_dv_telemetry` GROUP BY pull_time ORDER BY pull_time DESC LIMIT 5;
-- å„设备记录与异常概况
SELECT device_name, COUNT(*) total,
       SUM(whether_anomaly = 1) anomaly
FROM `mom-xgdl`.`mes_dv_telemetry` GROUP BY device_name;
-- å•设备最近信号
SELECT param_name, timely_value, whether_anomaly, telemetry_data_time
FROM `mom-xgdl`.`mes_dv_telemetry`
WHERE tb_device_id = '773543983287631941' ORDER BY id DESC LIMIT 20;
```