|
@@ -1,11 +1,194 @@
|
|
|
import sys
|
|
import sys
|
|
|
import json
|
|
import json
|
|
|
|
|
+import threading
|
|
|
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QHBoxLayout,
|
|
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QHBoxLayout,
|
|
|
QVBoxLayout, QListWidget, QListWidgetItem, QCheckBox,
|
|
QVBoxLayout, QListWidget, QListWidgetItem, QCheckBox,
|
|
|
QPushButton, QLineEdit, QTextEdit, QGroupBox,
|
|
QPushButton, QLineEdit, QTextEdit, QGroupBox,
|
|
|
QSplitter, QLabel, QMessageBox, QComboBox, QShortcut)
|
|
QSplitter, QLabel, QMessageBox, QComboBox, QShortcut)
|
|
|
-from PyQt5.QtCore import Qt
|
|
|
|
|
|
|
+from PyQt5.QtCore import Qt, QTimer, pyqtSignal, QObject
|
|
|
from PyQt5.QtGui import QKeySequence
|
|
from PyQt5.QtGui import QKeySequence
|
|
|
|
|
+import websocket
|
|
|
|
|
+import time
|
|
|
|
|
+
|
|
|
|
|
+class WebSocketClient(QObject):
|
|
|
|
|
+ """WebSocket客户端,用于与服务器通信"""
|
|
|
|
|
+ user_list_updated = pyqtSignal(list) # 用户列表更新信号
|
|
|
|
|
+ message_received = pyqtSignal(dict) # 接收消息信号
|
|
|
|
|
+ connection_status = pyqtSignal(bool) # 连接状态信号
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, type_str="抖音自动评论-153"):
|
|
|
|
|
+ super().__init__()
|
|
|
|
|
+ self.type_str = type_str
|
|
|
|
|
+ self.ws = None
|
|
|
|
|
+ self.ws_user_info = None
|
|
|
|
|
+ self.is_connected = False
|
|
|
|
|
+ self.running = True
|
|
|
|
|
+ self.is_admin = True
|
|
|
|
|
+ self.user_id = None
|
|
|
|
|
+ self.ws_thread = None
|
|
|
|
|
+
|
|
|
|
|
+ def start(self):
|
|
|
|
|
+ """启动WebSocket连接"""
|
|
|
|
|
+ self.running = True
|
|
|
|
|
+ self.ws_thread = threading.Thread(target=self._connect_websocket, daemon=True)
|
|
|
|
|
+ self.ws_thread.start()
|
|
|
|
|
+
|
|
|
|
|
+ def stop(self):
|
|
|
|
|
+ """停止WebSocket连接"""
|
|
|
|
|
+ self.running = False
|
|
|
|
|
+ if self.ws:
|
|
|
|
|
+ try:
|
|
|
|
|
+ self.ws.close()
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+ def _connect_websocket(self):
|
|
|
|
|
+ """WebSocket连接逻辑(在独立线程中运行)"""
|
|
|
|
|
+ time_connect = 0
|
|
|
|
|
+
|
|
|
|
|
+ def reconnect():
|
|
|
|
|
+ nonlocal time_connect
|
|
|
|
|
+ while self.running:
|
|
|
|
|
+ try:
|
|
|
|
|
+ time_connect += 1
|
|
|
|
|
+ print(f"第{time_connect}次重连")
|
|
|
|
|
+
|
|
|
|
|
+ # 创建WebSocket连接
|
|
|
|
|
+ self.ws = websocket.WebSocketApp(
|
|
|
|
|
+ 'wss://ws.lamp.run',
|
|
|
|
|
+ on_open=self._on_open,
|
|
|
|
|
+ on_message=self._on_message,
|
|
|
|
|
+ on_error=self._on_error,
|
|
|
|
|
+ on_close=self._on_close
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ # 运行WebSocket
|
|
|
|
|
+ self.ws.run_forever()
|
|
|
|
|
+
|
|
|
|
|
+ # 如果连接断开且还在运行中,等待后重连
|
|
|
|
|
+ if self.running:
|
|
|
|
|
+ time.sleep(3)
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"WebSocket错误: {e}")
|
|
|
|
|
+ if self.running:
|
|
|
|
|
+ time.sleep(3)
|
|
|
|
|
+
|
|
|
|
|
+ # 启动连接
|
|
|
|
|
+ reconnect()
|
|
|
|
|
+
|
|
|
|
|
+ def _on_open(self, ws):
|
|
|
|
|
+ """WebSocket打开回调"""
|
|
|
|
|
+ login_data = {
|
|
|
|
|
+ "route": "login",
|
|
|
|
|
+ "type": self.type_str,
|
|
|
|
|
+ "admin": self.is_admin,
|
|
|
|
|
+ "id": "PYQT_CLIENT"
|
|
|
|
|
+ }
|
|
|
|
|
+ ws.send(json.dumps(login_data))
|
|
|
|
|
+ self.is_connected = True
|
|
|
|
|
+ self.connection_status.emit(True)
|
|
|
|
|
+ print("WebSocket连接成功")
|
|
|
|
|
+
|
|
|
|
|
+ # 延迟一下,等登录完成后再获取列表
|
|
|
|
|
+ def get_list():
|
|
|
|
|
+ time.sleep(0.5)
|
|
|
|
|
+ if self.ws and self.is_connected:
|
|
|
|
|
+ self.send("getList")
|
|
|
|
|
+
|
|
|
|
|
+ threading.Thread(target=get_list, daemon=True).start()
|
|
|
|
|
+
|
|
|
|
|
+ def _on_message(self, ws, message):
|
|
|
|
|
+ """接收消息回调"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ data = json.loads(message)
|
|
|
|
|
+
|
|
|
|
|
+ if data.get('type') == 'userInfo':
|
|
|
|
|
+ self.ws_user_info = data.get('value')
|
|
|
|
|
+ if self.ws_user_info:
|
|
|
|
|
+ self.user_id = self.ws_user_info.get('userID')
|
|
|
|
|
+ print(f"用户信息: {data.get('value')}")
|
|
|
|
|
+
|
|
|
|
|
+ elif data.get('type') == 'getList':
|
|
|
|
|
+ # 接收到用户列表
|
|
|
|
|
+ user_list = data.get('value', [])
|
|
|
|
|
+ # 提取用户ID列表
|
|
|
|
|
+ user_ids = []
|
|
|
|
|
+ for user in user_list:
|
|
|
|
|
+ user_id = user.get('id')
|
|
|
|
|
+ if user_id and user_id != 'PYQT_CLIENT': # 排除自己
|
|
|
|
|
+ user_ids.append(user_id)
|
|
|
|
|
+
|
|
|
|
|
+ # 发送信号更新UI
|
|
|
|
|
+ self.user_list_updated.emit(user_ids)
|
|
|
|
|
+ print(f"收到用户列表: {user_ids}")
|
|
|
|
|
+
|
|
|
|
|
+ else:
|
|
|
|
|
+ # 其他消息
|
|
|
|
|
+ self.message_received.emit(data)
|
|
|
|
|
+
|
|
|
|
|
+ except json.JSONDecodeError as e:
|
|
|
|
|
+ print(f"JSON解析错误: {e}")
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"消息处理错误: {e}")
|
|
|
|
|
+
|
|
|
|
|
+ def _on_error(self, ws, error):
|
|
|
|
|
+ """WebSocket错误回调"""
|
|
|
|
|
+ print(f"WebSocket错误: {error}")
|
|
|
|
|
+ self.is_connected = False
|
|
|
|
|
+ self.connection_status.emit(False)
|
|
|
|
|
+
|
|
|
|
|
+ def _on_close(self, ws, close_status_code, close_msg):
|
|
|
|
|
+ """WebSocket关闭回调"""
|
|
|
|
|
+ print("WebSocket连接关闭")
|
|
|
|
|
+ self.is_connected = False
|
|
|
|
|
+ self.connection_status.emit(False)
|
|
|
|
|
+
|
|
|
|
|
+ def send(self, route, value=None, send_to=None):
|
|
|
|
|
+ """发送消息
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ route: 路由名称,如 "sendmessage"
|
|
|
|
|
+ value: 要发送的内容(话术)
|
|
|
|
|
+ send_to: 接收方的userID
|
|
|
|
|
+ """
|
|
|
|
|
+ if not self.ws or not self.is_connected:
|
|
|
|
|
+ print("WebSocket未连接")
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ try:
|
|
|
|
|
+ message = {
|
|
|
|
|
+ "route": route,
|
|
|
|
|
+ "type": self.type_str,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # 添加userID(发送者的ID)
|
|
|
|
|
+ if self.user_id:
|
|
|
|
|
+ message["userID"] = self.user_id
|
|
|
|
|
+
|
|
|
|
|
+ # 添加接收者ID
|
|
|
|
|
+ if send_to:
|
|
|
|
|
+ message["id"] = "抖音自动评论-153-" + send_to
|
|
|
|
|
+
|
|
|
|
|
+ # 添加内容
|
|
|
|
|
+ if value is not None:
|
|
|
|
|
+ message["value"] = value
|
|
|
|
|
+
|
|
|
|
|
+ # 发送消息
|
|
|
|
|
+ self.ws.send(json.dumps(message))
|
|
|
|
|
+ print(f"发送消息: {message}")
|
|
|
|
|
+ return True
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"发送消息失败: {e}")
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ def get_user_list(self):
|
|
|
|
|
+ """主动获取用户列表"""
|
|
|
|
|
+ if self.is_connected:
|
|
|
|
|
+ return self.send("getList")
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
|
|
|
class MainWindow(QMainWindow):
|
|
class MainWindow(QMainWindow):
|
|
|
def __init__(self):
|
|
def __init__(self):
|
|
@@ -17,6 +200,10 @@ class MainWindow(QMainWindow):
|
|
|
self.user_scripts = {}
|
|
self.user_scripts = {}
|
|
|
# 当前选中的用户
|
|
# 当前选中的用户
|
|
|
self.current_user = None
|
|
self.current_user = None
|
|
|
|
|
+ # WebSocket客户端
|
|
|
|
|
+ self.ws_client = None
|
|
|
|
|
+ # 用户列表缓存
|
|
|
|
|
+ self.user_cache = []
|
|
|
|
|
|
|
|
# 中央部件
|
|
# 中央部件
|
|
|
central_widget = QWidget()
|
|
central_widget = QWidget()
|
|
@@ -61,6 +248,19 @@ class MainWindow(QMainWindow):
|
|
|
user_label.setStyleSheet("font-weight: bold; font-size: 14px;")
|
|
user_label.setStyleSheet("font-weight: bold; font-size: 14px;")
|
|
|
middle_layout.addWidget(user_label)
|
|
middle_layout.addWidget(user_label)
|
|
|
|
|
|
|
|
|
|
+ # 连接状态和控制按钮
|
|
|
|
|
+ control_layout = QHBoxLayout()
|
|
|
|
|
+ self.status_label = QLabel("⚪ 未连接")
|
|
|
|
|
+ self.status_label.setStyleSheet("color: red;")
|
|
|
|
|
+ control_layout.addWidget(self.status_label)
|
|
|
|
|
+ control_layout.addStretch()
|
|
|
|
|
+
|
|
|
|
|
+ self.refresh_btn = QPushButton("🔄 刷新列表")
|
|
|
|
|
+ self.refresh_btn.clicked.connect(self.refresh_user_list)
|
|
|
|
|
+ self.refresh_btn.setEnabled(False)
|
|
|
|
|
+ control_layout.addWidget(self.refresh_btn)
|
|
|
|
|
+ middle_layout.addLayout(control_layout)
|
|
|
|
|
+
|
|
|
select_btn_layout = QHBoxLayout()
|
|
select_btn_layout = QHBoxLayout()
|
|
|
self.select_all_btn = QPushButton("✅ 全选")
|
|
self.select_all_btn = QPushButton("✅ 全选")
|
|
|
self.deselect_all_btn = QPushButton("❌ 取消全选")
|
|
self.deselect_all_btn = QPushButton("❌ 取消全选")
|
|
@@ -73,19 +273,11 @@ class MainWindow(QMainWindow):
|
|
|
|
|
|
|
|
self.user_list_widget = QListWidget()
|
|
self.user_list_widget = QListWidget()
|
|
|
self.user_list_widget.setSelectionMode(QListWidget.NoSelection)
|
|
self.user_list_widget.setSelectionMode(QListWidget.NoSelection)
|
|
|
- # 添加示例用户
|
|
|
|
|
- sample_users = ["用户A", "用户B", "用户C", "用户D", "用户E"]
|
|
|
|
|
- for user in sample_users:
|
|
|
|
|
- self.add_user_item(user)
|
|
|
|
|
- # 初始化用户话术数据
|
|
|
|
|
- self.user_scripts[user] = [f"话术1: 您好{user},请问有什么可以帮您?",
|
|
|
|
|
- f"话术2: {user},感谢您的反馈,我们会尽快处理。",
|
|
|
|
|
- f"话术3: {user},请您稍等,我为您转接专员。"]
|
|
|
|
|
middle_layout.addWidget(self.user_list_widget)
|
|
middle_layout.addWidget(self.user_list_widget)
|
|
|
|
|
|
|
|
- user_count_label = QLabel(f"当前在线人数: {self.user_list_widget.count()}")
|
|
|
|
|
- user_count_label.setStyleSheet("color: gray;")
|
|
|
|
|
- middle_layout.addWidget(user_count_label)
|
|
|
|
|
|
|
+ self.user_count_label = QLabel("当前在线人数: 0")
|
|
|
|
|
+ self.user_count_label.setStyleSheet("color: gray;")
|
|
|
|
|
+ middle_layout.addWidget(self.user_count_label)
|
|
|
|
|
|
|
|
# ---------- 右侧:用户独立话术列表 ----------
|
|
# ---------- 右侧:用户独立话术列表 ----------
|
|
|
right_widget = QWidget()
|
|
right_widget = QWidget()
|
|
@@ -96,7 +288,6 @@ class MainWindow(QMainWindow):
|
|
|
user_select_layout = QHBoxLayout()
|
|
user_select_layout = QHBoxLayout()
|
|
|
user_select_layout.addWidget(QLabel("选择用户 (快捷键F1-F5):"))
|
|
user_select_layout.addWidget(QLabel("选择用户 (快捷键F1-F5):"))
|
|
|
self.user_combo = QComboBox()
|
|
self.user_combo = QComboBox()
|
|
|
- self.user_combo.addItems(sample_users)
|
|
|
|
|
self.user_combo.currentTextChanged.connect(self.on_user_changed)
|
|
self.user_combo.currentTextChanged.connect(self.on_user_changed)
|
|
|
user_select_layout.addWidget(self.user_combo)
|
|
user_select_layout.addWidget(self.user_combo)
|
|
|
user_select_layout.addStretch()
|
|
user_select_layout.addStretch()
|
|
@@ -160,11 +351,6 @@ class MainWindow(QMainWindow):
|
|
|
main_splitter.addWidget(right_widget)
|
|
main_splitter.addWidget(right_widget)
|
|
|
main_splitter.setSizes([300, 450, 450])
|
|
main_splitter.setSizes([300, 450, 450])
|
|
|
|
|
|
|
|
- # 初始化显示第一个用户的话术
|
|
|
|
|
- if sample_users:
|
|
|
|
|
- self.current_user = sample_users[0]
|
|
|
|
|
- self.load_user_scripts(self.current_user)
|
|
|
|
|
-
|
|
|
|
|
# ---------- 设置快捷键 F1-F5 ----------
|
|
# ---------- 设置快捷键 F1-F5 ----------
|
|
|
self.setup_shortcuts()
|
|
self.setup_shortcuts()
|
|
|
|
|
|
|
@@ -193,34 +379,116 @@ class MainWindow(QMainWindow):
|
|
|
min-width: 150px;
|
|
min-width: 150px;
|
|
|
}
|
|
}
|
|
|
""")
|
|
""")
|
|
|
-
|
|
|
|
|
- # ---------- 快捷键设置 ----------
|
|
|
|
|
- def setup_shortcuts(self):
|
|
|
|
|
- """设置F1-F5快捷键切换用户"""
|
|
|
|
|
- # F1 选择第一个用户,F2 第二个,以此类推
|
|
|
|
|
- shortcuts = [
|
|
|
|
|
- (Qt.Key_F1, 0),
|
|
|
|
|
- (Qt.Key_F2, 1),
|
|
|
|
|
- (Qt.Key_F3, 2),
|
|
|
|
|
- (Qt.Key_F4, 3),
|
|
|
|
|
- (Qt.Key_F5, 4),
|
|
|
|
|
- ]
|
|
|
|
|
|
|
|
|
|
- for key, index in shortcuts:
|
|
|
|
|
- shortcut = QShortcut(QKeySequence(key), self)
|
|
|
|
|
- # 使用lambda捕获index,并绑定到切换函数
|
|
|
|
|
- shortcut.activated.connect(lambda idx=index: self.switch_to_user_by_index(idx))
|
|
|
|
|
|
|
+ # 连接WebSocket
|
|
|
|
|
+ self.connect_websocket()
|
|
|
|
|
|
|
|
- def switch_to_user_by_index(self, index):
|
|
|
|
|
- """根据索引切换到对应用户"""
|
|
|
|
|
- if index < self.user_combo.count():
|
|
|
|
|
- user = self.user_combo.itemText(index)
|
|
|
|
|
- self.user_combo.setCurrentText(user)
|
|
|
|
|
- self.log_text.append(f"[快捷键] 切换到用户: {user}")
|
|
|
|
|
|
|
+ # ---------- WebSocket连接管理 ----------
|
|
|
|
|
+ def connect_websocket(self):
|
|
|
|
|
+ """连接到WebSocket服务器"""
|
|
|
|
|
+ self.log_text.append("[系统] 正在连接WebSocket服务器...")
|
|
|
|
|
+ self.status_label.setText("🔄 正在连接...")
|
|
|
|
|
+ self.status_label.setStyleSheet("color: orange;")
|
|
|
|
|
+
|
|
|
|
|
+ # 创建WebSocket客户端
|
|
|
|
|
+ self.ws_client = WebSocketClient("抖音自动评论-153")
|
|
|
|
|
+
|
|
|
|
|
+ # 连接信号
|
|
|
|
|
+ self.ws_client.user_list_updated.connect(self.on_user_list_updated)
|
|
|
|
|
+ self.ws_client.message_received.connect(self.on_ws_message)
|
|
|
|
|
+ self.ws_client.connection_status.connect(self.on_connection_status)
|
|
|
|
|
+
|
|
|
|
|
+ # 启动WebSocket
|
|
|
|
|
+ self.ws_client.start()
|
|
|
|
|
+
|
|
|
|
|
+ # 定时器检查连接状态
|
|
|
|
|
+ self.status_timer = QTimer()
|
|
|
|
|
+ self.status_timer.timeout.connect(self.check_connection)
|
|
|
|
|
+ self.status_timer.start(5000) # 每5秒检查一次
|
|
|
|
|
+
|
|
|
|
|
+ def on_connection_status(self, connected):
|
|
|
|
|
+ """WebSocket连接状态变化"""
|
|
|
|
|
+ if connected:
|
|
|
|
|
+ self.status_label.setText("🟢 已连接")
|
|
|
|
|
+ self.status_label.setStyleSheet("color: green;")
|
|
|
|
|
+ self.refresh_btn.setEnabled(True)
|
|
|
|
|
+ self.log_text.append("[系统] WebSocket连接成功")
|
|
|
|
|
+ # 延迟获取用户列表
|
|
|
|
|
+ QTimer.singleShot(1000, self.refresh_user_list)
|
|
|
else:
|
|
else:
|
|
|
- self.log_text.append(f"[快捷键] 用户索引 {index} 不存在")
|
|
|
|
|
|
|
+ self.status_label.setText("🔴 已断开")
|
|
|
|
|
+ self.status_label.setStyleSheet("color: red;")
|
|
|
|
|
+ self.refresh_btn.setEnabled(False)
|
|
|
|
|
+ self.log_text.append("[系统] WebSocket连接断开")
|
|
|
|
|
+
|
|
|
|
|
+ def check_connection(self):
|
|
|
|
|
+ """检查WebSocket连接状态"""
|
|
|
|
|
+ if self.ws_client:
|
|
|
|
|
+ if not self.ws_client.is_connected:
|
|
|
|
|
+ # 尝试重新获取列表
|
|
|
|
|
+ self.ws_client.get_user_list()
|
|
|
|
|
+
|
|
|
|
|
+ def refresh_user_list(self):
|
|
|
|
|
+ """刷新用户列表"""
|
|
|
|
|
+ if self.ws_client and self.ws_client.is_connected:
|
|
|
|
|
+ self.log_text.append("[系统] 刷新用户列表...")
|
|
|
|
|
+ self.ws_client.get_user_list()
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.log_text.append("[系统] WebSocket未连接,无法刷新列表")
|
|
|
|
|
+
|
|
|
|
|
+ def on_user_list_updated(self, user_list):
|
|
|
|
|
+ """用户列表更新"""
|
|
|
|
|
+ self.user_cache = user_list
|
|
|
|
|
+ self.update_user_list(user_list)
|
|
|
|
|
+ self.log_text.append(f"[系统] 更新用户列表,当前在线: {len(user_list)}人")
|
|
|
|
|
+
|
|
|
|
|
+ def on_ws_message(self, message):
|
|
|
|
|
+ """WebSocket消息接收"""
|
|
|
|
|
+ # 处理其他类型的消息
|
|
|
|
|
+ msg_type = message.get('type')
|
|
|
|
|
+ if msg_type:
|
|
|
|
|
+ self.log_text.append(f"[WebSocket] 收到消息: {msg_type}")
|
|
|
|
|
|
|
|
# ---------- 用户管理 ----------
|
|
# ---------- 用户管理 ----------
|
|
|
|
|
+ def update_user_list(self, user_list):
|
|
|
|
|
+ """更新用户列表UI"""
|
|
|
|
|
+ # 保存当前选中的用户
|
|
|
|
|
+ selected_users = self.get_selected_users()
|
|
|
|
|
+ current_combo_text = self.user_combo.currentText()
|
|
|
|
|
+
|
|
|
|
|
+ # 清空列表
|
|
|
|
|
+ self.user_list_widget.clear()
|
|
|
|
|
+
|
|
|
|
|
+ # 添加用户
|
|
|
|
|
+ for user_id in user_list:
|
|
|
|
|
+ self.add_user_item(user_id)
|
|
|
|
|
+ # 如果用户不存在,初始化话术数据
|
|
|
|
|
+ if user_id not in self.user_scripts:
|
|
|
|
|
+ self.user_scripts[user_id] = [f"{user_id},666"]
|
|
|
|
|
+
|
|
|
|
|
+ # 更新下拉框
|
|
|
|
|
+ self.user_combo.clear()
|
|
|
|
|
+ self.user_combo.addItems(user_list)
|
|
|
|
|
+
|
|
|
|
|
+ # 恢复选中状态
|
|
|
|
|
+ if current_combo_text in user_list:
|
|
|
|
|
+ self.user_combo.setCurrentText(current_combo_text)
|
|
|
|
|
+ elif user_list:
|
|
|
|
|
+ self.user_combo.setCurrentIndex(0)
|
|
|
|
|
+
|
|
|
|
|
+ # 恢复复选框选中状态
|
|
|
|
|
+ for user in selected_users:
|
|
|
|
|
+ if user in user_list:
|
|
|
|
|
+ for i in range(self.user_list_widget.count()):
|
|
|
|
|
+ item = self.user_list_widget.item(i)
|
|
|
|
|
+ widget = self.user_list_widget.itemWidget(item)
|
|
|
|
|
+ if isinstance(widget, QCheckBox) and widget.text() == user:
|
|
|
|
|
+ widget.setChecked(True)
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ # 更新人数
|
|
|
|
|
+ self.user_count_label.setText(f"当前在线人数: {len(user_list)}")
|
|
|
|
|
+
|
|
|
def add_user_item(self, username):
|
|
def add_user_item(self, username):
|
|
|
"""添加一个带复选框的用户项"""
|
|
"""添加一个带复选框的用户项"""
|
|
|
item = QListWidgetItem()
|
|
item = QListWidgetItem()
|
|
@@ -278,6 +546,31 @@ class MainWindow(QMainWindow):
|
|
|
elif current_users:
|
|
elif current_users:
|
|
|
self.user_combo.setCurrentIndex(0)
|
|
self.user_combo.setCurrentIndex(0)
|
|
|
|
|
|
|
|
|
|
+ # ---------- 快捷键设置 ----------
|
|
|
|
|
+ def setup_shortcuts(self):
|
|
|
|
|
+ """设置F1-F5快捷键切换用户"""
|
|
|
|
|
+ shortcuts = [
|
|
|
|
|
+ (Qt.Key_F1, 0),
|
|
|
|
|
+ (Qt.Key_F2, 1),
|
|
|
|
|
+ (Qt.Key_F3, 2),
|
|
|
|
|
+ (Qt.Key_F4, 3),
|
|
|
|
|
+ (Qt.Key_F5, 4),
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
|
|
+ for key, index in shortcuts:
|
|
|
|
|
+ shortcut = QShortcut(QKeySequence(key), self)
|
|
|
|
|
+ shortcut.activated.connect(lambda idx=index: self.switch_to_user_by_index(idx))
|
|
|
|
|
+
|
|
|
|
|
+ def switch_to_user_by_index(self, index):
|
|
|
|
|
+ """根据索引切换到对应用户"""
|
|
|
|
|
+ if index < self.user_combo.count():
|
|
|
|
|
+ user = self.user_combo.itemText(index)
|
|
|
|
|
+ if user:
|
|
|
|
|
+ self.user_combo.setCurrentText(user)
|
|
|
|
|
+ self.log_text.append(f"[快捷键] 切换到用户: {user}")
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.log_text.append(f"[快捷键] 用户索引 {index} 不存在")
|
|
|
|
|
+
|
|
|
# ---------- 话术管理 (用户独立) ----------
|
|
# ---------- 话术管理 (用户独立) ----------
|
|
|
def load_user_scripts(self, username):
|
|
def load_user_scripts(self, username):
|
|
|
"""加载指定用户的话术列表"""
|
|
"""加载指定用户的话术列表"""
|
|
@@ -293,7 +586,6 @@ class MainWindow(QMainWindow):
|
|
|
if username and username != self.current_user:
|
|
if username and username != self.current_user:
|
|
|
# 如果当前用户有修改但未保存,先保存
|
|
# 如果当前用户有修改但未保存,先保存
|
|
|
if self.current_user and self.current_user in self.user_scripts:
|
|
if self.current_user and self.current_user in self.user_scripts:
|
|
|
- # 自动保存当前用户的话术
|
|
|
|
|
self.save_current_user_scripts()
|
|
self.save_current_user_scripts()
|
|
|
|
|
|
|
|
self.load_user_scripts(username)
|
|
self.load_user_scripts(username)
|
|
@@ -331,7 +623,6 @@ class MainWindow(QMainWindow):
|
|
|
if text:
|
|
if text:
|
|
|
self.script_list_widget.addItem(text)
|
|
self.script_list_widget.addItem(text)
|
|
|
self.script_input.clear()
|
|
self.script_input.clear()
|
|
|
- # 自动保存
|
|
|
|
|
self.save_current_user_scripts()
|
|
self.save_current_user_scripts()
|
|
|
self.log_text.append(f"[操作] 为用户 '{self.current_user}' 添加话术: {text}")
|
|
self.log_text.append(f"[操作] 为用户 '{self.current_user}' 添加话术: {text}")
|
|
|
else:
|
|
else:
|
|
@@ -343,7 +634,6 @@ class MainWindow(QMainWindow):
|
|
|
if current_row >= 0:
|
|
if current_row >= 0:
|
|
|
item_text = self.script_list_widget.item(current_row).text()
|
|
item_text = self.script_list_widget.item(current_row).text()
|
|
|
self.script_list_widget.takeItem(current_row)
|
|
self.script_list_widget.takeItem(current_row)
|
|
|
- # 自动保存
|
|
|
|
|
self.save_current_user_scripts()
|
|
self.save_current_user_scripts()
|
|
|
self.log_text.append(f"[操作] 删除用户 '{self.current_user}' 的话术: {item_text}")
|
|
self.log_text.append(f"[操作] 删除用户 '{self.current_user}' 的话术: {item_text}")
|
|
|
else:
|
|
else:
|
|
@@ -358,7 +648,6 @@ class MainWindow(QMainWindow):
|
|
|
text=old_text)
|
|
text=old_text)
|
|
|
if ok and new_text.strip():
|
|
if ok and new_text.strip():
|
|
|
self.script_list_widget.item(current_row).setText(new_text.strip())
|
|
self.script_list_widget.item(current_row).setText(new_text.strip())
|
|
|
- # 自动保存
|
|
|
|
|
self.save_current_user_scripts()
|
|
self.save_current_user_scripts()
|
|
|
self.log_text.append(f"[操作] 修改用户 '{self.current_user}' 的话术: {old_text} -> {new_text.strip()}")
|
|
self.log_text.append(f"[操作] 修改用户 '{self.current_user}' 的话术: {old_text} -> {new_text.strip()}")
|
|
|
elif ok and not new_text.strip():
|
|
elif ok and not new_text.strip():
|
|
@@ -380,39 +669,53 @@ class MainWindow(QMainWindow):
|
|
|
QMessageBox.warning(self, "提示", "请至少选择一个用户!")
|
|
QMessageBox.warning(self, "提示", "请至少选择一个用户!")
|
|
|
return
|
|
return
|
|
|
|
|
|
|
|
- # 获取每个用户选中的话术 (这里演示:取每个用户的第一条话术)
|
|
|
|
|
- task_details = []
|
|
|
|
|
- for user in selected_users:
|
|
|
|
|
- if user in self.user_scripts and self.user_scripts[user]:
|
|
|
|
|
- script = self.user_scripts[user][0] # 取第一条
|
|
|
|
|
- task_details.append(f"{user}: {script}")
|
|
|
|
|
- else:
|
|
|
|
|
- task_details.append(f"{user}: (无话术)")
|
|
|
|
|
|
|
+ # 获取当前选中的话术
|
|
|
|
|
+ current_row = self.script_list_widget.currentRow()
|
|
|
|
|
+ if current_row < 0:
|
|
|
|
|
+ QMessageBox.warning(self, "提示", "请先在话术列表中选中一条话术!")
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ selected_script = self.script_list_widget.item(current_row).text()
|
|
|
|
|
|
|
|
# 记录日志
|
|
# 记录日志
|
|
|
|
|
+ self.log_text.append(f"[任务] 发送话术: {selected_script}")
|
|
|
self.log_text.append(f"[任务] 发送给 {len(selected_users)} 个用户:")
|
|
self.log_text.append(f"[任务] 发送给 {len(selected_users)} 个用户:")
|
|
|
- for detail in task_details:
|
|
|
|
|
- self.log_text.append(f" - {detail}")
|
|
|
|
|
- self.log_text.append("[任务] 发送完成 (功能待实现)")
|
|
|
|
|
|
|
|
|
|
- # 显示详情
|
|
|
|
|
- msg = "\n".join(task_details)
|
|
|
|
|
- QMessageBox.information(self, "发送任务",
|
|
|
|
|
- f"已发送任务给 {len(selected_users)} 个用户:\n\n{msg}")
|
|
|
|
|
|
|
+ # 通过WebSocket发送任务
|
|
|
|
|
+ if self.ws_client and self.ws_client.is_connected:
|
|
|
|
|
+ success_count = 0
|
|
|
|
|
+ for user in selected_users:
|
|
|
|
|
+ # 发送给指定用户,路由为 "sendmessage"
|
|
|
|
|
+ if self.ws_client.send("sendmessage", selected_script, user):
|
|
|
|
|
+ success_count += 1
|
|
|
|
|
+ self.log_text.append(f"[任务] 已发送给用户: {user}")
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.log_text.append(f"[任务] 发送给用户 {user} 失败")
|
|
|
|
|
+
|
|
|
|
|
+ self.log_text.append(f"[任务] 发送完成,成功发送给 {success_count}/{len(selected_users)} 个用户")
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.log_text.append("[任务] WebSocket未连接,无法发送")
|
|
|
|
|
|
|
|
# ---------- 窗口关闭时保存 ----------
|
|
# ---------- 窗口关闭时保存 ----------
|
|
|
def closeEvent(self, event):
|
|
def closeEvent(self, event):
|
|
|
"""关闭窗口时自动保存所有用户话术"""
|
|
"""关闭窗口时自动保存所有用户话术"""
|
|
|
if self.current_user:
|
|
if self.current_user:
|
|
|
self.save_current_user_scripts()
|
|
self.save_current_user_scripts()
|
|
|
|
|
+
|
|
|
try:
|
|
try:
|
|
|
with open("user_scripts_backup.json", "w", encoding="utf-8") as f:
|
|
with open("user_scripts_backup.json", "w", encoding="utf-8") as f:
|
|
|
json.dump(self.user_scripts, f, ensure_ascii=False, indent=2)
|
|
json.dump(self.user_scripts, f, ensure_ascii=False, indent=2)
|
|
|
self.log_text.append("[系统] 程序退出,已自动保存所有话术配置")
|
|
self.log_text.append("[系统] 程序退出,已自动保存所有话术配置")
|
|
|
except:
|
|
except:
|
|
|
pass
|
|
pass
|
|
|
|
|
+
|
|
|
|
|
+ # 关闭WebSocket连接
|
|
|
|
|
+ if self.ws_client:
|
|
|
|
|
+ self.ws_client.stop()
|
|
|
|
|
+
|
|
|
event.accept()
|
|
event.accept()
|
|
|
|
|
|
|
|
|
|
+
|
|
|
if __name__ == "__main__":
|
|
if __name__ == "__main__":
|
|
|
app = QApplication(sys.argv)
|
|
app = QApplication(sys.argv)
|
|
|
window = MainWindow()
|
|
window = MainWindow()
|