| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- 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;
|