388 lines
13 KiB
Python
388 lines
13 KiB
Python
|
|
import sys
|
|||
|
|
from PyQt5.QtCore import Qt
|
|||
|
|
from PyQt5.QtGui import QFont, QPalette, QColor
|
|||
|
|
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
|
|||
|
|
QHBoxLayout, QLabel, QPushButton, QLineEdit,
|
|||
|
|
QTextEdit, QFrame, QDialog, QDialogButtonBox, QComboBox)
|
|||
|
|
|
|||
|
|
import config
|
|||
|
|
from WebSocket.backend_singleton import get_websocket_manager
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 新增: 用户名密码输入对话框类
|
|||
|
|
|
|||
|
|
class LoginWindow(QMainWindow):
|
|||
|
|
def __init__(self):
|
|||
|
|
super().__init__()
|
|||
|
|
self.jd_worker = None
|
|||
|
|
self.progress_dialog = None
|
|||
|
|
self.douyin_worker = None
|
|||
|
|
self.qian_niu_worker = None
|
|||
|
|
self.pdd_worker = None
|
|||
|
|
|
|||
|
|
# 重复执行防护
|
|||
|
|
self.platform_combo_connected = False
|
|||
|
|
self.last_login_time = 0
|
|||
|
|
self.login_cooldown = 2 # 登录冷却时间(秒)
|
|||
|
|
|
|||
|
|
# 日志管理相关变量已删除
|
|||
|
|
|
|||
|
|
self.initUI()
|
|||
|
|
|
|||
|
|
# 设置当前平台为ComboBox的当前值
|
|||
|
|
self.current_platform = self.platform_combo.currentText()
|
|||
|
|
|
|||
|
|
def initUI(self):
|
|||
|
|
# 设置窗口基本属性
|
|||
|
|
self.setWindowTitle('AI回复连接入口-V1.0')
|
|||
|
|
self.setGeometry(300, 300, 800, 600) # 增大窗口尺寸
|
|||
|
|
self.setMinimumSize(700, 500) # 设置最小尺寸保证显示完整
|
|||
|
|
|
|||
|
|
# 创建中央widget
|
|||
|
|
central_widget = QWidget()
|
|||
|
|
self.setCentralWidget(central_widget)
|
|||
|
|
|
|||
|
|
# 创建主布局
|
|||
|
|
main_layout = QVBoxLayout()
|
|||
|
|
main_layout.setSpacing(25) # 增加间距
|
|||
|
|
main_layout.setContentsMargins(40, 40, 40, 40) # 增加边距
|
|||
|
|
central_widget.setLayout(main_layout)
|
|||
|
|
|
|||
|
|
# 添加标题
|
|||
|
|
title_label = QLabel('AI回复连接入口')
|
|||
|
|
title_label.setAlignment(Qt.AlignCenter)
|
|||
|
|
title_label.setFont(QFont('Microsoft YaHei', 24, QFont.Bold)) # 使用系统自带字体
|
|||
|
|
title_label.setStyleSheet("color: #2c3e50;")
|
|||
|
|
main_layout.addWidget(title_label)
|
|||
|
|
|
|||
|
|
# 添加分隔线
|
|||
|
|
line = QFrame()
|
|||
|
|
line.setFrameShape(QFrame.HLine)
|
|||
|
|
line.setFrameShadow(QFrame.Sunken)
|
|||
|
|
line.setStyleSheet("color: #bdc3c7;")
|
|||
|
|
main_layout.addWidget(line)
|
|||
|
|
|
|||
|
|
# 在token_input之前添加平台选择区域
|
|||
|
|
platform_layout = QHBoxLayout()
|
|||
|
|
platform_label = QLabel("选择平台:")
|
|||
|
|
self.platform_combo = QComboBox()
|
|||
|
|
self.platform_combo.addItems(["JD", "抖音", "千牛(淘宝)", "拼多多"])
|
|||
|
|
|
|||
|
|
# 防止重复连接信号 - 更强的保护
|
|||
|
|
if not hasattr(self, 'platform_combo_connected') or not self.platform_combo_connected:
|
|||
|
|
try:
|
|||
|
|
self.platform_combo.currentIndexChanged.disconnect()
|
|||
|
|
except TypeError:
|
|||
|
|
pass # 如果没有连接则忽略
|
|||
|
|
|
|||
|
|
self.platform_combo.currentIndexChanged.connect(self.on_platform_changed)
|
|||
|
|
self.platform_combo_connected = True
|
|||
|
|
platform_layout.addWidget(platform_label)
|
|||
|
|
platform_layout.addWidget(self.platform_combo)
|
|||
|
|
|
|||
|
|
# 将platform_layout添加到主布局中,在token_layout之前
|
|||
|
|
main_layout.addLayout(platform_layout)
|
|||
|
|
|
|||
|
|
# 创建令牌输入区域
|
|||
|
|
token_layout = QHBoxLayout()
|
|||
|
|
token_layout.setSpacing(15)
|
|||
|
|
|
|||
|
|
token_label = QLabel('令牌:')
|
|||
|
|
token_label.setFont(QFont('Microsoft YaHei', 12))
|
|||
|
|
token_label.setFixedWidth(80)
|
|||
|
|
|
|||
|
|
self.token_input = QLineEdit()
|
|||
|
|
self.token_input.setPlaceholderText('请输入您的访问令牌')
|
|||
|
|
self.token_input.setEchoMode(QLineEdit.Password)
|
|||
|
|
self.token_input.setFont(QFont('Microsoft YaHei', 11))
|
|||
|
|
# noinspection PyUnresolvedReferences
|
|||
|
|
self.token_input.returnPressed.connect(self.login) # 表示回车提交
|
|||
|
|
self.token_input.setMinimumHeight(40) # 增加输入框高度
|
|||
|
|
# 预填已保存的令牌(如果存在)
|
|||
|
|
try:
|
|||
|
|
from config import get_saved_token
|
|||
|
|
saved = get_saved_token()
|
|||
|
|
if saved:
|
|||
|
|
self.token_input.setText(saved)
|
|||
|
|
except Exception:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
token_layout.addWidget(token_label)
|
|||
|
|
token_layout.addWidget(self.token_input)
|
|||
|
|
main_layout.addLayout(token_layout)
|
|||
|
|
|
|||
|
|
# 创建连接按钮
|
|||
|
|
self.login_btn = QPushButton('是否连接')
|
|||
|
|
self.login_btn.setFont(QFont('Microsoft YaHei', 12, QFont.Bold))
|
|||
|
|
self.login_btn.setMinimumHeight(45) # 增大按钮高度
|
|||
|
|
self.login_btn.clicked.connect(self.login) # 表示点击提交
|
|||
|
|
main_layout.addWidget(self.login_btn)
|
|||
|
|
|
|||
|
|
# 添加分隔线
|
|||
|
|
line = QFrame()
|
|||
|
|
line.setFrameShape(QFrame.HLine)
|
|||
|
|
line.setFrameShadow(QFrame.Sunken)
|
|||
|
|
line.setStyleSheet("color: #bdc3c7;")
|
|||
|
|
main_layout.addWidget(line)
|
|||
|
|
|
|||
|
|
# 日志框已永久删除,只使用终端输出
|
|||
|
|
self.log_display = None
|
|||
|
|
|
|||
|
|
# 应用现代化样式
|
|||
|
|
self.apply_modern_styles()
|
|||
|
|
|
|||
|
|
# 系统初始化日志输出到终端
|
|||
|
|
print("[INFO] 系统初始化完成")
|
|||
|
|
|
|||
|
|
# # 在平台选择改变时添加调试日志
|
|||
|
|
# self.platform_combo.currentIndexChanged.connect(self.on_platform_changed)
|
|||
|
|
|
|||
|
|
# 设置默认平台
|
|||
|
|
self.platform_combo.setCurrentText("JD")
|
|||
|
|
print(f"🔥 设置默认平台为: {self.platform_combo.currentText()}")
|
|||
|
|
|
|||
|
|
def apply_modern_styles(self):
|
|||
|
|
"""应用现代化样式,兼容各Windows版本"""
|
|||
|
|
self.setStyleSheet("""
|
|||
|
|
QMainWindow {
|
|||
|
|
background-color: #f9f9f9;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QLabel {
|
|||
|
|
color: #34495e;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QLineEdit {
|
|||
|
|
padding: 10px;
|
|||
|
|
border: 2px solid #dfe6e9;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
background-color: white;
|
|||
|
|
selection-background-color: #3498db;
|
|||
|
|
selection-color: white;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QLineEdit:focus {
|
|||
|
|
border-color: #3498db;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QPushButton {
|
|||
|
|
background-color: #3498db;
|
|||
|
|
border: none;
|
|||
|
|
color: white;
|
|||
|
|
padding: 12px 24px;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
min-width: 120px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QPushButton:hover {
|
|||
|
|
background-color: #2980b9;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QPushButton:pressed {
|
|||
|
|
background-color: #1a6a9c;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QPushButton:disabled {
|
|||
|
|
background-color: #bdc3c7;
|
|||
|
|
color: #7f8c8d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QTextEdit {
|
|||
|
|
border: 2px solid #dfe6e9;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
background-color: white;
|
|||
|
|
padding: 8px;
|
|||
|
|
font-family: 'Consolas', 'Microsoft YaHei', monospace;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QFrame[frameShape="4"] {
|
|||
|
|
color: #dfe6e9;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QGroupBox {
|
|||
|
|
font-weight: bold;
|
|||
|
|
border: 2px solid #dfe6e9;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
margin-top: 10px;
|
|||
|
|
padding-top: 10px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QComboBox {
|
|||
|
|
padding: 8px;
|
|||
|
|
border: 2px solid #dfe6e9;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
background-color: white;
|
|||
|
|
min-width: 100px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QComboBox::drop-down {
|
|||
|
|
border: none;
|
|||
|
|
width: 20px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QComboBox QAbstractItemView {
|
|||
|
|
border: 2px solid #dfe6e9;
|
|||
|
|
selection-background-color: #3498db;
|
|||
|
|
selection-color: white;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
# 设置全局字体,确保各Windows版本显示一致
|
|||
|
|
font = QFont('Microsoft YaHei', 10) # Windows系统自带字体
|
|||
|
|
QApplication.setFont(font)
|
|||
|
|
|
|||
|
|
# 设置调色板确保颜色一致性
|
|||
|
|
palette = QPalette()
|
|||
|
|
palette.setColor(QPalette.Window, QColor(249, 249, 249))
|
|||
|
|
palette.setColor(QPalette.WindowText, QColor(52, 73, 94))
|
|||
|
|
palette.setColor(QPalette.Base, QColor(255, 255, 255))
|
|||
|
|
palette.setColor(QPalette.AlternateBase, QColor(233, 235, 239))
|
|||
|
|
palette.setColor(QPalette.ToolTipBase, QColor(255, 255, 255))
|
|||
|
|
palette.setColor(QPalette.ToolTipText, QColor(52, 73, 94))
|
|||
|
|
palette.setColor(QPalette.Text, QColor(52, 73, 94))
|
|||
|
|
palette.setColor(QPalette.Button, QColor(52, 152, 219))
|
|||
|
|
palette.setColor(QPalette.ButtonText, QColor(255, 255, 255))
|
|||
|
|
palette.setColor(QPalette.BrightText, QColor(255, 255, 255))
|
|||
|
|
palette.setColor(QPalette.Highlight, QColor(52, 152, 219))
|
|||
|
|
palette.setColor(QPalette.HighlightedText, QColor(255, 255, 255))
|
|||
|
|
QApplication.setPalette(palette)
|
|||
|
|
|
|||
|
|
def on_platform_changed(self, index):
|
|||
|
|
"""平台选择改变时的处理 - 新增方法"""
|
|||
|
|
platform = self.platform_combo.currentText()
|
|||
|
|
self.current_platform = platform
|
|||
|
|
self.add_log(f"已选择平台: {platform}", "INFO")
|
|||
|
|
print(f"🔥 平台已更改为: {platform}")
|
|||
|
|
|
|||
|
|
def add_log(self, message, log_type="INFO"):
|
|||
|
|
"""添加日志信息 - 只输出到终端"""
|
|||
|
|
from datetime import datetime
|
|||
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|||
|
|
|
|||
|
|
# 根据日志类型设置颜色(ANSI颜色码)
|
|||
|
|
colors = {
|
|||
|
|
"ERROR": "\033[91m", # 红色
|
|||
|
|
"SUCCESS": "\033[92m", # 绿色
|
|||
|
|
"WARNING": "\033[93m", # 黄色
|
|||
|
|
"INFO": "\033[94m", # 蓝色
|
|||
|
|
"DEBUG": "\033[95m" # 紫色
|
|||
|
|
}
|
|||
|
|
reset = "\033[0m" # 重置颜色
|
|||
|
|
|
|||
|
|
color = colors.get(log_type, colors["INFO"])
|
|||
|
|
log_entry = f"{color}[{timestamp}] [{log_type}] {message}{reset}"
|
|||
|
|
print(log_entry)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def login(self):
|
|||
|
|
"""处理连接逻辑"""
|
|||
|
|
# 防止重复快速点击
|
|||
|
|
import time
|
|||
|
|
current_time = time.time()
|
|||
|
|
if current_time - self.last_login_time < self.login_cooldown:
|
|||
|
|
self.add_log(f"请等待 {self.login_cooldown} 秒后再试", "WARNING")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
self.last_login_time = current_time
|
|||
|
|
|
|||
|
|
token = self.token_input.text().strip()
|
|||
|
|
if not token:
|
|||
|
|
self.add_log("请输入有效的连接令牌", "ERROR")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 禁用连接按钮,防止重复点击
|
|||
|
|
self.login_btn.setEnabled(False)
|
|||
|
|
self.login_btn.setText("连接中...")
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 使用 WebSocket 管理器处理连接
|
|||
|
|
ws_manager = get_websocket_manager()
|
|||
|
|
|
|||
|
|
# 设置回调函数
|
|||
|
|
ws_manager.set_callbacks(
|
|||
|
|
log=self.add_log,
|
|||
|
|
success=lambda: self.add_log("WebSocket连接管理器连接成功", "SUCCESS"),
|
|||
|
|
error=lambda error: self.add_log(f"WebSocket连接管理器错误: {error}", "ERROR")
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 连接后端
|
|||
|
|
success = ws_manager.connect_backend(token)
|
|||
|
|
|
|||
|
|
if success:
|
|||
|
|
self.add_log("已启动WebSocket连接管理器", "SUCCESS")
|
|||
|
|
else:
|
|||
|
|
self.add_log("WebSocket连接管理器启动失败", "ERROR")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
self.add_log(f"连接失败: {e}", "ERROR")
|
|||
|
|
finally:
|
|||
|
|
self.login_btn.setEnabled(True)
|
|||
|
|
self.login_btn.setText("开始连接")
|
|||
|
|
|
|||
|
|
def verify_token(self, token):
|
|||
|
|
"""简化的令牌校验:非空即通过(实际校验由后端承担)"""
|
|||
|
|
return bool(token)
|
|||
|
|
|
|||
|
|
def closeEvent(self, event):
|
|||
|
|
"""窗口关闭事件处理"""
|
|||
|
|
try:
|
|||
|
|
# 使用 WebSocket 管理器断开所有连接
|
|||
|
|
from WebSocket.backend_singleton import get_websocket_manager
|
|||
|
|
ws_manager = get_websocket_manager()
|
|||
|
|
ws_manager.disconnect_all()
|
|||
|
|
|
|||
|
|
# 停止所有工作线程(向后兼容)
|
|||
|
|
workers = []
|
|||
|
|
if hasattr(self, 'jd_worker') and self.jd_worker:
|
|||
|
|
workers.append(self.jd_worker)
|
|||
|
|
if hasattr(self, 'douyin_worker') and self.douyin_worker:
|
|||
|
|
workers.append(self.douyin_worker)
|
|||
|
|
if hasattr(self, 'qian_niu_worker') and self.qian_niu_worker:
|
|||
|
|
workers.append(self.qian_niu_worker)
|
|||
|
|
if hasattr(self, 'pdd_worker') and self.pdd_worker:
|
|||
|
|
workers.append(self.pdd_worker)
|
|||
|
|
|
|||
|
|
# 停止所有线程
|
|||
|
|
for worker in workers:
|
|||
|
|
if worker.isRunning():
|
|||
|
|
worker.stop()
|
|||
|
|
worker.quit()
|
|||
|
|
worker.wait(1000)
|
|||
|
|
|
|||
|
|
# 强制关闭事件循环
|
|||
|
|
for worker in workers:
|
|||
|
|
if hasattr(worker, 'loop') and worker.loop and not worker.loop.is_closed():
|
|||
|
|
worker.loop.close()
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"关闭窗口时发生错误: {str(e)}")
|
|||
|
|
finally:
|
|||
|
|
event.accept()
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
"""主函数,用于测试界面"""
|
|||
|
|
app = QApplication(sys.argv)
|
|||
|
|
|
|||
|
|
# 设置应用程序属性
|
|||
|
|
app.setApplicationName(config.WINDOW_TITLE)
|
|||
|
|
app.setApplicationVersion(config.VERSION)
|
|||
|
|
|
|||
|
|
# 创建主窗口
|
|||
|
|
window = LoginWindow()
|
|||
|
|
window.show() # 程序启动断点
|
|||
|
|
|
|||
|
|
# 运行应用程序
|
|||
|
|
sys.exit(app.exec_())
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
main() # sd_aAoHIO9fDRIkePZEhW6oaFgK6IzAPxuB 测试令牌(token)
|
|||
|
|
# username = "KLD测试"
|
|||
|
|
# password = "kld168168"
|
|||
|
|
# taobao nickname = "tb420723827:redboat"
|
|||
|
|
|