diff --git a/detection/src/main/java/com/njcn/gather/detection/handler/SocketSourceResponseService.java b/detection/src/main/java/com/njcn/gather/detection/handler/SocketSourceResponseService.java index d4b33f14..52842553 100644 --- a/detection/src/main/java/com/njcn/gather/detection/handler/SocketSourceResponseService.java +++ b/detection/src/main/java/com/njcn/gather/detection/handler/SocketSourceResponseService.java @@ -11,130 +11,260 @@ import com.njcn.gather.detection.pojo.vo.SocketDataMsg; import com.njcn.gather.detection.pojo.vo.SocketMsg; import com.njcn.gather.detection.pojo.vo.WebSocketVO; import com.njcn.gather.detection.util.socket.*; -import com.njcn.gather.detection.util.socket.cilent.NettyClient; -import com.njcn.gather.detection.util.socket.cilent.NettyDevClientHandler; import com.njcn.gather.detection.util.socket.websocket.WebServiceManager; import com.njcn.gather.device.pojo.vo.PreDetection; import com.njcn.gather.device.service.IPqDevService; import com.njcn.gather.script.pojo.po.SourceIssue; import com.njcn.gather.system.pojo.enums.DicDataEnum; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; +/** + * 程控源Socket响应处理服务 + *

+ * 该服务类负责处理来自程控源设备的Socket消息响应,包括: + * - 源初始化响应处理 + * - 检测流程控制和状态管理 + * - 相序检测、系数校验等特定检测类型的响应处理 + * - WebSocket消息推送给前端用户 + * - 错误处理和连接管理 + *

+ *

+ * 主要处理的操作类型: + * - YJC_YTXJY: 源通信校验/源初始化 + * - YJC_XUJY: 相序检测 + * - FORMAL_REAL: 正式检测 + * - Coefficient_Check: 系数校验 + * - QUITE_SOURCE: 退出源连接 + *

+ * + * @author CN_Gather Detection Team + * @version 1.0 + * @since 2023 + */ +@Slf4j @Service @RequiredArgsConstructor public class SocketSourceResponseService { /** - * 向webSocket客户端发送消息 + * 设备信息服务,提供设备基础信息查询功能 */ - private final SocketDevResponseService socketDevResponseService; private final IPqDevService iPqDevService; + + /** + * Socket连接管理器,负责管理设备和源的Socket连接 + */ private final SocketManager socketManager; + + /** + * 发送WebSocket消息到指定用户页面 + *

+ * 将数据对象转换为JSON字符串并通过WebSocket推送给前端用户, + * 用于实时通知用户检测进度、状态变化或错误信息。 + *

+ * + * @param userPageId 用户页面ID,用于标识消息接收方 + * @param data 要发送的数据对象,将被转换为JSON格式 + */ + private void sendWebSocketMessage(String userPageId, Object data) { + WebServiceManager.sendMsg(userPageId, JSON.toJSONString(data)); + } + + /** + * 发送错误消息并退出源连接 + *

+ * 当检测过程中发生错误时,执行以下操作: + * 1. 主动断开与程控源的连接 + * 2. 构造包含错误信息的Socket消息 + * 3. 通过WebSocket将错误信息推送给前端用户 + *

+ * + * @param param 检测参数,包含用户页面ID等信息 + * @param socketDataMsg 原始Socket消息,用于构造响应消息 + * @param errorMessage 具体的错误描述信息 + */ + private void sendErrorAndQuit(PreDetectionParam param, SocketDataMsg socketDataMsg, String errorMessage) { + CnSocketUtil.quitSendSource(param); + SocketMsg socketMsg = new SocketMsg<>(); + socketMsg.setRequestId(socketDataMsg.getRequestId()); + socketMsg.setOperateCode(socketDataMsg.getOperateCode()); + socketMsg.setData(errorMessage); + sendWebSocketMessage(param.getUserPageId(), socketMsg); + } + + /** + * 发送错误消息并退出源连接(使用枚举消息) + *

+ * 重载方法,使用预定义的错误码枚举来获取标准化的错误消息。 + * 确保错误信息的一致性和规范性。 + *

+ * + * @param param 检测参数 + * @param socketDataMsg 原始Socket消息 + * @param errorCode 错误码枚举,包含标准化的错误描述 + */ + private void sendErrorAndQuit(PreDetectionParam param, SocketDataMsg socketDataMsg, SourceResponseCodeEnum errorCode) { + sendErrorAndQuit(param, socketDataMsg, errorCode.getMessage()); + } + /** + * 当前检测会话中的设备列表 + *

+ * 存储正在进行检测的设备信息,包含设备基本信息和监测点配置。 + * 注意:该字段存在线程安全问题,建议后续重构为线程安全的设计。 + *

+ */ private List devList = new ArrayList<>(); + + /** + * 当前检测会话中的监测点ID列表 + *

+ * 从设备列表中提取的所有监测点ID集合,用于向设备发送数据请求时指定监测范围。 + * 与devList字段保持同步更新。 + *

+ */ private List monitorIdList = new ArrayList<>(); - + /** + * 程控源响应消息处理主入口 + *

+ * 根据消息中的操作码,分发到相应的处理方法: + * - 解析Socket消息,提取操作码 + * - 根据操作码类型调用对应的处理方法 + * - 支持检测计划模式和模拟测试模式的区分处理 + *

+ *

+ * 支持的操作类型: + * - YJC_YTXJY: 源通信校验/源初始化 + * - YJC_XUJY: 相序检测 + * - FORMAL_REAL: 正式检测 + * - Coefficient_Check: 系数校验 + * - QUITE_SOURCE: 退出源连接 + *

+ * + * @param param 检测参数,包含用户ID、设备ID、计划ID等关键信息 + * @param msg 从程控源接收的原始Socket消息 + * @throws Exception 当消息解析失败或处理过程中发生异常时抛出 + */ public void deal(PreDetectionParam param, String msg) throws Exception { + // 解析接收到的Socket消息 SocketDataMsg socketDataMsg = MsgUtil.socketDataMsg(msg); + + // 从requestId中提取操作码,requestId格式为:操作码_步骤标识 String[] tem = socketDataMsg.getRequestId().split(CnSocketUtil.STEP_TAG); SourceOperateCodeEnum enumByCode = SourceOperateCodeEnum.getDictDataEnumByCode(tem[0]); + if (ObjectUtil.isNotNull(enumByCode)) { switch (enumByCode) { - //源初始化 + // 源初始化处理:根据是否有计划ID判断是正式检测还是模拟检测 case YJC_YTXJY: if (ObjectUtil.isNotNull(param.getPlanId())) { + // 有计划ID:正式检测模式,源初始化成功后启动设备检测 detectionDev(param, socketDataMsg); } else { - // 程控源-源通信校验 + // 无计划ID:模拟检测模式,仅进行源通信校验 handleYtxjySimulate(param, socketDataMsg); } break; - //相序检测 + + // 相序检测:检测设备的相序是否正确 case YJC_XUJY: phaseSequenceDev(param, socketDataMsg); break; - //正式检测 + + // 正式检测:根据是否有计划ID选择不同的处理方式 case FORMAL_REAL: if (ObjectUtil.isNotNull(param.getPlanId())) { + // 有计划ID:向设备发送检测参数 senParamToDev(param, socketDataMsg); } else { + // 无计划ID:模拟测试模式 handleSimulateTest(param, socketDataMsg); } break; - //系数校验 + + // 系数校验:验证设备的计量系数是否准确 case Coefficient_Check: coefficient(param, socketDataMsg); break; + + // 退出源连接:清理资源并关闭连接 case QUITE_SOURCE: quitDeal(socketDataMsg, param); break; + + // YXT操作:暂未实现具体功能 case YXT: + // TODO: 实现YXT操作的具体逻辑 break; + default: - // todo... 要日志记录或者websocket送到前端友好提示用户 + // TODO: 记录未知操作码到日志,并向前端发送友好提示 break; } } else { - // todo... 要日志记录或者websocket送到前端友好提示用户 - System.out.println("fggggggggggggggggggggg" + enumByCode); + // TODO: 向前端发送错误提示 + log.error("程控源响应消息操作码解析失败,原始消息: {}, 解析结果: {}", msg, enumByCode); } } + /** + * 处理模拟检测中的源通信校验响应 + *

+ * 在模拟检测模式下(非计划检测),处理程控源的通信校验响应: + * - 成功时:根据参数决定是否向前端发送WebSocket消息 + * - 业务未处理:直接转发消息给前端 + * - 各种错误情况:统一处理为退出源连接并通知前端 + *

+ *

+ * 支持的错误类型包括: + * - 源连接错误、程控源错误、测试项解析错误 + * - 源控制错误、目标源错误、未初始化错误 + * - 未知错误、无法响应错误 + *

+ * + * @param param 检测参数,包含用户信息和WebSocket消息发送控制 + * @param socketDataMsg 程控源返回的响应消息 + */ private void handleYtxjySimulate(PreDetectionParam param, SocketDataMsg socketDataMsg) { SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode()); if (ObjectUtil.isNotNull(dictDataEnumByCode)) { switch (dictDataEnumByCode) { case SUCCESS: + // 源初始化成功:根据参数控制是否发送WebSocket消息 if (param.getSendWebMsg()) { - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); } - System.out.println(param.getSendWebMsg() + "模拟检测-源初始化成功"); + log.info("模拟检测源初始化成功,用户: {}, WebSocket发送: {}", + param.getUserPageId(), param.getSendWebMsg()); break; case UNPROCESSED_BUSINESS: - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + // 业务暂未处理:直接转发消息给前端等待处理 + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); break; + // 各种错误情况:源连接错误、程控源控制错误、测试项解析错误等 case SOURCE_CONNECTION_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case CONTROLLED_SOURCE_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case TEST_ITEM_PARSING_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case SOURCE_CONTROL_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case TARGET_SOURCE_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case NOT_INITIALIZED: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case UNKNOWN_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case UNABLE_TO_RESPOND: + // 所有错误情况统一处理:退出源连接并通知前端 CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); break; default: + // 未识别的响应码:发送通用错误消息 WebServiceManager.sendUnknownErrorMessage(param.getUserPageId()); break; } @@ -152,19 +282,15 @@ public class SocketSourceResponseService { if (ObjectUtil.isNotNull(dictDataEnumByCode)) { switch (dictDataEnumByCode) { case SUCCESS: - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - System.out.println("模拟检测-源成功执行脚本" + JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); + log.info("模拟检测源成功执行脚本,用户: {}, 响应消息: {}", + param.getUserPageId(), JSON.toJSONString(socketDataMsg)); break; case UNPROCESSED_BUSINESS: - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); break; default: - CnSocketUtil.quitSendSource(param); - SocketMsg socketMsg = new SocketMsg<>(); - socketMsg.setRequestId(socketDataMsg.getRequestId()); - socketMsg.setOperateCode(socketDataMsg.getOperateCode()); - socketMsg.setData(dictDataEnumByCode.getMessage()); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketMsg)); + sendErrorAndQuit(param, socketDataMsg, dictDataEnumByCode); break; } } @@ -173,6 +299,23 @@ public class SocketSourceResponseService { /** * 系数校验源数据返回处理 + *

+ * 处理系数校验阶段程控源的响应消息: + * 1. 成功时:向前端推送响应信息,然后向设备发送数据请求 + * 2. 构造设备数据请求参数,包含监测点列表和数据类型 + * 3. 设置固定的读取参数:读取3次数据,忽略前4次 + * 4. 请求的数据类型:实时电压有效值(real$VRMS)和实时电流有效值(real$IRMS) + *

+ *

+ * 数据请求配置: + * - 监测点:使用当前会话的monitorIdList + * - 数据类型:["real$VRMS", "real$IRMS"] + * - 读取次数:3次 + * - 忽略次数:4次(预热数据) + *

+ * + * @param param 检测参数 + * @param socketDataMsg 程控源响应消息 */ private void coefficient(PreDetectionParam param, SocketDataMsg socketDataMsg) { SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode()); @@ -181,29 +324,28 @@ public class SocketSourceResponseService { switch (dictDataEnumByCode) { case SUCCESS: //向前端推送信息 - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); String s = param.getUserPageId() + CnSocketUtil.DEV_TAG; socketMsg.setRequestId(SourceOperateCodeEnum.Coefficient_Check.getValue()); socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_02.getValue()); DevPhaseSequenceParam phaseSequenceParam = new DevPhaseSequenceParam(); phaseSequenceParam.setMoniterIdList(monitorIdList); + // 系数校验固定检测项:实时电压有效值和实时电流有效值 phaseSequenceParam.setDataType(Arrays.asList("real$VRMS", "real$IRMS")); + // 读取3次数据用于系数计算 phaseSequenceParam.setReadCount(3); + // 忽略前4次数据,等待测量稳定 phaseSequenceParam.setIgnoreCount(4); socketMsg.setData(JSON.toJSONString(phaseSequenceParam)); SocketManager.sendMsg(s, JSON.toJSONString(socketMsg)); break; case UNPROCESSED_BUSINESS: - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); break; default: - CnSocketUtil.quitSendSource(param); - socketMsg.setRequestId(socketDataMsg.getRequestId()); - socketMsg.setOperateCode(socketDataMsg.getOperateCode()); - socketMsg.setData(dictDataEnumByCode.getMessage()); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketMsg)); + sendErrorAndQuit(param, socketDataMsg, dictDataEnumByCode); break; } } @@ -222,7 +364,7 @@ public class SocketSourceResponseService { switch (dictDataEnumByCode) { case SUCCESS: //todo 前端推送收到的消息暂未处理好 - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); //开始设备通讯检测(发送设备初始化) Map> map = new HashMap<>(1); map.put("deviceList", FormalTestManager.devList); @@ -235,39 +377,18 @@ public class SocketSourceResponseService { socketManager.smartSendToDevice(param, json); break; case UNPROCESSED_BUSINESS: - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); break; case SOURCE_CONNECTION_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case CONTROLLED_SOURCE_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case TEST_ITEM_PARSING_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case SOURCE_CONTROL_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case TARGET_SOURCE_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case NOT_INITIALIZED: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case UNKNOWN_ERROR: - CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); - break; case UNABLE_TO_RESPOND: CnSocketUtil.quitSendSource(param); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); break; default: // todo... 这种情况是报文的状态码不一致,需要记录到日志表,以便问题追踪 @@ -292,7 +413,7 @@ public class SocketSourceResponseService { switch (dictDataEnumByCode) { case SUCCESS: //向前端推送信息 - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); String s = param.getUserPageId() + CnSocketUtil.DEV_TAG; socketMsg.setRequestId(SourceOperateCodeEnum.YJC_XUJY.getValue()); @@ -304,24 +425,23 @@ public class SocketSourceResponseService { DevPhaseSequenceParam phaseSequenceParam = new DevPhaseSequenceParam(); phaseSequenceParam.setMoniterIdList(moniterIdList); + // 相序检测项:电压有效值、电压角度、电流有效值、电流角度 phaseSequenceParam.setDataType(Arrays.asList("real$VRMS", "real$VA", "real$IRMS", "real$IA")); + // 相序检测只需要读取1次数据 phaseSequenceParam.setReadCount(1); + // 忽略前10次数据,确保相序稳定 phaseSequenceParam.setIgnoreCount(10); socketMsg.setData(JSON.toJSONString(phaseSequenceParam)); SocketManager.sendMsg(s, JSON.toJSONString(socketMsg)); break; case UNPROCESSED_BUSINESS: - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); break; case MESSAGE_PARSING_ERROR: CnSocketUtil.quitSendSource(param); break; default: - CnSocketUtil.quitSendSource(param); - socketMsg.setRequestId(socketDataMsg.getRequestId()); - socketMsg.setOperateCode(socketDataMsg.getOperateCode()); - socketMsg.setData(dictDataEnumByCode.getMessage()); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketMsg)); + sendErrorAndQuit(param, socketDataMsg, dictDataEnumByCode); break; } } @@ -329,10 +449,28 @@ public class SocketSourceResponseService { /** - * 组装和装置要数据 + * 正式检测时向设备发送参数请求 + *

+ * 当程控源成功执行脚本后,根据检测项目类型向设备发送相应的数据请求: + * 1. 获取源脚本信息,确定检测类型和数据类型 + * 2. 根据检测类型设置不同的读取参数: + * - 闪变(F):忽略1次,读取2次,使用DEV_DATA_REQUEST_01 + * - 暂态(VOLTAGE):忽略5次,读取1次,使用DEV_DATA_REQUEST_03 + * - 其他类型:忽略5次,读取5次,根据数据类型选择操作码 + * 3. 构造设备数据请求并发送 + * 4. 向前端推送检测开始信息 + *

+ *

+ * 检测参数配置: + * - 闪变检测:ignoreCount=1, readCount=2 + * - 暂态检测:ignoreCount=5, readCount=1 + * - 常规检测:ignoreCount=5, readCount=5 + * - 实时数据:使用DEV_DATA_REQUEST_02 + * - 分钟数据:使用DEV_DATA_REQUEST_01 + *

* - * @param param - * @param socketDataMsg + * @param param 检测参数,包含用户和设备信息 + * @param socketDataMsg 程控源成功响应消息 */ private void senParamToDev(PreDetectionParam param, SocketDataMsg socketDataMsg) { SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode()); @@ -343,42 +481,71 @@ public class SocketSourceResponseService { //向前端推送信息 // webSocketHandler.sendMsgToUser(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + // 构造设备通道标识:用户ID + 设备标签 String s = param.getUserPageId() + CnSocketUtil.DEV_TAG; + + // 获取当前检测的源脚本信息,包含检测类型和数据要求 SourceIssue sourceIssue = SocketManager.getSourceList().get(0); - List comm = sourceIssue.getDevValueTypeList(); //形如:类型&小项code这种形式。例如:real$VRMS、real$IRMS - System.out.println("向装置下发的参数>>>>>>>>" + comm); + // 数据类型列表,格式:real$VRMS、real$IRMS + List comm = sourceIssue.getDevValueTypeList(); + log.debug("向设备下发检测参数,用户: {}, 数据类型: {}", param.getUserPageId(), comm); + + // 设置请求ID:正式检测操作码 + 步骤标识 + 检测类型 socketMsg.setRequestId(SourceOperateCodeEnum.FORMAL_REAL.getValue() + CnSocketUtil.STEP_TAG + sourceIssue.getType()); + + // 根据检测类型设置不同的读取参数和操作码 int ignoreCount; int readData; + if (DicDataEnum.F.getCode().equals(sourceIssue.getType())) { + // 闪变检测:数据变化较慢,只需少量预热和读取 + // 闪变测量稳定性好,预热1次即可 ignoreCount = 1; + // 读取2次数据计算闪变值 readData = 2; socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_01.getValue()); } else if (DicDataEnum.VOLTAGE.getCode().equals(sourceIssue.getType())) { + // 暂态电压检测:需要更多预热时间,但只读取一次快照 + // 暂态事件需要5次预热确保触发稳定 ignoreCount = 5; + // 暂态检测只需要捕获一次事件 readData = 1; socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_03.getValue()); } else { + // 常规检测(谐波、不平衡度等):需要多次采样以提高精度 + // 常规检测预热5次等待稳定 ignoreCount = 5; + // 读取5次数据进行统计分析 readData = 5; - //区分实时数据还是分钟数据 + + // 根据数据类型选择相应的请求操作码 if ("real".equals(sourceIssue.getDataType())) { + // 实时数据:瞬时值或有效值 socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_02.getValue()); } else { + // 分钟数据:统计周期内的平均值或累计值 socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_01.getValue()); } } - System.out.println("devList is empty:" + CollectionUtils.isEmpty(devList)); + log.debug("检测设备列表状态检查,用户: {}, 设备列表为空: {}", + param.getUserPageId(), CollectionUtils.isEmpty(devList)); - //List moniterIdList = devList.stream().flatMap(x -> x.getMonitorList().stream()).map(PreDetection.MonitorListDTO::getLineId).collect(Collectors.toList()); + // 构造设备数据请求参数 DevPhaseSequenceParam phaseSequenceParam = new DevPhaseSequenceParam(); + // 设置监测点ID列表 phaseSequenceParam.setMoniterIdList(monitorIdList); + // 设置数据类型列表 phaseSequenceParam.setDataType(comm); + // 设置读取次数 phaseSequenceParam.setReadCount(readData); + // 设置忽略次数 phaseSequenceParam.setIgnoreCount(ignoreCount); socketMsg.setData(JSON.toJSONString(phaseSequenceParam)); + + // 向设备发送数据请求 SocketManager.sendMsg(s, JSON.toJSONString(socketMsg)); + // 构造前端显示的设备列表,只包含设备ID和名称 List devListRes = new ArrayList<>(); devList.forEach(item -> { DevLineTestResult devLineTestResult = new DevLineTestResult(); @@ -387,21 +554,21 @@ public class SocketSourceResponseService { devListRes.add(devLineTestResult); }); + // 构造WebSocket消息并推送给前端,通知检测开始 WebSocketVO webSocketVO = new WebSocketVO<>(); + // 设置请求ID:检测类型 + 开始标识 webSocketVO.setRequestId(socketDataMsg.getRequestId().split(CnSocketUtil.STEP_TAG)[1] + CnSocketUtil.START_TAG); + // 检测描述信息 webSocketVO.setDesc(SocketManager.getSourceList().get(0).getDesc()); + // 参与检测的设备列表 webSocketVO.setData(devListRes); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(webSocketVO)); + sendWebSocketMessage(param.getUserPageId(), webSocketVO); break; case UNPROCESSED_BUSINESS: - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); break; default: - CnSocketUtil.quitSendSource(param); - socketMsg.setRequestId(socketDataMsg.getRequestId()); - socketMsg.setOperateCode(socketDataMsg.getOperateCode()); - socketMsg.setData(dictDataEnumByCode.getMessage()); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketMsg)); + sendErrorAndQuit(param, socketDataMsg, dictDataEnumByCode); break; } } @@ -409,7 +576,23 @@ public class SocketSourceResponseService { /** - * 退出检测返回 + * 处理退出检测的响应 + *

+ * 当用户主动退出检测或系统需要终止检测时,处理程控源的退出响应: + * - 成功退出:移除Socket连接管理中的用户信息,向前端发送成功消息 + * - 业务未处理:不做特殊处理 + * - 消息解析错误/无法响应:移除用户连接信息 + * - 其他错误:调用退出源连接方法 + *

+ *

+ * 退出流程: + * 1. 解析响应状态码 + * 2. 根据状态码执行相应的清理操作 + * 3. 确保Socket连接资源得到正确释放 + *

+ * + * @param socketDataMsg 程控源退出响应消息 + * @param param 检测参数,包含用户信息 */ private void quitDeal(SocketDataMsg socketDataMsg, PreDetectionParam param) { SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode()); @@ -417,7 +600,7 @@ public class SocketSourceResponseService { case SUCCESS: //通讯校验成功 SocketManager.removeUser(param.getUserPageId() + CnSocketUtil.SOURCE_TAG); - WebServiceManager.sendMsg(param.getUserPageId(), JSON.toJSONString(socketDataMsg)); + sendWebSocketMessage(param.getUserPageId(), socketDataMsg); break; case UNPROCESSED_BUSINESS: break; @@ -435,13 +618,37 @@ public class SocketSourceResponseService { } + /** + * 初始化检测设备和监测点列表 + *

+ * 在开始检测前,根据检测参数初始化当前会话的设备信息: + * 1. 清空之前的设备列表和监测点列表 + * 2. 根据设备ID列表查询设备详细信息 + * 3. 从设备信息中提取所有监测点的线路ID + * 4. 同步更新XiNumberManager中的设备列表 + *

+ *

+ * 该方法通常在检测开始前调用,确保后续的检测流程能够获取到正确的 + * 设备配置和监测点信息。 + *

+ * + * @param param 检测参数,包含要检测的设备ID列表 + */ public void initList(PreDetectionParam param) { + // 清空现有列表,为新的检测会话做准备 devList.clear(); monitorIdList.clear(); + + // 查询设备详细信息,包含监测点配置 this.devList = iPqDevService.getDevInfo(param.getDevIds()); - this.monitorIdList = devList.stream().flatMap(x -> x.getMonitorList().stream()) + + // 提取所有设备的监测点线路ID + this.monitorIdList = devList.stream() + .flatMap(x -> x.getMonitorList().stream()) .map(PreDetection.MonitorListDTO::getLineId) .collect(Collectors.toList()); + + // 同步更新系数管理器中的设备列表 XiNumberManager.xiDevList = devList; } diff --git a/detection/src/main/java/com/njcn/gather/detection/util/socket/CnSocketUtil.java b/detection/src/main/java/com/njcn/gather/detection/util/socket/CnSocketUtil.java index 12e1d94e..2dc913d9 100644 --- a/detection/src/main/java/com/njcn/gather/detection/util/socket/CnSocketUtil.java +++ b/detection/src/main/java/com/njcn/gather/detection/util/socket/CnSocketUtil.java @@ -37,7 +37,7 @@ public class CnSocketUtil { socketMsg.setRequestId(SourceOperateCodeEnum.QUITE.getValue()); socketMsg.setOperateCode(SourceOperateCodeEnum.QUIT_INIT_03.getValue()); SocketManager.sendMsg(param.getUserPageId() + DEV_TAG, JSON.toJSONString(socketMsg)); - WebServiceManager.removePreDetectionParam(); + WebServiceManager.removePreDetectionParam(param.getUserPageId()); } /** @@ -51,7 +51,7 @@ public class CnSocketUtil { jsonObject.put("sourceId", param.getSourceId()); socketMsg.setData(jsonObject.toJSONString()); SocketManager.sendMsg(param.getUserPageId() + SOURCE_TAG, JSON.toJSONString(socketMsg)); - WebServiceManager.removePreDetectionParam(); + WebServiceManager.removePreDetectionParam(param.getUserPageId()); } @@ -64,7 +64,7 @@ public class CnSocketUtil { socketMsg.setRequestId(SourceOperateCodeEnum.QUITE.getValue()); socketMsg.setOperateCode(SourceOperateCodeEnum.QUIT_INIT_02.getValue()); SocketManager.sendMsg(loginName + CONTRAST_DEV_TAG, JSON.toJSONString(socketMsg)); - WebServiceManager.removePreDetectionParam(); + WebServiceManager.removePreDetectionParam(loginName); FormalTestManager.currentStep=SourceOperateCodeEnum.QUITE; } }