20260728:平台对接优化
This commit is contained in:
parent
be2e868ef5
commit
7877a3ccec
@ -28,7 +28,9 @@
|
||||
"Bash(npm run:*)",
|
||||
"mcp__filesystem__read_text_file",
|
||||
"Bash(sips:*)",
|
||||
"Bash(mysql -h localhost -u root -pfastbee fastbee -e \"SELECT id, name, config_json FROM bridge WHERE id = 9;\")"
|
||||
"Bash(mysql -h localhost -u root -pfastbee fastbee -e \"SELECT id, name, config_json FROM bridge WHERE id = 9;\")",
|
||||
"Bash(mysql:*)",
|
||||
"Bash(git:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,6 +299,11 @@ public interface FastBeeConstant {
|
||||
*/
|
||||
String DATA_REPAIR_CONFIG_KEY = "data:repair:config";
|
||||
|
||||
/**
|
||||
* 平台对接KEYS
|
||||
* DCP平台项目列表缓存key
|
||||
*/
|
||||
String DCP_PROJECT_INFO_KEY = "platform:dcp:projectInfoKey:";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -161,6 +161,10 @@ public class RedisKeyBuilder {
|
||||
return FastBeeConstant.REDIS.MODBUS_TCP_RUNTIME + serialNumber;
|
||||
}
|
||||
|
||||
public static String buildDCPProjectInfoKey(String platformUserId) {
|
||||
return FastBeeConstant.REDIS.DCP_PROJECT_INFO_KEY + platformUserId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设备OTA升级实时数据
|
||||
|
||||
@ -68,9 +68,16 @@ public class PlatformInstanceController extends BaseController {
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('platform:instance:edit')")
|
||||
@PostMapping("/{id}/initialize")
|
||||
@ApiOperation("初始化平台(执行初始化流程,获取userId/projectId等)")
|
||||
@ApiOperation("初始化平台(执行初始化流程,获取userId)")
|
||||
public AjaxResult initialize(@PathVariable Long id) {
|
||||
instanceService.initialize(id);
|
||||
return success("初始化成功");
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasAnyPermi('platform:instance:list,platform:deviceMapping:list,platform:deviceMapping:add,platform:deviceMapping:edit')")
|
||||
@GetMapping("/{id}/projects")
|
||||
@ApiOperation("查询平台项目列表")
|
||||
public AjaxResult getProjects(@PathVariable Long id) {
|
||||
return success(instanceService.getProjectsByPlatformId(id));
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,12 @@ public class PlatformDeviceMapping implements Serializable {
|
||||
@ApiModelProperty("所属平台ID")
|
||||
private Long platformId;
|
||||
|
||||
@ApiModelProperty("DCP项目ID,绑定页面用户自己选择")
|
||||
private String platformProjectId;
|
||||
|
||||
@ApiModelProperty("DCP项目名称")
|
||||
private String platformProjectName;
|
||||
|
||||
@ApiModelProperty("FastBee设备ID")
|
||||
private Long deviceId;
|
||||
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package com.fastbee.iot.platform.flow;
|
||||
|
||||
import com.fastbee.iot.platform.domain.PlatformDeviceMapping;
|
||||
import com.fastbee.iot.platform.domain.PlatformDeviceSubMapping;
|
||||
import com.fastbee.iot.platform.domain.PlatformInstance;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -19,6 +21,9 @@ public class FlowContext {
|
||||
* 绑定推送关系
|
||||
*/
|
||||
private final PlatformDeviceMapping deviceMapping;
|
||||
// 绑定推送子关系
|
||||
private List<PlatformDeviceSubMapping> monitorSubMappings;
|
||||
|
||||
/**
|
||||
* 设备上报的原始 payload(实时推送时有值)
|
||||
*/
|
||||
@ -107,6 +112,14 @@ public class FlowContext {
|
||||
this.currentMonitorIndex = currentMonitorIndex;
|
||||
}
|
||||
|
||||
public List<PlatformDeviceSubMapping> getMonitorSubMappings() {
|
||||
return monitorSubMappings;
|
||||
}
|
||||
|
||||
public void setMonitorSubMappings(List<PlatformDeviceSubMapping> monitorSubMappings) {
|
||||
this.monitorSubMappings = monitorSubMappings;
|
||||
}
|
||||
|
||||
public String getSubMappingOnboardConfig() {
|
||||
return subMappingOnboardConfig;
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import com.fastbee.iot.platform.mapper.PlatformInterfaceMapper;
|
||||
import com.fastbee.iot.platform.service.IPlatformPushLogService;
|
||||
import com.dtflys.forest.http.ForestRequestType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
@ -293,6 +294,10 @@ public class PlatformFlowExecutor {
|
||||
String df = fd.getString("field");
|
||||
if ("platform_device_id".equals(df)) return ctx.getDeviceMapping().getPlatformDeviceId();
|
||||
if ("platform_point_id".equals(df)) return ctx.getDeviceMapping().getPlatformPointId();
|
||||
// 支持从设备绑定表读取项目信息
|
||||
if ("platform_project_id".equals(df)) {
|
||||
return ctx.getDeviceMapping().getPlatformProjectId();
|
||||
}
|
||||
if ("serial_number".equals(df)) {
|
||||
// 网关入网时优先使用当前监测点序列号(每个 point/device 以监测点命名)
|
||||
if (StringUtils.hasText(ctx.getCurrentMonitorSerialNumber())) {
|
||||
@ -321,7 +326,7 @@ public class PlatformFlowExecutor {
|
||||
case "cascadedSubDeviceSensorIds":
|
||||
return collectCascadedSubDeviceSensorIds(ctx);
|
||||
case "cascadedSubDeviceDepths":
|
||||
return collectCascadedSubDeviceDepths(ctx, fd);
|
||||
return collectCascadedSubDeviceDepths(ctx);
|
||||
case "referenceSubDeviceSensorIdPairs":
|
||||
return collectReferenceSubDeviceSensorIdPairs(ctx);
|
||||
default:
|
||||
@ -403,20 +408,19 @@ public class PlatformFlowExecutor {
|
||||
|
||||
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;
|
||||
List<PlatformDeviceSubMapping> monitorSubMappings = ctx.getMonitorSubMappings();
|
||||
if (ctx.getCurrentMonitorIndex() != null && CollectionUtils.isNotEmpty(monitorSubMappings)) {
|
||||
int index = ctx.getCurrentMonitorIndex();
|
||||
if (index >= values.size()) {
|
||||
throw new RuntimeException("入网参数 " + name + " 数组长度不足,当前子设备序号="
|
||||
+ (index + 1) + ",数组长度=" + values.size());
|
||||
PlatformDeviceSubMapping platformDeviceSubMapping = monitorSubMappings.get(index);
|
||||
JSONObject authConfig = StringUtils.hasText(platformDeviceSubMapping.getOnboardConfig())
|
||||
? JSON.parseObject(platformDeviceSubMapping.getOnboardConfig()) : new JSONObject();
|
||||
String value = authConfig.getString(name);
|
||||
if (value == null) {
|
||||
throw new RuntimeException("入网失败,子设备" + platformDeviceSubMapping.getSubDeviceName() + "未配置值:" + name);
|
||||
}
|
||||
return values.get(index);
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
throw new RuntimeException("入网失败," + name + "未配置值");
|
||||
}
|
||||
|
||||
private String newGeneratedId() {
|
||||
@ -555,21 +559,26 @@ public class PlatformFlowExecutor {
|
||||
private List<String> collectCascadedSubDeviceSensorIds(FlowContext ctx) {
|
||||
List<PlatformDeviceSubMapping> suffix = collectCascadedSubDeviceSuffix(ctx);
|
||||
Collections.reverse(suffix);
|
||||
return suffix.stream()
|
||||
List<String> sensorIds = suffix.stream()
|
||||
.map(sub -> resolveOnboardSensorId(sub.getOnboardConfig(), sub.getSubSerialNumber()))
|
||||
.filter(StringUtils::hasText)
|
||||
.collect(Collectors.toList());
|
||||
if (sensorIds.stream().anyMatch(id -> !StringUtils.hasText(id))) {
|
||||
throw new RuntimeException("深部位移子设备缺少 sensorId");
|
||||
}
|
||||
return sensorIds;
|
||||
}
|
||||
|
||||
private List<Object> collectCascadedSubDeviceDepths(FlowContext ctx, JSONObject fieldDef) {
|
||||
private List<Object> collectCascadedSubDeviceDepths(FlowContext ctx) {
|
||||
List<PlatformDeviceSubMapping> monitors = collectCascadedSubDeviceMonitors(ctx);
|
||||
int currentIndex = resolveCurrentMonitorIndex(ctx, monitors);
|
||||
List<Object> allDepths = resolveConfiguredDepths(fieldDef);
|
||||
if (allDepths.size() < monitors.size()) {
|
||||
throw new RuntimeException("串联子设备深度数组配置数量不足,监测点数量="
|
||||
+ monitors.size() + ",深度数量=" + allDepths.size());
|
||||
List<Object> suffix = new ArrayList<>();
|
||||
for (PlatformDeviceSubMapping monitor : monitors.subList(currentIndex, monitors.size())) {
|
||||
Object depth = readSensorDepth(monitor);
|
||||
if (depth == null) {
|
||||
throw new RuntimeException("深部位移子设备 " + monitor.getSubSerialNumber() + " 缺少传感器深度");
|
||||
}
|
||||
suffix.add(depth);
|
||||
}
|
||||
List<Object> suffix = new ArrayList<>(allDepths.subList(currentIndex, monitors.size()));
|
||||
Collections.reverse(suffix);
|
||||
return suffix;
|
||||
}
|
||||
@ -588,10 +597,13 @@ public class PlatformFlowExecutor {
|
||||
if (mapping.getId() == null) {
|
||||
throw new RuntimeException("串联子设备入网缺少映射ID");
|
||||
}
|
||||
List<PlatformDeviceSubMapping> subMappings = subMappingMapper.selectByParentId(mapping.getId());
|
||||
List<PlatformDeviceSubMapping> monitors = subMappings == null ? Collections.emptyList() : subMappings.stream()
|
||||
.filter(PlatformDeviceSubMapping::isMonitor)
|
||||
.collect(Collectors.toList());
|
||||
List<PlatformDeviceSubMapping> monitors = ctx.getMonitorSubMappings();
|
||||
if (monitors == null) {
|
||||
List<PlatformDeviceSubMapping> subMappings = subMappingMapper.selectByParentId(mapping.getId());
|
||||
monitors = subMappings == null ? Collections.emptyList() : subMappings.stream()
|
||||
.filter(PlatformDeviceSubMapping::isMonitor)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
if (monitors.isEmpty()) {
|
||||
throw new RuntimeException("串联子设备入网未配置监测点子设备");
|
||||
}
|
||||
@ -614,23 +626,15 @@ public class PlatformFlowExecutor {
|
||||
throw new RuntimeException("串联子设备入网无法确定当前监测点序号");
|
||||
}
|
||||
|
||||
private List<Object> resolveConfiguredDepths(JSONObject fieldDef) {
|
||||
if (!fieldDef.containsKey("value")) {
|
||||
throw new RuntimeException("串联子设备未配置深度数组");
|
||||
private Object readSensorDepth(PlatformDeviceSubMapping mapping) {
|
||||
if (mapping == null || !StringUtils.hasText(mapping.getOnboardConfig())) {
|
||||
return null;
|
||||
}
|
||||
Object value = fieldDef.get("value");
|
||||
List<?> list = toList(value);
|
||||
if (list == null && value instanceof String) {
|
||||
try {
|
||||
list = JSON.parseArray(((String) value).trim());
|
||||
} catch (Exception ignored) {
|
||||
list = null;
|
||||
}
|
||||
try {
|
||||
return JSON.parseObject(mapping.getOnboardConfig()).get("sensorDepth");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("子设备 " + mapping.getSubSerialNumber() + " 入网参数不是有效JSON");
|
||||
}
|
||||
if (list == null || list.isEmpty()) {
|
||||
throw new RuntimeException("串联子设备深度数组为空");
|
||||
}
|
||||
return new ArrayList<>(list);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1208,7 +1212,7 @@ public class PlatformFlowExecutor {
|
||||
}
|
||||
|
||||
/** 确保 Token 有效,过期则刷新 */
|
||||
private String ensureToken(PlatformInstance platform) {
|
||||
public String ensureToken(PlatformInstance platform) {
|
||||
Date now = new Date();
|
||||
// 提前 5 分钟视为过期
|
||||
boolean expired = platform.getTokenExpiresAt() == null
|
||||
|
||||
@ -5,6 +5,7 @@ import com.fastbee.iot.platform.domain.PlatformInstance;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IPlatformInstanceService extends IService<PlatformInstance> {
|
||||
|
||||
@ -18,4 +19,9 @@ public interface IPlatformInstanceService extends IService<PlatformInstance> {
|
||||
|
||||
/** 更新 extra_config 中的某个字段 */
|
||||
void updateExtraConfig(Long platformId, String key, String value);
|
||||
|
||||
/**
|
||||
* 根据平台ID查询项目列表
|
||||
*/
|
||||
List<Map<String, Object>> getProjectsByPlatformId(Long platformId);
|
||||
}
|
||||
|
||||
@ -72,6 +72,10 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
||||
throw new RuntimeException("设备绑定关系不存在: " + mappingId);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(mapping.getPlatformProjectId())) {
|
||||
throw new RuntimeException("请选择所属项目后再执行入网");
|
||||
}
|
||||
|
||||
PlatformInstance platform = instanceMapper.selectById(mapping.getPlatformId());
|
||||
if (platform == null) {
|
||||
throw new RuntimeException("平台不存在: " + mapping.getPlatformId());
|
||||
@ -132,6 +136,7 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
||||
ctx.setCurrentMonitorSerialNumber(monitor.getSubSerialNumber());
|
||||
ctx.setCurrentMonitorDeviceName(monitor.getSubDeviceName());
|
||||
ctx.setCurrentMonitorIndex(i);
|
||||
ctx.setMonitorSubMappings(monitors);
|
||||
ctx.setSubMappingOnboardConfig(monitor.getOnboardConfig());
|
||||
if (reference != null) {
|
||||
ctx.setCurrentReferenceSerialNumber(reference.getSubSerialNumber());
|
||||
|
||||
@ -5,6 +5,12 @@ import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.dtflys.forest.http.ForestRequest;
|
||||
import com.dtflys.forest.http.ForestRequestType;
|
||||
import com.fastbee.common.core.redis.RedisCache;
|
||||
import com.fastbee.common.core.redis.RedisKeyBuilder;
|
||||
import com.fastbee.http.model.HttpClientConfig;
|
||||
import com.fastbee.http.service.HttpClientFactory;
|
||||
import com.fastbee.iot.platform.domain.PlatformFlow;
|
||||
import com.fastbee.iot.platform.domain.PlatformInstance;
|
||||
import com.fastbee.iot.platform.flow.FlowContext;
|
||||
@ -16,8 +22,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class PlatformInstanceServiceImpl extends ServiceImpl<PlatformInstanceMapper, PlatformInstance>
|
||||
@ -27,6 +34,8 @@ public class PlatformInstanceServiceImpl extends ServiceImpl<PlatformInstanceMap
|
||||
private PlatformFlowMapper flowMapper;
|
||||
@Autowired
|
||||
private PlatformFlowExecutor flowExecutor;
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Override
|
||||
public List<PlatformInstance> selectList(PlatformInstance query) {
|
||||
@ -75,4 +84,73 @@ public class PlatformInstanceServiceImpl extends ServiceImpl<PlatformInstanceMap
|
||||
update.setExtraConfig(extra.toJSONString());
|
||||
this.updateById(update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getProjectsByPlatformId(Long platformId) {
|
||||
PlatformInstance platform = this.getById(platformId);
|
||||
if (platform == null) {
|
||||
throw new RuntimeException("平台不存在: " + platformId);
|
||||
}
|
||||
|
||||
// 从extra_config读取userId
|
||||
JSONObject extraConfig = JSON.parseObject(platform.getExtraConfig());
|
||||
String userId = extraConfig == null ? null : extraConfig.getString("userId");
|
||||
if (!StringUtils.hasText(userId)) {
|
||||
throw new RuntimeException("平台未完成初始化,缺少userId。请先执行平台初始化流程。");
|
||||
}
|
||||
|
||||
String key = RedisKeyBuilder.buildDCPProjectInfoKey(userId);
|
||||
Object cacheObject = redisCache.getCacheObject(key);
|
||||
if (cacheObject != null) {
|
||||
return (List<Map<String, Object>>) cacheObject;
|
||||
}
|
||||
|
||||
// 确保 token 有效(过期自动刷新)
|
||||
String token = flowExecutor.ensureToken(platform);
|
||||
String url = platform.getBaseUrl() + "/api/app/project/by-user-id/" + userId;
|
||||
|
||||
HttpClientConfig config = HttpClientConfig.builder()
|
||||
.url(url)
|
||||
.method(ForestRequestType.GET)
|
||||
.headers(Collections.singletonMap("Authorization", "Bearer " + token))
|
||||
.build();
|
||||
|
||||
ForestRequest<?> request = HttpClientFactory.instance(config);
|
||||
String responseBody = request.executeAsString();
|
||||
|
||||
if (!StringUtils.hasText(responseBody)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Map<String, Object>> result = parseProjectsResponse(responseBody);
|
||||
redisCache.setCacheObject(key, result, 10, TimeUnit.MINUTES);
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Map<String, Object>> parseProjectsResponse(String responseBody) {
|
||||
String trimmed = responseBody.trim();
|
||||
List<Map<String, Object>> rawList;
|
||||
|
||||
if (trimmed.startsWith("[")) {
|
||||
rawList = JSON.parseArray(trimmed, Map.class);
|
||||
} else {
|
||||
JSONObject json = JSON.parseObject(trimmed);
|
||||
Object data = json.get("data");
|
||||
if (data instanceof List) {
|
||||
rawList = (List<Map<String, Object>>) data;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
return rawList.stream()
|
||||
.map(m -> {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("id", m.get("id"));
|
||||
item.put("name", m.get("name"));
|
||||
return item;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,28 +3,30 @@
|
||||
<mapper namespace="com.fastbee.iot.platform.mapper.PlatformDeviceMappingMapper">
|
||||
|
||||
<resultMap type="com.fastbee.iot.platform.domain.PlatformDeviceMapping" id="PlatformDeviceMappingResult">
|
||||
<result property="id" column="id"/>
|
||||
<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"/>
|
||||
<result property="deviceType" column="device_type"/>
|
||||
<result property="pushInterfaceId" column="push_interface_id"/>
|
||||
<result property="fieldMapping" column="field_mapping"/>
|
||||
<result property="extraMapping" column="extra_mapping"/>
|
||||
<result property="netStatus" column="net_status"/>
|
||||
<result property="enable" column="enable"/>
|
||||
<result property="pushMode" column="push_mode"/>
|
||||
<result property="pushInterval" column="push_interval"/>
|
||||
<result property="lastPushTime" column="last_push_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="id" column="id"/>
|
||||
<result property="platformId" column="platform_id"/>
|
||||
<result property="platformProjectId" column="platform_project_id"/>
|
||||
<result property="platformProjectName" column="platform_project_name"/>
|
||||
<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"/>
|
||||
<result property="deviceType" column="device_type"/>
|
||||
<result property="pushInterfaceId" column="push_interface_id"/>
|
||||
<result property="fieldMapping" column="field_mapping"/>
|
||||
<result property="extraMapping" column="extra_mapping"/>
|
||||
<result property="netStatus" column="net_status"/>
|
||||
<result property="enable" column="enable"/>
|
||||
<result property="pushMode" column="push_mode"/>
|
||||
<result property="pushInterval" column="push_interval"/>
|
||||
<result property="lastPushTime" column="last_push_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectBySerialNumber" resultMap="PlatformDeviceMappingResult">
|
||||
|
||||
@ -8,8 +8,36 @@
|
||||
|
||||
SET @dcp_platform_id = (SELECT id FROM platform_instance WHERE code = 'dcp' LIMIT 1);
|
||||
|
||||
-- 重新执行时先清理本脚本维护的流程和接口,避免旧配置被 LIMIT 1 命中。
|
||||
DELETE s FROM platform_flow_step s
|
||||
INNER JOIN platform_flow f ON f.id = s.flow_id
|
||||
WHERE f.platform_id = @dcp_platform_id
|
||||
AND f.code IN (
|
||||
'dcp_init', 'dcp_token_refresh', 'dcp_onboard_inclino',
|
||||
'dcp_onboard_stress', 'dcp_onboard_hyeto',
|
||||
'dcp_onboard_static_level', 'dcp_onboard_deep_inclino'
|
||||
);
|
||||
|
||||
DELETE FROM platform_flow
|
||||
WHERE platform_id = @dcp_platform_id
|
||||
AND code IN (
|
||||
'dcp_init', 'dcp_token_refresh', 'dcp_onboard_inclino',
|
||||
'dcp_onboard_stress', 'dcp_onboard_hyeto',
|
||||
'dcp_onboard_static_level', 'dcp_onboard_deep_inclino'
|
||||
);
|
||||
|
||||
DELETE FROM platform_interface
|
||||
WHERE platform_id = @dcp_platform_id
|
||||
AND code IN (
|
||||
'dcp_auth', 'dcp_get_user', 'dcp_get_projects', 'dcp_create_point',
|
||||
'dcp_bind_inclino', 'dcp_bind_stress', 'dcp_bind_hyeto',
|
||||
'dcp_bind_static_level', 'dcp_bind_deep_inclino',
|
||||
'dcp_push_inclino', 'dcp_push_stress', 'dcp_push_hyeto',
|
||||
'dcp_push_static_level'
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 一、接口定义(8个)
|
||||
-- 一、接口定义(13个)
|
||||
-- =============================================
|
||||
|
||||
-- 1. 认证接口
|
||||
@ -47,16 +75,16 @@ VALUES (@dcp_platform_id, '获取项目列表', 'dcp_get_projects', 'GET', '/api
|
||||
{"name":"userId","type":"string","source":"context","contextKey":"step2.id","required":true,"desc":"用户ID,来自上一步"}
|
||||
]',
|
||||
'[
|
||||
{"name":"id", "type":"string","path":"[0].id", "desc":"第一个项目ID"},
|
||||
{"name":"name", "type":"string","path":"[0].name", "desc":"项目名称"}
|
||||
{"name":"id", "type":"string","path":"id", "desc":"项目ID"},
|
||||
{"name":"name", "type":"string","path":"name", "desc":"项目名称"}
|
||||
]',
|
||||
3, '获取用户下的项目列表,取第一个项目', 'system', NOW());
|
||||
3, '获取用户下的完整项目列表', 'system', NOW());
|
||||
|
||||
-- 4. 创建测点
|
||||
INSERT INTO `platform_interface` (`platform_id`,`name`,`code`,`method`,`path`,`content_type`,`request_schema`,`response_schema`,`sort_order`,`remark`,`create_by`,`create_time`)
|
||||
VALUES (@dcp_platform_id, '创建测点', 'dcp_create_point', 'POST', '/api/app/point', 'application/json',
|
||||
'[
|
||||
{"name":"projectId","type":"string","source":"extra","field":"projectId","required":true,"desc":"项目ID"},
|
||||
{"name":"projectId","type":"string","source":"device","field":"platform_project_id","required":true,"desc":"项目ID"},
|
||||
{"name":"name", "type":"string","source":"device","field":"serial_number","required":true,"desc":"测点名称,用设备序列号"},
|
||||
{"name":"type", "type":"number","source":"fixed","value":3,"required":true,"desc":"测点类型,固定为3"}
|
||||
]',
|
||||
@ -69,7 +97,7 @@ VALUES (@dcp_platform_id, '创建测点', 'dcp_create_point', 'POST', '/api/app/
|
||||
INSERT INTO `platform_interface` (`platform_id`,`name`,`code`,`method`,`path`,`content_type`,`request_schema`,`response_schema`,`sort_order`,`remark`,`create_by`,`create_time`)
|
||||
VALUES (@dcp_platform_id, '绑定倾角传感器', 'dcp_bind_inclino', 'POST', '/api/app/inclino-sensor', 'application/json',
|
||||
'[
|
||||
{"name":"projectId", "type":"string","source":"extra", "field":"projectId", "required":true,"desc":"项目ID"},
|
||||
{"name":"projectId", "type":"string","source":"device", "field":"platform_project_id", "required":true,"desc":"项目ID"},
|
||||
{"name":"pointId", "type":"string","source":"context","contextKey":"step1.id","required":true,"desc":"测点ID,来自创建测点步骤"},
|
||||
{"name":"deviceType", "type":"number","source":"fixed", "value":5, "required":true,"desc":"设备类型,倾角=5"},
|
||||
{"name":"name", "type":"string","source":"device", "field":"serial_number","required":true,"desc":"传感器名称"},
|
||||
@ -86,7 +114,7 @@ VALUES (@dcp_platform_id, '绑定倾角传感器', 'dcp_bind_inclino', 'POST', '
|
||||
INSERT INTO `platform_interface` (`platform_id`,`name`,`code`,`method`,`path`,`content_type`,`request_schema`,`response_schema`,`sort_order`,`remark`,`create_by`,`create_time`)
|
||||
VALUES (@dcp_platform_id, '绑定轴力计', 'dcp_bind_stress', 'POST', '/api/app/stress-sensor', 'application/json',
|
||||
'[
|
||||
{"name":"projectId", "type":"string","source":"extra", "field":"projectId", "required":true,"desc":"项目ID"},
|
||||
{"name":"projectId", "type":"string","source":"device", "field":"platform_project_id", "required":true,"desc":"项目ID"},
|
||||
{"name":"pointId", "type":"string","source":"context","contextKey":"step1.id","required":true,"desc":"测点ID"},
|
||||
{"name":"deviceType", "type":"number","source":"fixed", "value":10, "required":true,"desc":"设备类型,轴力计=10"},
|
||||
{"name":"name", "type":"string","source":"device", "field":"serial_number","required":true,"desc":"传感器名称"},
|
||||
@ -101,7 +129,7 @@ VALUES (@dcp_platform_id, '绑定轴力计', 'dcp_bind_stress', 'POST', '/api/ap
|
||||
INSERT INTO `platform_interface` (`platform_id`,`name`,`code`,`method`,`path`,`content_type`,`request_schema`,`response_schema`,`sort_order`,`remark`,`create_by`,`create_time`)
|
||||
VALUES (@dcp_platform_id, '绑定雨量计', 'dcp_bind_hyeto', 'POST', '/api/app/hyeto-sensor', 'application/json',
|
||||
'[
|
||||
{"name":"projectId", "type":"string","source":"extra", "field":"projectId", "required":true},
|
||||
{"name":"projectId", "type":"string","source":"device", "field":"platform_project_id", "required":true},
|
||||
{"name":"pointId", "type":"string","source":"context","contextKey":"step1.id","required":true},
|
||||
{"name":"deviceType", "type":"number","source":"fixed", "value":3, "required":true,"desc":"雨量计=3"},
|
||||
{"name":"name", "type":"string","source":"device", "field":"serial_number","required":true},
|
||||
@ -115,7 +143,7 @@ VALUES (@dcp_platform_id, '绑定雨量计', 'dcp_bind_hyeto', 'POST', '/api/app
|
||||
INSERT INTO `platform_interface` (`platform_id`,`name`,`code`,`method`,`path`,`content_type`,`request_schema`,`response_schema`,`sort_order`,`remark`,`create_by`,`create_time`)
|
||||
VALUES (@dcp_platform_id, '绑定静力水准', 'dcp_bind_static_level', 'POST', '/api/app/static-level-device', 'application/json',
|
||||
'[
|
||||
{"name":"projectId", "type":"string","source":"extra", "field":"projectId", "required":true},
|
||||
{"name":"projectId", "type":"string","source":"device", "field":"platform_project_id", "required":true},
|
||||
{"name":"pointId", "type":"string","source":"context","contextKey":"step1.id","required":true},
|
||||
{"name":"deviceType", "type":"number","source":"fixed", "value":1002, "required":true,"desc":"静力水准=1002"},
|
||||
{"name":"name", "type":"string","source":"device", "field":"serial_number","required":true},
|
||||
@ -126,6 +154,24 @@ VALUES (@dcp_platform_id, '绑定静力水准', 'dcp_bind_static_level', 'POST',
|
||||
'[{"name":"id","type":"string","path":"id","desc":"DCP设备ID"}]',
|
||||
8, '将静力水准传感器绑定到测点', 'system', NOW());
|
||||
|
||||
-- 9. 绑定深部位移
|
||||
INSERT INTO `platform_interface` (`platform_id`,`name`,`code`,`method`,`path`,`content_type`,`request_schema`,`response_schema`,`sort_order`,`remark`,`create_by`,`create_time`)
|
||||
VALUES (@dcp_platform_id, '绑定深部位移', 'dcp_bind_deep_inclino', 'POST', '/api/app/deep-inclino-device', 'application/json',
|
||||
'[
|
||||
{"name":"projectId", "type":"string","source":"device", "field":"platform_project_id","required":true},
|
||||
{"name":"pointId", "type":"string","source":"context", "contextKey":"step1.id", "required":true},
|
||||
{"name":"deviceType", "type":"number","source":"fixed", "value":1001, "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":"sensorIds", "type":"array", "source":"cascadedSubDeviceSensorIds", "required":true},
|
||||
{"name":"sensorDepths", "type":"array", "source":"cascadedSubDeviceDepths", "required":true},
|
||||
{"name":"holeDepth", "type":"number","source":"onboard_config", "field":"holeDepth", "required":true},
|
||||
{"name":"holeElevation","type":"number","source":"onboard_config", "field":"holeElevation", "required":true}
|
||||
]',
|
||||
'[{"name":"id","type":"string","path":"id","desc":"DCP设备ID"}]',
|
||||
9, '将深部位移设备绑定到测点', 'system', NOW());
|
||||
|
||||
|
||||
-- =============================================
|
||||
-- 1.5 推送数据接口(4个,设备绑定时选择推送接口用)
|
||||
@ -184,12 +230,12 @@ VALUES (@dcp_platform_id, '推送静力水准数据', 'dcp_push_static_level', '
|
||||
|
||||
|
||||
-- =============================================
|
||||
-- 二、流程定义(6个)
|
||||
-- 二、流程定义(7个)
|
||||
-- =============================================
|
||||
|
||||
-- 流程1:平台初始化(flow_type=1)
|
||||
INSERT INTO `platform_flow` (`platform_id`,`name`,`code`,`flow_type`,`sensor_type`,`enable`,`remark`,`create_by`,`create_time`)
|
||||
VALUES (@dcp_platform_id, 'DCP平台初始化', 'dcp_init', 1, NULL, '1', '获取Token→userId→projectId,一次性执行', 'system', NOW());
|
||||
VALUES (@dcp_platform_id, 'DCP平台初始化', 'dcp_init', 1, NULL, '1', '获取Token→userId,一次性执行', 'system', NOW());
|
||||
|
||||
SET @flow_init_id = LAST_INSERT_ID();
|
||||
|
||||
@ -208,14 +254,6 @@ VALUES (@flow_init_id, 2,
|
||||
'[{"field":"id","saveTo":"extra_config.userId"}]',
|
||||
'获取userId并保存');
|
||||
|
||||
INSERT INTO `platform_flow_step` (`flow_id`,`step_order`,`interface_id`,`param_mapping`,`result_key`,`result_save`,`remark`)
|
||||
VALUES (@flow_init_id, 3,
|
||||
(SELECT id FROM platform_interface WHERE platform_id=@dcp_platform_id AND code='dcp_get_projects' LIMIT 1),
|
||||
'{"userId":{"source":"context","contextKey":"step2.id"}}',
|
||||
'step3',
|
||||
'[{"field":"id","saveTo":"extra_config.projectId"},{"field":"name","saveTo":"extra_config.projectName"}]',
|
||||
'获取projectId并保存');
|
||||
|
||||
|
||||
-- 流程2:Token刷新(flow_type=3)
|
||||
INSERT INTO `platform_flow` (`platform_id`,`name`,`code`,`flow_type`,`sensor_type`,`enable`,`remark`,`create_by`,`create_time`)
|
||||
@ -314,6 +352,25 @@ VALUES (@flow_static_level_id, 2,
|
||||
'[{"field":"id","saveTo":"device_mapping.platform_device_id"}]',
|
||||
'绑定静力水准');
|
||||
|
||||
-- 流程7:深部位移设备入网(flow_type=2)
|
||||
INSERT INTO `platform_flow` (`platform_id`,`name`,`code`,`flow_type`,`sensor_type`,`enable`,`remark`,`create_by`,`create_time`)
|
||||
VALUES (@dcp_platform_id, 'DCP深部位移入网', 'dcp_onboard_deep_inclino', 2, 'deep_inclino', '1', '创建测点→绑定深部位移', 'system', NOW());
|
||||
|
||||
SET @flow_deep_inclino_id = LAST_INSERT_ID();
|
||||
|
||||
INSERT INTO `platform_flow_step` (`flow_id`,`step_order`,`interface_id`,`result_key`,`result_save`,`remark`)
|
||||
VALUES (@flow_deep_inclino_id, 1,
|
||||
(SELECT id FROM platform_interface WHERE platform_id=@dcp_platform_id AND code='dcp_create_point' LIMIT 1),
|
||||
'step1',
|
||||
'[{"field":"id","saveTo":"device_mapping.platform_point_id"}]',
|
||||
'创建测点');
|
||||
|
||||
INSERT INTO `platform_flow_step` (`flow_id`,`step_order`,`interface_id`,`result_key`,`result_save`,`remark`)
|
||||
VALUES (@flow_deep_inclino_id, 2,
|
||||
(SELECT id FROM platform_interface WHERE platform_id=@dcp_platform_id AND code='dcp_bind_deep_inclino' LIMIT 1),
|
||||
'step2',
|
||||
'[{"field":"id","saveTo":"device_mapping.platform_device_id"}]',
|
||||
'绑定深部位移');
|
||||
|
||||
|
||||
|
||||
@ -324,7 +381,23 @@ SET @platform_id = (SELECT id FROM platform_instance WHERE code = 'dcp' LIMIT 1)
|
||||
|
||||
UPDATE platform_interface
|
||||
SET request_schema = '[
|
||||
{"name":"projectId", "type":"string","source":"extra", "field":"projectId", "required":true,"desc":"项目ID"},
|
||||
{"name":"projectId","type":"string","source":"device","field":"platform_project_id","required":true,"desc":"项目ID"},
|
||||
{"name":"name", "type":"string","source":"device","field":"serial_number","required":true,"desc":"测点名称,用设备序列号"},
|
||||
{"name":"type", "type":"number","source":"fixed","value":3,"required":true,"desc":"测点类型,固定为3"}
|
||||
]', update_by = 'system', update_time = NOW()
|
||||
WHERE platform_id = @platform_id AND code = 'dcp_create_point';
|
||||
|
||||
DELETE s FROM platform_flow_step s
|
||||
INNER JOIN platform_flow f ON f.id = s.flow_id
|
||||
WHERE f.platform_id = @platform_id AND f.code = 'dcp_init' AND s.step_order > 2;
|
||||
|
||||
UPDATE platform_flow
|
||||
SET remark = '获取Token→userId,一次性执行', update_by = 'system', update_time = NOW()
|
||||
WHERE platform_id = @platform_id AND code = 'dcp_init';
|
||||
|
||||
UPDATE platform_interface
|
||||
SET request_schema = '[
|
||||
{"name":"projectId", "type":"string","source":"device", "field":"platform_project_id", "required":true,"desc":"项目ID"},
|
||||
{"name":"pointId", "type":"string","source":"context","contextKey":"step1.id","required":true,"desc":"测点ID,来自创建测点步骤"},
|
||||
{"name":"deviceType", "type":"number","source":"fixed", "value":5, "required":true,"desc":"设备类型,倾角=5"},
|
||||
{"name":"name", "type":"string","source":"device", "field":"serial_number","required":true,"desc":"传感器名称"},
|
||||
@ -339,7 +412,7 @@ WHERE platform_id = @platform_id
|
||||
|
||||
UPDATE platform_interface
|
||||
SET request_schema = '[
|
||||
{"name":"projectId", "type":"string","source":"extra", "field":"projectId", "required":true,"desc":"项目ID"},
|
||||
{"name":"projectId", "type":"string","source":"device", "field":"platform_project_id", "required":true,"desc":"项目ID"},
|
||||
{"name":"pointId", "type":"string","source":"context","contextKey":"step1.id","required":true,"desc":"测点ID"},
|
||||
{"name":"deviceType", "type":"number","source":"fixed", "value":10, "required":true,"desc":"设备类型,轴力计=10"},
|
||||
{"name":"name", "type":"string","source":"device", "field":"serial_number","required":true,"desc":"传感器名称"},
|
||||
@ -354,7 +427,7 @@ WHERE platform_id = @platform_id
|
||||
|
||||
UPDATE platform_interface
|
||||
SET request_schema = '[
|
||||
{"name":"projectId", "type":"string","source":"extra", "field":"projectId", "required":true},
|
||||
{"name":"projectId", "type":"string","source":"device", "field":"platform_project_id", "required":true},
|
||||
{"name":"pointId", "type":"string","source":"context","contextKey":"step1.id","required":true},
|
||||
{"name":"deviceType", "type":"number","source":"fixed", "value":3, "required":true,"desc":"雨量计=3"},
|
||||
{"name":"name", "type":"string","source":"device", "field":"serial_number","required":true},
|
||||
@ -368,7 +441,7 @@ WHERE platform_id = @platform_id
|
||||
|
||||
UPDATE platform_interface
|
||||
SET request_schema = '[
|
||||
{"name":"projectId", "type":"string","source":"extra", "field":"projectId", "required":true},
|
||||
{"name":"projectId", "type":"string","source":"device", "field":"platform_project_id", "required":true},
|
||||
{"name":"pointId", "type":"string","source":"context","contextKey":"step1.id","required":true},
|
||||
{"name":"deviceType", "type":"number","source":"fixed", "value":1002, "required":true,"desc":"静力水准=1002"},
|
||||
{"name":"name", "type":"string","source":"device", "field":"serial_number","required":true},
|
||||
|
||||
@ -120,6 +120,8 @@ CREATE TABLE IF NOT EXISTS `platform_flow_step` (
|
||||
CREATE TABLE IF NOT EXISTS `platform_device_mapping` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`platform_id` bigint(20) NOT NULL COMMENT '所属平台ID',
|
||||
`platform_project_id` varchar(100) NOT NULL COMMENT 'DCP项目ID',
|
||||
`platform_project_name` varchar(255) DEFAULT NULL COMMENT 'DCP项目名称',
|
||||
`device_id` bigint(20) NOT NULL COMMENT 'FastBee设备ID',
|
||||
`serial_number` varchar(64) NOT NULL COMMENT 'FastBee设备序列号',
|
||||
`device_name` varchar(64) DEFAULT NULL COMMENT '默认为本平台设备名称,可以修改为对方平台需要的名称',
|
||||
@ -146,8 +148,12 @@ CREATE TABLE IF NOT EXISTS `platform_device_mapping` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台设备绑定关系';
|
||||
|
||||
-- ----------------------------
|
||||
-- 5.1 设备绑定关系 - 新增 device_type 字段
|
||||
-- 5.1 设备绑定关系 - 补充绑定项目和设备类型字段
|
||||
-- ----------------------------
|
||||
ALTER TABLE `platform_device_mapping`
|
||||
ADD COLUMN IF NOT EXISTS `platform_project_id` varchar(100) DEFAULT NULL COMMENT 'DCP项目ID' AFTER `platform_id`,
|
||||
ADD COLUMN IF NOT EXISTS `platform_project_name` varchar(255) DEFAULT NULL COMMENT 'DCP项目名称' AFTER `platform_project_id`;
|
||||
|
||||
ALTER TABLE `platform_device_mapping`
|
||||
ADD COLUMN IF NOT EXISTS `device_type` tinyint(1) NOT NULL DEFAULT 0
|
||||
COMMENT '设备类型: 0=直连设备 1=网关设备(多子设备)' AFTER `sensor_type`;
|
||||
|
||||
@ -23,3 +23,7 @@ export function delPlatformInstance(ids) {
|
||||
export function initializePlatform(id) {
|
||||
return request({ url: `/platform/instance/${id}/initialize`, method: 'post' })
|
||||
}
|
||||
|
||||
export function getProjectsByPlatformId(id) {
|
||||
return request({ url: `/platform/instance/${id}/projects`, method: 'get' })
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@
|
||||
<el-divider content-position="left">入参定义(request_schema)</el-divider>
|
||||
<div class="schema-tip">
|
||||
定义接口需要的入参字段。参数来源使用业务化名称:
|
||||
固定值、认证参数、平台参数、上一步结果、当前设备、自动UUID、子设备传感器列表、串联子设备传感器列表、串联子设备深度数组、基准点成对传感器列表、设备物模型、上报时间。数组字段可配置组包模式。
|
||||
固定值、认证参数、平台参数、上一步结果、当前设备、自动UUID、子设备传感器列表、串联子设备传感器列表、入网深度数组、基准点成对传感器列表、设备物模型、上报时间。数组字段可配置组包模式。
|
||||
</div>
|
||||
<el-table :data="requestSchemaRows" size="mini" border style="width:100%;margin-top:8px">
|
||||
<el-table-column label="字段名" width="130">
|
||||
@ -145,7 +145,7 @@
|
||||
<el-option label="自动UUID" value="uuid" />
|
||||
<el-option label="子设备传感器列表" value="subDeviceSensorIds" />
|
||||
<el-option label="串联子设备传感器列表" value="cascadedSubDeviceSensorIds" />
|
||||
<el-option label="串联子设备深度数组" value="cascadedSubDeviceDepths" />
|
||||
<el-option label="入网深度数组" value="cascadedSubDeviceDepths" />
|
||||
<el-option label="基准点成对传感器列表" value="referenceSubDeviceSensorIdPairs" />
|
||||
<el-option label="设备物模型" value="thingsModel" />
|
||||
<el-option label="上报时间" value="ts" />
|
||||
|
||||
@ -64,6 +64,12 @@
|
||||
<el-table-column label="平台" width="120">
|
||||
<template slot-scope="scope">{{ platformName(scope.row.platformId) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="项目" min-width="120" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.platformProjectName">{{ scope.row.platformProjectName }}</span>
|
||||
<span v-else style="color:#909399">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="设备名称" min-width="140">
|
||||
<template slot-scope="scope">{{ scope.row.deviceName || deviceName(scope.row.deviceId) }}</template>
|
||||
</el-table-column>
|
||||
@ -128,6 +134,11 @@
|
||||
<el-option v-for="p in platformList" :key="p.id" :label="p.name" :value="p.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属项目" prop="platformProjectId">
|
||||
<el-select v-model="form.platformProjectId" placeholder="请选择项目" style="width:100%" @change="onProjectChange" :disabled="!form.platformId || form.netStatus === 1" clearable>
|
||||
<el-option v-for="proj in projectOptions" :key="proj.id" :label="proj.name" :value="String(proj.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="系统设备" prop="deviceId">
|
||||
<el-select v-model="form.deviceId" placeholder="选择直连或网关设备,支持名称/编号搜索" filterable remote clearable
|
||||
:remote-method="searchDevice" :loading="deviceSearchLoading" style="width:100%"
|
||||
@ -229,6 +240,23 @@
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template v-if="form.sensorType === 'deep_inclino'">
|
||||
<el-table-column label="传感器深度(m)" min-width="140">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number v-model="scope.row.sensorDepth" :min="0" :precision="2" size="mini" style="width:100%" @change="refreshOnboardConfig" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="孔深(m)" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number v-model="scope.row.holeDepth" :min="0" :precision="2" size="mini" style="width:100%" @change="syncHoleDepthToAllMonitors" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="孔口高程(m)" min-width="140">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number v-model="scope.row.holeElevation" :min="0" :precision="2" size="mini" style="width:100%" @change="syncHoleElevationToAllMonitors" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<el-table-column label="入网参数 (JSON)" min-width="220">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.onboardConfig" size="mini" :placeholder="getOnboardConfigPlaceholder(scope.row)" />
|
||||
@ -270,18 +298,16 @@
|
||||
<!-- 标量字段映射 -->
|
||||
<el-form-item v-if="fieldMappingRows.length > 0" label="字段映射">
|
||||
<el-table :data="fieldMappingRows" size="mini" border style="width:100%">
|
||||
<el-table-column label="平台字段" min-width="160">
|
||||
<template slot-scope="scope">{{ scope.row.platformField }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="物模型标识" min-width="180">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.identifier" size="mini" placeholder="选择物模型字段" filterable style="width:100%">
|
||||
<el-option v-for="tm in uniqueThingsModelOptions" :key="tm.identifier" :label="`${tm.modelName}(${tm.identifier})`" :value="tm.identifier" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="平台字段" min-width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.platformField" size="mini" placeholder="平台字段名" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="60" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="fieldMappingRows.splice(scope.$index,1)" />
|
||||
@ -305,7 +331,7 @@
|
||||
|
||||
<script>
|
||||
import { listPlatformDeviceMapping, addPlatformDeviceMapping, updatePlatformDeviceMapping, delPlatformDeviceMapping, onboardDevice, listSubMappings, syncSubMappings } from '@/api/platform/deviceMapping'
|
||||
import { listPlatformInstance } from '@/api/platform/instance'
|
||||
import { listPlatformInstance, getProjectsByPlatformId } 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'
|
||||
@ -323,6 +349,7 @@ export default {
|
||||
subDeviceOptions: [],
|
||||
deviceSearchLoading: false, thingsModelOptions: [],
|
||||
interfaceOptions: [],
|
||||
projectOptions: [],
|
||||
open: false, title: '',
|
||||
fieldMappingRows: [],
|
||||
// 网关子设备映射行
|
||||
@ -333,9 +360,15 @@ export default {
|
||||
subMappingCache: {},
|
||||
sensorTypeDictOptions: [],
|
||||
queryParams: { pageNum: 1, pageSize: 20, platformId: null, serialNumber: '', sensorType: '', netStatus: null },
|
||||
form: { enable: '1', deviceType: 0, reportIntervalSec: 300, deviceName: '' },
|
||||
form: {
|
||||
enable: '1', deviceType: 0, reportIntervalSec: 300, deviceName: '',
|
||||
platformId: null, platformProjectId: null, platformProjectName: '',
|
||||
pushInterfaceId: null, pushMode: 1, pushInterval: 5,
|
||||
deviceId: null, serialNumber: '', sensorType: '', remark: ''
|
||||
},
|
||||
rules: {
|
||||
platformId: [{ required: true, message: '请选择平台', trigger: 'change' }],
|
||||
platformProjectId: [{ required: true, message: '请选择所属项目', trigger: 'change' }],
|
||||
deviceId: [{ required: true, message: '请选择设备', trigger: 'change' }],
|
||||
sensorType: [{ required: true, message: '请选择或输入设备类型', trigger: 'change' }],
|
||||
pushInterfaceId: [{ required: true, message: '请选择推送接口', trigger: 'change' }]
|
||||
@ -433,7 +466,11 @@ export default {
|
||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||
resetQuery() { this.resetForm('queryForm'); this.handleQuery() },
|
||||
handleAdd() {
|
||||
this.form = { enable: '1', deviceType: 0, pushInterfaceId: null, pushMode: 1, pushInterval: 5, reportIntervalSec: 300, deviceName: '' }
|
||||
this.form = {
|
||||
enable: '1', deviceType: 0, pushInterfaceId: null, pushMode: 1, pushInterval: 5, reportIntervalSec: 300, deviceName: '',
|
||||
platformId: null, platformProjectId: null, platformProjectName: '',
|
||||
deviceId: null, serialNumber: '', sensorType: '', remark: ''
|
||||
}
|
||||
this.fieldMappingRows = []
|
||||
this.subMappingRows = []
|
||||
this.itemFieldMappingRows = []
|
||||
@ -441,6 +478,7 @@ export default {
|
||||
this.subDeviceOptions = []
|
||||
this.thingsModelOptions = []
|
||||
this.interfaceOptions = []
|
||||
this.projectOptions = []
|
||||
this.title = '新增设备绑定'; this.open = true
|
||||
},
|
||||
handleUpdate(row) {
|
||||
@ -459,11 +497,21 @@ export default {
|
||||
// 加载该平台的接口列表
|
||||
if (row.platformId) {
|
||||
this.loadInterfaces(row.platformId)
|
||||
this.loadProjects(row.platformId)
|
||||
}
|
||||
// 加载子设备映射(网关设备)
|
||||
if (row.deviceType === 1 && row.id) {
|
||||
listSubMappings(row.id).then(res => {
|
||||
this.subMappingRows = (res.data || []).map(s => ({ ...s, subDeviceName: s.subDeviceName || s.subSerialNumber }))
|
||||
this.subMappingRows = (res.data || []).map(s => {
|
||||
const config = this.safeParseJson(s.onboardConfig, {})
|
||||
return {
|
||||
...s,
|
||||
subDeviceName: s.subDeviceName || s.subSerialNumber,
|
||||
sensorDepth: config.sensorDepth != null ? config.sensorDepth : null,
|
||||
holeDepth: config.holeDepth != null ? config.holeDepth : null,
|
||||
holeElevation: config.holeElevation != null ? config.holeElevation : null
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
this.loadDeviceContext(row.deviceId)
|
||||
@ -485,7 +533,27 @@ export default {
|
||||
onPlatformChange(platformId) {
|
||||
this.interfaceOptions = []
|
||||
this.form.pushInterfaceId = null
|
||||
if (platformId) this.loadInterfaces(platformId)
|
||||
this.projectOptions = []
|
||||
this.form.platformProjectId = null
|
||||
this.form.platformProjectName = ''
|
||||
if (platformId) {
|
||||
this.loadInterfaces(platformId)
|
||||
this.loadProjects(platformId)
|
||||
}
|
||||
},
|
||||
loadProjects(platformId) {
|
||||
if (!platformId) { this.projectOptions = []; return }
|
||||
getProjectsByPlatformId(platformId).then(res => {
|
||||
this.projectOptions = res.data || []
|
||||
}).catch(() => { this.projectOptions = [] })
|
||||
},
|
||||
onProjectChange(projectId) {
|
||||
if (projectId) {
|
||||
const proj = this.projectOptions.find(p => String(p.id) === String(projectId))
|
||||
this.form.platformProjectName = proj ? proj.name : ''
|
||||
} else {
|
||||
this.form.platformProjectName = ''
|
||||
}
|
||||
},
|
||||
onDeviceTypeChange(val) {
|
||||
if (val === 1 && this.subMappingRows.length === 0 && this.subDeviceOptions.length > 0) {
|
||||
@ -508,6 +576,15 @@ export default {
|
||||
})
|
||||
},
|
||||
onPushInterfaceChange(interfaceId) {
|
||||
// 根据接口的 isBatchPush 自动设置推送模式:0=实时推送(1),1=定时推送(2)
|
||||
if (interfaceId) {
|
||||
const iface = this.interfaceOptions.find(x => x.id === interfaceId)
|
||||
if (iface) {
|
||||
this.form.pushMode = iface.isBatchPush === 1 ? 2 : 1
|
||||
}
|
||||
} else {
|
||||
this.form.pushMode = 1
|
||||
}
|
||||
// 从推送接口的 requestSchema 提取字段作为数据映射模板,切换接口时全量刷新
|
||||
if (!interfaceId) return
|
||||
const iface = this.interfaceOptions.find(x => x.id === interfaceId)
|
||||
@ -654,7 +731,7 @@ export default {
|
||||
},
|
||||
addFieldMapping() { this.fieldMappingRows.push({ identifier: '', platformField: '' }) },
|
||||
addSubMapping() {
|
||||
this.subMappingRows.push({ subSerialNumber: '', subDeviceName: '', deviceRole: 'monitor', onboardConfig: '', platformDeviceId: '', platformPointId: '' })
|
||||
this.subMappingRows.push({ subSerialNumber: '', subDeviceName: '', deviceRole: 'monitor', onboardConfig: '', sensorDepth: null, holeDepth: null, holeElevation: null, platformDeviceId: '', platformPointId: '' })
|
||||
},
|
||||
onSubRoleChange(row) {
|
||||
if (row.deviceRole === 'reference') {
|
||||
@ -665,6 +742,7 @@ export default {
|
||||
})
|
||||
}
|
||||
this.refreshSubMappingOnboardConfigs()
|
||||
if (this.form.sensorType === 'deep_inclino') this.refreshOnboardConfig()
|
||||
},
|
||||
onSubSerialChange(row) {
|
||||
if (!row.subSerialNumber) return
|
||||
@ -676,6 +754,7 @@ export default {
|
||||
config.sensorId = config.sensorId || row.subSerialNumber
|
||||
row.onboardConfig = JSON.stringify(config)
|
||||
this.refreshSubMappingOnboardConfigs()
|
||||
if (this.form.sensorType === 'deep_inclino') this.refreshOnboardConfig()
|
||||
},
|
||||
findReferenceRow(rows = this.subMappingRows) {
|
||||
return (rows || []).find(r => r.deviceRole === 'reference' && r.subSerialNumber)
|
||||
@ -706,10 +785,42 @@ export default {
|
||||
row.onboardConfig = this.buildOnboardConfig(row, refRow)
|
||||
})
|
||||
},
|
||||
refreshOnboardConfig() {
|
||||
this.subMappingRows.forEach(row => {
|
||||
const existing = this.safeParseJson(row.onboardConfig, {})
|
||||
if (!existing.sensorId) existing.sensorId = row.subSerialNumber
|
||||
if (this.form.sensorType === 'deep_inclino' && row.deviceRole === 'monitor') {
|
||||
if (row.sensorDepth != null) existing.sensorDepth = row.sensorDepth
|
||||
if (row.holeDepth != null) existing.holeDepth = row.holeDepth
|
||||
if (row.holeElevation != null) existing.holeElevation = row.holeElevation
|
||||
} else {
|
||||
delete existing.sensorDepth
|
||||
delete existing.holeDepth
|
||||
delete existing.holeElevation
|
||||
}
|
||||
row.onboardConfig = JSON.stringify(existing)
|
||||
})
|
||||
},
|
||||
syncHoleDepthToAllMonitors(value) {
|
||||
this.subMappingRows.forEach(row => {
|
||||
if (row.deviceRole === 'monitor') row.holeDepth = value
|
||||
})
|
||||
this.refreshOnboardConfig()
|
||||
},
|
||||
syncHoleElevationToAllMonitors(value) {
|
||||
this.subMappingRows.forEach(row => {
|
||||
if (row.deviceRole === 'monitor') row.holeElevation = value
|
||||
})
|
||||
this.refreshOnboardConfig()
|
||||
},
|
||||
normalizeSubMappingsForSubmit() {
|
||||
const rows = (this.subMappingRows || [])
|
||||
.filter(r => r.subSerialNumber)
|
||||
.map(r => ({ ...r, deviceRole: r.deviceRole || 'monitor' }))
|
||||
if (new Set(rows.map(r => r.subSerialNumber)).size !== rows.length) {
|
||||
this.$modal.msgError('子设备编号不能重复')
|
||||
return null
|
||||
}
|
||||
const references = rows.filter(r => r.deviceRole === 'reference')
|
||||
const monitors = rows.filter(r => r.deviceRole === 'monitor')
|
||||
if (references.length > 1) {
|
||||
@ -720,11 +831,27 @@ export default {
|
||||
this.$modal.msgError('静力水准需配置 1 个基准点和至少 1 个监测点')
|
||||
return null
|
||||
}
|
||||
if (this.form.sensorType === 'deep_inclino') {
|
||||
if (monitors.length === 0) {
|
||||
this.$modal.msgError('深部位移至少配置 1 个监测点')
|
||||
return null
|
||||
}
|
||||
const invalid = monitors.find(r => r.sensorDepth == null || r.holeDepth == null || r.holeElevation == null || r.sensorDepth > r.holeDepth)
|
||||
if (invalid) {
|
||||
this.$modal.msgError(`子设备 ${invalid.subSerialNumber} 的传感器深度、孔深、孔口高程必填,且传感器深度不能大于孔深`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
const refRow = references[0] || null
|
||||
return rows.map(row => ({
|
||||
...row,
|
||||
onboardConfig: this.buildOnboardConfig(row, refRow)
|
||||
}))
|
||||
return rows.map(row => {
|
||||
const onboardConfig = this.safeParseJson(this.buildOnboardConfig(row, refRow), {})
|
||||
if (this.form.sensorType === 'deep_inclino' && row.deviceRole === 'monitor') {
|
||||
onboardConfig.sensorDepth = row.sensorDepth
|
||||
onboardConfig.holeDepth = row.holeDepth
|
||||
onboardConfig.holeElevation = row.holeElevation
|
||||
}
|
||||
return { ...row, onboardConfig: JSON.stringify(onboardConfig) }
|
||||
})
|
||||
},
|
||||
safeParseJson(value, defaultValue) {
|
||||
if (!value) return defaultValue
|
||||
@ -733,7 +860,18 @@ export default {
|
||||
cancel() { this.open = false },
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
if (!valid) {
|
||||
// 自动定位到第一个校验失败的字段
|
||||
this.$nextTick(() => {
|
||||
const firstError = this.$refs.form.$el.querySelector('.el-form-item.is-error')
|
||||
if (firstError) {
|
||||
firstError.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
const input = firstError.querySelector('input, .el-select .el-input__inner, textarea')
|
||||
if (input) input.focus()
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
this.form.fieldMapping = this.fieldMappingRows.length > 0
|
||||
? JSON.stringify(this.fieldMappingRows) : null
|
||||
const normalizedSubRows = this.form.deviceType === 1
|
||||
|
||||
@ -119,14 +119,14 @@
|
||||
</template>
|
||||
<el-divider content-position="left">平台参数</el-divider>
|
||||
<div class="schema-tip" style="margin-bottom:8px">
|
||||
这里维护平台运行所需的业务参数,例如 `projectId`、项目名称、站点编码等;初始化流程写回的值也会保存在这里,可直接前端补录或修改。
|
||||
这里维护平台运行所需的业务参数,例如站点编码等;初始化流程写回的值也会保存在这里,可直接前端补录或修改。
|
||||
</div>
|
||||
<key-value-editor
|
||||
v-model="platformConfigRows"
|
||||
add-text="添加平台参数"
|
||||
:show-enabled="false"
|
||||
:show-description="true"
|
||||
key-placeholder="参数名,如 projectId"
|
||||
key-placeholder="参数名"
|
||||
value-placeholder="参数值"
|
||||
/>
|
||||
<el-form-item label="启用">
|
||||
@ -224,7 +224,7 @@ export default {
|
||||
})
|
||||
},
|
||||
handleInitialize(row) {
|
||||
this.$confirm(`确认初始化平台【${row.name}】?将执行初始化流程获取 userId/projectId 等信息。`).then(() => {
|
||||
this.$confirm(`确认初始化平台【${row.name}】?将执行初始化流程获取 userId。`).then(() => {
|
||||
initializePlatform(row.id).then(() => {
|
||||
this.$modal.msgSuccess('初始化成功')
|
||||
this.getList()
|
||||
@ -240,7 +240,7 @@ export default {
|
||||
if (!value) return []
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
return Object.keys(parsed).map(key => ({
|
||||
return Object.keys(parsed).filter(key => !['projectId', 'projectName'].includes(key)).map(key => ({
|
||||
key,
|
||||
value: parsed[key] == null ? '' : String(parsed[key]),
|
||||
description: ''
|
||||
@ -252,7 +252,7 @@ export default {
|
||||
buildObjectJson(rows) {
|
||||
const result = {}
|
||||
;(rows || []).forEach(item => {
|
||||
if (!item || !item.key) return
|
||||
if (!item || !item.key || ['projectId', 'projectName'].includes(item.key)) return
|
||||
result[item.key] = item.value
|
||||
})
|
||||
return Object.keys(result).length > 0 ? JSON.stringify(result) : null
|
||||
|
||||
Loading…
Reference in New Issue
Block a user