import { ElMessage } from 'element-plus'; // 定义扫描动作类型 type ScanAction = 'connectMessage' | 'getScannerList' | 'scanResult' | string; // 定义接收到的消息结构 interface ScanMessage { code: number; action?: ScanAction; data?: any; message?: string; param?: any; // 扩展参数,用于传递额外信息 } // 定义回调函数类型 type ScanCallback = (data: ScanMessage) => void; type ConnectionCallback = (isOnline: boolean,clientVersion: string) => void; class ScanCommonService { // 扫描客户端WebSocket 服务器地址 private url: string = 'ws://127.0.0.1:9999'; // 扫描端口9999 图片服务端口9998 // WebSocket 实例 private ws: WebSocket | null = null; // 当前客户端连接状态 public isOnline: boolean = false; public isScanned: boolean = false; // 是否有扫描仪 是否可以扫描 public clientVersion: string = '1.0.0'; // 客户端版本号 // 心跳定时器 private timerPing: number | null = null; private timerClose: number | null = null; private connectionInterval: number | null = null; // 监听连接状态变化的定时器 // 心跳间隔时间(单位:毫秒) private intervalPing: number = 10000; // 每隔10秒发送一次ping private intervalClose: number = 5000; // 等待5秒未收到pong则判定断开 private isManuallyStopped: boolean = false; // 是否手动停止,防止重复连接 private scanCallback: ScanCallback | null = null;//传入的回调函数 /** * 初始化 WebSocket 连接 * @param callback - 接收扫描结果的回调函数 */ init(callback?: ScanCallback): void { if (callback) { this.scanCallback = callback; } // 如果已经连接且未手动停止,不重复初始化 if (this.ws && this.ws.readyState === WebSocket.OPEN && !this.isManuallyStopped) { return; } // 重置手动停止标志,允许重连 this.isManuallyStopped = false; try { this.ws = new WebSocket(this.url); } catch (error) { console.error('WebSocket 初始化失败:', error); ElMessage({ type: 'error', message: '无法初始化 WebSocket 连接,请检查网络设置', duration: 5000 }); return; } /** * WebSocket 连接建立成功时触发 */ this.ws.onopen = () => { this.isOnline = true; // 发送连接成功消息 const sendConnectMsg = () => { if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.ws.send("client connect success"); } }; sendConnectMsg(); // 兜底延迟发送,防止某些极端情况下的就绪延迟 setTimeout(sendConnectMsg, 500); this.startHeartbeat(); // 启动心跳检测 }; /** * 接收到服务端消息时触发 */ this.ws.onmessage = (evt: MessageEvent) => { if (evt.data != null) { if (evt.data === "ping") { this.send("pong"); // 回复 pong } else if (evt.data === "pong") { // 收到 pong 不做处理,仅用于重置心跳 } else { try { const objectData: ScanMessage = JSON.parse(evt.data); console.log("处理扫描结果的objectData:", objectData); if (objectData.code === 200) { if (objectData.action === 'connectMessage') { this.clientVersion = objectData.param.appVersion || ''; const version = objectData.param.appVersion || '未知版本'; ElMessage({ type: 'success', message: `客户端连接成功……版本号:${version}` }); } else if (objectData.action === 'getScannerList') { // 获取扫描仪结果 if (objectData.data && Array.isArray(objectData.data) && objectData.data.length > 0) { // 有扫描仪连接 this.isScanned = true; ElMessage({ type: 'success', message: '扫描仪连接成功……' }); } else { // 没有扫描仪连接 this.isScanned = false; } } else { // 其他业务数据回调 if (this.scanCallback) this.scanCallback(objectData); } } else { // 未检测到纸张或卡纸 console.log("未检测到纸张或者卡纸:", callback); if (this.scanCallback) { this.scanCallback(objectData); } else { ElMessage({ type: 'error', message: '未检测到纸张或者卡纸' }); } } } catch (error) { console.error("解析消息失败:", error); } } } this.resetHeartbeat(); // 重置心跳 }; /** * WebSocket 连接关闭时触发 */ this.ws.onclose = () => { this.handleOffline(); }; /** * WebSocket 发生错误时触发 */ this.ws.onerror = () => { this.isOnline = false; if (this.ws) { this.ws.close(); } }; } /** * 发送消息给 WebSocket 服务端 * @param data - 要发送的消息内容 */ send(data: string): void { if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { // 静默失败或根据需要提示 return; } try { this.ws.send(data); } catch (e) { console.error("发送数据失败:", e); ElMessage({ type: 'error', message: '发送数据失败,请检查连接状态', duration: 5000 }); } } /** * 启动心跳机制 */ private startHeartbeat(): void { this.clearHeartbeatTimers(); this.timerPing = window.setTimeout(() => { if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.send("ping"); // 发送心跳 ping this.timerClose = window.setTimeout(() => { if (this.ws) { this.ws.close(); // 若长时间无响应,主动断开连接 } this.isOnline = false; this.handleOffline(); // 处理离线逻辑 }, this.intervalClose); } }, this.intervalPing); } /** * 清除心跳定时器 */ private clearHeartbeatTimers(): void { if (this.timerPing) { clearTimeout(this.timerPing); this.timerPing = null; } if (this.timerClose) { clearTimeout(this.timerClose); this.timerClose = null; } } /** * 重置心跳定时器 */ private resetHeartbeat(): void { this.clearHeartbeatTimers(); this.startHeartbeat(); // 重新启动心跳 } /** * 停止 WebSocket 连接并清除所有定时器 */ stop(): void { // 标记为手动停止,防止后续自动重连 this.isManuallyStopped = true; // 清除心跳定时器 this.clearHeartbeatTimers(); // 清除连接状态监听定时器 this.stopWatchingConnection(); // 关闭 WebSocket 连接 if (this.ws) { // 移除事件监听,防止触发 handleOffline 导致重连 this.ws.onclose = null; this.ws.onerror = null; this.ws.onmessage = null; this.ws.onopen = null; if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) { this.ws.close(); } this.ws = null; } // 重置连接状态 this.isOnline = false; this.isScanned = false; } /** * 处理设备离线逻辑,尝试自动重连 */ private handleOffline(): void { this.isOnline = false; // 如果是手动停止,则不再尝试重连 if (this.isManuallyStopped) { return; } // 延迟尝试重连 setTimeout(() => { if (!this.isOnline && !this.isManuallyStopped) { this.init(); // 重新初始化连接 } }, this.intervalClose * 2); } /** * 检查客户端是否已连接 * @returns {boolean} */ isClientConnected(): boolean { return this.ws !== null && this.ws.readyState === WebSocket.OPEN; } /** * 监听连接状态变化 * @param callback - 回调函数,接收 isOnline 布尔值参数 */ watchConnection(callback: ConnectionCallback): void { if (this.connectionInterval) { clearInterval(this.connectionInterval); // 防止重复启动 } const checkStatus = () => { const isOnline = this.isClientConnected(); // 调用检测扫描仪指令 if (isOnline) { if (!this.isScanned) { // 没有扫描仪连接 实时发送指令获取状态 const json = { action: 'getScannerList', // 获取扫描仪信息 }; this.ws?.send(JSON.stringify(json)); } callback(true,this.clientVersion); // 告诉网页 客户端打开状态 } else { callback(false,this.clientVersion); // 告诉网页 连接已经断开 } }; checkStatus(); // 立即执行一次 this.connectionInterval = window.setInterval(checkStatus, 3000); // 每3秒检测一次 } /** * 停止监听连接状态 */ stopWatchingConnection(): void { if (this.connectionInterval) { clearInterval(this.connectionInterval); this.connectionInterval = null; } } } // 导出单例 const scanCommon = new ScanCommonService(); export default scanCommon;