[patch] 新增用户余额不足 交互模式代码

This commit is contained in:
2025-10-17 17:38:02 +08:00
parent a5c2a44512
commit 8eb03ddedc
4 changed files with 225 additions and 77 deletions

View File

@@ -32,6 +32,7 @@ class BackendClient:
self.token_error_callback: Optional[Callable] = None # 新增token错误回调
self.version_callback: Optional[Callable] = None # 新增:版本检查回调
self.disconnect_callback: Optional[Callable] = None # 新增:被踢下线回调
self.balance_insufficient_callback: Optional[Callable] = None # 新增:余额不足回调
self.log_callback: Optional[Callable] = None # 新增:日志回调
self.is_connected = False
@@ -52,7 +53,7 @@ class BackendClient:
"""Unified logging method that works in both dev and packaged environments"""
# Always print to console (visible in dev mode)
print(f"[{level}] {message}")
# Also call the log callback if available (for file logging)
if self.log_callback:
try:
@@ -130,10 +131,10 @@ class BackendClient:
self._log("已禁用心跳机制", "WARNING")
self.is_connected = True
# 🔥 在重置之前记录是否是重连(用于后续上报平台状态)
was_reconnecting = self.reconnect_attempts > 0
self.reconnect_attempts = 0 # 重置重连计数
self.is_reconnecting = False
self._log("后端WebSocket连接成功", "SUCCESS")
@@ -285,6 +286,7 @@ class BackendClient:
token_error: Callable = None,
version: Callable = None,
disconnect: Callable = None,
balance_insufficient: Callable = None,
log: Callable = None):
"""设置各种消息类型的回调函数"""
if store_list:
@@ -309,6 +311,8 @@ class BackendClient:
self.version_callback = version
if disconnect:
self.disconnect_callback = disconnect
if balance_insufficient:
self.balance_insufficient_callback = balance_insufficient
if log:
self.log_callback = log
@@ -333,11 +337,11 @@ class BackendClient:
if hasattr(manager, 'platform_listeners') and manager.platform_listeners:
platform_count = len(manager.platform_listeners)
self._log(f"🔄 检测到 {platform_count} 个活跃平台连接,准备重新上报状态", "INFO")
# 延迟1秒确保后端完全准备好
import time
time.sleep(1.0)
for platform_key, listener_info in manager.platform_listeners.items():
store_id = listener_info.get('store_id')
platform = listener_info.get('platform')
@@ -353,7 +357,7 @@ class BackendClient:
"status": True,
"cookies": "" # 重连时无需再次发送cookies
}
# 同步发送,确保发送成功
future = asyncio.run_coroutine_threadsafe(
self._send_to_backend(reconnect_message),
@@ -361,7 +365,7 @@ class BackendClient:
)
# 等待发送完成最多2秒
future.result(timeout=2)
self._log(f"✅ 已重新上报 {platform} 平台状态: {store_display}", "SUCCESS")
except Exception as e:
self._log(f"❌ 上报 {platform} 平台状态失败: {e}", "ERROR")
@@ -386,7 +390,7 @@ class BackendClient:
try:
from WebSocket.backend_singleton import get_websocket_manager
manager = get_websocket_manager()
# 从 platform_listeners 获取活跃平台
if hasattr(manager, 'platform_listeners') and manager.platform_listeners:
# 获取第一个活跃平台的 store_id
@@ -475,6 +479,8 @@ class BackendClient:
self._handle_version_response(message)
elif msg_type == 'disconnect': # 新增:被踢下线
self._handle_disconnect(message)
elif msg_type == 'balance_insufficient': # 新增:余额不足
self._handle_balance_insufficient(message)
else:
print(f"未知消息类型: {msg_type}")
@@ -1203,7 +1209,8 @@ class BackendClient:
self.login_callback(platform_name, store_id, full_message, store_name)
else:
# 普通Cookie模式
print(f"收到登录指令: 平台={platform_name}, 店铺={store_name or store_id}, cookies_len={len(cookies) if cookies else 0}")
print(
f"收到登录指令: 平台={platform_name}, 店铺={store_name or store_id}, cookies_len={len(cookies) if cookies else 0}")
if self.login_callback:
self.login_callback(platform_name, store_id, cookies, store_name)
@@ -1275,6 +1282,16 @@ class BackendClient:
if self.disconnect_callback:
self.disconnect_callback(disconnect_message)
def _handle_balance_insufficient(self, message: Dict[str, Any]):
"""处理余额不足消息"""
balance_message = message.get('content', '所有平台已断开。请充值条数后,重新连接')
self._log(f"⚠️ 余额不足: {balance_message}", "WARNING")
# 触发余额不足回调(在主线程中处理断开逻辑)
if self.balance_insufficient_callback:
self.balance_insufficient_callback(balance_message)
# ==================== 辅助方法 ====================
def set_token(self, token: str):

