diff --git a/WebSocket/BackendClient.py b/WebSocket/BackendClient.py index 31972bd..c1b9f84 100644 --- a/WebSocket/BackendClient.py +++ b/WebSocket/BackendClient.py @@ -31,6 +31,7 @@ class BackendClient: self.success_callback: Optional[Callable] = None # 新增:后端连接成功回调 self.token_error_callback: Optional[Callable] = None # 新增:token错误回调 self.version_callback: Optional[Callable] = None # 新增:版本检查回调 + self.disconnect_callback: Optional[Callable] = None # 新增:被踢下线回调 self.is_connected = False @@ -265,7 +266,8 @@ class BackendClient: login: Callable = None, success: Callable = None, token_error: Callable = None, - version: Callable = None): + version: Callable = None, + disconnect: Callable = None): """设置各种消息类型的回调函数""" if store_list: self.store_list_callback = store_list @@ -287,6 +289,8 @@ class BackendClient: self.token_error_callback = token_error if version: self.version_callback = version + if disconnect: + self.disconnect_callback = disconnect def on_connected(self): """连接成功时的处理""" @@ -443,6 +447,8 @@ class BackendClient: self._handle_staff_list(message) elif msg_type == 'version_response': # 新增:版本检查响应 self._handle_version_response(message) + elif msg_type == 'disconnect': # 新增:被踢下线 + self._handle_disconnect(message) else: print(f"未知消息类型: {msg_type}") @@ -1228,6 +1234,19 @@ class BackendClient: if self.version_callback: self.version_callback(message) + + def _handle_disconnect(self, message: Dict[str, Any]): + """处理被踢下线消息""" + disconnect_message = message.get('message', '您的账号在其他设备登录,当前连接已断开') + + print(f"[断开] 收到后端断开通知: {disconnect_message}") + + # 停止重连机制(不再尝试重连) + self.should_stop = True + + # 触发断开回调 + if self.disconnect_callback: + self.disconnect_callback(disconnect_message) # ==================== 辅助方法 ==================== diff --git a/WebSocket/backend_singleton.py b/WebSocket/backend_singleton.py index 92c324d..e44edcd 100644 --- a/WebSocket/backend_singleton.py +++ b/WebSocket/backend_singleton.py @@ -54,10 +54,11 @@ class WebSocketManager: 'error': None, 'platform_connected': None, 'token_error': None, + 'disconnect': None, # 新增:被踢下线回调 } def set_callbacks(self, log: Callable = None, success: Callable = None, error: Callable = None, - platform_connected: Callable = None, token_error: Callable = None): + platform_connected: Callable = None, token_error: Callable = None, disconnect: Callable = None): """设置回调函数""" if log: self.callbacks['log'] = log @@ -69,6 +70,8 @@ class WebSocketManager: self.callbacks['platform_connected'] = platform_connected if token_error: self.callbacks['token_error'] = token_error + if disconnect: + self.callbacks['disconnect'] = disconnect def _log(self, message: str, level: str = "INFO"): """内部日志方法""" @@ -145,9 +148,14 @@ class WebSocketManager: self._log(f"Token验证失败: {error_content}", "ERROR") if self.callbacks['token_error']: self.callbacks['token_error'](error_content) + + def _on_disconnect(disconnect_msg: str): + self._log(f"被踢下线: {disconnect_msg}", "WARNING") + if self.callbacks['disconnect']: + self.callbacks['disconnect'](disconnect_msg) backend.set_callbacks(success=_on_backend_success, login=_on_backend_login, - token_error=_on_token_error) + token_error=_on_token_error, disconnect=_on_disconnect) if not backend.is_connected: backend.connect() @@ -181,8 +189,14 @@ class WebSocketManager: self._log(f"Token验证失败: {error_content}", "ERROR") if self.callbacks['token_error']: self.callbacks['token_error'](error_content) + + def _on_disconnect(disconnect_msg: str): + self._log(f"被踢下线: {disconnect_msg}", "ERROR") + if self.callbacks['disconnect']: + self.callbacks['disconnect'](disconnect_msg) - backend.set_callbacks(login=_on_backend_login, success=_on_backend_success, token_error=_on_token_error) + backend.set_callbacks(login=_on_backend_login, success=_on_backend_success, + token_error=_on_token_error, disconnect=_on_disconnect) backend.connect() set_backend_client(backend) diff --git a/main.py b/main.py index f2e4f38..f335e1b 100644 --- a/main.py +++ b/main.py @@ -25,6 +25,12 @@ class UpdateSignals(QObject): update_available = pyqtSignal(str, str) # (latest_version, download_url) +# 新增: 断开连接信号类(用于线程安全的通知) +class DisconnectSignals(QObject): + """断开连接信号""" + account_disconnected = pyqtSignal(str) # (disconnect_message) + + # 新增: 用户名密码输入对话框类 class LoginWindow(QMainWindow): def __init__(self): @@ -49,6 +55,10 @@ class LoginWindow(QMainWindow): # 创建版本更新信号对象(线程安全) self.update_signals = UpdateSignals() self.update_signals.update_available.connect(self._show_update_dialog) + + # 创建断开连接信号对象(线程安全) + self.disconnect_signals = DisconnectSignals() + self.disconnect_signals.account_disconnected.connect(self._show_disconnect_dialog) self.initUI() @@ -436,6 +446,78 @@ class LoginWindow(QMainWindow): except Exception as e: self.add_log(f"处理token错误失败: {e}", "ERROR") + + def on_disconnect(self, disconnect_msg: str): + """处理被踢下线通知(可能在子线程中调用)""" + try: + self.add_log(f"⚠️ 收到断开通知: {disconnect_msg}", "WARNING") + # 通过信号发射到主线程(线程安全) + self.disconnect_signals.account_disconnected.emit(disconnect_msg) + except Exception as e: + self.add_log(f"❌ 处理断开通知失败: {e}", "ERROR") + + def _show_disconnect_dialog(self, disconnect_msg: str): + """显示断开连接对话框(信号槽函数,在主线程中执行)""" + try: + self.add_log(f"⚠️ 显示断开连接对话框: {disconnect_msg}", "WARNING") + + # 显示警告对话框 + QMessageBox.warning( + self, + "连接已断开", + f"{disconnect_msg}\n\n请确保用户只在一台设备登录。", + QMessageBox.Ok + ) + + # 断开所有连接 + self._disconnect_all_connections() + + # 重置 UI 状态(返回登录界面) + self._reset_to_login_state() + + self.add_log("✅ 已断开连接,返回登录界面", "INFO") + + except Exception as e: + self.add_log(f"❌ 显示断开对话框失败: {e}", "ERROR") + import traceback + self.add_log(f"详细错误: {traceback.format_exc()}", "ERROR") + + def _disconnect_all_connections(self): + """断开所有连接""" + try: + self.add_log("🔌 正在断开所有连接...", "INFO") + + # 使用 WebSocket 管理器断开所有连接 + from WebSocket.backend_singleton import get_websocket_manager + ws_manager = get_websocket_manager() + ws_manager.disconnect_all() + + self.add_log("✅ 所有连接已断开", "SUCCESS") + + except Exception as e: + self.add_log(f"❌ 断开连接失败: {e}", "ERROR") + + def _reset_to_login_state(self): + """重置到登录状态""" + try: + # 清空已连接平台列表 + self.connected_platforms.clear() + + # 重置状态标签 + self.status_label.setText("等待连接...") + self.status_label.setStyleSheet( + "color: #95a5a6; margin-top: 5px;") + + # 重置按钮状态 + self.login_btn.setEnabled(True) + self.login_btn.setText("重新连接") + self.login_btn.setObjectName("loginButton") # 恢复原始样式 + self.login_btn.setStyleSheet(self.login_btn.styleSheet()) # 刷新样式 + + self.add_log("✅ UI 已重置到登录状态", "DEBUG") + + except Exception as e: + self.add_log(f"❌ 重置 UI 状态失败: {e}", "ERROR") def delayed_platform_summary(self): """定时器触发的汇总显示更新""" @@ -651,7 +733,8 @@ class LoginWindow(QMainWindow): success=lambda: self.add_log("WebSocket连接管理器连接成功", "SUCCESS"), error=lambda error: self.add_log(f"WebSocket连接管理器错误: {error}", "ERROR"), platform_connected=self.on_platform_connected, # 新增:平台连接回调 - token_error=self.on_token_error # 新增:token错误回调 + token_error=self.on_token_error, # 新增:token错误回调 + disconnect=self.on_disconnect # 新增:被踢下线回调 ) # 连接后端