From 9e8b8c5ed751348150f9002d97221032d064687b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=82=E7=B3=96?= Date: Fri, 15 Aug 2025 11:42:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=AB=E7=A0=81=E6=9E=AA=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- klp-ui/src/views/wms/print/scaner.vue | 216 +++++++++++++--- .../components/MergeSourceSelector.vue | 9 +- scaner/src/main/java/org/example/Main.java | 235 +++++++++--------- .../src/main/java/org/example/WsServer.java | 34 +-- 4 files changed, 323 insertions(+), 171 deletions(-) diff --git a/klp-ui/src/views/wms/print/scaner.vue b/klp-ui/src/views/wms/print/scaner.vue index dfee62e5..39835727 100644 --- a/klp-ui/src/views/wms/print/scaner.vue +++ b/klp-ui/src/views/wms/print/scaner.vue @@ -3,11 +3,20 @@

设备列表

+ 刷新 +
+
+ 总设备: {{ deviceStats.totalCount || 0 }} + 活跃设备: {{ deviceStats.activeCount || 0 }}
@@ -123,6 +132,10 @@ export default { data() { return { deviceList: [], + deviceStats: { + totalCount: 0, + activeCount: 0 + }, messageList: [], socket: null, defaultForm: { @@ -141,42 +154,88 @@ export default { this.initSocket(); this.fetchMaster(); }, + beforeDestroy() { + // 组件销毁时关闭WebSocket连接 + if (this.socket) { + this.socket.close(); + } + }, methods: { initSocket() { + // 处理WebSocket连接 this.socket = new WebSocket("ws://localhost:9000/ws"); + this.socket.onopen = () => { console.log("Socket 连接已建立"); }; + this.socket.onmessage = (event) => { - const data = JSON.parse(event.data); - if (data.type === "deviceList") { - console.log(data, '获取设备列表'); - this.deviceList = data.devices; - } else if (data.type === "scanMessage") { - console.log(data, '获取消息'); - this.messageList.push({ - time: new Date().toLocaleString(), - itemId: data.itemId, - itemType: data.itemType, - stockIoId: this.defaultForm.stockIoId, - quantity: this.defaultForm.quantity, - ioType: this.defaultForm.ioType, - warehouseId: this.defaultForm.warehouseId, - batchNo: this.defaultForm.batchNo, - unit: '个' - }); + try { + const data = JSON.parse(event.data); + + // 处理设备列表数据 + if (data.type === "allDevices") { + console.log("获取设备列表", data); + this.deviceList = data.devices || []; + this.deviceStats = { + totalCount: data.totalCount || 0, + activeCount: data.activeCount || 0 + }; + } + // 处理扫描消息 + else if (data.type === "scanMessage") { + console.log("获取扫描消息", data); + this.messageList.push({ + time: new Date().toLocaleString(), + itemId: data.itemId, + itemType: data.itemType, + stockIoId: this.defaultForm.stockIoId, + quantity: this.defaultForm.quantity, + ioType: this.defaultForm.ioType, + warehouseId: this.defaultForm.warehouseId, + batchNo: this.defaultForm.batchNo, + unit: '个' + }); + } + } catch (error) { + console.error("解析WebSocket消息失败", error); } }; + this.socket.onclose = () => { console.log("Socket 连接已关闭"); + // 连接关闭后尝试重连 + setTimeout(() => { + this.initSocket(); + }, 5000); + }; + + this.socket.onerror = (error) => { + console.error("Socket 错误", error); }; }, + + // 刷新设备列表 + refreshDevices() { + if (this.socket && this.socket.readyState === WebSocket.OPEN) { + this.socket.send(JSON.stringify({ type: "refreshDevices" })); + } else { + this.$message.warning("WebSocket连接未建立,无法刷新设备列表"); + // 尝试重新连接 + this.initSocket(); + } + }, + fetchMaster() { listStockIo({ pageSize: 9999, pageNum: 1 }).then(res => { - console.log(res, '获取挂载单据'); - this.masterList = res.rows; + console.log("获取挂载单据", res); + this.masterList = res.rows || []; + }).catch(error => { + console.error("获取挂载单据失败", error); + this.$message.error("获取挂载单据失败"); }); }, + handleDeviceChange(item) { this.socket.send( JSON.stringify({ @@ -185,35 +244,67 @@ export default { }) ); }, + handleBatchConfirm() { // 汇总会导致的库存变更,需要确认 - console.log(this.selectedList, '批量确认'); - this.selectedList.forEach(item => { - console.log(item, 'item'); - }); + console.log("批量确认", this.selectedList); + if (this.selectedList.length === 0) { + this.$message.warning("请选择需要确认的记录"); + return; + } + + // 批量处理逻辑 + Promise.all(this.selectedList.map(item => this.processRecord(item))) + .then(() => { + this.$message.success("批量确认成功"); + // 从列表中移除已确认的项 + this.messageList = this.messageList.filter( + item => !this.selectedList.some(selected => selected.time === item.time) + ); + this.selectedList = []; + }) + .catch(error => { + console.error("批量确认失败", error); + this.$message.error("批量确认失败"); + }); }, + handleSelectionChange(selection) { this.selectedList = selection; }, + handleDelete(row) { this.messageList = this.messageList.filter(item => item.time !== row.time); }, + async handleConfirm(row) { - // 同时做两件事,插入记录,修改库存 - // recordType为1表明记录来源扫码枪 - await this.insertRecord({...row, recordType: 1}) - await this.updateStock(row) - this.handleDelete(row); - this.$message.success('确认成功'); + try { + await this.processRecord(row); + this.handleDelete(row); + this.$message.success('确认成功'); + } catch (error) { + console.error("确认失败", error); + this.$message.error('确认失败'); + } }, + + // 处理单条记录的确认逻辑 + async processRecord(row) { + // 插入记录 + await this.insertRecord({...row, recordType: 1}); + // 更新库存 + await this.updateStock(row); + }, + insertRecord(row) { - return addStockIoDetail(row) + return addStockIoDetail(row); }, + updateStock(row) { if (row.ioType === 'in') { - return scanInStock(row) + return scanInStock(row); } else { - return scanOutStock(row) + return scanOutStock(row); } } }, @@ -249,6 +340,9 @@ export default { border-bottom: 1px solid #ebeef5; background-color: #f8fafc; border-radius: 8px 8px 0 0; + display: flex; + justify-content: space-between; + align-items: center; } .panel-header h3 { @@ -258,6 +352,16 @@ export default { font-weight: 500; } +/* 设备统计信息 */ +.device-stats { + padding: 10px 20px; + border-bottom: 1px solid #ebeef5; + display: flex; + justify-content: space-between; + font-size: 13px; + color: #606266; +} + .device-list { flex: 1; overflow-y: auto; @@ -267,25 +371,57 @@ export default { .device-item { display: flex; - justify-content: space-between; align-items: center; padding: 12px 20px; border-bottom: 1px solid #ebeef5; transition: background-color 0.3s; + cursor: pointer; } .device-item:hover { background-color: #f5f7fa; } -.device-id { - font-weight: 500; - color: #606266; +/* 设备状态指示器 */ +.device-status { + width: 10px; + height: 10px; + border-radius: 50%; + background-color: #ccc; + margin-right: 12px; +} + +.device-status.online { + background-color: #42b983; /* 绿色表示在线 */ +} + +.device-info { + flex: 1; } .device-name { + display: block; + font-weight: 500; + color: #303133; + margin-bottom: 4px; +} + +.device-id { + display: block; + font-size: 12px; + color: #606266; + margin-bottom: 2px; +} + +.device-ip { + display: block; + font-size: 12px; color: #909399; - font-size: 13px; +} + +/* 活跃设备高亮 */ +.device-item.active { + background-color: #f0f9eb; } .form-panel { diff --git a/klp-ui/src/views/wms/work/schedulePlan/components/MergeSourceSelector.vue b/klp-ui/src/views/wms/work/schedulePlan/components/MergeSourceSelector.vue index 64af9ab7..32afc985 100644 --- a/klp-ui/src/views/wms/work/schedulePlan/components/MergeSourceSelector.vue +++ b/klp-ui/src/views/wms/work/schedulePlan/components/MergeSourceSelector.vue @@ -35,9 +35,14 @@ + > +
+ + + 数量: {{ task.taskQuantity }} +
+ diff --git a/scaner/src/main/java/org/example/Main.java b/scaner/src/main/java/org/example/Main.java index 0abe65c5..a77ace6b 100644 --- a/scaner/src/main/java/org/example/Main.java +++ b/scaner/src/main/java/org/example/Main.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; -// Main.java 顶部增加 import org.glassfish.tyrus.server.Server; import MvCodeReaderCtrlWrapper.*; @@ -19,56 +18,83 @@ import java.io.*; public class Main { static Handle hHandle = null; - // 保存设备列表 - private static ArrayList stCamListCache = new ArrayList<>(); + // 保存所有读取到的设备列表 + private static ArrayList allDevices = new ArrayList<>(); - // 获取设备列表JSON(推送给前端) - public static String getDeviceListJson() { + // 保存正在监听的设备列表 + private static ArrayList activeDevices = new ArrayList<>(); + + // 获取所有读取到的设备列表JSON(推送给前端) + public static String getAllDevicesJson() { org.json.JSONObject obj = new org.json.JSONObject(); - obj.put("type", "deviceList"); + obj.put("type", "allDevices"); org.json.JSONArray arr = new org.json.JSONArray(); - for (int i = 0; i < stCamListCache.size(); i++) { - MV_CODEREADER_DEVICE_INFO camInfo = stCamListCache.get(i); -// System.out.println(camInfo.toString() + "设备相信信息"); - System.out.println(camInfo.stGigEInfo.chModelName + camInfo.stGigEInfo.chUserDefinedName + camInfo.stGigEInfo.nCurrentIp + camInfo.stGigEInfo.chSerialNumber + camInfo.stGigEInfo.chDeviceVersion - + camInfo.stGigEInfo.chManufacturerName + camInfo.stGigEInfo.chManufacturerSpecificInfo + camInfo.stGigEInfo.nIpCfgCurrent); + + for (MV_CODEREADER_DEVICE_INFO camInfo : allDevices) { org.json.JSONObject dev = new org.json.JSONObject(); dev.put("id", camInfo.stGigEInfo.chSerialNumber); // 序列号 - dev.put("name", camInfo.stGigEInfo.chUserDefinedName != null ? camInfo.stGigEInfo.chUserDefinedName : camInfo.stGigEInfo.chModelName); - dev.put("type", "scanner"); - dev.put("on", true); // 默认开 + dev.put("name", camInfo.stGigEInfo.chUserDefinedName != null ? + camInfo.stGigEInfo.chUserDefinedName : camInfo.stGigEInfo.chModelName); + dev.put("model", camInfo.stGigEInfo.chModelName); // 型号 + dev.put("manufacturer", camInfo.stGigEInfo.chManufacturerName); // 制造商 + dev.put("ip", getIpAddress(camInfo.stGigEInfo.nCurrentIp)); // IP地址 + dev.put("version", camInfo.stGigEInfo.chDeviceVersion); // 设备版本 + dev.put("isActive", isDeviceActive(camInfo)); // 是否正在监听 arr.put(dev); } + obj.put("devices", arr); + obj.put("totalCount", allDevices.size()); // 设备总数 + obj.put("activeCount", activeDevices.size()); // 活跃设备数 return obj.toString(); } + // 检查设备是否正在监听 + private static boolean isDeviceActive(MV_CODEREADER_DEVICE_INFO device) { + for (MV_CODEREADER_DEVICE_INFO active : activeDevices) { + if (active.stGigEInfo.chSerialNumber.equals(device.stGigEInfo.chSerialNumber)) { + return true; + } + } + return false; + } + + // 将IP整数转换为字符串格式 + private static String getIpAddress(int ipInt) { + return ((ipInt & 0xff000000) >> 24) + "." + + ((ipInt & 0x00ff0000) >> 16) + "." + + ((ipInt & 0x0000ff00) >> 8) + "." + + (ipInt & 0x000000ff); + } + public static void saveDataToFile(byte[] dataToSave, int dataSize, String fileName) { OutputStream os = null; try { - // Create saveImg directory + // 创建保存目录 File tempFile = new File("saveImg"); if (!tempFile.exists()) { tempFile.mkdirs(); } - stCamListCache = MvCodeReaderCtrl.MV_CODEREADER_EnumDevices(); + os = new FileOutputStream("saveImg/" + fileName); os.write(dataToSave, 0, dataSize); - System.out.println("SaveImage succeed."); + System.out.println("图像保存成功: " + fileName); } catch (IOException e) { e.printStackTrace(); } finally { - // Close file stream + // 关闭文件流 try { - os.close(); + if (os != null) { + os.close(); + } } catch (IOException e) { e.printStackTrace(); } } } - // CallBack function + // 回调函数 private static void printImgCBInfo(byte[] pdata, MV_CODEREADER_IMAGE_OUT_INFO_EX2 stOutInfo) { if (null == stOutInfo) { System.out.println("stOutInfo is null"); @@ -77,131 +103,95 @@ public class Main { System.out.print("/**CBpstOutInfo***************************************/\n"); + System.out.print(String.format("获取一帧: nEventID[%d], nChannelID[%d], nWidth[%d], nHeight[%d], nFrameNum[%d], nTriggerIndex[%d], nFrameLen[%d], " + + " nCodeNumber[%d] \r\n", + stOutInfo.nEventID, stOutInfo.nChannelID, stOutInfo.nWidth, stOutInfo.nHeight, stOutInfo.nFrameNum, + stOutInfo.nTriggerIndex, stOutInfo.nFrameLen, stOutInfo.pstCodeListEx.nCodeNum)); - // 示例:扫码时调用POST接口,解析扫码内容并发送JSON - try { - // 假设扫码内容为第一个条码内容 - // String scanStr = null; - // if (stOutInfo != null && stOutInfo.pstCodeListEx != null && stOutInfo.pstCodeListEx.nCodeNum > 0) { - // scanStr = stOutInfo.pstCodeListEx.stBcrInfoEx.get(0).chCode; - // } - // if (scanStr != null && !scanStr.isEmpty()) { - // String json = ScanDataUtil.buildRequestJson( - // scanStr, - // "raw_material", // 物品类型 - // "扫码入库", // 备注 - // null, // 源库位ID - // 1 // 记录类型 - // ); - // System.out.println("json: " + json); - // // 发送两次请求:修改库存并且插入一条记录 - // // 插入记录 - // String postUrl1 = "http://localhost:8080/wms/stockIoDetail"; // TODO: 替换为实际接口 - // String postResponse = HttpRequestUtil.postJson(postUrl1, json); - // System.out.println("POST接口响应: " + postResponse); - // // 修改库存 - // String postUrl2 = "http://localhost:8080/wms/stockIo/scanInStock"; - // String postResponse2 = HttpRequestUtil.postJson(postUrl2, json); - // System.out.println("修改库存POST接口响应: " + postResponse2); - // } else { - // System.out.println("未获取到扫码内容,未发送POST请求"); - // } - } catch (Exception e) { - System.err.println("POST请求失败: " + e.getMessage()); - } + System.out.print("解码状态: bIsGetCode[" + stOutInfo.bIsGetCode + "]\r\n"); - // save buffer to file follow Image Type to Save - // saveDataToFile(pdata, stOutInfo.nFrameLen, "Image.jpg"); - // saveDataToFile(pdata, stOutInfo.nFrameLen, "Image.raw"); + System.out.print("像素类型: MvCodeReaderGvspPixelType[" + stOutInfo.enPixelType + "]\r\n"); - System.out.print(String.format("Get One Frame: nEventID[%d], nChannelID[%d], nWidth[%d], nHeight[%d], nFrameNum[%d], nTriggerIndex[%d], nFrameLen[%d], " - + " nCodeNumber[%d] \r\n", - stOutInfo.nEventID, stOutInfo.nChannelID, stOutInfo.nWidth, stOutInfo.nHeight, stOutInfo.nFrameNum, - stOutInfo.nTriggerIndex, stOutInfo.nFrameLen, stOutInfo.pstCodeListEx.nCodeNum)); - - System.out.print("Get One Code: bIsGetCode[" + stOutInfo.bIsGetCode + "]success\r\n"); - - System.out.print("Get GvspPixelType: MvCodeReaderGvspPixelType[" + stOutInfo.enPixelType + "]success\r\n"); - - // print code info + // 打印解码信息 for (int a = 0; a < stOutInfo.pstCodeListEx.nCodeNum; a++) { org.json.JSONObject obj = new org.json.JSONObject(); obj.put("type", "scanMessage"); // 解析码中的数据,用下划线分割,第一个为物料类型,第二个为物料id String code = stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).chCode; String[] parts = code.split("__"); - String itemType = parts[0]; - String itemId = parts[1]; - obj.put("itemType", itemType); - obj.put("itemId", itemId); + if (parts.length >= 2) { + String itemType = parts[0]; + String itemId = parts[1]; + obj.put("itemType", itemType); + obj.put("itemId", itemId); + } else { + obj.put("rawCode", code); + obj.put("error", "格式不正确"); + } WsServer.broadcast(obj.toString()); - System.out.print(String.format("CodeInfo: TheCodeID[%d], CodeString[%s], nCodeLen[%d], nAngle[%d], nBarType[%d]," - + "sAlgoCost[%d], nIDRScore[%d], n1DIsGetQuality[%d]\r\n", - a, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).chCode, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).nLen, - stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).nAngle, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).nBarType, - stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).sAlgoCost, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).nIDRScore, - stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).n1DIsGetQuality)); - System.out.print(String.format("CodePointInfo: stCornerLeftTop.X[%d], stCornerLeftTop.Y[%d], stCornerRightTop.X[%d], stCornerRightTop.Y[%d]," - + "stCornerRightBottom.X[%d], stCornerRightBottom.Y[%d], stCornerLeftBottom.X[%d], stCornerLeftBottom.Y[%d]\r\n", - stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).stCornerLeftTop.nX, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).stCornerLeftTop.nY, - stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).stCornerRightTop.nX, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).stCornerRightTop.nY, - stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).stCornerRightBottom.nX, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).stCornerRightBottom.nY, - stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).stCornerLeftBottom.nX, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).stCornerLeftBottom.nY)); - - System.out.print("Get CodeQuality: bIsGetQuality[" + stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).bIsGetQuality + "]success\r\n"); + System.out.print(String.format("解码信息: TheCodeID[%d], CodeString[%s], nCodeLen[%d], nAngle[%d], nBarType[%d]," + + "sAlgoCost[%d], nIDRScore[%d], n1DIsGetQuality[%d]\r\n", + a, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).chCode, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).nLen, + stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).nAngle, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).nBarType, + stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).sAlgoCost, stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).nIDRScore, + stOutInfo.pstCodeListEx.stBcrInfoEx.get(a).n1DIsGetQuality)); } } private static void PrintDeviceInfo(MV_CODEREADER_DEVICE_INFO stCamInfo) { if (stCamInfo.nTLayerType == MvCodeReaderCtrlDefine.MV_CODEREADER_GIGE_DEVICE) { - int nIp1 = ((stCamInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24) & 0xff; - int nIp2 = ((stCamInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16); - int nIp3 = ((stCamInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8); - int nIp4 = (stCamInfo.stGigEInfo.nCurrentIp & 0x000000ff); - - System.out.print("CurrentIp: " + nIp1 + "." + nIp2 + "." + nIp3 + "." + nIp4 + "\r\n"); - - System.out.print(String.format("GiGEInfo: UserDefinedName:[%s], chSerialNumber:[%s] \r\n\r\n", - stCamInfo.stGigEInfo.chUserDefinedName, stCamInfo.stGigEInfo.chSerialNumber)); + System.out.print("IP地址: " + getIpAddress(stCamInfo.stGigEInfo.nCurrentIp) + "\r\n"); + System.out.print(String.format("设备信息: 自定义名称:[%s], 序列号:[%s], 型号:[%s] \r\n\r\n", + stCamInfo.stGigEInfo.chUserDefinedName, + stCamInfo.stGigEInfo.chSerialNumber, + stCamInfo.stGigEInfo.chModelName)); } } public static void main(String[] args) throws InterruptedException { - - System.out.print(" ***************Begin****************** \r\n"); + System.out.print(" ***************程序开始****************** \r\n"); String strVersion = MvCodeReaderCtrl.MV_CODEREADER_GetSDKVersion(); - System.out.print("Get version " + strVersion + "\r\n"); + System.out.print("SDK版本: " + strVersion + "\r\n"); - ArrayList stCamList = MvCodeReaderCtrl.MV_CODEREADER_EnumDevices(); - Main.stCamListCache = stCamList; - if (stCamList == null || stCamList.isEmpty()) { - System.out.print("Find No Device!\r\n"); - return; + // 枚举所有设备 + allDevices = MvCodeReaderCtrl.MV_CODEREADER_EnumDevices(); + if (allDevices == null || allDevices.isEmpty()) { + System.out.print("未发现任何设备!\r\n"); + } else { + System.out.print("发现" + allDevices.size() + "个设备:\r\n"); + for (MV_CODEREADER_DEVICE_INFO device : allDevices) { + PrintDeviceInfo(device); + } } ArrayList handleList = new ArrayList<>(); - for (int i = 0; i < stCamList.size(); i++) { - MV_CODEREADER_DEVICE_INFO camInfo = stCamList.get(i); - PrintDeviceInfo(camInfo); + // 尝试打开并启动所有发现的设备 + for (int i = 0; i < allDevices.size(); i++) { + MV_CODEREADER_DEVICE_INFO camInfo = allDevices.get(i); + System.out.print("处理设备 " + i + ": " + camInfo.stGigEInfo.chSerialNumber + "\r\n"); Handle handle = null; try { handle = MvCodeReaderCtrl.MV_CODEREADER_CreateHandle(camInfo); } catch (ParameterException e) { - throw new RuntimeException(e); - } - if (handle == null) { - System.out.print("Create handle failed for device " + i + "!\r\n"); + System.out.print("创建句柄失败: " + e.getMessage() + "\r\n"); continue; } + + if (handle == null) { + System.out.print("创建句柄失败 for device " + i + "!\r\n"); + continue; + } + int nRet = MvCodeReaderCtrl.MV_CODEREADER_OpenDevice(handle); if (nRet != 0) { - System.out.print("Open Device fail for device " + i + "! nRet[" + String.format("0x%x", nRet) + "]\r\n"); + System.out.print("打开设备失败 for device " + i + "! 错误码[" + String.format("0x%x", nRet) + "]\r\n"); continue; } + nRet = MvCodeReaderCtrl.MV_CODEREADER_RegisterImageCallBackEx2(handle, new ImageCallBack() { @Override public int OnImageCallBack(byte[] pdata, MV_CODEREADER_IMAGE_OUT_INFO_EX2 stOutInfo) { @@ -209,32 +199,47 @@ public class Main { return 0; } }); + if (nRet != 0) { - System.out.print("RegisterImageCallBackEx2 Failed for device " + i + "! nRet[" + String.format("0x%x", nRet) + "]\r\n"); + System.out.print("注册回调失败 for device " + i + "! 错误码[" + String.format("0x%x", nRet) + "]\r\n"); + MvCodeReaderCtrl.MV_CODEREADER_CloseDevice(handle); continue; } + nRet = MvCodeReaderCtrl.MV_CODEREADER_StartGrabbing(handle); if (nRet != 0) { - System.out.print("StartGrabbing Failed for device " + i + "! nRet[" + String.format("0x%x", nRet) + "]\r\n"); + System.out.print("启动抓取失败 for device " + i + "! 错误码[" + String.format("0x%x", nRet) + "]\r\n"); + MvCodeReaderCtrl.MV_CODEREADER_CloseDevice(handle); continue; } + + // 如果所有步骤都成功,添加到活跃设备列表 handleList.add(handle); - System.out.print("Device " + i + " startGrabbing success!\r\n"); + activeDevices.add(camInfo); + System.out.print("设备 " + i + " 启动成功,开始监听!\r\n"); } - // 阻塞主线程直到退出 - System.out.println("所有扫码枪已开始监听"); + System.out.println("所有设备处理完毕。活跃设备数量: " + activeDevices.size() + "\r\n"); - // 启动 Socket 服务器 - Server server = new Server("localhost", 9000, "/", null, WsServer.class); + // 启动WebSocket服务器,用于向前端推送设备列表和扫描结果 + Server server = new Server("localhost", 9000, "/", null, WsServer.class); try { server.start(); System.out.println("WebSocket服务器已启动,端口9000"); + System.out.println("按Enter键退出程序..."); System.in.read(); // 阻塞主线程直到回车 } catch (Exception e) { - throw new RuntimeException(e); + System.out.println("WebSocket服务器错误: " + e.getMessage()); + e.printStackTrace(); } finally { + // 停止所有设备 + System.out.println("停止所有设备..."); + for (Handle handle : handleList) { + MvCodeReaderCtrl.MV_CODEREADER_StopGrabbing(handle); + MvCodeReaderCtrl.MV_CODEREADER_CloseDevice(handle); + } server.stop(); + System.out.println("程序已退出"); } } } diff --git a/scaner/src/main/java/org/example/WsServer.java b/scaner/src/main/java/org/example/WsServer.java index 607b7fbc..0cd5de4e 100644 --- a/scaner/src/main/java/org/example/WsServer.java +++ b/scaner/src/main/java/org/example/WsServer.java @@ -9,38 +9,44 @@ import java.io.IOException; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; -@javax.websocket.server.ServerEndpoint("/ws") +@ServerEndpoint("/ws") public class WsServer { - private static final Set sessions = new CopyOnWriteArraySet<>(); + private static final Set sessions = new CopyOnWriteArraySet<>(); - @javax.websocket.OnOpen - public void onOpen(javax.websocket.Session session) { + @OnOpen + public void onOpen(Session session) { sessions.add(session); System.out.println("WebSocket连接已建立: " + session.getId()); - // 推送扫码枪列表给前端 - String deviceListJson = org.example.Main.getDeviceListJson(); + // 推送所有扫码枪列表给前端(使用修改后的方法名) + String deviceListJson = Main.getAllDevicesJson(); try { - System.out.println("发送消息到前端"); + System.out.println("发送设备列表到前端: " + deviceListJson); session.getBasicRemote().sendText(deviceListJson); } catch (IOException e) { e.printStackTrace(); } } - @javax.websocket.OnMessage - public void onMessage(String message, javax.websocket.Session session) throws IOException { + @OnMessage + public void onMessage(String message, Session session) throws IOException { System.out.println("收到消息: " + message); - session.getBasicRemote().sendText("服务器已收到: " + message); + // 可以根据前端需求,在这里处理命令(比如刷新设备列表) + if ("refreshDevices".equals(message)) { + String deviceListJson = Main.getAllDevicesJson(); + session.getBasicRemote().sendText(deviceListJson); + } else { + session.getBasicRemote().sendText("服务器已收到: " + message); + } } - @javax.websocket.OnClose - public void onClose(javax.websocket.Session session) { + @OnClose + public void onClose(Session session) { sessions.remove(session); System.out.println("WebSocket连接已关闭: " + session.getId()); } public static void broadcast(String message) { - for (javax.websocket.Session session : sessions) { + for (Session session : sessions) { if (session.isOpen()) { try { session.getBasicRemote().sendText(message); @@ -50,4 +56,4 @@ public class WsServer { } } } -} \ No newline at end of file +}