View File

@@ -60,7 +60,8 @@ class WebSocketManager:
def set_callbacks(self, log: Callable = None, success: Callable = None, error: Callable = None,
platform_connected: Callable = None, platform_disconnected: Callable = None,
token_error: Callable = None, disconnect: Callable = None):
token_error: Callable = None, disconnect: Callable = None,
balance_insufficient: Callable = None):
"""设置回调函数"""
if log:
self.callbacks['log'] = log
@@ -76,6 +77,8 @@ class WebSocketManager:
self.callbacks['token_error'] = token_error
if disconnect:
self.callbacks['disconnect'] = disconnect
if balance_insufficient:
self.callbacks['balance_insufficient'] = balance_insufficient
def _log(self, message: str, level: str = "INFO"):
"""内部日志方法"""
@@ -104,15 +107,16 @@ class WebSocketManager:
except Exception as e:
self._log(f"通知平台连接失败: {e}", "ERROR")
def notify_platform_kicked(self, platform_name: str, store_name: str, reason: str = "账号在其他设备登录", store_id: str = None):
def notify_platform_kicked(self, platform_name: str, store_name: str, reason: str = "账号在其他设备登录",
store_id: str = None):
"""通知GUI平台被踢下线供平台监听器调用"""
try:
self._log(f"⚠️ 平台被踢下线: {platform_name} - {store_name}, 原因: {reason}", "WARNING")
# 从连接列表中移除
if platform_name in self.connected_platforms:
self.connected_platforms.remove(platform_name)
# 🔥 发送平台断开消息给后端status=false
if store_id and self.backend_client:
try:
@@ -126,13 +130,63 @@ class WebSocketManager:
self._log(f"✅ 已通知后端 {platform_name} 平台断开: {store_id}", "INFO")
except Exception as send_error:
self._log(f"❌ 发送平台断开消息失败: {send_error}", "ERROR")
# 通知GUI显示弹窗
if self.callbacks['platform_disconnected']:
self.callbacks['platform_disconnected'](platform_name, store_name, reason)
except Exception as e:
self._log(f"通知平台断开失败: {e}", "ERROR")
def disconnect_all_async(self):
"""异步断开所有连接(余额不足时调用)- 不阻塞当前线程"""
try:
self._log("🔴 收到余额不足通知,开始断开所有连接...", "ERROR")
# 1. 断开所有平台连接
if self.platform_listeners:
platform_count = len(self.platform_listeners)
self._log(f"正在断开 {platform_count} 个平台连接...", "INFO")
# 复制键列表,避免遍历时修改字典
platform_keys = list(self.platform_listeners.keys())
for key in platform_keys:
try:
listener_info = self.platform_listeners.get(key)
if listener_info:
platform_type = listener_info.get('platform', '')
self._log(f"断开 {platform_type} 平台连接: {key}", "INFO")
# 移除连接记录
self.platform_listeners.pop(key, None)
except Exception as e:
self._log(f"断开平台连接失败: {e}", "ERROR")
self._log(f"✅ 已断开所有 {platform_count} 个平台连接", "INFO")
# 清空连接列表
self.connected_platforms.clear()
# 2. 延迟断开后端连接(在新线程中执行,避免阻塞)
import threading
def _delayed_backend_disconnect():
try:
import time
time.sleep(0.5) # 延迟0.5秒,确保上面的操作完成
if self.backend_client:
self.backend_client.should_stop = True
self.backend_client.is_connected = False
self._log("✅ 已标记后端连接为断开状态", "INFO")
except Exception as e:
self._log(f"断开后端连接失败: {e}", "ERROR")
disconnect_thread = threading.Thread(target=_delayed_backend_disconnect, daemon=True)
disconnect_thread.start()
except Exception as e:
self._log(f"断开所有连接失败: {e}", "ERROR")
def connect_backend(self, token: str) -> bool:
"""连接后端WebSocket"""
try:
@@ -188,12 +242,18 @@ class WebSocketManager:
if self.callbacks['disconnect']:
self.callbacks['disconnect'](disconnect_msg)
def _on_balance_insufficient(balance_msg: str):
"""余额不足回调"""
if self.callbacks['balance_insufficient']:
self.callbacks['balance_insufficient'](balance_msg)
def _on_log(message: str, level: str = "INFO"):
"""Backend client log callback"""
self._log(message, level)
backend.set_callbacks(success=_on_backend_success, login=_on_backend_login,
token_error=_on_token_error, disconnect=_on_disconnect,
balance_insufficient=_on_balance_insufficient,
log=_on_log)
if not backend.is_connected:
@@ -235,12 +295,18 @@ class WebSocketManager:
if self.callbacks['disconnect']:
self.callbacks['disconnect'](disconnect_msg)
def _on_balance_insufficient(balance_msg: str):
"""余额不足回调"""
if self.callbacks['balance_insufficient']:
self.callbacks['balance_insufficient'](balance_msg)
def _on_log(message: str, level: str = "INFO"):
"""Backend client log callback"""
self._log(message, level)
backend.set_callbacks(login=_on_backend_login, success=_on_backend_success,
token_error=_on_token_error, disconnect=_on_disconnect,
balance_insufficient=_on_balance_insufficient,
log=_on_log)
backend.connect()
@@ -261,15 +327,15 @@ class WebSocketManager:
# 🔥 检查并断开当前店铺的旧连接策略B先断开旧连接再建立新连接
store_key_pattern = f":{store_id}" # 匹配 "平台名:store_id" 格式
keys_to_remove = [key for key in self.platform_listeners.keys() if key.endswith(store_key_pattern)]
if keys_to_remove:
self._log(f"🔄 检测到店铺 {store_id} 重复登录,断开 {len(keys_to_remove)} 个旧连接", "INFO")
for key in keys_to_remove:
listener_info = self.platform_listeners.get(key)
if listener_info:
platform_type = listener_info.get('platform', '')
# 从各平台的 WebsocketManager 中获取连接并关闭WebSocket
try:
if platform_type == "京东":
@@ -289,7 +355,7 @@ class WebSocketManager:
pass
jd_mgr.remove_connection(key)
self._log(f"✅ 已从京东管理器移除连接: {key}", "DEBUG")
elif platform_type == "抖音":
from Utils.Dy.DyUtils import DouYinWebsocketManager as DYWSManager
dy_mgr = DYWSManager()
@@ -307,13 +373,13 @@ class WebSocketManager:
pass
dy_mgr.remove_connection(key)
self._log(f"✅ 已从抖音管理器移除连接: {key}", "DEBUG")
elif platform_type == "千牛":
from Utils.QianNiu.QianNiuUtils import QianNiuWebsocketManager as QNWSManager
qn_mgr = QNWSManager()
qn_mgr.remove_connection(key)
self._log(f"✅ 已从千牛管理器移除连接: {key}", "DEBUG")
elif platform_type == "拼多多":
from Utils.Pdd.PddUtils import WebsocketManager as PDDWSManager
pdd_mgr = PDDWSManager()
@@ -332,17 +398,17 @@ class WebSocketManager:
self._log(f"⚠️ 关闭WebSocket时出错: {ws_e}", "DEBUG")
pdd_mgr.remove_connection(key)
self._log(f"✅ 已从拼多多管理器移除连接: {key}", "DEBUG")
except Exception as e:
self._log(f"⚠️ 移除{platform_type}连接时出错: {e}", "WARNING")
# 从监听器字典中移除
self.platform_listeners.pop(key, None)
# 给WebSocket一点时间完全关闭
import time
time.sleep(0.5)
self._log(f"✅ 旧连接已全部断开,准备建立新连接", "INFO")
# 平台名称映射

