20260704:1、加入设备名称推送;2、明确入网参数绑定数组数据(孔深、高程);3、清空推送日志,按设备类型查询推送日志
This commit is contained in:
parent
820bd95632
commit
355e0eaa27
@ -120,11 +120,27 @@ DDL 以 `sql/platform-integration.sql` 为准。
|
||||
| `auth` | 从 `platform_instance.auth_config` 按 `field` 取值 |
|
||||
| `extra` | 从 `platform_instance.extra_config` 按 `field` 取值 |
|
||||
| `context` | 从 `FlowContext` 按 `contextKey` 取值 |
|
||||
| `device` | 从 `PlatformDeviceMapping` 取 `platform_device_id`、`platform_point_id`、`serial_number`、`gateway_serial_number`、`monitor_serial_number` |
|
||||
| `onboard_config` | 从当前子映射 `onboard_config` 取值 |
|
||||
| `device` | 从 `PlatformDeviceMapping` / 当前网关子设备上下文取 `platform_device_id`、`platform_point_id`、`serial_number`、`device_name`、`gateway_serial_number`、`monitor_serial_number` |
|
||||
| `thingsModel` | 从流程上下文 payload 按物模型标识取值,通常用于手动流程或扩展流程 |
|
||||
| `ts` | 从流程上下文 payload 取时间戳 |
|
||||
| `onboard_config` | 入网参数,直接取接口 `request_schema` 或步骤覆盖配置中的 `value`,不再读取子映射表 `onboard_config` |
|
||||
| `subDeviceSensorIds` | 收集子设备 sensorId 列表 |
|
||||
| `referenceSubDeviceSensorIdPairs` | 收集 `[基准点sensorId, 监测点sensorId]` 配对列表,可能展开为多次请求 |
|
||||
|
||||
`onboard_config` 是设备入网专用的可配置入参。接口管理页或流程步骤覆盖页直接维护 `value`:
|
||||
|
||||
```json
|
||||
{"name":"sensorDepths","type":"array","source":"onboard_config","value":[1.7,3.4,5.1,6.8]}
|
||||
{"name":"holeDepth","type":"number","source":"onboard_config","value":[1.7,3.4,5.1,6.8]}
|
||||
```
|
||||
|
||||
网关多 monitor 入网时,`PlatformDeviceMappingServiceImpl` 按 `PlatformDeviceSubMappingMapper.selectByParentId` 返回顺序筛选 monitor,并把当前下标写入 `FlowContext.currentMonitorIndex`。流程执行器解析 `onboard_config` 时:
|
||||
|
||||
- `value` 不是数组:每个子设备使用同一个值。
|
||||
- `value` 是数组:按当前 monitor 下标取对应元素。
|
||||
- schema `type=array` 且取到单值:最终请求体会包装为单元素数组,例如 `1.7` -> `[1.7]`。
|
||||
- 数组长度小于待入网 monitor 数量:直接抛错,避免错绑。
|
||||
|
||||
实时推送适配器中支持的 `source`:
|
||||
|
||||
| source | 含义 |
|
||||
@ -149,7 +165,7 @@ DDL 以 `sql/platform-integration.sql` 为准。
|
||||
| `platform_id` | 所属平台 |
|
||||
| `name` / `code` | 流程名称与标识 |
|
||||
| `flow_type` | `1=平台初始化`、`2=设备入网`、`3=Token刷新` |
|
||||
| `sensor_type` | 入网流程适用传感器类型,如 `inclino`、`stress`、`hyeto`、`static_level` |
|
||||
| `sensor_type` | 入网流程适用传感器类型,如 `inclino`、`deep_inclino`、`stress`、`hyeto`、`static_level` |
|
||||
| `enable` | 是否启用 |
|
||||
|
||||
### 3.4 `platform_flow_step` 流程步骤
|
||||
@ -185,7 +201,7 @@ DDL 以 `sql/platform-integration.sql` 为准。
|
||||
| `device_id` / `serial_number` | FastBee 设备 ID 与序列号 |
|
||||
| `platform_device_id` | 平台侧 deviceId,直连设备入网后回填 |
|
||||
| `platform_point_id` | 平台侧 pointId,直连设备入网后回填 |
|
||||
| `sensor_type` | `inclino`、`stress`、`hyeto`、`static_level` |
|
||||
| `sensor_type` | 传感器类型,来自 `platform_sensor_type` 字典;当前包含 `inclino`、`deep_inclino`、`stress`、`hyeto`、`static_level` |
|
||||
| `device_type` | `0=直连设备`、`1=网关设备` |
|
||||
| `push_interface_id` | 推送接口 ID,用于动态字段映射和推送路径 |
|
||||
| `field_mapping` | 标量字段映射,格式如 `[{identifier, platformField, transform}]` |
|
||||
@ -206,7 +222,7 @@ DDL 以 `sql/platform-integration.sql` 为准。
|
||||
| `device_role` | `reference=基准点`、`monitor=监测点` |
|
||||
| `platform_device_id` | 平台分配给该监测点的 deviceId |
|
||||
| `platform_point_id` | 平台分配给该监测点的 pointId |
|
||||
| `onboard_config` | 入网参数 JSON,例如 `sensorId`、`refSensorId`、`refSerialNumber` |
|
||||
| `onboard_config` | 子设备平台标识 JSON,例如 `sensorId`、`refSensorId`、`refSerialNumber`;普通绑定接口参数不放这里 |
|
||||
| `net_status` | 子设备入网状态 |
|
||||
|
||||
唯一约束:`parent_mapping_id + sub_serial_number`。
|
||||
@ -326,8 +342,10 @@ execute(flow, context)
|
||||
2. 筛选 `device_role=monitor` 且未入网的子设备。
|
||||
3. 对每个 monitor 创建独立 `FlowContext`:
|
||||
- `currentMonitorSerialNumber = monitor.sub_serial_number`
|
||||
- `currentMonitorDeviceName = monitor.sub_device_name`
|
||||
- `currentMonitorIndex = monitor 在待入网 monitor 列表中的下标`
|
||||
- `subMappingOnboardConfig = monitor.onboard_config`
|
||||
4. 执行同一个入网流程。
|
||||
4. 执行同一个入网流程。若绑定接口 schema 使用 `source=onboard_config` 且 `value` 为数组,会按 `currentMonitorIndex` 拆出当前子设备的值。
|
||||
5. 从上下文 `step1.id`、`step2.id` 取 pointId/deviceId,写回当前 monitor 子表。
|
||||
6. 所有 monitor 都入网后,主绑定 `net_status=1`。
|
||||
7. 若部分成功部分失败,已成功子设备会保留结果,接口返回明确失败信息。
|
||||
@ -355,19 +373,11 @@ WHERE s.sub_serial_number = #{serialNumber} AND m.enable = '1'
|
||||
|
||||
### 5.4 DCP 普通推送
|
||||
|
||||
DCP 推送接口优先使用设备绑定的 `push_interface_id`:
|
||||
DCP 实时推送必须在设备绑定中配置 `push_interface_id`:
|
||||
|
||||
- 有推送接口:使用接口 `path`、`code`、`request_schema`。
|
||||
- 未配置或解析失败:按 `sensor_type` 回退到内置路径。
|
||||
|
||||
内置路径:
|
||||
|
||||
| sensor_type | 路径 |
|
||||
|---|---|
|
||||
| `inclino` | `/api/app/inclino-data/many` |
|
||||
| `stress` | `/api/app/stress-data/many` |
|
||||
| `hyeto` | `/api/app/hyeto-data/many` |
|
||||
| `static_level` | `/api/app/static-level-data/many` |
|
||||
- 使用推送接口的 `path`、`code`、`request_schema` 组装并发送请求。
|
||||
- 未配置推送接口时,`DcpPlatformAdapter.resolvePushPath` 直接抛错,不再按 `sensor_type` 回退到内置路径。
|
||||
- `resolveInterfaceCode` 仍会在接口 `code` 为空时使用 `dcp_push_{sensorType}` 作为日志标识兜底。
|
||||
|
||||
请求体构建规则:
|
||||
|
||||
@ -468,6 +478,7 @@ Redis TTL 为 `reportIntervalSec * 2`,读取时超过 `reportIntervalSec * 1.5
|
||||
- 按平台维护接口。
|
||||
- 配置 method、path、content-type、请求 schema、响应 schema。
|
||||
- 请求 schema 用于流程执行和设备绑定页动态字段映射。
|
||||
- `source=onboard_config` 的取值配置编辑 `value`,支持填写 JSON 数组或数字/字符串。保存时前端会把 `[1.7,3.4]` 转成数组,把 `6.8` 转成数字。
|
||||
|
||||
### 6.3 流程编排
|
||||
|
||||
@ -481,6 +492,7 @@ Redis TTL 为 `reportIntervalSec * 2`,读取时超过 `reportIntervalSec * 1.5
|
||||
- 新增、编辑流程及步骤。
|
||||
- 查看流程详情时返回 `{flow, steps}`。
|
||||
- 手动执行:`POST /platform/flow/{id}/execute`,可选 `mappingId`。
|
||||
- 步骤入参覆盖同样支持 `source=onboard_config`,语义与接口管理一致:配置 `value`,不配置子映射字段名。
|
||||
|
||||
### 6.4 设备绑定
|
||||
|
||||
@ -557,6 +569,47 @@ SET @dcp_platform_id = (SELECT id FROM platform_instance WHERE code = 'dcp' LIMI
|
||||
- 静力水准推送接口定义了数组字段 `sensorData`,其 `itemSchema` 包含 `epoch`、`height`、`temperature`、`sensorId`。
|
||||
- 轴力计和雨量计 DCP 文档要求累计值递增;当前代码未在适配器中实现“查询上次成功值并跳过非递增值”的通用校验,若目标平台严格校验,需要在推送前补充该逻辑或依赖平台返回失败日志。
|
||||
|
||||
### 7.4 深部位移计扩展配置
|
||||
|
||||
`sql/platform-integration.sql` 已在 `platform_sensor_type` 字典中维护 `deep_inclino`,前端传感器类型下拉也支持从字典读取和手动输入。`sql/platform-dcp-init-data.sql` 当前未内置深部位移计绑定接口和入网流程,需要在接口管理和流程编排中配置。
|
||||
|
||||
DCP 深部位移绑定接口:
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| code 建议 | `dcp_bind_deep_inclino` |
|
||||
| method | `POST` |
|
||||
| path | `/api/app/deep-inclino-device` |
|
||||
| content-type | `application/json` |
|
||||
|
||||
典型 `request_schema`:
|
||||
|
||||
```json
|
||||
[
|
||||
{"name":"projectId","type":"string","source":"extra","field":"projectId","required":true},
|
||||
{"name":"pointId","type":"string","source":"context","contextKey":"step1.id","required":true},
|
||||
{"name":"name","type":"string","source":"device","field":"serial_number","required":true},
|
||||
{"name":"moduleId","type":"string","source":"uuid","required":true},
|
||||
{"name":"virtualId","type":"string","source":"uuid","required":true},
|
||||
{"name":"sensorDepths","type":"array","source":"onboard_config","value":[1.7,3.4,5.1,6.8],"required":true},
|
||||
{"name":"holeDepth","type":"number","source":"onboard_config","value":[1.7,3.4,5.1,6.8],"required":true},
|
||||
{"name":"sensorIds","type":"array","source":"subDeviceSensorIds","required":true},
|
||||
{"name":"axisDirection","type":"string","source":"onboard_config","value":"X","required":false},
|
||||
{"name":"holeElevation","type":"number","source":"onboard_config","value":0,"required":false},
|
||||
{"name":"zipDuring","type":"number","source":"onboard_config","value":0,"required":false},
|
||||
{"name":"frequency","type":"number","source":"onboard_config","value":2147483647,"required":false},
|
||||
{"name":"remark","type":"string","source":"onboard_config","value":"","required":false}
|
||||
]
|
||||
```
|
||||
|
||||
网关多子设备绑定深部位移计时,`sensorDepths` 与 `holeDepth` 这类数组值按待入网 monitor 子设备顺序逐个拆分:
|
||||
|
||||
- 第 1 个 monitor:`sensorDepths` 取 `1.7`,因字段类型为 `array`,最终请求为 `"sensorDepths":[1.7]`;`holeDepth` 为 `1.7`。
|
||||
- 第 2 个 monitor:`sensorDepths` 为 `[3.4]`,`holeDepth` 为 `3.4`。
|
||||
- 依此类推。
|
||||
|
||||
深度类字段按工程习惯使用正数,表示距孔口向下的距离;若需要平台侧高程,按 `holeElevation - sensorDepth` 计算,不通过负深度表达方向。
|
||||
|
||||
---
|
||||
|
||||
## 8. 关键复用点
|
||||
@ -577,6 +630,7 @@ SET @dcp_platform_id = (SELECT id FROM platform_instance WHERE code = 'dcp' LIMI
|
||||
|
||||
- 当前适配器只有 DCP。新增平台需要新增 adapter,并在 `DeviceReportTrigger.dispatchPush` 中按平台 `code` 路由。
|
||||
- 文档中的“可视化配置”已覆盖平台、接口、流程、设备绑定、子映射和日志,但平台适配器路由仍需要代码扩展。
|
||||
- DCP 实时推送必须配置 `push_interface_id`,未配置时不会按传感器类型自动回退路径。
|
||||
- 实时推送只支持 POST JSON,流程执行支持 GET、form、JSON。
|
||||
- `idempotency_key` 字段已建表,但实时推送未生成幂等键。
|
||||
- `PlatformInstanceController.getInfo` 只清空 `access_token`,注释提到密码脱敏,但当前代码未改写 `auth_config` 内密码。
|
||||
|
||||
@ -50,4 +50,12 @@ public class PlatformPushLogController extends BaseController {
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(pushLogService.removeByIds(Arrays.asList(ids)));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('platform:pushLog:remove')")
|
||||
@DeleteMapping("/clean")
|
||||
@ApiOperation("批量删除推送日志")
|
||||
public AjaxResult clean(@PathVariable Long[] ids) {
|
||||
pushLogService.cleanPushLog();
|
||||
return success();
|
||||
}
|
||||
}
|
||||
|
||||
@ -816,7 +816,7 @@ public class DcpPlatformAdapter {
|
||||
}
|
||||
|
||||
private Object resolveDeviceField(PlatformDeviceMapping mapping, String field) {
|
||||
if (!StringUtils.hasText(field)) {
|
||||
if (mapping == null || !StringUtils.hasText(field)) {
|
||||
return null;
|
||||
}
|
||||
switch (field) {
|
||||
@ -826,11 +826,22 @@ public class DcpPlatformAdapter {
|
||||
return mapping.getPlatformPointId();
|
||||
case "serial_number":
|
||||
return mapping.getSerialNumber();
|
||||
case "device_name":
|
||||
return resolveDeviceName(mapping);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveDeviceName(PlatformDeviceMapping mapping) {
|
||||
if (mapping == null) {
|
||||
return null;
|
||||
}
|
||||
return StringUtils.hasText(mapping.getDeviceName())
|
||||
? mapping.getDeviceName()
|
||||
: mapping.getSerialNumber();
|
||||
}
|
||||
|
||||
private Object resolveJsonField(String json, String field) {
|
||||
if (!StringUtils.hasText(json) || !StringUtils.hasText(field)) {
|
||||
return null;
|
||||
|
||||
@ -33,6 +33,9 @@ public class PlatformDeviceMapping implements Serializable {
|
||||
@ApiModelProperty("FastBee设备序列号")
|
||||
private String serialNumber;
|
||||
|
||||
@ApiModelProperty("FastBee设备名称")
|
||||
private String deviceName;
|
||||
|
||||
@ApiModelProperty("DCP侧deviceId,入网后自动回填")
|
||||
private String platformDeviceId;
|
||||
|
||||
|
||||
@ -30,6 +30,9 @@ public class PlatformDeviceSubMapping implements Serializable {
|
||||
@ApiModelProperty("子设备序列号")
|
||||
private String subSerialNumber;
|
||||
|
||||
@ApiModelProperty("子设备名称")
|
||||
private String subDeviceName;
|
||||
|
||||
@ApiModelProperty("角色: reference=基准 monitor=监测")
|
||||
private String deviceRole;
|
||||
|
||||
|
||||
@ -11,19 +11,50 @@ import java.util.Map;
|
||||
*/
|
||||
public class FlowContext {
|
||||
|
||||
/**
|
||||
* 平台实体
|
||||
*/
|
||||
private final PlatformInstance platform;
|
||||
/**
|
||||
* 绑定推送关系
|
||||
*/
|
||||
private final PlatformDeviceMapping deviceMapping;
|
||||
/** 设备上报的原始 payload(实时推送时有值) */
|
||||
/**
|
||||
* 设备上报的原始 payload(实时推送时有值)
|
||||
*/
|
||||
private final String payload;
|
||||
/** 步骤出参存储,key = step.resultKey,value = 解析后的 JSON Map */
|
||||
/**
|
||||
* 步骤出参存储,key = step.resultKey,value = 解析后的 JSON Map
|
||||
*/
|
||||
private final Map<String, Object> stepResults = new HashMap<>();
|
||||
/** 网关入网时,指定当前处理的监测点序列号 */
|
||||
/**
|
||||
* 网关入网时,指定当前处理的监测点序列号
|
||||
*/
|
||||
private String currentMonitorSerialNumber;
|
||||
/** 网关子设备入网时,当前子映射行的 onboard_config JSON(平台相关参数) */
|
||||
/**
|
||||
* 网关入网时,指定当前处理的监测点名称
|
||||
*/
|
||||
private String currentMonitorDeviceName;
|
||||
/**
|
||||
* 网关入网时,当前监测点在 PlatformDeviceSubMapping 监测点列表中的顺序
|
||||
*/
|
||||
private Integer currentMonitorIndex;
|
||||
|
||||
/**
|
||||
* 网关子设备入网时,当前子映射行的 onboard_config JSON(平台相关参数)
|
||||
*/
|
||||
private String subMappingOnboardConfig;
|
||||
/** 网关子设备入网时,当前基准点序列号 */
|
||||
/**
|
||||
* 网关子设备入网时,当前基准点序列号
|
||||
*/
|
||||
private String currentReferenceSerialNumber;
|
||||
/** 网关子设备入网时,基准点子映射行的 onboard_config JSON */
|
||||
/**
|
||||
* 网关子设备入网时,当前基准点名称
|
||||
*/
|
||||
private String currentReferenceDeviceName;
|
||||
/**
|
||||
* 网关子设备入网时,基准点子映射行的 onboard_config JSON
|
||||
*/
|
||||
private String referenceSubMappingOnboardConfig;
|
||||
|
||||
public FlowContext(PlatformInstance platform, PlatformDeviceMapping deviceMapping, String payload) {
|
||||
@ -60,6 +91,22 @@ public class FlowContext {
|
||||
this.currentMonitorSerialNumber = currentMonitorSerialNumber;
|
||||
}
|
||||
|
||||
public String getCurrentMonitorDeviceName() {
|
||||
return currentMonitorDeviceName;
|
||||
}
|
||||
|
||||
public void setCurrentMonitorDeviceName(String currentMonitorDeviceName) {
|
||||
this.currentMonitorDeviceName = currentMonitorDeviceName;
|
||||
}
|
||||
|
||||
public Integer getCurrentMonitorIndex() {
|
||||
return currentMonitorIndex;
|
||||
}
|
||||
|
||||
public void setCurrentMonitorIndex(Integer currentMonitorIndex) {
|
||||
this.currentMonitorIndex = currentMonitorIndex;
|
||||
}
|
||||
|
||||
public String getSubMappingOnboardConfig() {
|
||||
return subMappingOnboardConfig;
|
||||
}
|
||||
@ -76,6 +123,14 @@ public class FlowContext {
|
||||
this.currentReferenceSerialNumber = currentReferenceSerialNumber;
|
||||
}
|
||||
|
||||
public String getCurrentReferenceDeviceName() {
|
||||
return currentReferenceDeviceName;
|
||||
}
|
||||
|
||||
public void setCurrentReferenceDeviceName(String currentReferenceDeviceName) {
|
||||
this.currentReferenceDeviceName = currentReferenceDeviceName;
|
||||
}
|
||||
|
||||
public String getReferenceSubMappingOnboardConfig() {
|
||||
return referenceSubMappingOnboardConfig;
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ public class PlatformFlowExecutor {
|
||||
|
||||
/**
|
||||
* 解析步骤入参
|
||||
* source 枚举: fixed / auth / extra / context / device
|
||||
* source 枚举: fixed / auth / extra / context / device / thingsModel / ts
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> resolveParams(PlatformInterface iface, PlatformFlowStep step, FlowContext ctx) {
|
||||
@ -297,6 +297,9 @@ public class PlatformFlowExecutor {
|
||||
}
|
||||
return normalizeValueByType(fd.getString("type"), resolveGatewaySerialNumber(ctx.getDeviceMapping()));
|
||||
}
|
||||
if ("device_name".equals(df)) {
|
||||
return resolveDeviceName(ctx);
|
||||
}
|
||||
if ("gateway_serial_number".equals(df)) {
|
||||
return resolveGatewaySerialNumber(ctx.getDeviceMapping());
|
||||
}
|
||||
@ -304,9 +307,12 @@ public class PlatformFlowExecutor {
|
||||
return ctx.getCurrentMonitorSerialNumber();
|
||||
}
|
||||
return null;
|
||||
case "thingsModel":
|
||||
return resolveThingsModelValue(ctx, fd);
|
||||
case "ts":
|
||||
return resolveThingsModelTs(ctx, fd);
|
||||
case "onboard_config":
|
||||
// 从子映射的 onboard_config JSON 中取指定字段
|
||||
return resolveOnboardConfigField(ctx, fd.getString("field"));
|
||||
return resolveOnboardConfigValue(ctx, fd);
|
||||
case "subDeviceSensorIds":
|
||||
return collectSubDeviceSensorIds(ctx);
|
||||
case "referenceSubDeviceSensorIdPairs":
|
||||
@ -316,19 +322,94 @@ public class PlatformFlowExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从子映射 onboard_config 中取字段值
|
||||
*/
|
||||
private Object resolveOnboardConfigField(FlowContext ctx, String field) {
|
||||
if (!StringUtils.hasText(field) || !StringUtils.hasText(ctx.getSubMappingOnboardConfig())) {
|
||||
private Object resolveThingsModelValue(FlowContext ctx, JSONObject fieldDef) {
|
||||
JSONObject payload = parsePayloadToObject(ctx.getPayload());
|
||||
if (payload == null) {
|
||||
return null;
|
||||
}
|
||||
String identifier = resolveThingsModelIdentifier(fieldDef);
|
||||
return StringUtils.hasText(identifier) ? payload.get(identifier) : null;
|
||||
}
|
||||
|
||||
private Object resolveThingsModelTs(FlowContext ctx, JSONObject fieldDef) {
|
||||
JSONObject payload = parsePayloadToObject(ctx.getPayload());
|
||||
if (payload == null) {
|
||||
return null;
|
||||
}
|
||||
String identifier = resolveThingsModelIdentifier(fieldDef);
|
||||
if (StringUtils.hasText(identifier)) {
|
||||
Object value = payload.get(identifier + "__ts");
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Object ts = payload.get("ts");
|
||||
return ts != null ? ts : payload.get("timestamp");
|
||||
}
|
||||
|
||||
private String resolveThingsModelIdentifier(JSONObject fieldDef) {
|
||||
String identifier = fieldDef.getString("identifier");
|
||||
if (StringUtils.hasText(identifier)) {
|
||||
return identifier;
|
||||
}
|
||||
String field = fieldDef.getString("field");
|
||||
return StringUtils.hasText(field) ? field : fieldDef.getString("contextKey");
|
||||
}
|
||||
|
||||
private JSONObject parsePayloadToObject(String payload) {
|
||||
if (!StringUtils.hasText(payload)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JSONObject config = JSON.parseObject(ctx.getSubMappingOnboardConfig());
|
||||
return config.get(field);
|
||||
String trimmed = payload.trim();
|
||||
if (trimmed.startsWith("{")) {
|
||||
return JSON.parseObject(trimmed);
|
||||
}
|
||||
if (trimmed.startsWith("[")) {
|
||||
JSONObject result = new JSONObject();
|
||||
JSONArray arr = JSON.parseArray(trimmed);
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
JSONObject item = arr.getJSONObject(i);
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
String id = item.getString("identifier");
|
||||
if (!StringUtils.hasText(id)) {
|
||||
id = item.getString("id");
|
||||
}
|
||||
if (!StringUtils.hasText(id)) {
|
||||
continue;
|
||||
}
|
||||
result.put(id, item.get("value"));
|
||||
Object ts = item.get("ts");
|
||||
if (ts != null) {
|
||||
result.put(id + "__ts", ts);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
log.warn("[PlatformFlow] 解析设备上报 payload 失败: {}", e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object resolveOnboardConfigValue(FlowContext ctx, JSONObject fieldDef) {
|
||||
String name = fieldDef.getString("name");
|
||||
if (!fieldDef.containsKey("value")) {
|
||||
throw new RuntimeException("入网参数 " + name + " 未配置值");
|
||||
}
|
||||
Object value = fieldDef.get("value");
|
||||
if (value instanceof JSONArray && ctx.getCurrentMonitorIndex() != null) {
|
||||
JSONArray values = (JSONArray) value;
|
||||
int index = ctx.getCurrentMonitorIndex();
|
||||
if (index >= values.size()) {
|
||||
throw new RuntimeException("入网参数 " + name + " 数组长度不足,当前子设备序号="
|
||||
+ (index + 1) + ",数组长度=" + values.size());
|
||||
}
|
||||
return values.get(index);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String newGeneratedId() {
|
||||
@ -679,6 +760,9 @@ public class PlatformFlowExecutor {
|
||||
}
|
||||
|
||||
private String resolveGatewaySerialNumber(PlatformDeviceMapping mapping) {
|
||||
if (mapping == null) {
|
||||
return null;
|
||||
}
|
||||
String serialNumber = normalizeText(mapping.getSerialNumber());
|
||||
if (StringUtils.hasText(serialNumber)) {
|
||||
return serialNumber;
|
||||
@ -696,6 +780,21 @@ public class PlatformFlowExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveDeviceName(FlowContext ctx) {
|
||||
if (ctx == null || ctx.getDeviceMapping() == null) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.hasText(ctx.getCurrentMonitorSerialNumber())) {
|
||||
return StringUtils.hasText(ctx.getCurrentMonitorDeviceName())
|
||||
? ctx.getCurrentMonitorDeviceName()
|
||||
: ctx.getCurrentMonitorSerialNumber();
|
||||
}
|
||||
PlatformDeviceMapping mapping = ctx.getDeviceMapping();
|
||||
return StringUtils.hasText(mapping.getDeviceName())
|
||||
? mapping.getDeviceName()
|
||||
: mapping.getSerialNumber();
|
||||
}
|
||||
|
||||
private boolean sameText(String left, String right) {
|
||||
return Objects.equals(normalizeText(left), normalizeText(right));
|
||||
}
|
||||
@ -1093,7 +1192,9 @@ public class PlatformFlowExecutor {
|
||||
return value;
|
||||
}
|
||||
if (!(value instanceof String)) {
|
||||
return value;
|
||||
JSONArray array = new JSONArray();
|
||||
array.add(value);
|
||||
return array;
|
||||
}
|
||||
String text = ((String) value).trim();
|
||||
if (!StringUtils.hasText(text)) {
|
||||
|
||||
@ -11,4 +11,7 @@ public interface PlatformPushLogMapper extends BaseMapperX<PlatformPushLog> {
|
||||
*/
|
||||
String selectLastSuccessResponseBody(@Param("deviceId") Long deviceId,
|
||||
@Param("interfaceCode") String interfaceCode);
|
||||
|
||||
void cleanPushLog();
|
||||
|
||||
}
|
||||
|
||||
@ -17,4 +17,10 @@ public interface IPlatformPushLogService extends IService<PlatformPushLog> {
|
||||
|
||||
/** 手动重推:重新发送已记录的请求,更新日志状态 */
|
||||
void retry(Long id);
|
||||
|
||||
/**
|
||||
* 情况日志
|
||||
*/
|
||||
void cleanPushLog();
|
||||
|
||||
}
|
||||
|
||||
@ -125,12 +125,16 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
||||
int successCount = 0;
|
||||
List<String> failedMessages = new ArrayList<>();
|
||||
|
||||
for (PlatformDeviceSubMapping monitor : monitors) {
|
||||
for (int i = 0; i < monitors.size(); i++) {
|
||||
PlatformDeviceSubMapping monitor = monitors.get(i);
|
||||
FlowContext ctx = new FlowContext(platform, mapping, null);
|
||||
ctx.setCurrentMonitorSerialNumber(monitor.getSubSerialNumber());
|
||||
ctx.setCurrentMonitorDeviceName(monitor.getSubDeviceName());
|
||||
ctx.setCurrentMonitorIndex(i);
|
||||
ctx.setSubMappingOnboardConfig(monitor.getOnboardConfig());
|
||||
if (reference != null) {
|
||||
ctx.setCurrentReferenceSerialNumber(reference.getSubSerialNumber());
|
||||
ctx.setCurrentReferenceDeviceName(reference.getSubDeviceName());
|
||||
ctx.setReferenceSubMappingOnboardConfig(reference.getOnboardConfig());
|
||||
}
|
||||
|
||||
@ -173,6 +177,12 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析基准点,默认都是监测点
|
||||
* @param mapping 平台设备绑定关系
|
||||
* @param subMappings 平台子设备绑定关系
|
||||
* @return 基准点
|
||||
*/
|
||||
private PlatformDeviceSubMapping resolveGatewayReference(PlatformDeviceMapping mapping,
|
||||
List<PlatformDeviceSubMapping> subMappings) {
|
||||
List<PlatformDeviceSubMapping> references = subMappings.stream()
|
||||
|
||||
@ -38,6 +38,7 @@ public class PlatformPushLogServiceImpl extends ServiceImpl<PlatformPushLogMappe
|
||||
.eq(query.getStatus() != null, PlatformPushLog::getStatus, query.getStatus())
|
||||
.eq(query.getLogType() != null, PlatformPushLog::getLogType, query.getLogType())
|
||||
.eq(StringUtils.hasText(query.getSerialNumber()), PlatformPushLog::getSerialNumber, query.getSerialNumber())
|
||||
.eq(StringUtils.hasText(query.getInterfaceCode()), PlatformPushLog::getInterfaceCode, query.getInterfaceCode())
|
||||
.orderByDesc(PlatformPushLog::getCreateTime);
|
||||
return this.list(wrapper);
|
||||
}
|
||||
@ -114,4 +115,10 @@ public class PlatformPushLogServiceImpl extends ServiceImpl<PlatformPushLogMappe
|
||||
throw new RuntimeException("重推失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanPushLog() {
|
||||
pushLogMapper.cleanPushLog();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
<result property="platformId" column="platform_id"/>
|
||||
<result property="deviceId" column="device_id"/>
|
||||
<result property="serialNumber" column="serial_number"/>
|
||||
<result property="deviceName" column="device_name"/>
|
||||
<result property="platformDeviceId" column="platform_device_id"/>
|
||||
<result property="platformPointId" column="platform_point_id"/>
|
||||
<result property="sensorType" column="sensor_type"/>
|
||||
|
||||
@ -32,4 +32,7 @@
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<update id="cleanPushLog">
|
||||
truncate table platform_push_log
|
||||
</update>
|
||||
</mapper>
|
||||
|
||||
@ -119,6 +119,7 @@ CREATE TABLE IF NOT EXISTS `platform_device_mapping` (
|
||||
`platform_id` bigint(20) NOT NULL COMMENT '所属平台ID',
|
||||
`device_id` bigint(20) NOT NULL COMMENT 'FastBee设备ID',
|
||||
`serial_number` varchar(64) NOT NULL COMMENT 'FastBee设备序列号',
|
||||
`device_name` varchar(64) DEFAULT NULL COMMENT 'FastBee设备名称',
|
||||
`platform_device_id` varchar(100) DEFAULT NULL COMMENT 'DCP侧deviceId,入网后自动回填',
|
||||
`platform_point_id` varchar(100) DEFAULT NULL COMMENT 'DCP侧pointId,入网后自动回填',
|
||||
`sensor_type` varchar(50) NOT NULL COMMENT '传感器类型,来自字典 platform_sensor_type',
|
||||
@ -145,6 +146,10 @@ ALTER TABLE `platform_device_mapping`
|
||||
ADD COLUMN IF NOT EXISTS `device_type` tinyint(1) NOT NULL DEFAULT 0
|
||||
COMMENT '设备类型: 0=直连设备 1=网关设备(多子设备)' AFTER `sensor_type`;
|
||||
|
||||
ALTER TABLE `platform_device_mapping`
|
||||
ADD COLUMN IF NOT EXISTS `device_name` varchar(64) DEFAULT NULL
|
||||
COMMENT 'FastBee设备名称' AFTER `serial_number`;
|
||||
|
||||
-- ----------------------------
|
||||
-- 5.2 子设备映射(网关多子设备通用)
|
||||
-- ----------------------------
|
||||
@ -152,6 +157,7 @@ CREATE TABLE IF NOT EXISTS `platform_device_sub_mapping` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`parent_mapping_id` bigint(20) NOT NULL COMMENT '父映射ID (platform_device_mapping.id)',
|
||||
`sub_serial_number` varchar(64) NOT NULL COMMENT '子设备序列号',
|
||||
`sub_device_name` varchar(64) DEFAULT NULL COMMENT '子设备名称',
|
||||
`device_role` varchar(20) NOT NULL DEFAULT 'monitor' COMMENT '角色: reference=基准 monitor=监测',
|
||||
`platform_device_id` varchar(100) DEFAULT NULL COMMENT '平台分配的设备ID (入网后回填)',
|
||||
`platform_point_id` varchar(100) DEFAULT NULL COMMENT '平台分配的测点/辅助ID (入网后回填)',
|
||||
@ -165,6 +171,10 @@ CREATE TABLE IF NOT EXISTS `platform_device_sub_mapping` (
|
||||
UNIQUE KEY `uk_parent_sub` (`parent_mapping_id`, `sub_serial_number`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台设备子映射(网关多子设备通用)';
|
||||
|
||||
ALTER TABLE `platform_device_sub_mapping`
|
||||
ADD COLUMN IF NOT EXISTS `sub_device_name` varchar(64) DEFAULT NULL
|
||||
COMMENT '子设备名称' AFTER `sub_serial_number`;
|
||||
|
||||
-- ----------------------------
|
||||
-- 6. 推送日志
|
||||
-- ----------------------------
|
||||
|
||||
@ -15,3 +15,11 @@ export function retryPlatformPushLog(id) {
|
||||
export function delPlatformPushLog(ids) {
|
||||
return request({ url: `/platform/push-log/${ids}`, method: 'delete' })
|
||||
}
|
||||
|
||||
// 清空推送日志
|
||||
export function cleanPushLog() {
|
||||
return request({
|
||||
url: '/platform/push-log/clean',
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
@ -156,8 +156,9 @@
|
||||
<el-option label="平台设备ID" value="platform_device_id" />
|
||||
<el-option label="平台测点ID" value="platform_point_id" />
|
||||
<el-option label="系统设备编号" value="serial_number" />
|
||||
<el-option label="系统设备名称" value="device_name" />
|
||||
</el-select>
|
||||
<el-input v-else-if="scope.row.source === 'onboard_config'" v-model="scope.row.field" size="mini" placeholder="入网参数字段,如 sensorDepths" />
|
||||
<el-input v-else-if="scope.row.source === 'onboard_config'" v-model="scope.row.value" size="mini" placeholder="入网参数值,数组填 [1.7,3.4]" />
|
||||
<span v-else-if="scope.row.source === 'uuid'" class="schema-hint">每次请求自动生成UUID</span>
|
||||
<span v-else-if="scope.row.source === 'subDeviceSensorIds'" class="schema-hint">自动取设备绑定页子设备映射中的 sensorId 列表</span>
|
||||
<span v-else-if="scope.row.source === 'referenceSubDeviceSensorIdPairs'" class="schema-hint">按基准点与每个监测点成对拆分请求</span>
|
||||
@ -388,7 +389,12 @@ export default {
|
||||
if (!json) return []
|
||||
try {
|
||||
const arr = JSON.parse(json)
|
||||
return arr.map(f => ({ ...f, itemSchema: f.itemSchema || [], required: !!f.required }))
|
||||
return arr.map(f => ({
|
||||
...f,
|
||||
value: f.source === 'onboard_config' ? this.stringifySchemaValue(f.value) : f.value,
|
||||
itemSchema: f.itemSchema || [],
|
||||
required: !!f.required
|
||||
}))
|
||||
} catch (e) { return [] }
|
||||
},
|
||||
handleDelete(row) {
|
||||
@ -474,7 +480,8 @@ export default {
|
||||
})
|
||||
}
|
||||
if (r.source === 'fixed') field.value = r.value
|
||||
if (r.source === 'auth' || r.source === 'extra' || r.source === 'device' || r.source === 'onboard_config') field.field = r.field
|
||||
if (r.source === 'onboard_config') field.value = this.parseSchemaValue(r.value)
|
||||
if (r.source === 'auth' || r.source === 'extra' || r.source === 'device') field.field = r.field
|
||||
if (r.source === 'context') field.contextKey = r.contextKey
|
||||
return field
|
||||
}))
|
||||
@ -490,6 +497,27 @@ export default {
|
||||
this.getList()
|
||||
}).finally(() => { this.submitLoading = false })
|
||||
})
|
||||
},
|
||||
parseSchemaValue(value) {
|
||||
if (typeof value !== 'string') return value
|
||||
const text = value.trim()
|
||||
if (!text) return ''
|
||||
if ((text.startsWith('[') && text.endsWith(']')) || (text.startsWith('{') && text.endsWith('}'))) {
|
||||
return JSON.parse(text)
|
||||
}
|
||||
if (/^-?\d+(\.\d+)?$/.test(text)) {
|
||||
return Number(text)
|
||||
}
|
||||
if (text === 'true' || text === 'false') {
|
||||
return text === 'true'
|
||||
}
|
||||
return value
|
||||
},
|
||||
stringifySchemaValue(value) {
|
||||
if (Array.isArray(value) || (value && typeof value === 'object')) {
|
||||
return JSON.stringify(value)
|
||||
}
|
||||
return value == null ? '' : String(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@
|
||||
<div v-if="scope.row.deviceType === 1 && getSubDevicePairs(scope.row).length > 0" style="padding:10px 50px">
|
||||
<el-table :data="getSubDevicePairs(scope.row)" size="mini" border>
|
||||
<el-table-column label="子设备序列号" prop="subSerialNumber" min-width="140" />
|
||||
<el-table-column label="子设备名称" prop="subDeviceName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="角色" prop="deviceRole" width="80">
|
||||
<template slot-scope="s">
|
||||
<el-tag size="mini" :type="s.row.deviceRole === 'reference' ? 'warning' : ''">{{ s.row.deviceRole === 'reference' ? '基准' : '监测' }}</el-tag>
|
||||
@ -64,7 +65,7 @@
|
||||
<template slot-scope="scope">{{ platformName(scope.row.platformId) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="设备名称" min-width="140">
|
||||
<template slot-scope="scope">{{ deviceName(scope.row.deviceId) }}</template>
|
||||
<template slot-scope="scope">{{ scope.row.deviceName || deviceName(scope.row.deviceId) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="序列号" prop="serialNumber" width="140" />
|
||||
<el-table-column label="传感器类型" width="110" align="center">
|
||||
@ -128,6 +129,9 @@
|
||||
<el-form-item label="序列号">
|
||||
<el-input v-model="form.serialNumber" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="设备名称">
|
||||
<el-input v-model="form.deviceName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="传感器类型" prop="sensorType">
|
||||
<el-select v-model="form.sensorType" placeholder="选择或输入设备类型" filterable allow-create default-first-option style="width:100%">
|
||||
<el-option v-for="s in sensorTypeOptions" :key="s.value" :label="s.label" :value="s.value" />
|
||||
@ -167,11 +171,16 @@
|
||||
<el-select v-if="subDeviceOptions.length > 0"
|
||||
v-model="scope.row.subSerialNumber" size="mini" placeholder="选择子设备" filterable style="width:100%"
|
||||
@change="onSubSerialChange(scope.row)">
|
||||
<el-option v-for="device in subDeviceOptions" :key="device.serialNumber" :label="device.serialNumber" :value="device.serialNumber" />
|
||||
<el-option v-for="device in subDeviceOptions" :key="device.serialNumber" :label="subDeviceOptionLabel(device)" :value="device.serialNumber" />
|
||||
</el-select>
|
||||
<el-input v-else v-model="scope.row.subSerialNumber" size="mini" placeholder="填写子设备编号" @change="onSubSerialChange(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="子设备名称" min-width="140">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.subDeviceName" size="mini" placeholder="默认同子设备编号" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="角色" width="120" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.deviceRole" size="mini" style="width:100%" @change="onSubRoleChange(scope.row)">
|
||||
@ -258,6 +267,7 @@
|
||||
import { listPlatformDeviceMapping, addPlatformDeviceMapping, updatePlatformDeviceMapping, delPlatformDeviceMapping, onboardDevice, listSubMappings, syncSubMappings } from '@/api/platform/deviceMapping'
|
||||
import { listPlatformInstance } from '@/api/platform/instance'
|
||||
import { listPlatformInterface } from '@/api/platform/interface'
|
||||
import { listPlatformFlow, getPlatformFlow } from '@/api/platform/flow'
|
||||
import { listDevice, listThingsModel, getDevice, listDeviceShort } from '@/api/iot/device'
|
||||
import { listGateway } from '@/api/iot/gateway'
|
||||
import { getDicts } from '@/api/system/dict/data'
|
||||
@ -283,7 +293,7 @@ export default {
|
||||
subMappingCache: {},
|
||||
sensorTypeDictOptions: [],
|
||||
queryParams: { pageNum: 1, pageSize: 20, platformId: null, serialNumber: '', sensorType: '', netStatus: null },
|
||||
form: { enable: '1', deviceType: 0, reportIntervalSec: 300 },
|
||||
form: { enable: '1', deviceType: 0, reportIntervalSec: 300, deviceName: '' },
|
||||
rules: {
|
||||
platformId: [{ required: true, message: '请选择平台', trigger: 'change' }],
|
||||
deviceId: [{ required: true, message: '请选择设备', trigger: 'change' }],
|
||||
@ -363,6 +373,11 @@ export default {
|
||||
const sn = device.serialNumber ? `(${device.serialNumber})` : ''
|
||||
return `${name}${sn} - ${typeText}`
|
||||
},
|
||||
subDeviceOptionLabel(device) {
|
||||
const name = device.deviceName || device.serialNumber
|
||||
const sn = device.serialNumber && device.deviceName ? `(${device.serialNumber})` : ''
|
||||
return `${name}${sn}`
|
||||
},
|
||||
sensorLabel(v) {
|
||||
const option = this.sensorTypeOptions.find(item => item.value === v)
|
||||
return option ? option.label : v
|
||||
@ -378,7 +393,7 @@ export default {
|
||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||
resetQuery() { this.resetForm('queryForm'); this.handleQuery() },
|
||||
handleAdd() {
|
||||
this.form = { enable: '1', deviceType: 0, pushInterfaceId: null, reportIntervalSec: 300 }
|
||||
this.form = { enable: '1', deviceType: 0, pushInterfaceId: null, reportIntervalSec: 300, deviceName: '' }
|
||||
this.fieldMappingRows = []
|
||||
this.subMappingRows = []
|
||||
this.itemFieldMappingRows = []
|
||||
@ -389,7 +404,7 @@ export default {
|
||||
this.title = '新增设备绑定'; this.open = true
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.form = { ...row, reportIntervalSec: 300 }
|
||||
this.form = { ...row, deviceName: row.deviceName || '', reportIntervalSec: 300 }
|
||||
this.fieldMappingRows = this.safeParseJson(row.fieldMapping, [])
|
||||
this.subMappingRows = []
|
||||
this.itemFieldMappingRows = []
|
||||
@ -408,7 +423,7 @@ export default {
|
||||
// 加载子设备映射(网关设备)
|
||||
if (row.deviceType === 1 && row.id) {
|
||||
listSubMappings(row.id).then(res => {
|
||||
this.subMappingRows = (res.data || []).map(s => ({ ...s }))
|
||||
this.subMappingRows = (res.data || []).map(s => ({ ...s, subDeviceName: s.subDeviceName || s.subSerialNumber }))
|
||||
})
|
||||
}
|
||||
this.loadDeviceContext(row.deviceId)
|
||||
@ -438,6 +453,7 @@ export default {
|
||||
this.subMappingRows = this.subDeviceOptions.map(device => {
|
||||
return {
|
||||
subSerialNumber: device.serialNumber,
|
||||
subDeviceName: device.deviceName || device.serialNumber,
|
||||
deviceRole: 'monitor',
|
||||
onboardConfig: JSON.stringify({ sensorId: device.serialNumber }),
|
||||
platformDeviceId: '',
|
||||
@ -489,9 +505,11 @@ export default {
|
||||
const d = this.deviceOptions.find(x => x.deviceId === deviceId)
|
||||
if (d) {
|
||||
this.form.serialNumber = d.serialNumber
|
||||
this.form.deviceName = d.deviceName || d.serialNumber
|
||||
this.loadSubDeviceOptions(d)
|
||||
} else {
|
||||
this.form.serialNumber = ''
|
||||
this.form.deviceName = ''
|
||||
this.subDeviceOptions = []
|
||||
this.thingsModelOptions = []
|
||||
}
|
||||
@ -537,6 +555,7 @@ export default {
|
||||
this.deviceOptions = [{ deviceId: device.deviceId, deviceName: device.deviceName, serialNumber: device.serialNumber }]
|
||||
this.form.deviceId = device.deviceId
|
||||
this.form.serialNumber = device.serialNumber
|
||||
this.form.deviceName = device.deviceName || device.serialNumber
|
||||
this.loadThingsModel(device.deviceId)
|
||||
this.loadSubDeviceOptions(device)
|
||||
}).catch(() => {
|
||||
@ -577,6 +596,7 @@ export default {
|
||||
this.subMappingRows = this.subDeviceOptions.map(device => {
|
||||
return {
|
||||
subSerialNumber: device.serialNumber,
|
||||
subDeviceName: device.deviceName || device.serialNumber,
|
||||
deviceRole: 'monitor',
|
||||
onboardConfig: JSON.stringify({ sensorId: device.serialNumber }),
|
||||
platformDeviceId: '',
|
||||
@ -594,7 +614,7 @@ export default {
|
||||
},
|
||||
addFieldMapping() { this.fieldMappingRows.push({ identifier: '', platformField: '' }) },
|
||||
addSubMapping() {
|
||||
this.subMappingRows.push({ subSerialNumber: '', deviceRole: 'monitor', onboardConfig: '', platformDeviceId: '', platformPointId: '' })
|
||||
this.subMappingRows.push({ subSerialNumber: '', subDeviceName: '', deviceRole: 'monitor', onboardConfig: '', platformDeviceId: '', platformPointId: '' })
|
||||
},
|
||||
onSubRoleChange(row) {
|
||||
if (row.deviceRole === 'reference') {
|
||||
@ -608,7 +628,13 @@ export default {
|
||||
},
|
||||
onSubSerialChange(row) {
|
||||
if (!row.subSerialNumber) return
|
||||
row.onboardConfig = JSON.stringify({ sensorId: row.subSerialNumber })
|
||||
const selected = this.subDeviceOptions.find(device => device.serialNumber === row.subSerialNumber)
|
||||
if (selected) {
|
||||
row.subDeviceName = selected.deviceName || selected.serialNumber
|
||||
}
|
||||
const config = this.safeParseJson(row.onboardConfig, {})
|
||||
config.sensorId = config.sensorId || row.subSerialNumber
|
||||
row.onboardConfig = JSON.stringify(config)
|
||||
this.refreshSubMappingOnboardConfigs()
|
||||
},
|
||||
findReferenceRow(rows = this.subMappingRows) {
|
||||
@ -693,8 +719,9 @@ export default {
|
||||
// 网关设备:保存后同步子映射
|
||||
if (this.form.deviceType === 1 && mappingId) {
|
||||
const subData = normalizedSubRows
|
||||
.map(r => ({
|
||||
.map(r => ({
|
||||
subSerialNumber: r.subSerialNumber,
|
||||
subDeviceName: r.subDeviceName || r.subSerialNumber,
|
||||
deviceRole: r.deviceRole || 'monitor',
|
||||
onboardConfig: r.onboardConfig || null,
|
||||
platformDeviceId: r.platformDeviceId || null,
|
||||
|
||||
@ -205,7 +205,7 @@
|
||||
<el-option label="平台测点ID" value="platform_point_id" />
|
||||
<el-option label="系统设备编号" value="serial_number" />
|
||||
</el-select>
|
||||
<el-input v-else-if="scope.row.source === 'onboard_config'" v-model="scope.row.field" size="mini" placeholder="入网参数字段,如 sensorDepths" />
|
||||
<el-input v-else-if="scope.row.source === 'onboard_config'" v-model="scope.row.value" size="mini" placeholder="入网参数,数组值与子设备数量相等" />
|
||||
<span v-else-if="scope.row.source === 'uuid'" class="schema-hint">每次请求自动生成UUID</span>
|
||||
<span v-else-if="scope.row.source === 'subDeviceSensorIds'" class="schema-hint">自动取设备绑定页子设备映射中的 sensorId 列表</span>
|
||||
<span v-else-if="scope.row.source === 'referenceSubDeviceSensorIdPairs'" class="schema-hint">按基准点与每个监测点成对拆分请求</span>
|
||||
@ -449,6 +449,27 @@ export default {
|
||||
return defaultValue
|
||||
}
|
||||
},
|
||||
parseSchemaValue(value) {
|
||||
if (typeof value !== 'string') return value
|
||||
const text = value.trim()
|
||||
if (!text) return ''
|
||||
if ((text.startsWith('[') && text.endsWith(']')) || (text.startsWith('{') && text.endsWith('}'))) {
|
||||
return JSON.parse(text)
|
||||
}
|
||||
if (/^-?\d+(\.\d+)?$/.test(text)) {
|
||||
return Number(text)
|
||||
}
|
||||
if (text === 'true' || text === 'false') {
|
||||
return text === 'true'
|
||||
}
|
||||
return value
|
||||
},
|
||||
stringifySchemaValue(value) {
|
||||
if (Array.isArray(value) || (value && typeof value === 'object')) {
|
||||
return JSON.stringify(value)
|
||||
}
|
||||
return value == null ? '' : String(value)
|
||||
},
|
||||
parseRequestSchema(interfaceId) {
|
||||
const iface = this.interfaceOptions.find(item => item.id === interfaceId)
|
||||
return this.safeParseJson(iface && iface.requestSchema, [])
|
||||
@ -459,7 +480,7 @@ export default {
|
||||
if (field.source === 'auth') return `认证参数 / ${field.field || ''}`
|
||||
if (field.source === 'extra') return `平台参数 / ${field.field || ''}`
|
||||
if (field.source === 'context') return `上一步结果 / ${field.contextKey || ''}`
|
||||
if (field.source === 'onboard_config') return `入网参数 / ${field.field || ''}`
|
||||
if (field.source === 'onboard_config') return `入网参数 / ${this.stringifySchemaValue(field.value)}`
|
||||
if (field.source === 'device') {
|
||||
const deviceLabels = {
|
||||
platform_device_id: '平台设备ID',
|
||||
@ -529,7 +550,7 @@ export default {
|
||||
name: field.name,
|
||||
defaultSource: this.describeFieldSource(field),
|
||||
source: saved.source || '',
|
||||
value: saved.value !== undefined ? saved.value : '',
|
||||
value: saved.value !== undefined ? this.stringifySchemaValue(saved.value) : '',
|
||||
field: saved.field || '',
|
||||
contextKey: saved.contextKey || ''
|
||||
}
|
||||
@ -547,7 +568,8 @@ export default {
|
||||
if (!row.name || !row.source) return
|
||||
const item = { source: row.source }
|
||||
if (row.source === 'fixed') item.value = row.value
|
||||
if (row.source === 'auth' || row.source === 'extra' || row.source === 'device' || row.source === 'onboard_config') item.field = row.field
|
||||
if (row.source === 'onboard_config') item.value = this.parseSchemaValue(row.value)
|
||||
if (row.source === 'auth' || row.source === 'extra' || row.source === 'device') item.field = row.field
|
||||
if (row.source === 'context') item.contextKey = row.contextKey
|
||||
mappings[row.name] = item
|
||||
})
|
||||
|
||||
@ -11,6 +11,11 @@
|
||||
<el-form-item label="设备序列号" prop="serialNumber">
|
||||
<el-input v-model="queryParams.serialNumber" placeholder="序列号" clearable style="width:140px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="设备类型" prop="interfaceCode">
|
||||
<el-select v-model="queryParams.interfaceCode" placeholder="全部" clearable filterable style="width:140px">
|
||||
<el-option v-for="s in sensorTypeOptions" :key="s.value" :label="s.label" :value="s.interfaceCode" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="全部" clearable style="width:100px">
|
||||
<el-option label="进行中" :value="0" />
|
||||
@ -30,6 +35,9 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="selectedIds.length === 0" @click="handleBatchDelete" v-hasPermi="['platform:pushLog:remove']">删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" @click="handleClean" v-hasPermi="['monitor:logininfor:remove']">{{ $t('operlog.874509-7') }}</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
</el-row>
|
||||
|
||||
@ -105,8 +113,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listPlatformPushLog, getPlatformPushLog, retryPlatformPushLog, delPlatformPushLog } from '@/api/platform/pushLog'
|
||||
import { listPlatformPushLog, getPlatformPushLog, retryPlatformPushLog, delPlatformPushLog, cleanPushLog } from '@/api/platform/pushLog'
|
||||
import { listPlatformInstance } from '@/api/platform/instance'
|
||||
import { getDicts } from '@/api/system/dict/data'
|
||||
|
||||
const SENSOR_TYPE_DICT = 'platform_sensor_type'
|
||||
|
||||
export default {
|
||||
name: 'PlatformPushLog',
|
||||
@ -117,20 +128,36 @@ export default {
|
||||
total: 0,
|
||||
list: [],
|
||||
platformList: [],
|
||||
sensorTypeOptions: [],
|
||||
selectedIds: [],
|
||||
activeTab: '1',
|
||||
retryingId: null,
|
||||
detailOpen: false,
|
||||
detailTab: 'req',
|
||||
detail: {},
|
||||
queryParams: { pageNum: 1, pageSize: 20, platformId: null, serialNumber: '', status: null, logType: 1 }
|
||||
queryParams: { pageNum: 1, pageSize: 20, platformId: null, serialNumber: '', interfaceCode: '', status: null, logType: 1 }
|
||||
}
|
||||
},
|
||||
created() {
|
||||
listPlatformInstance({ pageNum: 1, pageSize: 100 }).then(res => { this.platformList = res.rows })
|
||||
this.loadSensorTypeOptions()
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
loadSensorTypeOptions() {
|
||||
getDicts(SENSOR_TYPE_DICT).then(res => {
|
||||
this.sensorTypeOptions = ((res && res.data) || []).map(item => {
|
||||
const value = item.dictValue
|
||||
return {
|
||||
value,
|
||||
label: item.dictLabel || value,
|
||||
interfaceCode: `dcp_push_${value}`
|
||||
}
|
||||
}).filter(item => item.value)
|
||||
}).catch(() => {
|
||||
this.sensorTypeOptions = []
|
||||
})
|
||||
},
|
||||
getList() {
|
||||
this.loading = true
|
||||
listPlatformPushLog(this.queryParams).then(res => {
|
||||
@ -169,6 +196,7 @@ export default {
|
||||
this.retryingId = null
|
||||
})
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleBatchDelete() {
|
||||
if (this.selectedIds.length === 0) return
|
||||
this.$confirm(`确认删除选中的 ${this.selectedIds.length} 条日志?`).then(() => {
|
||||
@ -179,6 +207,19 @@ export default {
|
||||
})
|
||||
})
|
||||
},
|
||||
/** 清空按钮操作 */
|
||||
handleClean() {
|
||||
this.$modal
|
||||
.confirm(this.$t('是否确认清空所有推送日志数据项'))
|
||||
.then(function () {
|
||||
return cleanPushLog();
|
||||
})
|
||||
.then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess(this.$t('operlog.874509-29'));
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
formatJson(str) {
|
||||
if (!str) return ''
|
||||
try { return JSON.stringify(JSON.parse(str), null, 2) } catch { return str }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user