# 工位客户端设备状态上报接口说明 > 服务根地址:`http://127.0.0.1:8980` > 上下文路径:`/js` > 管理路径:`/a` > **接口无需登录**(Shiro 已配置 `anon`) > 上报数据用于 **设备综合效率管理大屏**(`mesDeviceOeeScreen`)的开动率、状态总览、最后上报时间等展示 --- ## 一、背景说明 ### 1.1 大屏数据来源 设备综合效率大屏通过接口 `POST /js/a/mes/mesDevice/oeeScreenData` 聚合展示,核心数据来自: | 数据表 | 用途 | |:-------|:-----| | `mes_device` | 设备主数据(名称、编号、产线、当前工作状态) | | `mes_device_state` | 设备状态变更历史(开始时间、结束时间、持续时长) | 大屏当前展示的是 **时间开动率**(基于状态记录计算),**不是完整 OEE**(缺少计划产量、良品数、理想节拍)。 ### 1.2 客户端上报原则 | 时机 | 建议 state | 说明 | |:-----|:-----------|:-----| | 工位登录成功 | `1` | 标记设备开始运行,开动率从此刻累计 | | 工位退出 / 收班 | 非 `1`/`2` | 停止开动率累计,刷新「最后上报」 | | 运行中心跳(可选) | `1` | 建议每 5~15 分钟一次,避免「最后上报」长期不更新 | | 故障 / 报警 / 维修 | `3`/`4`/`5`/`6` | 状态变化时立即上报 | | 故障恢复 | `1` | 恢复运行 | > **注意**:若工位登录后上报 `state=1`,但退出时不上报,设备会一直保持「运行」状态,大屏开动率可能虚高(即使「最后上报」已过期)。 --- ## 二、设备状态码 字典类型:`mes_device_state` | state | 含义 | 大屏归类 | 是否计入开动率 | |:------|:-----|:---------|:---------------| | `1` | 正常 | 运行 | 是 | | `2` | 手动 | 运行 | 是 | | `3` | 故障 | 故障 | 否 | | `4` | 维修 | 维修 | 否 | | `5` | 质量报警 | 报警 | 否 | | `6` | 物流堵料 | 报警 | 否 | > 当前字典 **没有「停机 / 待机」** 专用状态。工位退出时可暂用 `4`(维修/收班),或与现场统一约定后再调整;后续可在字典中扩展 `0`「停机」等状态。 --- ## 三、推荐接口:上报设备状态(JSON) 工位客户端 **优先使用本接口**,参数少、支持 JSON,与项目 `api.http` 示例一致。 ### 3.1 基本信息 | 项 | 说明 | |:---|:-----| | 请求 URL | `POST {baseUrl}/js/a/mes/mesProductRecord/device` | | 示例 | `http://192.168.1.100:8980/js/a/mes/mesProductRecord/device` | | Content-Type | `application/json` 或 `application/x-www-form-urlencoded` | | 鉴权 | 无需登录,无需 `__sid` / token | ### 3.2 请求参数 | 参数 | 类型 | 必填 | 说明 | |:-----|:-----|:-----|:-----| | oprno | string | 是 | 设备编号,对应 `mes_device.sn`(大屏「设备编号」,如 `115OP030`) | | lineSn | string | 建议 | 产线编号,与设备档案一致(如 `115XT`) | | state | string | 是 | 设备状态码,见 [二、设备状态码](#二设备状态码) | | content | string | 否 | 状态描述,大屏设备卡片会展示(如「工位登录,开始运行」) | | codes | string | 否 | 故障码,一般场景可不传 | ### 3.3 响应格式 JeeSite 标准 JSON 字符串: ```json { "result": "true", "message": "操作成功!" } ``` 失败示例: ```json { "result": "false", "message": "错误信息" } ``` ### 3.4 请求示例 #### 工位登录 — 上报运行 ```http POST /js/a/mes/mesProductRecord/device Content-Type: application/json { "oprno": "115OP030", "lineSn": "115XT", "state": "1", "content": "工位登录,开始运行" } ``` #### 工位退出 — 停止运行 ```http POST /js/a/mes/mesProductRecord/device Content-Type: application/json { "oprno": "115OP030", "lineSn": "115XT", "state": "4", "content": "工位退出,停止运行" } ``` #### 运行心跳(可选) ```http POST /js/a/mes/mesProductRecord/device Content-Type: application/json { "oprno": "115OP030", "lineSn": "115XT", "state": "1", "content": "运行心跳" } ``` #### 设备故障 ```http POST /js/a/mes/mesProductRecord/device Content-Type: application/json { "oprno": "115OP030", "lineSn": "115XT", "state": "3", "content": "设备故障:伺服报警" } ``` #### form 表单方式(等价) ```http POST /js/a/mes/mesProductRecord/device Content-Type: application/x-www-form-urlencoded __ajax=json&oprno=115OP030&lineSn=115XT&state=1&content=工位登录,开始运行 ``` --- ## 四、备选接口:上报设备状态(Form) 适用于不便发送 JSON 的客户端(如部分 PLC 网关、老旧 WinForm 组件)。 ### 4.1 基本信息 | 项 | 说明 | |:---|:-----| | 请求 URL | `POST {baseUrl}/js/a/mes/mesProductRecord/deviceState` | | Content-Type | `application/x-www-form-urlencoded` | | 鉴权 | 无需登录 | ### 4.2 请求参数 | 参数 | 类型 | 必填 | 说明 | |:-----|:-----|:-----|:-----| | oprno | string | 是 | 设备编号 | | state | string | 是 | 设备状态码 | | productCate | string | 是 | 产线编号(等同 `lineSn`) | | deviceContent | string | 否 | 状态描述 | | paramsNums | int | 是 | 无故障码时固定传 `0` | | errorCode | string | 否 | 故障码;`paramsNums=0` 时可传空字符串 | ### 4.3 响应格式 `CommonResp` 结构: | 字段 | 类型 | 说明 | |:-----|:-----|:-----| | result | string | `"true"` 成功 / `"false"` 失败 | | message | string | 提示信息 | | data | string | 成功时为 `{state}OK`,如 `"1OK"` | ```json { "result": "true", "message": "成功", "data": "1OK" } ``` ### 4.4 请求示例 ```http POST /js/a/mes/mesProductRecord/deviceState Content-Type: application/x-www-form-urlencoded oprno=115OP030&state=1&productCate=115XT&deviceContent=工位登录¶msNums=0&errorCode= ``` --- ## 五、TCP 报文方式(MSBW,可选) 若工位客户端通过 **Netty TCP 网关** 与 MES 通信,可使用设备状态报文 `MSBW`(与 HTTP 接口写入同一张表)。 | 项 | 说明 | |:---|:-----| | 报文类型 | `MSBW` | | 处理入口 | `MesProductRecordController.deviceState(msg)` | | 说明 | 一般由设备网关 / 产线控制器上报,工位 WinForm 客户端通常直接用 HTTP 即可 | 报文示例(注释格式,实际为定长协议): ``` aaaabbbbbABWMSBWGWOP040 LX01ID151245P00000106200123062900001 DA2023-08-18ZT14:32:33 ``` - `GWOP040`:工位号(oprno) - `LX01`:状态码(01 → state=1) - 产线等信息按 `ProtocolParam` 解析 > 工位客户端集成 **建议优先 HTTP `/device` 接口**,无需拼装 TCP 定长报文。 --- ## 六、客户端集成流程 ``` ┌─────────────┐ 登录成功 ┌──────────────────────────────┐ │ 工位客户端 │ ───────────────► │ POST /device state=1 │ └─────────────┘ └──────────────────────────────┘ │ │ │ 运行中(可选,每 5~15 分钟) ▼ ├──────────────────────────────► mes_device_state 新增记录 │ │ │ 退出 / 收班 ▼ └──────────────────────────────► POST /device state=4(或非 1/2) │ ▼ 上一条记录闭合 end_date / interval │ ▼ 大屏 oeeScreenData 刷新展示 ``` ### 6.1 集成检查清单 - [ ] `oprno` 与 `mes_device.sn` 一致(可在 MES 设备管理模块核对) - [ ] `lineSn` 与设备档案产线一致 - [ ] 登录成功后调用 `/device`,`state=1` - [ ] 退出 / 关闭客户端前调用 `/device`,`state` 为非运行状态 - [ ] (可选)运行中定时心跳,`state=1` - [ ] 故障、报警发生时即时上报对应 `state` ### 6.2 C# 调用示例 ```csharp using System.Net.Http; using System.Text; using System.Text.Json; public static async Task ReportDeviceStateAsync( string baseUrl, string oprno, string lineSn, string state, string content) { using var client = new HttpClient(); var payload = new { oprno, lineSn, state, content }; var json = JsonSerializer.Serialize(payload); var resp = await client.PostAsync( $"{baseUrl.TrimEnd('/')}/js/a/mes/mesProductRecord/device", new StringContent(json, Encoding.UTF8, "application/json")); var body = await resp.Content.ReadAsStringAsync(); return body.Contains("\"result\":\"true\""); } // 工位登录 await ReportDeviceStateAsync("http://192.168.1.100:8980", "115OP030", "115XT", "1", "工位登录,开始运行"); // 工位退出 await ReportDeviceStateAsync("http://192.168.1.100:8980", "115OP030", "115XT", "4", "工位退出,停止运行"); ``` ### 6.3 JavaScript 调用示例 ```javascript async function reportDeviceState(baseUrl, oprno, lineSn, state, content) { const resp = await fetch(`${baseUrl}/js/a/mes/mesProductRecord/device`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ oprno, lineSn, state, content }) }); return resp.json(); } // 工位登录 await reportDeviceState('http://192.168.1.100:8980', '115OP030', '115XT', '1', '工位登录,开始运行'); ``` --- ## 七、服务端处理逻辑(供联调参考) 上报成功后,服务端执行: 1. **`mes_device_state`**:闭合上一条记录的 `end_date`、`interval`,插入新状态记录(`start_date` 为当前时间) 2. **`mes_device`**:更新 `work_status`、`work_time` 大屏 `oeeScreenData` 读取逻辑摘要: - **当前状态**:取 `mes_device_state` 最新一条;无记录则用 `mes_device.work_status` - **开动率**:统计当日 state 为 `1` 或 `2` 的累计时长 ÷ 当日已过时长 - **最后上报**:最新状态记录的 `start_date`;无记录则用 `mes_device.work_time` --- ## 八、常见问题 ### Q1:`oprno` 填工位号还是设备编号? 填 **`mes_device.sn`**(设备档案中的「唯一编号 / 设备编号」)。大屏卡片「设备编号」列即此字段。若工位与设备一一对应,需先在 MES 设备管理中确认映射关系。 ### Q2:退出时 state 传什么? 当前无「停机」状态,建议退出传 `4`,`content` 注明「工位退出」。若业务需要独立「待机」状态,需先在字典 `mes_device_state` 中扩展并在 OEE 计算逻辑中适配。 ### Q3:同一状态重复上报会怎样? `/device` 接口每次调用都会 **新增一条记录** 并闭合上一条,开动率统计仍正确;可用于心跳刷新「最后上报」时间。 ### Q4:接口需要登录吗? 不需要。`application.yml` 中已配置: ```yaml ${adminPath}/mes/mesProductRecord/device = anon ${adminPath}/mes/mesProductRecord/deviceState = anon ``` ### Q5:上报失败如何排查? 1. 确认 `oprno` 在 `mes_device` 表中存在 2. 确认 `state` 为 `1`~`6` 的有效值 3. 查看 MES 接口日志(`mes_log` 表,`apisave2` 会记录请求内容) --- ## 九、相关代码位置 | 模块 | 路径 | |:-----|:-----| | HTTP 接口(推荐) | `MesProductRecordController.device()` | | HTTP 接口(Form) | `MesProductRecordController.deviceStateApi()` | | TCP MSBW | `MesProductRecordController.deviceState()` | | 状态持久化 | `MesDeviceStateService.updateState()` | | OEE 大屏数据 | `MesDeviceController.oeeScreenData()` | | 大屏页面 | `src/main/resources/views/modules/mes/mesDeviceOeeScreen.html` | | 请求体 DTO | `com.jeesite.modules.mes.req.MesDeviceStateReq` | --- ## 十、修订记录 | 日期 | 说明 | |:-----|:-----| | 2026-06-30 | 初版:工位客户端设备状态上报接口说明 |