[patch] 修改逻辑: 在用户误触或开了多个GUI程序的时候不能同时建立多个连接 确保一个账号只能建立一个与后端的连接 友好提示的集成review
This commit is contained in:
@@ -31,6 +31,7 @@ class BackendClient:
|
|||||||
self.success_callback: Optional[Callable] = None # 新增:后端连接成功回调
|
self.success_callback: Optional[Callable] = None # 新增:后端连接成功回调
|
||||||
self.token_error_callback: Optional[Callable] = None # 新增:token错误回调
|
self.token_error_callback: Optional[Callable] = None # 新增:token错误回调
|
||||||
self.version_callback: Optional[Callable] = None # 新增:版本检查回调
|
self.version_callback: Optional[Callable] = None # 新增:版本检查回调
|
||||||
|
self.disconnect_callback: Optional[Callable] = None # 新增:被踢下线回调
|
||||||
|
|
||||||
self.is_connected = False
|
self.is_connected = False
|
||||||
|
|
||||||
@@ -265,7 +266,8 @@ class BackendClient:
|
|||||||
login: Callable = None,
|
login: Callable = None,
|
||||||
success: Callable = None,
|
success: Callable = None,
|
||||||
token_error: Callable = None,
|
token_error: Callable = None,
|
||||||
version: Callable = None):
|
version: Callable = None,
|
||||||
|
disconnect: Callable = None):
|
||||||
"""设置各种消息类型的回调函数"""
|
"""设置各种消息类型的回调函数"""
|
||||||
if store_list:
|
if store_list:
|
||||||
self.store_list_callback = store_list
|
self.store_list_callback = store_list
|
||||||
@@ -287,6 +289,8 @@ class BackendClient:
|
|||||||
self.token_error_callback = token_error
|
self.token_error_callback = token_error
|
||||||
if version:
|
if version:
|
||||||
self.version_callback = version
|
self.version_callback = version
|
||||||
|
if disconnect:
|
||||||
|
self.disconnect_callback = disconnect
|
||||||
|
|
||||||
def on_connected(self):
|
def on_connected(self):
|
||||||
"""连接成功时的处理"""
|
"""连接成功时的处理"""
|
||||||
@@ -443,6 +447,8 @@ class BackendClient:
|
|||||||
self._handle_staff_list(message)
|
self._handle_staff_list(message)
|
||||||
elif msg_type == 'version_response': # 新增:版本检查响应
|
elif msg_type == 'version_response': # 新增:版本检查响应
|
||||||
self._handle_version_response(message)
|
self._handle_version_response(message)
|
||||||
|
elif msg_type == 'disconnect': # 新增:被踢下线
|
||||||
|
self._handle_disconnect(message)
|
||||||
else:
|
else:
|
||||||
print(f"未知消息类型: {msg_type}")
|
print(f"未知消息类型: {msg_type}")
|
||||||
|
|
||||||
@@ -1229,6 +1235,19 @@ class BackendClient:
|
|||||||
if self.version_callback:
|
if self.version_callback:
|
||||||
self.version_callback(message)
|
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)
|
||||||
|
|
||||||
# ==================== 辅助方法 ====================
|
# ==================== 辅助方法 ====================
|
||||||
|
|
||||||
def set_token(self, token: str):
|
def set_token(self, token: str):
|
||||||
|
|||||||
@@ -54,10 +54,11 @@ class WebSocketManager:
|
|||||||
'error': None,
|
'error': None,
|
||||||
'platform_connected': None,
|
'platform_connected': None,
|
||||||
'token_error': None,
|
'token_error': None,
|
||||||
|
'disconnect': None, # 新增:被踢下线回调
|
||||||
}
|
}
|
||||||
|
|
||||||
def set_callbacks(self, log: Callable = None, success: Callable = None, error: Callable = 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:
|
if log:
|
||||||
self.callbacks['log'] = log
|
self.callbacks['log'] = log
|
||||||
@@ -69,6 +70,8 @@ class WebSocketManager:
|
|||||||
self.callbacks['platform_connected'] = platform_connected
|
self.callbacks['platform_connected'] = platform_connected
|
||||||
if token_error:
|
if token_error:
|
||||||
self.callbacks['token_error'] = token_error
|
self.callbacks['token_error'] = token_error
|
||||||
|
if disconnect:
|
||||||
|
self.callbacks['disconnect'] = disconnect
|
||||||
|
|
||||||
def _log(self, message: str, level: str = "INFO"):
|
def _log(self, message: str, level: str = "INFO"):
|
||||||
"""内部日志方法"""
|
"""内部日志方法"""
|
||||||
@@ -146,8 +149,13 @@ class WebSocketManager:
|
|||||||
if self.callbacks['token_error']:
|
if self.callbacks['token_error']:
|
||||||
self.callbacks['token_error'](error_content)
|
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,
|
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:
|
if not backend.is_connected:
|
||||||
backend.connect()
|
backend.connect()
|
||||||
@@ -182,7 +190,13 @@ class WebSocketManager:
|
|||||||
if self.callbacks['token_error']:
|
if self.callbacks['token_error']:
|
||||||
self.callbacks['token_error'](error_content)
|
self.callbacks['token_error'](error_content)
|
||||||
|
|
||||||
backend.set_callbacks(login=_on_backend_login, success=_on_backend_success, token_error=_on_token_error)
|
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, disconnect=_on_disconnect)
|
||||||
backend.connect()
|
backend.connect()
|
||||||
|
|
||||||
set_backend_client(backend)
|
set_backend_client(backend)
|
||||||
|
|||||||
268
config.py
268
config.py
@@ -1,135 +1,135 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
项目配置文件
|
项目配置文件
|
||||||
统一管理所有配置参数,避免硬编码
|
统一管理所有配置参数,避免硬编码
|
||||||
"""
|
"""
|
||||||
# 用户访问令牌(默认空字符串)
|
# 用户访问令牌(默认空字符串)
|
||||||
import os # 用于路径与目录操作(写入用户配置目录)
|
import os # 用于路径与目录操作(写入用户配置目录)
|
||||||
import json # 用于将令牌保存为 JSON 格式
|
import json # 用于将令牌保存为 JSON 格式
|
||||||
|
|
||||||
# 后端服务器配置
|
# 后端服务器配置
|
||||||
# BACKEND_HOST = "192.168.5.233"
|
# BACKEND_HOST = "192.168.5.233"
|
||||||
BACKEND_HOST = "192.168.5.12"
|
BACKEND_HOST = "192.168.5.12"
|
||||||
# BACKEND_HOST = "shuidrop.com"
|
# BACKEND_HOST = "shuidrop.com"
|
||||||
# BACKEND_HOST = "test.shuidrop.com"
|
# BACKEND_HOST = "test.shuidrop.com"
|
||||||
BACKEND_PORT = "8000"
|
BACKEND_PORT = "8000"
|
||||||
# BACKEND_PORT = ""
|
# BACKEND_PORT = ""
|
||||||
BACKEND_WS_URL = f"ws://{BACKEND_HOST}:{BACKEND_PORT}"
|
BACKEND_WS_URL = f"ws://{BACKEND_HOST}:{BACKEND_PORT}"
|
||||||
# BACKEND_WS_URL = f"wss://{BACKEND_HOST}"
|
# BACKEND_WS_URL = f"wss://{BACKEND_HOST}"
|
||||||
|
|
||||||
# WebSocket配置
|
# WebSocket配置
|
||||||
WS_CONNECT_TIMEOUT = 16.0
|
WS_CONNECT_TIMEOUT = 16.0
|
||||||
WS_MESSAGE_TIMEOUT = 30.0
|
WS_MESSAGE_TIMEOUT = 30.0
|
||||||
WS_PING_INTERVAL = 10 # 10秒ping间隔(提高检测频率)
|
WS_PING_INTERVAL = 10 # 10秒ping间隔(提高检测频率)
|
||||||
WS_PING_TIMEOUT = 5 # 5秒ping超时(更快检测断线)
|
WS_PING_TIMEOUT = 5 # 5秒ping超时(更快检测断线)
|
||||||
WS_ENABLE_PING = True # 是否启用WebSocket原生ping心跳
|
WS_ENABLE_PING = True # 是否启用WebSocket原生ping心跳
|
||||||
WS_ENABLE_APP_PING = False # 禁用应用层ping心跳(避免重复)
|
WS_ENABLE_APP_PING = False # 禁用应用层ping心跳(避免重复)
|
||||||
|
|
||||||
# AI处理超时配置
|
# AI处理超时配置
|
||||||
AI_PROCESS_TIMEOUT = 30 # AI处理超时时间(秒)
|
AI_PROCESS_TIMEOUT = 30 # AI处理超时时间(秒)
|
||||||
AI_LONG_PROCESS_THRESHOLD = 10 # AI长时间处理阈值(秒)
|
AI_LONG_PROCESS_THRESHOLD = 10 # AI长时间处理阈值(秒)
|
||||||
|
|
||||||
# 内存管理配置
|
# 内存管理配置
|
||||||
MAX_PENDING_REPLIES = 100
|
MAX_PENDING_REPLIES = 100
|
||||||
CLEANUP_INTERVAL = 300 # 5分钟
|
CLEANUP_INTERVAL = 300 # 5分钟
|
||||||
FUTURE_TIMEOUT = 300 # 5分钟
|
FUTURE_TIMEOUT = 300 # 5分钟
|
||||||
|
|
||||||
# 终端日志配置(简化)
|
# 终端日志配置(简化)
|
||||||
LOG_LEVEL = "INFO"
|
LOG_LEVEL = "INFO"
|
||||||
VERSION = "1.0"
|
VERSION = "1.0"
|
||||||
|
|
||||||
# GUI配置
|
# GUI配置
|
||||||
WINDOW_TITLE = "AI回复连接入口-V1.0"
|
WINDOW_TITLE = "AI回复连接入口-V1.0"
|
||||||
|
|
||||||
# 应用版本号(用于版本检查)
|
# 应用版本号(用于版本检查)
|
||||||
APP_VERSION = "1.5.13"
|
APP_VERSION = "1.5.13"
|
||||||
|
|
||||||
# 平台特定配置
|
# 平台特定配置
|
||||||
PLATFORMS = {
|
PLATFORMS = {
|
||||||
"JD": {
|
"JD": {
|
||||||
"name": "京东",
|
"name": "京东",
|
||||||
"ws_url": "wss://dongdong.jd.com/workbench/websocket"
|
"ws_url": "wss://dongdong.jd.com/workbench/websocket"
|
||||||
},
|
},
|
||||||
"DOUYIN": {
|
"DOUYIN": {
|
||||||
"name": "抖音",
|
"name": "抖音",
|
||||||
"ws_url": None # 动态获取
|
"ws_url": None # 动态获取
|
||||||
},
|
},
|
||||||
"QIANNIU": {
|
"QIANNIU": {
|
||||||
"name": "千牛(淘宝)",
|
"name": "千牛(淘宝)",
|
||||||
"ws_url": "ws://127.0.0.1:3030"
|
"ws_url": "ws://127.0.0.1:3030"
|
||||||
},
|
},
|
||||||
"PDD": {
|
"PDD": {
|
||||||
"name": "拼多多",
|
"name": "拼多多",
|
||||||
"ws_url": None # 动态获取
|
"ws_url": None # 动态获取
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_backend_ws_url(platform: str, store_id: str) -> str:
|
def get_backend_ws_url(platform: str, store_id: str) -> str:
|
||||||
"""获取旧版后端WebSocket URL(按店铺建连接,保留兼容)"""
|
"""获取旧版后端WebSocket URL(按店铺建连接,保留兼容)"""
|
||||||
return f"{BACKEND_WS_URL}/ws/platform/{platform.lower()}/{store_id}/"
|
return f"{BACKEND_WS_URL}/ws/platform/{platform.lower()}/{store_id}/"
|
||||||
|
|
||||||
def get_gui_ws_url(exe_token: str) -> str:
|
def get_gui_ws_url(exe_token: str) -> str:
|
||||||
"""获取新版单连接GUI专用WebSocket URL(按用户token建一条连接)"""
|
"""获取新版单连接GUI专用WebSocket URL(按用户token建一条连接)"""
|
||||||
return f"{BACKEND_WS_URL}/ws/gui/{exe_token}/"
|
return f"{BACKEND_WS_URL}/ws/gui/{exe_token}/"
|
||||||
|
|
||||||
def get_config():
|
def get_config():
|
||||||
"""获取所有配置"""
|
"""获取所有配置"""
|
||||||
return {
|
return {
|
||||||
'backend_host': BACKEND_HOST,
|
'backend_host': BACKEND_HOST,
|
||||||
'backend_port': BACKEND_PORT,
|
'backend_port': BACKEND_PORT,
|
||||||
'backend_ws_url': BACKEND_WS_URL,
|
'backend_ws_url': BACKEND_WS_URL,
|
||||||
'ws_connect_timeout': WS_CONNECT_TIMEOUT,
|
'ws_connect_timeout': WS_CONNECT_TIMEOUT,
|
||||||
'ws_message_timeout': WS_MESSAGE_TIMEOUT,
|
'ws_message_timeout': WS_MESSAGE_TIMEOUT,
|
||||||
'max_pending_replies': MAX_PENDING_REPLIES,
|
'max_pending_replies': MAX_PENDING_REPLIES,
|
||||||
'cleanup_interval': CLEANUP_INTERVAL,
|
'cleanup_interval': CLEANUP_INTERVAL,
|
||||||
'platforms': PLATFORMS
|
'platforms': PLATFORMS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
APP_NAME = "ShuidropGUI" # 应用名称(作为配置目录名)
|
APP_NAME = "ShuidropGUI" # 应用名称(作为配置目录名)
|
||||||
|
|
||||||
API_TOKEN = 'sd_acF0TisgfFOtsBm4ytqb17MQbcxuX9Vp' # 默认回退令牌(仅当未找到外部配置时使用)
|
API_TOKEN = 'sd_acF0TisgfFOtsBm4ytqb17MQbcxuX9Vp' # 默认回退令牌(仅当未找到外部配置时使用)
|
||||||
|
|
||||||
def _get_config_paths():
|
def _get_config_paths():
|
||||||
"""返回(配置目录, 配置文件路径),位于 %APPDATA%/ShuidropGUI/config.json"""
|
"""返回(配置目录, 配置文件路径),位于 %APPDATA%/ShuidropGUI/config.json"""
|
||||||
base_dir = os.getenv('APPDATA') or os.path.expanduser('~') # 优先使用 APPDATA,其次使用用户主目录
|
base_dir = os.getenv('APPDATA') or os.path.expanduser('~') # 优先使用 APPDATA,其次使用用户主目录
|
||||||
cfg_dir = os.path.join(base_dir, APP_NAME) # 组合配置目录路径
|
cfg_dir = os.path.join(base_dir, APP_NAME) # 组合配置目录路径
|
||||||
cfg_file = os.path.join(cfg_dir, 'config.json') # 组合配置文件路径
|
cfg_file = os.path.join(cfg_dir, 'config.json') # 组合配置文件路径
|
||||||
return cfg_dir, cfg_file
|
return cfg_dir, cfg_file
|
||||||
|
|
||||||
|
|
||||||
def get_saved_token() -> str:
|
def get_saved_token() -> str:
|
||||||
"""优先从外部 JSON 配置读取令牌,不存在时回退到内置 API_TOKEN"""
|
"""优先从外部 JSON 配置读取令牌,不存在时回退到内置 API_TOKEN"""
|
||||||
try:
|
try:
|
||||||
cfg_dir, cfg_file = _get_config_paths() # 获取目录与文件路径
|
cfg_dir, cfg_file = _get_config_paths() # 获取目录与文件路径
|
||||||
if os.path.exists(cfg_file): # 如果配置文件存在
|
if os.path.exists(cfg_file): # 如果配置文件存在
|
||||||
with open(cfg_file, 'r', encoding='utf-8') as f: # 以 UTF-8 读取
|
with open(cfg_file, 'r', encoding='utf-8') as f: # 以 UTF-8 读取
|
||||||
data = json.load(f) # 解析 JSON 内容
|
data = json.load(f) # 解析 JSON 内容
|
||||||
token = data.get('token', '') # 读取 token 字段
|
token = data.get('token', '') # 读取 token 字段
|
||||||
if token: # 如果有效
|
if token: # 如果有效
|
||||||
return token # 返回读取到的令牌
|
return token # 返回读取到的令牌
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # 读取失败时静默回退
|
pass # 读取失败时静默回退
|
||||||
return API_TOKEN # 回退为内置的默认值
|
return API_TOKEN # 回退为内置的默认值
|
||||||
|
|
||||||
|
|
||||||
def set_saved_token(new_token: str) -> bool:
|
def set_saved_token(new_token: str) -> bool:
|
||||||
"""将访问令牌写入外部 JSON 配置,并更新内存中的值
|
"""将访问令牌写入外部 JSON 配置,并更新内存中的值
|
||||||
- new_token: 新的访问令牌字符串
|
- new_token: 新的访问令牌字符串
|
||||||
返回: True 表示写入成功,False 表示失败
|
返回: True 表示写入成功,False 表示失败
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
cfg_dir, cfg_file = _get_config_paths()
|
cfg_dir, cfg_file = _get_config_paths()
|
||||||
os.makedirs(cfg_dir, exist_ok=True)
|
os.makedirs(cfg_dir, exist_ok=True)
|
||||||
data = {'token': new_token}
|
data = {'token': new_token}
|
||||||
with open(cfg_file, 'w', encoding='utf-8') as f:
|
with open(cfg_file, 'w', encoding='utf-8') as f:
|
||||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||||
# 同步更新内存变量,保证运行期可立即生效
|
# 同步更新内存变量,保证运行期可立即生效
|
||||||
global API_TOKEN
|
global API_TOKEN
|
||||||
API_TOKEN = new_token
|
API_TOKEN = new_token
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# 发生异常时打印提示并返回失败
|
# 发生异常时打印提示并返回失败
|
||||||
print(f"写入令牌失败: {e}")
|
print(f"写入令牌失败: {e}")
|
||||||
return False
|
return False
|
||||||
61
main.py
61
main.py
@@ -25,6 +25,12 @@ class UpdateSignals(QObject):
|
|||||||
update_available = pyqtSignal(str, str) # (latest_version, download_url)
|
update_available = pyqtSignal(str, str) # (latest_version, download_url)
|
||||||
|
|
||||||
|
|
||||||
|
# 新增: 断开连接信号类(用于线程安全的断开提示)
|
||||||
|
class DisconnectSignals(QObject):
|
||||||
|
"""断开连接信号"""
|
||||||
|
disconnected = pyqtSignal(str) # (disconnect_message)
|
||||||
|
|
||||||
|
|
||||||
# 新增: 用户名密码输入对话框类
|
# 新增: 用户名密码输入对话框类
|
||||||
class LoginWindow(QMainWindow):
|
class LoginWindow(QMainWindow):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -50,6 +56,10 @@ class LoginWindow(QMainWindow):
|
|||||||
self.update_signals = UpdateSignals()
|
self.update_signals = UpdateSignals()
|
||||||
self.update_signals.update_available.connect(self._show_update_dialog)
|
self.update_signals.update_available.connect(self._show_update_dialog)
|
||||||
|
|
||||||
|
# 创建断开连接信号对象(线程安全)
|
||||||
|
self.disconnect_signals = DisconnectSignals()
|
||||||
|
self.disconnect_signals.disconnected.connect(self._show_disconnect_dialog)
|
||||||
|
|
||||||
self.initUI()
|
self.initUI()
|
||||||
|
|
||||||
# 延迟设置版本检查器,确保WebSocket连接已建立
|
# 延迟设置版本检查器,确保WebSocket连接已建立
|
||||||
@@ -437,6 +447,54 @@ class LoginWindow(QMainWindow):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.add_log(f"处理token错误失败: {e}", "ERROR")
|
self.add_log(f"处理token错误失败: {e}", "ERROR")
|
||||||
|
|
||||||
|
def on_disconnect(self, disconnect_msg: str):
|
||||||
|
"""处理被踢下线 - 发射信号到主线程(可在任何线程中调用)"""
|
||||||
|
try:
|
||||||
|
self.add_log(f"📡 收到断开通知,准备发射信号: {disconnect_msg}", "INFO")
|
||||||
|
# 发射信号(Qt 自动调度到主线程)
|
||||||
|
self.disconnect_signals.disconnected.emit(disconnect_msg)
|
||||||
|
self.add_log(f"✅ 断开信号已发射", "DEBUG")
|
||||||
|
except Exception as e:
|
||||||
|
self.add_log(f"❌ 发射断开信号失败: {e}", "ERROR")
|
||||||
|
import traceback
|
||||||
|
self.add_log(f"详细错误: {traceback.format_exc()}", "ERROR")
|
||||||
|
|
||||||
|
def _show_disconnect_dialog(self, disconnect_msg: str):
|
||||||
|
"""显示断开连接提示框(信号槽函数,始终在主线程中执行)"""
|
||||||
|
try:
|
||||||
|
self.add_log(f"🎯 主线程收到断开信号: {disconnect_msg}", "INFO")
|
||||||
|
|
||||||
|
# 在状态标签显示警告信息
|
||||||
|
self.status_label.setText(f"⚠️ 账号在其他设备登录")
|
||||||
|
self.status_label.setStyleSheet(
|
||||||
|
"color: #ff9800; background: rgba(255, 152, 0, 0.1); border-radius: 12px; padding: 5px 10px; font-weight: bold;")
|
||||||
|
|
||||||
|
# 重置按钮状态
|
||||||
|
self.login_btn.setEnabled(True)
|
||||||
|
self.login_btn.setText("重新连接")
|
||||||
|
self.login_btn.setObjectName("loginButton") # 恢复原始样式
|
||||||
|
self.login_btn.setStyleSheet(self.login_btn.styleSheet()) # 刷新样式
|
||||||
|
|
||||||
|
# 清空已连接平台列表
|
||||||
|
self.connected_platforms.clear()
|
||||||
|
|
||||||
|
# 显示友好的提示对话框(主线程中执行,不会卡顿)
|
||||||
|
QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
"连接已断开",
|
||||||
|
f"{disconnect_msg}\n\n"
|
||||||
|
"如果是您本人在其他设备登录,可以忽略此提示。\n"
|
||||||
|
"如需继续使用,请点击\"重新连接\"按钮。",
|
||||||
|
QMessageBox.Ok
|
||||||
|
)
|
||||||
|
|
||||||
|
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 delayed_platform_summary(self):
|
def delayed_platform_summary(self):
|
||||||
"""定时器触发的汇总显示更新"""
|
"""定时器触发的汇总显示更新"""
|
||||||
try:
|
try:
|
||||||
@@ -651,7 +709,8 @@ class LoginWindow(QMainWindow):
|
|||||||
success=lambda: self.add_log("WebSocket连接管理器连接成功", "SUCCESS"),
|
success=lambda: self.add_log("WebSocket连接管理器连接成功", "SUCCESS"),
|
||||||
error=lambda error: self.add_log(f"WebSocket连接管理器错误: {error}", "ERROR"),
|
error=lambda error: self.add_log(f"WebSocket连接管理器错误: {error}", "ERROR"),
|
||||||
platform_connected=self.on_platform_connected, # 新增:平台连接回调
|
platform_connected=self.on_platform_connected, # 新增:平台连接回调
|
||||||
token_error=self.on_token_error # 新增:token错误回调
|
token_error=self.on_token_error, # 新增:token错误回调
|
||||||
|
disconnect=self.on_disconnect # 新增:被踢下线回调
|
||||||
)
|
)
|
||||||
|
|
||||||
# 连接后端
|
# 连接后端
|
||||||
|
|||||||
Reference in New Issue
Block a user