View File

@@ -52,7 +52,7 @@ PLATFORMS = {
"ws_url": "wss://dongdong.jd.com/workbench/websocket"
},
"DOUYIN": {
"name": "抖音",
"name": "抖音",
"ws_url": None # 动态获取
},
"QIANNIU": {

169
main.py
View File

@@ -12,7 +12,6 @@ from WebSocket.backend_singleton import get_websocket_manager
from windows_taskbar_fix import setup_windows_taskbar_icon
import os
# ===================== 文件日志系统 - 生产环境启用 =====================
# 重定向所有输出到文件,确保有日志记录
from exe_file_logger import setup_file_logging, log_to_file # 开发环境启用
@@ -33,6 +32,12 @@ class DisconnectSignals(QObject):
disconnected = pyqtSignal(str) # (disconnect_message)
# 新增: 余额不足信号类(用于线程安全的余额不足提示)
class BalanceInsufficientSignals(QObject):
"""余额不足信号"""
balance_insufficient = pyqtSignal(str) # (balance_message)
# 新增: 用户名密码输入对话框类
class LoginWindow(QMainWindow):
def __init__(self):
@@ -62,6 +67,10 @@ class LoginWindow(QMainWindow):
self.disconnect_signals = DisconnectSignals()
self.disconnect_signals.disconnected.connect(self._show_disconnect_dialog)
# 创建余额不足信号对象(线程安全)
self.balance_insufficient_signals = BalanceInsufficientSignals()
self.balance_insufficient_signals.balance_insufficient.connect(self._show_balance_insufficient_dialog)
# 横幅相关
self.promo_banner = None
self.banner_shadow = None # 阴影效果引用
@@ -170,7 +179,7 @@ class LoginWindow(QMainWindow):
# 系统初始化日志输出到终端
print("[INFO] 系统初始化完成")
# 让窗口自适应内容高度(最小化)
self.adjustSize()
print("[INFO] 窗口已自适应内容大小")
@@ -182,41 +191,41 @@ class LoginWindow(QMainWindow):
banner_frame = QFrame()
banner_frame.setObjectName("promoBanner")
banner_frame.setCursor(Qt.PointingHandCursor) # 鼠标变手型
# 保存横幅引用,用于动画
self.promo_banner = banner_frame
# 使用图片标签
banner_image = QLabel()
banner_image.setObjectName("bannerImage")
# 加载横幅图片
from windows_taskbar_fix import get_resource_path
image_path = get_resource_path("static/hengfu.jpg")
if os.path.exists(image_path):
from PyQt5.QtGui import QPixmap
pixmap = QPixmap(image_path)
# 设置固定的横幅尺寸
target_width = 400 # 固定宽度
target_height = 70 # 固定高度调整为70px更紧凑
# 缩放图片以适应目标尺寸
scaled_pixmap = pixmap.scaled(
target_width,
target_width,
target_height,
Qt.IgnoreAspectRatio, # 忽略宽高比,拉伸填充
Qt.SmoothTransformation # 平滑缩放,提高图片质量
)
# 设置图片
banner_image.setPixmap(scaled_pixmap)
banner_image.setScaledContents(False)
banner_frame.setFixedHeight(target_height)
banner_image.setFixedSize(target_width, target_height)
# 🔧 使用CSS圆角来处理边角更简单稳定
banner_image.setStyleSheet("""
QLabel#bannerImage {
@@ -224,7 +233,7 @@ class LoginWindow(QMainWindow):
background-color: transparent;
}
""")
print(f"[INFO] 横幅图片已加载: {image_path}, 尺寸: {target_width}x{target_height}")
else:
# 图片不存在时的备用方案
@@ -241,14 +250,14 @@ class LoginWindow(QMainWindow):
""")
banner_frame.setFixedHeight(60)
print(f"[WARNING] 横幅图片未找到: {image_path},使用备用样式")
# 创建布局
banner_layout = QHBoxLayout()
banner_layout.setContentsMargins(0, 0, 0, 0)
banner_layout.setSpacing(0)
banner_frame.setLayout(banner_layout)
banner_layout.addWidget(banner_image)
# 设置圆角和边框
banner_frame.setStyleSheet("""
QFrame#promoBanner {
@@ -256,7 +265,7 @@ class LoginWindow(QMainWindow):
background: transparent;
}
""")
# 初始阴影效果
self.banner_shadow = QGraphicsDropShadowEffect()
self.banner_shadow.setBlurRadius(15)
@@ -264,7 +273,7 @@ class LoginWindow(QMainWindow):
self.banner_shadow.setYOffset(3)
self.banner_shadow.setColor(QColor(0, 0, 0, 60))
banner_frame.setGraphicsEffect(self.banner_shadow)
# 点击事件 - 跳转官网
def open_official_website():
try:
@@ -274,9 +283,9 @@ class LoginWindow(QMainWindow):
self.add_log(f"已打开官网: {official_url}", "INFO")
except Exception as e:
self.add_log(f"打开官网失败: {e}", "ERROR")
banner_frame.mousePressEvent = lambda event: open_official_website()
# 🎯 添加鼠标悬停事件(动态效果)
def on_enter(event):
"""鼠标进入时的动画效果"""
@@ -285,30 +294,30 @@ class LoginWindow(QMainWindow):
self.banner_shadow.setBlurRadius(25)
self.banner_shadow.setYOffset(5)
self.banner_shadow.setColor(QColor(0, 0, 0, 100))
# 轻微放大动画
animation = QPropertyAnimation(banner_frame, b"geometry")
original_rect = banner_frame.geometry()
expanded_rect = QRect(
original_rect.x() - 3,
original_rect.y() - 2,
original_rect.width() + 6,
original_rect.height() + 4
)
animation.setDuration(200)
animation.setStartValue(original_rect)
animation.setEndValue(expanded_rect)
animation.setEasingCurve(QEasingCurve.OutCubic)
animation.start()
# 保存动画引用避免被垃圾回收
banner_frame.hover_animation = animation
except Exception as e:
print(f"[DEBUG] 悬停动画错误: {e}")
def on_leave(event):
"""鼠标离开时的动画效果"""
try:
@@ -316,42 +325,42 @@ class LoginWindow(QMainWindow):
self.banner_shadow.setBlurRadius(15)
self.banner_shadow.setYOffset(3)
self.banner_shadow.setColor(QColor(0, 0, 0, 60))
# 恢复原始大小
animation = QPropertyAnimation(banner_frame, b"geometry")
current_rect = banner_frame.geometry()
original_rect = QRect(
current_rect.x() + 3,
current_rect.y() + 2,
current_rect.width() - 6,
current_rect.height() - 4
)
animation.setDuration(200)
animation.setStartValue(current_rect)
animation.setEndValue(original_rect)
animation.setEasingCurve(QEasingCurve.InCubic)
animation.start()
# 保存动画引用避免被垃圾回收
banner_frame.leave_animation = animation
except Exception as e:
print(f"[DEBUG] 离开动画错误: {e}")
# 安装事件过滤器
banner_frame.enterEvent = on_enter
banner_frame.leaveEvent = on_leave
# 添加到主布局
layout.addWidget(banner_frame)
print("[INFO] 宣传横幅已创建(使用图片,带悬停动画)")
except Exception as e:
print(f"[WARNING] 创建宣传横幅失败: {e}")
# 横幅颜色动画相关方法已移除(改用图片横幅)
def apply_modern_styles(self):
@@ -617,7 +626,7 @@ class LoginWindow(QMainWindow):
"""处理平台被踢下线 - 显示弹窗警告"""
try:
self.add_log(f"⚠️ {platform_name}平台被踢下线: {store_name}, 原因: {reason}", "WARNING")
# 显示弹窗提示
message_text = (
f"{store_name}】连接已断开\n\n"
@@ -634,12 +643,12 @@ class LoginWindow(QMainWindow):
message_text,
QMessageBox.Ok
)
# 更新状态显示
self.status_label.setText(f"⚠️ {platform_name}已断开")
self.status_label.setStyleSheet(
"color: #ff6b6b; background: rgba(255, 107, 107, 0.1); border-radius: 12px; padding: 5px 10px;")
except Exception as e:
self.add_log(f"显示平台断开提示失败: {e}", "ERROR")
@@ -678,6 +687,18 @@ class LoginWindow(QMainWindow):
import traceback
self.add_log(f"详细错误: {traceback.format_exc()}", "ERROR")
def on_balance_insufficient(self, balance_msg: str):
"""处理余额不足 - 发射信号到主线程(可在任何线程中调用)"""
try:
self.add_log(f"📡 收到余额不足通知,准备发射信号: {balance_msg}", "INFO")
# 发射信号Qt 自动调度到主线程)
self.balance_insufficient_signals.balance_insufficient.emit(balance_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:
@@ -714,6 +735,49 @@ class LoginWindow(QMainWindow):
import traceback
self.add_log(f"详细错误: {traceback.format_exc()}", "ERROR")
def _show_balance_insufficient_dialog(self, balance_msg: str):
"""显示余额不足提示框(信号槽函数,始终在主线程中执行)"""
try:
self.add_log(f"🎯 主线程收到余额不足信号: {balance_msg}", "INFO")
# 1. 断开所有连接(异步,不阻塞)
ws_manager = get_websocket_manager()
if ws_manager:
self.add_log("🔴 开始断开所有连接...", "INFO")
ws_manager.disconnect_all_async()
self.add_log("✅ 断开连接指令已发送", "INFO")
# 2. 更新UI状态
self.status_label.setText("🔴 余额不足")
self.status_label.setStyleSheet(
"color: #dc3545; background: rgba(220, 53, 69, 0.1); border-radius: 12px; padding: 5px 10px; font-weight: bold;")
# 3. 重置按钮状态
self.login_btn.setEnabled(True)
self.login_btn.setText("重新连接")
self.login_btn.setObjectName("loginButton")
self.login_btn.setStyleSheet(self.login_btn.styleSheet()) # 刷新样式
# 4. 清空已连接平台列表
self.connected_platforms.clear()
# 5. 显示弹窗提示(主线程中执行,不会卡顿)
QMessageBox.critical(
self,
"余额不足",
f"{balance_msg}\n\n"
f"已断开所有平台连接和后端连接。\n\n"
f"请充值后,点击「连接服务」按钮重新连接。",
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):
"""定时器触发的汇总显示更新"""
try:
@@ -818,16 +882,16 @@ class LoginWindow(QMainWindow):
try:
# 清空现有菜单
self.tray_menu.clear()
# 获取WebSocket管理器
ws_manager = get_websocket_manager()
# 1. 显示后端连接状态
if ws_manager and ws_manager.backend_client and ws_manager.backend_client.is_connected:
backend_status = QAction("✅ 后端已连接", self)
backend_status.setEnabled(False) # 不可点击
self.tray_menu.addAction(backend_status)
# 2. 显示已连接的平台信息
platform_listeners = ws_manager.platform_listeners
if platform_listeners:
@@ -837,18 +901,18 @@ class LoginWindow(QMainWindow):
platform = info.get('platform', '')
store_name = info.get('store_name', '')
store_id = info.get('store_id', '')
if platform not in platform_stores:
platform_stores[platform] = []
# 优先显示店铺名称,如果没有则显示 store_id 前8位
if store_name:
display_name = store_name
else:
display_name = store_id[:8] + "..." if len(store_id) > 8 else store_id
platform_stores[platform].append(display_name)
# 显示每个平台的店铺
for platform, stores in platform_stores.items():
stores_text = ", ".join(stores)
@@ -865,23 +929,23 @@ class LoginWindow(QMainWindow):
backend_disconnected = QAction("❌ 后端未连接", self)
backend_disconnected.setEnabled(False)
self.tray_menu.addAction(backend_disconnected)
# 添加分隔线
self.tray_menu.addSeparator()
# 3. 显示主窗口
show_action = QAction("显示主窗口", self)
show_action.triggered.connect(self.show_window)
self.tray_menu.addAction(show_action)
# 添加分隔线
self.tray_menu.addSeparator()
# 4. 退出程序
quit_action = QAction("退出程序", self)
quit_action.triggered.connect(self.quit_application)
self.tray_menu.addAction(quit_action)
except Exception as e:
print(f"[ERROR] 更新托盘菜单失败: {e}")
# 如果更新失败,至少保证基本功能可用
@@ -889,7 +953,7 @@ class LoginWindow(QMainWindow):
show_action = QAction("显示主窗口", self)
show_action.triggered.connect(self.show_window)
self.tray_menu.addAction(show_action)
quit_action = QAction("退出程序", self)
quit_action.triggered.connect(self.quit_application)
self.tray_menu.addAction(quit_action)
@@ -1004,7 +1068,8 @@ class LoginWindow(QMainWindow):
platform_connected=self.on_platform_connected, # 新增:平台连接回调
platform_disconnected=self.on_platform_kicked, # 新增:平台被踢回调
token_error=self.on_token_error, # 新增token错误回调
disconnect=self.on_disconnect # 新增:被踢下线回调
disconnect=self.on_disconnect, # 新增:被踢下线回调
balance_insufficient=self.on_balance_insufficient # 新增:余额不足回调
)
# 连接后端