From 4e467edb2b9b7a3c53d4a4cab85baa5772b563f3 Mon Sep 17 00:00:00 2001 From: zhugongping Date: Sat, 27 Jun 2026 21:53:27 +0800 Subject: [PATCH] =?UTF-8?q?20260627:=E6=8E=A5=E5=85=A5=E6=B7=B1=E5=BA=A6?= =?UTF-8?q?=E4=BD=8D=E7=A7=BB=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/send_modbus_and_register.py | 6 ++ .../adapter/dcp/DcpPlatformAdapter.java | 28 ++----- .../platform/flow/PlatformFlowExecutor.java | 84 ++++++++++++++++++- .../service/impl/SysDictTypeServiceImpl.java | 6 +- sql/platform-integration.sql | 30 ++++++- .../platform/components/InterfaceDrawer.vue | 4 +- .../views/platform/device-mapping/index.vue | 22 +++-- yack-web/src/views/platform/flow/index.vue | 35 ++++---- 8 files changed, 164 insertions(+), 51 deletions(-) diff --git a/bin/send_modbus_and_register.py b/bin/send_modbus_and_register.py index 3f9626c1..9f211ec8 100644 --- a/bin/send_modbus_and_register.py +++ b/bin/send_modbus_and_register.py @@ -16,6 +16,12 @@ MODBUS_DATA_HEX = ( "05031c41bd1c1941810000402bb38600000000bf4501bdc027dfcac2ae88538AEC" ) +# 深部位移计 +# "7e80DD33D43DFC5B7e", +# "0103204135317841ab8e39bf27bccd3f1fb19ac2b231bbc0b6f82040ae3207c3f9f80efa23", +# "020320413b9fa441acd34dc0024a003fa2a59ac2af34a0c18e17ea413167dbc3f9c7fe6d40", +# "0303204139565641ab21ddbff6af333fe26800c2aec626c18685244176ee82c3f9bd7568c8", +# "040320413a0d3e41a534d3bf461ccd403d7e00c2ade1e4c0d819c441ce9ca7c3f9a4d260bf" # 01 03 1c 4268 442f 41d3 0000 418b 6685 0000 0000 4026 f4ca c00d 1fd3 c2ad 2a9d 6311 # 从机地址 功能码 字节长度 2个字节 CRC校验 diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/platform/adapter/dcp/DcpPlatformAdapter.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/platform/adapter/dcp/DcpPlatformAdapter.java index 1ad9b427..9017cb60 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/platform/adapter/dcp/DcpPlatformAdapter.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/platform/adapter/dcp/DcpPlatformAdapter.java @@ -71,15 +71,6 @@ public class DcpPlatformAdapter { @Autowired private IPlatformDeviceSubMappingService subMappingService; - /** 传感器类型 → 推送接口路径 */ - private static final Map PUSH_PATH = new HashMap<>(); - static { - PUSH_PATH.put("inclino", "/api/app/inclino-data/many"); - PUSH_PATH.put("stress", "/api/app/stress-data/many"); - PUSH_PATH.put("hyeto", "/api/app/hyeto-data/many"); - PUSH_PATH.put("static_level", "/api/app/static-level-data/many"); - } - /** * 推送设备上报数据到 DCP(直连设备) */ @@ -93,13 +84,9 @@ public class DcpPlatformAdapter { PlatformInterface pushInterface = loadPushInterface(mapping); JSONArray requestSchema = loadRequestSchema(pushInterface); String interfaceCode = resolveInterfaceCode(sensorType, pushInterface); - String pushPath = resolvePushPath(sensorType, pushInterface); - if (pushPath == null) { - log.warn("[DCP] 未知传感器类型: {}", sensorType); - return; - } try { + String pushPath = resolvePushPath(mapping, pushInterface); handleNormalPush( platform, mapping, reportSerialNumber, payload, pushPath, interfaceCode, requestSchema); @@ -131,13 +118,9 @@ public class DcpPlatformAdapter { PlatformInterface pushInterface = loadPushInterface(mapping); JSONArray requestSchema = loadRequestSchema(pushInterface); String interfaceCode = resolveInterfaceCode(sensorType, pushInterface); - String pushPath = resolvePushPath(sensorType, pushInterface); - if (pushPath == null) { - log.warn("[DCP] 未知传感器类型: {}", sensorType); - return; - } try { + String pushPath = resolvePushPath(mapping, pushInterface); JSONObject reportData = parsePayloadToMap(payload); if (reportData == null || reportData.isEmpty()) { return; @@ -702,11 +685,14 @@ public class DcpPlatformAdapter { } } - private String resolvePushPath(String sensorType, PlatformInterface pushInterface) { + private String resolvePushPath(PlatformDeviceMapping mapping, PlatformInterface pushInterface) { if (pushInterface != null && StringUtils.hasText(pushInterface.getPath())) { return pushInterface.getPath(); } - return PUSH_PATH.get(sensorType); + String sensorType = mapping == null ? null : mapping.getSensorType(); + String serialNumber = mapping == null ? null : mapping.getSerialNumber(); + throw new RuntimeException("未配置推送接口,请在设备绑定中选择推送接口" + + ",设备=" + serialNumber + ",传感器类型=" + sensorType); } private String resolveInterfaceCode(String sensorType, PlatformInterface pushInterface) { diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/platform/flow/PlatformFlowExecutor.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/platform/flow/PlatformFlowExecutor.java index 546316d2..aa9d68c4 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/platform/flow/PlatformFlowExecutor.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/platform/flow/PlatformFlowExecutor.java @@ -255,15 +255,16 @@ public class PlatformFlowExecutor { if (override instanceof Map) { Map ov = (Map) override; String src = (String) ov.get("source"); - result.put(name, resolveValue(src, ov, authConfig, extraConfig, ctx)); + String type = ov.get("type") != null ? String.valueOf(ov.get("type")) : field.getString("type"); + result.put(name, normalizeValueByType(type, resolveValue(src, ov, authConfig, extraConfig, ctx))); } else { - result.put(name, override); + result.put(name, normalizeValueByType(field.getString("type"), override)); } continue; } String source = field.getString("source"); - result.put(name, resolveValue(source, field, authConfig, extraConfig, ctx)); + result.put(name, normalizeValueByType(field.getString("type"), resolveValue(source, field, authConfig, extraConfig, ctx))); } return result; } @@ -1069,4 +1070,81 @@ public class PlatformFlowExecutor { } } } + + // ============== 先不使用 =========== + private Object normalizeValueByType(String type, Object value) { + if (value == null || !StringUtils.hasText(type)) { + return value; + } + String normalizedType = type.trim().toLowerCase(Locale.ROOT); + switch (normalizedType) { + case "array": + return normalizeArrayValue(value); + case "number": + return normalizeNumberValue(value); + case "boolean": + return normalizeBooleanValue(value); + } + return value; + } + + private Object normalizeArrayValue(Object value) { + if (value instanceof List) { + return value; + } + if (!(value instanceof String)) { + return value; + } + String text = ((String) value).trim(); + if (!StringUtils.hasText(text)) { + return new JSONArray(); + } + try { + if (text.startsWith("[")) { + return JSON.parseArray(text); + } + } catch (Exception ignored) { + // Fall through to comma split. + } + JSONArray array = new JSONArray(); + for (String item : text.split(",")) { + String itemText = item.trim(); + if (!itemText.isEmpty()) { + array.add(normalizeNumberValue(itemText)); + } + } + return array; + } + + private Object normalizeNumberValue(Object value) { + if (value instanceof Number) { + return value; + } + if (!(value instanceof String)) { + return value; + } + String text = ((String) value).trim(); + if (!StringUtils.hasText(text)) { + return value; + } + try { + return text.contains(".") ? Double.parseDouble(text) : Long.parseLong(text); + } catch (NumberFormatException e) { + return value; + } + } + + private Object normalizeBooleanValue(Object value) { + if (value instanceof Boolean) { + return value; + } + if (!(value instanceof String)) { + return value; + } + String text = ((String) value).trim(); + if ("true".equalsIgnoreCase(text) || "false".equalsIgnoreCase(text)) { + return Boolean.parseBoolean(text); + } + return value; + } } diff --git a/fastbee-service/fastbee-system-service/src/main/java/com/fastbee/system/service/impl/SysDictTypeServiceImpl.java b/fastbee-service/fastbee-system-service/src/main/java/com/fastbee/system/service/impl/SysDictTypeServiceImpl.java index 8f59d6ed..0126c0c0 100644 --- a/fastbee-service/fastbee-system-service/src/main/java/com/fastbee/system/service/impl/SysDictTypeServiceImpl.java +++ b/fastbee-service/fastbee-system-service/src/main/java/com/fastbee/system/service/impl/SysDictTypeServiceImpl.java @@ -38,7 +38,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService { /** * 多语言转换 - * + * todo 还没有同步维护 sys_dict_data_translate 表 先🧑‍注释 * @param list * @param language * @return @@ -98,13 +98,13 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService { public List selectDictDataByType(String dictType) { List dictDatas = DictUtils.getDictCache(dictType); if (StringUtils.isNotEmpty(dictDatas)) { - convertDictLabel(dictDatas, SecurityUtils.getLanguage()); + //convertDictLabel(dictDatas, SecurityUtils.getLanguage()); return dictDatas; } dictDatas = dictDataMapper.selectDictDataByType(dictType); if (StringUtils.isNotEmpty(dictDatas)) { DictUtils.setDictCache(dictType, dictDatas); - convertDictLabel(dictDatas, SecurityUtils.getLanguage()); + //convertDictLabel(dictDatas, SecurityUtils.getLanguage()); return dictDatas; } return null; diff --git a/sql/platform-integration.sql b/sql/platform-integration.sql index 994a0d1c..5e025831 100644 --- a/sql/platform-integration.sql +++ b/sql/platform-integration.sql @@ -1,6 +1,32 @@ -- 平台对接模块 DDL -- 创建时间: 2026-05-30 +-- ---------------------------- +-- 0. 平台传感器类型字典 +-- 页面从 platform_sensor_type 读取选项,新增类型只需维护字典。 +-- ---------------------------- +INSERT IGNORE INTO `sys_dict_type` (`dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `remark`) +VALUES ('平台传感器类型', 'platform_sensor_type', '0', 'system', NOW(), '第三方平台对接使用的传感器类型'); + +DELETE FROM `sys_dict_data` +WHERE `dict_type` = 'platform_sensor_type' + AND `dict_value` IN ('inclino', 'deep_inclino', 'stress', 'hyeto', 'static_level'); + +INSERT INTO `sys_dict_data` (`dict_sort`, `dict_label`, `dict_value`, `dict_type`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `remark`) +VALUES + (1, '倾角', 'inclino', 'platform_sensor_type', 'primary', 'N', '0', 'system', NOW(), 'DCP倾角'), + (2, '深部位移计', 'deep_inclino', 'platform_sensor_type', 'primary', 'N', '0', 'system', NOW(), 'DCP深部位移计'), + (3, '轴力计', 'stress', 'platform_sensor_type', 'primary', 'N', '0', 'system', NOW(), 'DCP轴力计'), + (4, '雨量计', 'hyeto', 'platform_sensor_type', 'primary', 'N', '0', 'system', NOW(), 'DCP雨量计'), + (5, '静力水准仪', 'static_level', 'platform_sensor_type', 'primary', 'N', '0', 'system', NOW(), 'DCP静力水准'); + +INSERT INTO `sys_dict_data_translate` (`id`,`zh_cn`, `en_us`) +VALUES (738,'倾角','inclino'), + (739,'深部位移','deepInclino'), + (740,'轴力','stress'), + (741,'雨量','hyeto'), + (742,'静力水准','staticLevel') +; -- ---------------------------- -- 1. 平台实体 -- ---------------------------- @@ -58,7 +84,7 @@ CREATE TABLE IF NOT EXISTS `platform_flow` ( `name` varchar(100) NOT NULL COMMENT '流程名称', `code` varchar(100) NOT NULL COMMENT '流程标识', `flow_type` tinyint(1) NOT NULL COMMENT '流程类型(1=平台初始化,2=设备入网,3=Token刷新)', - `sensor_type` varchar(50) DEFAULT NULL COMMENT '传感器类型,flow_type=2时有效: inclino/stress/hyeto/static_level', + `sensor_type` varchar(50) DEFAULT NULL COMMENT '传感器类型,flow_type=2时有效,来自字典 platform_sensor_type', `enable` char(1) NOT NULL DEFAULT '1' COMMENT '是否启用', `remark` varchar(500) DEFAULT NULL COMMENT '备注', `create_by` varchar(64) DEFAULT '' COMMENT '创建者', @@ -95,7 +121,7 @@ CREATE TABLE IF NOT EXISTS `platform_device_mapping` ( `serial_number` varchar(64) NOT 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 '传感器类型: inclino/stress/hyeto/static_level', + `sensor_type` varchar(50) NOT NULL COMMENT '传感器类型,来自字典 platform_sensor_type', `device_type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '设备类型: 0=直连设备 1=网关设备(多子设备)', `push_interface_id` bigint(20) DEFAULT NULL COMMENT '推送接口ID,用于字段映射参照', `field_mapping` json DEFAULT NULL COMMENT '字段映射 [{identifier,platformField,transform}]', diff --git a/yack-web/src/views/platform/components/InterfaceDrawer.vue b/yack-web/src/views/platform/components/InterfaceDrawer.vue index efde5678..ff3e28cf 100644 --- a/yack-web/src/views/platform/components/InterfaceDrawer.vue +++ b/yack-web/src/views/platform/components/InterfaceDrawer.vue @@ -126,6 +126,7 @@ + @@ -156,6 +157,7 @@ + 每次请求自动生成UUID 自动取设备绑定页子设备映射中的 sensorId 列表 按基准点与每个监测点成对拆分请求 @@ -463,7 +465,7 @@ export default { }) } if (r.source === 'fixed') field.value = r.value - if (r.source === 'auth' || r.source === 'extra' || r.source === 'device') field.field = r.field + if (r.source === 'auth' || r.source === 'extra' || r.source === 'device' || r.source === 'onboard_config') field.field = r.field if (r.source === 'context') field.contextKey = r.contextKey return field })) diff --git a/yack-web/src/views/platform/device-mapping/index.vue b/yack-web/src/views/platform/device-mapping/index.vue index 627c7256..46ff5f40 100644 --- a/yack-web/src/views/platform/device-mapping/index.vue +++ b/yack-web/src/views/platform/device-mapping/index.vue @@ -256,13 +256,9 @@ import { listPlatformInstance } from '@/api/platform/instance' import { listPlatformInterface } from '@/api/platform/interface' import { listDevice, listThingsModel, getDevice } from '@/api/iot/device' import { listGateway } from '@/api/iot/gateway' +import { getDicts } from '@/api/system/dict/data' -const DEFAULT_SENSOR_TYPES = [ - { value: 'inclino', label: '倾角' }, - { value: 'stress', label: '轴力计' }, - { value: 'hyeto', label: '雨量计' }, - { value: 'static_level', label: '静力水准' } -] +const SENSOR_TYPE_DICT = 'platform_sensor_type' export default { name: 'PlatformDeviceMapping', @@ -281,6 +277,7 @@ export default { itemFieldMappingRows: [], // 子表缓存 (列表展开行使用) subMappingCache: {}, + sensorTypeDictOptions: [], queryParams: { pageNum: 1, pageSize: 20, platformId: null, sensorType: '', netStatus: null }, form: { enable: '1', deviceType: 0, reportIntervalSec: 300 }, rules: { @@ -304,7 +301,7 @@ export default { }, sensorTypeOptions() { const optionMap = new Map() - DEFAULT_SENSOR_TYPES.forEach(item => optionMap.set(item.value, { ...item })) + this.sensorTypeDictOptions.forEach(item => optionMap.set(item.value, { ...item })) ;(this.list || []).forEach(item => { if (item && item.sensorType && !optionMap.has(item.sensorType)) { optionMap.set(item.sensorType, { value: item.sensorType, label: item.sensorType }) @@ -314,10 +311,21 @@ export default { } }, created() { + this.loadSensorTypeOptions() listPlatformInstance({ pageNum: 1, pageSize: 100 }).then(res => { this.platformList = res.rows || [] }) this.getList() }, methods: { + loadSensorTypeOptions() { + getDicts(SENSOR_TYPE_DICT).then(res => { + this.sensorTypeDictOptions = ((res && res.data) || []).map(item => ({ + value: item.dictValue, + label: item.dictLabel || item.dictValue + })).filter(item => item.value) + }).catch(() => { + this.sensorTypeDictOptions = [] + }) + }, getList() { this.loading = true listPlatformDeviceMapping(this.queryParams).then(res => { diff --git a/yack-web/src/views/platform/flow/index.vue b/yack-web/src/views/platform/flow/index.vue index 4fb92282..023d33b3 100644 --- a/yack-web/src/views/platform/flow/index.vue +++ b/yack-web/src/views/platform/flow/index.vue @@ -178,6 +178,7 @@ + @@ -204,6 +205,7 @@ + 每次请求自动生成UUID 自动取设备绑定页子设备映射中的 sensorId 列表 按基准点与每个监测点成对拆分请求 @@ -252,18 +254,9 @@ import { listPlatformFlow, getPlatformFlow, savePlatformFlow, delPlatformFlow, executePlatformFlow } from '@/api/platform/flow' import { listPlatformInstance, getPlatformInstance } from '@/api/platform/instance' import { listPlatformInterface } from '@/api/platform/interface' +import { getDicts } from '@/api/system/dict/data' -const DEFAULT_SENSOR_TYPES = [ - { value: 'inclino', label: '倾角' }, - { value: 'stress', label: '轴力计' }, - { value: 'hyeto', label: '雨量计' }, - { value: 'static_level', label: '静力水准' } -] - -const SENSOR_LABELS = DEFAULT_SENSOR_TYPES.reduce((acc, item) => { - acc[item.value] = item.label - return acc -}, {}) +const SENSOR_TYPE_DICT = 'platform_sensor_type' export default { name: 'PlatformFlow', @@ -278,6 +271,7 @@ export default { interfaceOptions: [], platformAuthFields: [], platformExtraFields: [], + sensorTypeDictOptions: [], open: false, title: '', steps: [], @@ -301,17 +295,29 @@ export default { computed: { sensorTypeOptions() { const optionMap = new Map() - DEFAULT_SENSOR_TYPES.forEach(item => optionMap.set(item.value, { ...item })) + this.sensorTypeDictOptions.forEach(item => optionMap.set(item.value, { ...item })) ;(this.list || []).forEach(item => this.appendSensorTypeOption(optionMap, item && item.sensorType)) this.appendSensorTypeOption(optionMap, this.form.sensorType) return Array.from(optionMap.values()) } }, created() { + this.loadSensorTypeOptions() listPlatformInstance({ pageNum: 1, pageSize: 100 }).then(res => { this.platformList = res.rows || [] }) this.getList() }, methods: { + loadSensorTypeOptions() { + getDicts(SENSOR_TYPE_DICT).then(res => { + this.sensorTypeDictOptions = ((res && res.data) || []).map(item => { + const value = item.dict_value || item.dictValue + const label = item.dict_label || item.dictLabel || value + return { value, label } + }).filter(item => item.value) + }).catch(() => { + this.sensorTypeDictOptions = [] + }) + }, getList() { this.loading = true listPlatformFlow(this.queryParams).then(res => { @@ -322,7 +328,7 @@ export default { }, appendSensorTypeOption(optionMap, value) { if (!value || optionMap.has(value)) return - optionMap.set(value, { value, label: SENSOR_LABELS[value] || value }) + optionMap.set(value, { value, label: value }) }, platformName(id) { const platform = this.platformList.find(item => item.id === id) @@ -453,6 +459,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 === 'device') { const deviceLabels = { platform_device_id: '平台设备ID', @@ -540,7 +547,7 @@ 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') item.field = row.field + if (row.source === 'auth' || row.source === 'extra' || row.source === 'device' || row.source === 'onboard_config') item.field = row.field if (row.source === 'context') item.contextKey = row.contextKey mappings[row.name] = item })