20260627:监测点可以任意指定子设备
This commit is contained in:
parent
d07288b64d
commit
1846f4e717
@ -8,12 +8,14 @@ TARGET_PORT = 8888 # 请根据实际情况修改
|
||||
|
||||
# 元数组 modbus 指令
|
||||
MODBUS_DATA_HEX = (
|
||||
"7e80D55746B29F687e",
|
||||
"010310c07ffffe45217c3d41dfe9964140686641f4"
|
||||
"7e80D21F6C448E8D7e",
|
||||
"01031c41b6dcec418b0000402d2148000000004017e0b8400c19efc2ad8a8acb2b",
|
||||
"02031c41babecc419d8000402be3560000000040137c30bfb2f4d0c2ae9bc1b582",
|
||||
"03031c41bd1c1941810000402bb38600000000bf4501bdc027dfcac2ae8853eaef",
|
||||
"04031c41babecc419d8000402be3560000000040137c30bfb2f4d0c2ae9bc1D581",
|
||||
"05031c41bd1c1941810000402bb38600000000bf4501bdc027dfcac2ae88538AEC"
|
||||
)
|
||||
# "01031c4268442f41d30000418b6685000000004026f4cac00d1fd3c2ad2a9d6311",
|
||||
# "02031c42488fd041c5800041865ab7000000003f364458c03f765ec2add9722da5",
|
||||
# "03031c42ffdad541c78000421529b8000000003d5f38f94082080dc2abdf4f1f94"
|
||||
|
||||
# 01 03 1c 4268 442f 41d3 0000 418b 6685 0000 0000 4026 f4ca c00d 1fd3 c2ad 2a9d 6311
|
||||
# 从机地址 功能码 字节长度 2个字节 CRC校验
|
||||
|
||||
@ -45,7 +47,7 @@ def main():
|
||||
|
||||
# 2. 等待0.5秒
|
||||
print("等待 0.1 秒...")
|
||||
time.sleep(0.5)
|
||||
time.sleep(1)
|
||||
|
||||
# (可选)接收最终响应
|
||||
try:
|
||||
|
||||
@ -133,7 +133,7 @@ public class CRC16Utils {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String hex = "0103028000";
|
||||
String hex = "006000000000";
|
||||
byte[] bytes = ByteUtils.hexToByte(hex);
|
||||
String crc = getCRC(bytes);
|
||||
System.out.println(crc);
|
||||
|
||||
@ -303,9 +303,9 @@ public class ByteUtils {
|
||||
return data.getBytes(charset);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* 把16进制字符串转换成字节数组
|
||||
* @param hex
|
||||
* @param hexStr 16进制字符
|
||||
* @return
|
||||
*/
|
||||
public static byte[] hexToByte(String hexStr) {
|
||||
|
||||
@ -19,6 +19,7 @@ import com.fastbee.iot.platform.flow.FlowContext;
|
||||
import com.fastbee.iot.platform.flow.PlatformFlowExecutor;
|
||||
import com.fastbee.iot.platform.mapper.PlatformFlowMapper;
|
||||
import com.fastbee.iot.platform.mapper.PlatformInterfaceMapper;
|
||||
import com.fastbee.iot.platform.service.IPlatformDeviceSubMappingService;
|
||||
import com.fastbee.iot.platform.service.IPlatformInstanceService;
|
||||
import com.fastbee.iot.platform.service.IPlatformPushLogService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -34,6 +35,7 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -66,6 +68,8 @@ public class DcpPlatformAdapter {
|
||||
private StaticLevelBufferService bufferService;
|
||||
@Autowired
|
||||
private PlatformInterfaceMapper interfaceMapper;
|
||||
@Autowired
|
||||
private IPlatformDeviceSubMappingService subMappingService;
|
||||
|
||||
/** 传感器类型 → 推送接口路径 */
|
||||
private static final Map<String, String> PUSH_PATH = new HashMap<>();
|
||||
@ -184,10 +188,12 @@ public class DcpPlatformAdapter {
|
||||
JSONObject currentBodyFields = buildObjectBySchema(platform, mapping, requestSchema, reportData, fieldMappings);
|
||||
|
||||
if (subMapping.isReference()) {
|
||||
// 基准点上报:仅缓存,不推送
|
||||
// 基准点上报:缓存当前基准点,并补推此前已缓存的监测点
|
||||
bufferService.saveReferenceData(
|
||||
platform.getId(), fieldName, reportSerialNumber, currentItem, reportIntervalSec);
|
||||
log.info("[DCP] 基准点 {} 已缓存,等待监测点上报", reportSerialNumber);
|
||||
int replayCount = replayPendingMonitorData(platform, mapping, fieldName, currentItem,
|
||||
reportIntervalSec, baseUrl, interfaceCode);
|
||||
log.info("[DCP] 基准点 {} 已缓存,补推监测点 {} 条", reportSerialNumber, replayCount);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -198,7 +204,7 @@ public class DcpPlatformAdapter {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取基准点序列号(从 onboard_config 中取 refSensorId 对应的原始序列号)
|
||||
// 获取基准点序列号,优先使用子映射中当前标记的 reference 行
|
||||
String refSerialNumber = resolveRefSerialNumber(subMapping, mapping);
|
||||
|
||||
JSONObject refData = bufferService.getReferenceDataIfFresh(
|
||||
@ -243,12 +249,18 @@ public class DcpPlatformAdapter {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从子映射的 onboard_config 解析基准点序列号
|
||||
*/
|
||||
/** 解析基准点序列号 */
|
||||
private String resolveRefSerialNumber(PlatformDeviceSubMapping subMapping, PlatformDeviceMapping mapping) {
|
||||
// 从 onboard_config 取 refSensorId 对应的子设备序列号
|
||||
// 通常基准点的 sensorId == 基准点的 serialNumber
|
||||
try {
|
||||
PlatformDeviceSubMapping reference = subMappingService.findReference(mapping.getId());
|
||||
if (reference != null && StringUtils.hasText(reference.getSubSerialNumber())) {
|
||||
return reference.getSubSerialNumber();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("[DCP] 查询静力水准基准点失败 mappingId={}, error={}", mapping.getId(), e.getMessage());
|
||||
}
|
||||
|
||||
// 兼容历史配置:从 onboard_config 取基准点原始序列号
|
||||
if (StringUtils.hasText(subMapping.getOnboardConfig())) {
|
||||
try {
|
||||
JSONObject config = JSON.parseObject(subMapping.getOnboardConfig());
|
||||
@ -262,6 +274,67 @@ public class DcpPlatformAdapter {
|
||||
return mapping.getSerialNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* 基准点后到时,补推此前缓存的监测点数据。
|
||||
*/
|
||||
private int replayPendingMonitorData(PlatformInstance platform, PlatformDeviceMapping mapping,
|
||||
String fieldName, JSONObject referenceItem,
|
||||
int reportIntervalSec, String baseUrl, String interfaceCode) {
|
||||
List<PlatformDeviceSubMapping> subMappings = subMappingService.selectByParentId(mapping.getId());
|
||||
if (subMappings == null || subMappings.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int replayCount = 0;
|
||||
for (PlatformDeviceSubMapping monitor : subMappings) {
|
||||
if (monitor == null || !monitor.isMonitor()
|
||||
|| !StringUtils.hasText(monitor.getSubSerialNumber())) {
|
||||
continue;
|
||||
}
|
||||
JSONObject monitorData = bufferService.getMonitorDataIfFresh(
|
||||
platform.getId(), fieldName, monitor.getSubSerialNumber(), reportIntervalSec);
|
||||
if (monitorData == null) {
|
||||
continue;
|
||||
}
|
||||
if (!StringUtils.hasText(monitor.getPlatformDeviceId())) {
|
||||
log.warn("[DCP] 监测点 {} 有缓存但未分配平台设备ID,暂不补推",
|
||||
monitor.getSubSerialNumber());
|
||||
continue;
|
||||
}
|
||||
|
||||
JSONObject monitorItem = monitorData.getJSONObject("itemData");
|
||||
if (monitorItem == null || monitorItem.isEmpty()) {
|
||||
bufferService.removeMonitorData(platform.getId(), fieldName, monitor.getSubSerialNumber());
|
||||
continue;
|
||||
}
|
||||
JSONObject bodyFields = monitorData.getJSONObject("bodyFields");
|
||||
if (bodyFields == null) {
|
||||
bodyFields = new JSONObject();
|
||||
}
|
||||
|
||||
JSONArray sensorData = new JSONArray();
|
||||
sensorData.add(referenceItem);
|
||||
sensorData.add(monitorItem);
|
||||
JSONArray pushBody = buildArrayPushBody(mapping, bodyFields, fieldName,
|
||||
sensorData, monitor.getPlatformDeviceId());
|
||||
|
||||
PlatformPushLog logEntry = createLogEntry(platform, mapping, interfaceCode,
|
||||
monitor.getSubSerialNumber());
|
||||
doHttpPost(platform, baseUrl, JSON.toJSONString(pushBody), logEntry);
|
||||
pushLogService.asyncSave(logEntry);
|
||||
if (logEntry.getStatus() != null && logEntry.getStatus() == 1) {
|
||||
bufferService.removeMonitorData(platform.getId(), fieldName, monitor.getSubSerialNumber());
|
||||
replayCount++;
|
||||
log.info("[DCP] 基准点后到,已补推监测点 {} deviceId={}",
|
||||
monitor.getSubSerialNumber(), monitor.getPlatformDeviceId());
|
||||
} else {
|
||||
log.warn("[DCP] 基准点后到,补推监测点 {} 失败,保留缓存等待下次基准点上报",
|
||||
monitor.getSubSerialNumber());
|
||||
}
|
||||
}
|
||||
return replayCount;
|
||||
}
|
||||
|
||||
// ==================== 普通推送 ====================
|
||||
|
||||
private void handleNormalPush(PlatformInstance platform, PlatformDeviceMapping mapping,
|
||||
|
||||
@ -21,6 +21,10 @@ public class FlowContext {
|
||||
private String currentMonitorSerialNumber;
|
||||
/** 网关子设备入网时,当前子映射行的 onboard_config JSON(平台相关参数) */
|
||||
private String subMappingOnboardConfig;
|
||||
/** 网关子设备入网时,当前基准点序列号 */
|
||||
private String currentReferenceSerialNumber;
|
||||
/** 网关子设备入网时,基准点子映射行的 onboard_config JSON */
|
||||
private String referenceSubMappingOnboardConfig;
|
||||
|
||||
public FlowContext(PlatformInstance platform, PlatformDeviceMapping deviceMapping, String payload) {
|
||||
this.platform = platform;
|
||||
@ -64,6 +68,22 @@ public class FlowContext {
|
||||
this.subMappingOnboardConfig = subMappingOnboardConfig;
|
||||
}
|
||||
|
||||
public String getCurrentReferenceSerialNumber() {
|
||||
return currentReferenceSerialNumber;
|
||||
}
|
||||
|
||||
public void setCurrentReferenceSerialNumber(String currentReferenceSerialNumber) {
|
||||
this.currentReferenceSerialNumber = currentReferenceSerialNumber;
|
||||
}
|
||||
|
||||
public String getReferenceSubMappingOnboardConfig() {
|
||||
return referenceSubMappingOnboardConfig;
|
||||
}
|
||||
|
||||
public void setReferenceSubMappingOnboardConfig(String referenceSubMappingOnboardConfig) {
|
||||
this.referenceSubMappingOnboardConfig = referenceSubMappingOnboardConfig;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getFromContext(String contextKey) {
|
||||
// contextKey 格式: "step1.access_token" 或 "step1"
|
||||
|
||||
@ -429,6 +429,20 @@ public class PlatformFlowExecutor {
|
||||
}
|
||||
|
||||
private List<String> collectSubDeviceSensorIds(FlowContext ctx) {
|
||||
if (StringUtils.hasText(ctx.getCurrentMonitorSerialNumber())
|
||||
&& StringUtils.hasText(ctx.getCurrentReferenceSerialNumber())) {
|
||||
String refSensorId = resolveOnboardSensorId(
|
||||
ctx.getReferenceSubMappingOnboardConfig(), ctx.getCurrentReferenceSerialNumber());
|
||||
String monitorSensorId = resolveOnboardSensorId(
|
||||
ctx.getSubMappingOnboardConfig(), ctx.getCurrentMonitorSerialNumber());
|
||||
List<String> ids = new ArrayList<>();
|
||||
if (StringUtils.hasText(refSensorId)) ids.add(refSensorId);
|
||||
if (StringUtils.hasText(monitorSensorId)) ids.add(monitorSensorId);
|
||||
if (!ids.isEmpty()) {
|
||||
return ids.stream().distinct().collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
// 网关入网时,从子表 onboard_config 获取 sensorId
|
||||
if (StringUtils.hasText(ctx.getSubMappingOnboardConfig())) {
|
||||
try {
|
||||
@ -450,10 +464,32 @@ public class PlatformFlowExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* 网关入网时:从当前子映射的 onboard_config 取 [refSensorId, sensorId] 一对。
|
||||
* 网关入网时:优先按子表中当前 reference 行取 [基准点sensorId, 监测点sensorId] 一对。
|
||||
* 直连设备/旧逻辑:从 extra_mapping 解析所有配对。
|
||||
*/
|
||||
private List<List<String>> collectReferenceSubDeviceSensorIdPairs(FlowContext ctx) {
|
||||
if (StringUtils.hasText(ctx.getCurrentMonitorSerialNumber())) {
|
||||
String sensorId = resolveOnboardSensorId(
|
||||
ctx.getSubMappingOnboardConfig(), ctx.getCurrentMonitorSerialNumber());
|
||||
String refSensorId = resolveOnboardSensorId(
|
||||
ctx.getReferenceSubMappingOnboardConfig(), ctx.getCurrentReferenceSerialNumber());
|
||||
if (!StringUtils.hasText(refSensorId)) {
|
||||
refSensorId = resolveOnboardConfigText(ctx.getSubMappingOnboardConfig(), "refSensorId");
|
||||
}
|
||||
if (StringUtils.hasText(sensorId) && StringUtils.hasText(refSensorId)) {
|
||||
if (sameText(refSensorId, sensorId)) {
|
||||
throw new RuntimeException("静力水准 sensorIds 配置无效:基准点和监测点 sensorId 相同");
|
||||
}
|
||||
List<List<String>> pairs = new ArrayList<>();
|
||||
pairs.add(Arrays.asList(refSensorId, sensorId));
|
||||
return pairs;
|
||||
}
|
||||
if (isStaticLevel(ctx.getDeviceMapping())) {
|
||||
throw new RuntimeException("静力水准监测点 " + ctx.getCurrentMonitorSerialNumber()
|
||||
+ " 缺少基准点或监测点 sensorId,请检查子设备映射");
|
||||
}
|
||||
}
|
||||
|
||||
// 网关入网:onboardConfig 已指定当前监测点
|
||||
if (StringUtils.hasText(ctx.getSubMappingOnboardConfig())) {
|
||||
try {
|
||||
@ -494,6 +530,27 @@ public class PlatformFlowExecutor {
|
||||
return pairs;
|
||||
}
|
||||
|
||||
private String resolveOnboardSensorId(String onboardConfig, String fallbackSerialNumber) {
|
||||
String sensorId = resolveOnboardConfigText(onboardConfig, "sensorId");
|
||||
return StringUtils.hasText(sensorId) ? sensorId : normalizeText(fallbackSerialNumber);
|
||||
}
|
||||
|
||||
private String resolveOnboardConfigText(String onboardConfig, String field) {
|
||||
if (!StringUtils.hasText(onboardConfig) || !StringUtils.hasText(field)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JSONObject config = JSON.parseObject(onboardConfig);
|
||||
return normalizeText(config.getString(field));
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStaticLevel(PlatformDeviceMapping mapping) {
|
||||
return mapping != null && Objects.equals("static_level", mapping.getSensorType());
|
||||
}
|
||||
|
||||
private List<SubDeviceSensorBinding> collectSubDeviceSensorBindings(PlatformDeviceMapping mapping) {
|
||||
if (mapping == null) {
|
||||
return Collections.emptyList();
|
||||
|
||||
@ -21,6 +21,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@ -105,6 +106,7 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
||||
*/
|
||||
private void onboardGateway(PlatformDeviceMapping mapping, PlatformInstance platform, PlatformFlow onboardFlow) {
|
||||
List<PlatformDeviceSubMapping> subMappings = subMappingService.selectByParentId(mapping.getId());
|
||||
PlatformDeviceSubMapping reference = resolveGatewayReference(mapping, subMappings);
|
||||
List<PlatformDeviceSubMapping> monitors = subMappings.stream()
|
||||
.filter(s -> s.isMonitor() && (s.getNetStatus() == null || s.getNetStatus() == 0))
|
||||
.collect(Collectors.toList());
|
||||
@ -120,6 +122,10 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
||||
FlowContext ctx = new FlowContext(platform, mapping, null);
|
||||
ctx.setCurrentMonitorSerialNumber(monitor.getSubSerialNumber());
|
||||
ctx.setSubMappingOnboardConfig(monitor.getOnboardConfig());
|
||||
if (reference != null) {
|
||||
ctx.setCurrentReferenceSerialNumber(reference.getSubSerialNumber());
|
||||
ctx.setReferenceSubMappingOnboardConfig(reference.getOnboardConfig());
|
||||
}
|
||||
|
||||
try {
|
||||
flowExecutor.execute(onboardFlow, ctx);
|
||||
@ -165,4 +171,22 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
||||
+ String.join("\n", failedMessages));
|
||||
}
|
||||
}
|
||||
|
||||
private PlatformDeviceSubMapping resolveGatewayReference(PlatformDeviceMapping mapping,
|
||||
List<PlatformDeviceSubMapping> subMappings) {
|
||||
List<PlatformDeviceSubMapping> references = subMappings.stream()
|
||||
.filter(PlatformDeviceSubMapping::isReference)
|
||||
.collect(Collectors.toList());
|
||||
boolean staticLevel = Objects.equals("static_level", mapping.getSensorType());
|
||||
if (references.size() > 1) {
|
||||
throw new RuntimeException("子表中只能指定一个基准点,请检查子设备映射");
|
||||
}
|
||||
if (references.isEmpty()) {
|
||||
if (staticLevel) {
|
||||
throw new RuntimeException("静力水准网关入网需在子设备映射中指定一个基准点");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return references.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<select id="selectByParentId" resultType="com.fastbee.iot.platform.domain.PlatformDeviceSubMapping">
|
||||
SELECT * FROM platform_device_sub_mapping
|
||||
WHERE parent_mapping_id = #{parentMappingId}
|
||||
ORDER BY device_role DESC, id ASC
|
||||
ORDER BY id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectByParentAndSerial" resultType="com.fastbee.iot.platform.domain.PlatformDeviceSubMapping">
|
||||
|
||||
@ -170,7 +170,7 @@
|
||||
</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%">
|
||||
<el-select v-model="scope.row.deviceRole" size="mini" style="width:100%" @change="onSubRoleChange(scope.row)">
|
||||
<el-option label="基准点" value="reference" />
|
||||
<el-option label="监测点" value="monitor" />
|
||||
</el-select>
|
||||
@ -178,7 +178,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="入网参数 (JSON)" min-width="220">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.onboardConfig" size="mini" :placeholder="scope.row.deviceRole === 'reference' ? '{\"sensorId\":\"...\"}' : '{\"sensorId\":\"...\",\"refSensorId\":\"...\",\"refSerialNumber\":\"...\"}'" />
|
||||
<el-input v-model="scope.row.onboardConfig" size="mini" :placeholder="getOnboardConfigPlaceholder(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="平台设备ID" width="140" v-if="form.netStatus===1">
|
||||
@ -323,11 +323,14 @@ export default {
|
||||
listPlatformDeviceMapping(this.queryParams).then(res => {
|
||||
this.list = res.rows; this.total = res.total; this.loading = false
|
||||
// 加载设备名称映射
|
||||
const ids = [...new Set(res.rows.map(r => r.deviceId))]
|
||||
const ids = [...new Set(res.rows.map(r => r.deviceId).filter(Boolean))]
|
||||
if (ids.length) {
|
||||
listDevice({ pageNum: 1, pageSize: 200 }).then(dr => {
|
||||
Promise.all(ids.map(id => getDevice(id).catch(() => null))).then(results => {
|
||||
const map = {}
|
||||
dr.rows.forEach(d => { map[d.deviceId] = d.deviceName })
|
||||
results.forEach(res => {
|
||||
const d = res && (res.data || res)
|
||||
if (d && d.deviceId) map[d.deviceId] = d.deviceName
|
||||
})
|
||||
this.deviceMap = map
|
||||
})
|
||||
}
|
||||
@ -349,6 +352,11 @@ export default {
|
||||
getSubDevicePairs(row) {
|
||||
return this.subMappingCache[row.id] || []
|
||||
},
|
||||
getOnboardConfigPlaceholder(row) {
|
||||
return row.deviceRole === 'reference'
|
||||
? '{"sensorId":"..."}'
|
||||
: '{"sensorId":"...","refSensorId":"...","refSerialNumber":"..."}'
|
||||
},
|
||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||
resetQuery() { this.resetForm('queryForm'); this.handleQuery() },
|
||||
handleAdd() {
|
||||
@ -409,16 +417,11 @@ export default {
|
||||
onDeviceTypeChange(val) {
|
||||
if (val === 1 && this.subMappingRows.length === 0 && this.subDeviceOptions.length > 0) {
|
||||
// 切换为网关设备时,自动用已加载的子设备列表预填
|
||||
const refSn = this.subDeviceOptions[0].serialNumber
|
||||
this.subMappingRows = this.subDeviceOptions.map((device, idx) => {
|
||||
const role = idx === 0 ? 'reference' : 'monitor'
|
||||
const config = role === 'reference'
|
||||
? JSON.stringify({ sensorId: device.serialNumber })
|
||||
: JSON.stringify({ sensorId: device.serialNumber, refSensorId: refSn, refSerialNumber: refSn })
|
||||
this.subMappingRows = this.subDeviceOptions.map(device => {
|
||||
return {
|
||||
subSerialNumber: device.serialNumber,
|
||||
deviceRole: role,
|
||||
onboardConfig: config,
|
||||
deviceRole: 'monitor',
|
||||
onboardConfig: JSON.stringify({ sensorId: device.serialNumber }),
|
||||
platformDeviceId: '',
|
||||
platformPointId: ''
|
||||
}
|
||||
@ -475,12 +478,20 @@ export default {
|
||||
this.loadThingsModel(deviceId)
|
||||
},
|
||||
searchDevice(query) {
|
||||
if (!query) return
|
||||
const keyword = (query || '').trim()
|
||||
if (!keyword) return
|
||||
this.deviceSearchLoading = true
|
||||
listDevice({ pageNum: 1, pageSize: 50, deviceName: query }).then(res => {
|
||||
listDevice({ pageNum: 1, pageSize: 50, ...this.buildDeviceSearchParams(keyword) }).then(res => {
|
||||
this.deviceOptions = res.rows; this.deviceSearchLoading = false
|
||||
})
|
||||
},
|
||||
buildDeviceSearchParams(query) {
|
||||
const keyword = (query || '').trim()
|
||||
if (keyword.length === 12) {
|
||||
return { serialNumber: keyword }
|
||||
}
|
||||
return { deviceName: keyword }
|
||||
},
|
||||
loadDeviceContext(deviceId) {
|
||||
if (!deviceId) return
|
||||
getDevice(deviceId).then(res => {
|
||||
@ -524,18 +535,13 @@ export default {
|
||||
if (!this.form.id) {
|
||||
this.form.deviceType = this.subDeviceOptions.length > 0 ? 1 : 0
|
||||
}
|
||||
// 网关设备且子映射为空时,自动预填所有子设备,第一个为基准点
|
||||
// 网关设备且子映射为空时,自动预填所有子设备;基准点由用户明确指定
|
||||
if (this.form.deviceType === 1 && this.subMappingRows.length === 0 && this.subDeviceOptions.length > 0) {
|
||||
this.subMappingRows = this.subDeviceOptions.map((device, idx) => {
|
||||
const role = idx === 0 ? 'reference' : 'monitor'
|
||||
const refSn = this.subDeviceOptions[0].serialNumber
|
||||
const config = role === 'reference'
|
||||
? JSON.stringify({ sensorId: device.serialNumber })
|
||||
: JSON.stringify({ sensorId: device.serialNumber, refSensorId: refSn, refSerialNumber: refSn })
|
||||
this.subMappingRows = this.subDeviceOptions.map(device => {
|
||||
return {
|
||||
subSerialNumber: device.serialNumber,
|
||||
deviceRole: role,
|
||||
onboardConfig: config,
|
||||
deviceRole: 'monitor',
|
||||
onboardConfig: JSON.stringify({ sensorId: device.serialNumber }),
|
||||
platformDeviceId: '',
|
||||
platformPointId: ''
|
||||
}
|
||||
@ -553,18 +559,69 @@ export default {
|
||||
addSubMapping() {
|
||||
this.subMappingRows.push({ subSerialNumber: '', deviceRole: 'monitor', onboardConfig: '', platformDeviceId: '', platformPointId: '' })
|
||||
},
|
||||
onSubSerialChange(row) {
|
||||
// 自动填充 onboardConfig 中的 sensorId
|
||||
if (!row.onboardConfig && row.subSerialNumber) {
|
||||
const refRow = this.subMappingRows.find(r => r.deviceRole === 'reference')
|
||||
onSubRoleChange(row) {
|
||||
if (row.deviceRole === 'reference') {
|
||||
this.subMappingRows.forEach(item => {
|
||||
if (item !== row && item.deviceRole === 'reference') {
|
||||
item.deviceRole = 'monitor'
|
||||
}
|
||||
})
|
||||
}
|
||||
this.refreshSubMappingOnboardConfigs()
|
||||
},
|
||||
onSubSerialChange(row) {
|
||||
if (!row.subSerialNumber) return
|
||||
row.onboardConfig = JSON.stringify({ sensorId: row.subSerialNumber })
|
||||
} else if (refRow) {
|
||||
row.onboardConfig = JSON.stringify({ sensorId: row.subSerialNumber, refSensorId: refRow.subSerialNumber, refSerialNumber: refRow.subSerialNumber })
|
||||
this.refreshSubMappingOnboardConfigs()
|
||||
},
|
||||
findReferenceRow(rows = this.subMappingRows) {
|
||||
return (rows || []).find(r => r.deviceRole === 'reference' && r.subSerialNumber)
|
||||
},
|
||||
buildOnboardConfig(row, refRow) {
|
||||
const config = this.safeParseJson(row.onboardConfig, {})
|
||||
const next = { ...config, sensorId: config.sensorId || row.subSerialNumber }
|
||||
if (row.deviceRole === 'reference') {
|
||||
delete next.refSensorId
|
||||
delete next.refSerialNumber
|
||||
} else if (refRow && refRow.subSerialNumber) {
|
||||
const refConfig = this.safeParseJson(refRow.onboardConfig, {})
|
||||
next.refSensorId = refConfig.sensorId || refRow.subSerialNumber
|
||||
next.refSerialNumber = refRow.subSerialNumber
|
||||
} else {
|
||||
row.onboardConfig = JSON.stringify({ sensorId: row.subSerialNumber })
|
||||
delete next.refSensorId
|
||||
delete next.refSerialNumber
|
||||
}
|
||||
return JSON.stringify(next)
|
||||
},
|
||||
refreshSubMappingOnboardConfigs() {
|
||||
const refRow = this.findReferenceRow()
|
||||
if (refRow && refRow.subSerialNumber) {
|
||||
refRow.onboardConfig = this.buildOnboardConfig(refRow, null)
|
||||
}
|
||||
this.subMappingRows.forEach(row => {
|
||||
if (!row.subSerialNumber || row === refRow) return
|
||||
row.onboardConfig = this.buildOnboardConfig(row, refRow)
|
||||
})
|
||||
},
|
||||
normalizeSubMappingsForSubmit() {
|
||||
const rows = (this.subMappingRows || [])
|
||||
.filter(r => r.subSerialNumber)
|
||||
.map(r => ({ ...r, deviceRole: r.deviceRole || 'monitor' }))
|
||||
const references = rows.filter(r => r.deviceRole === 'reference')
|
||||
const monitors = rows.filter(r => r.deviceRole === 'monitor')
|
||||
if (references.length > 1) {
|
||||
this.$modal.msgError('只能指定一个基准点')
|
||||
return null
|
||||
}
|
||||
if (this.form.sensorType === 'static_level' && (references.length !== 1 || monitors.length === 0)) {
|
||||
this.$modal.msgError('静力水准需配置 1 个基准点和至少 1 个监测点')
|
||||
return null
|
||||
}
|
||||
const refRow = references[0] || null
|
||||
return rows.map(row => ({
|
||||
...row,
|
||||
onboardConfig: this.buildOnboardConfig(row, refRow)
|
||||
}))
|
||||
},
|
||||
safeParseJson(value, defaultValue) {
|
||||
if (!value) return defaultValue
|
||||
@ -576,6 +633,13 @@ export default {
|
||||
if (!valid) return
|
||||
this.form.fieldMapping = this.fieldMappingRows.length > 0
|
||||
? JSON.stringify(this.fieldMappingRows) : null
|
||||
const normalizedSubRows = this.form.deviceType === 1
|
||||
? this.normalizeSubMappingsForSubmit()
|
||||
: []
|
||||
if (this.form.deviceType === 1 && normalizedSubRows === null) return
|
||||
if (this.form.deviceType === 1) {
|
||||
this.subMappingRows = normalizedSubRows
|
||||
}
|
||||
// 网关设备:extra_mapping 只存数据映射配置
|
||||
if (this.form.deviceType === 1) {
|
||||
this.form.extraMapping = JSON.stringify({
|
||||
@ -591,8 +655,7 @@ export default {
|
||||
const mappingId = this.form.id || (res.data && res.data.id) || res.data
|
||||
// 网关设备:保存后同步子映射
|
||||
if (this.form.deviceType === 1 && mappingId) {
|
||||
const subData = this.subMappingRows
|
||||
.filter(r => r.subSerialNumber)
|
||||
const subData = normalizedSubRows
|
||||
.map(r => ({
|
||||
subSerialNumber: r.subSerialNumber,
|
||||
deviceRole: r.deviceRole || 'monitor',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user