主播工具.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. import sys
  2. import json
  3. from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QHBoxLayout,
  4. QVBoxLayout, QListWidget, QListWidgetItem, QCheckBox,
  5. QPushButton, QLineEdit, QTextEdit, QGroupBox,
  6. QSplitter, QLabel, QMessageBox, QComboBox, QShortcut)
  7. from PyQt5.QtCore import Qt
  8. from PyQt5.QtGui import QKeySequence
  9. class MainWindow(QMainWindow):
  10. def __init__(self):
  11. super().__init__()
  12. self.setWindowTitle("三栏布局 - 用户独立话术管理 (快捷键F1-F5)")
  13. self.setGeometry(100, 100, 1300, 750)
  14. # 数据存储:用户话术字典 {用户名: [话术列表]}
  15. self.user_scripts = {}
  16. # 当前选中的用户
  17. self.current_user = None
  18. # 中央部件
  19. central_widget = QWidget()
  20. self.setCentralWidget(central_widget)
  21. # 主布局 - 水平分割器
  22. main_splitter = QSplitter(Qt.Horizontal)
  23. central_layout = QHBoxLayout(central_widget)
  24. central_layout.addWidget(main_splitter)
  25. central_layout.setContentsMargins(10, 10, 10, 10)
  26. # ---------- 左侧:日志显示 ----------
  27. left_widget = QWidget()
  28. left_layout = QVBoxLayout(left_widget)
  29. left_layout.setContentsMargins(5, 5, 5, 5)
  30. log_label = QLabel("📋 运行日志")
  31. log_label.setStyleSheet("font-weight: bold; font-size: 14px;")
  32. left_layout.addWidget(log_label)
  33. self.log_text = QTextEdit()
  34. self.log_text.setReadOnly(True)
  35. self.log_text.setPlaceholderText("日志信息将显示在这里...")
  36. self.log_text.append("[系统] 程序启动")
  37. self.log_text.append("[系统] 界面初始化完成")
  38. self.log_text.append("[系统] 快捷键: F1-F5 快速切换用户")
  39. left_layout.addWidget(self.log_text)
  40. log_btn_layout = QHBoxLayout()
  41. clear_log_btn = QPushButton("清空日志")
  42. clear_log_btn.clicked.connect(self.clear_log)
  43. log_btn_layout.addStretch()
  44. log_btn_layout.addWidget(clear_log_btn)
  45. left_layout.addLayout(log_btn_layout)
  46. # ---------- 中间:在线用户列表 ----------
  47. middle_widget = QWidget()
  48. middle_layout = QVBoxLayout(middle_widget)
  49. middle_layout.setContentsMargins(5, 5, 5, 5)
  50. user_label = QLabel("👥 在线用户列表")
  51. user_label.setStyleSheet("font-weight: bold; font-size: 14px;")
  52. middle_layout.addWidget(user_label)
  53. select_btn_layout = QHBoxLayout()
  54. self.select_all_btn = QPushButton("✅ 全选")
  55. self.deselect_all_btn = QPushButton("❌ 取消全选")
  56. self.select_all_btn.clicked.connect(self.select_all_users)
  57. self.deselect_all_btn.clicked.connect(self.deselect_all_users)
  58. select_btn_layout.addWidget(self.select_all_btn)
  59. select_btn_layout.addWidget(self.deselect_all_btn)
  60. select_btn_layout.addStretch()
  61. middle_layout.addLayout(select_btn_layout)
  62. self.user_list_widget = QListWidget()
  63. self.user_list_widget.setSelectionMode(QListWidget.NoSelection)
  64. # 添加示例用户
  65. sample_users = ["用户A", "用户B", "用户C", "用户D", "用户E"]
  66. for user in sample_users:
  67. self.add_user_item(user)
  68. # 初始化用户话术数据
  69. self.user_scripts[user] = [f"话术1: 您好{user},请问有什么可以帮您?",
  70. f"话术2: {user},感谢您的反馈,我们会尽快处理。",
  71. f"话术3: {user},请您稍等,我为您转接专员。"]
  72. middle_layout.addWidget(self.user_list_widget)
  73. user_count_label = QLabel(f"当前在线人数: {self.user_list_widget.count()}")
  74. user_count_label.setStyleSheet("color: gray;")
  75. middle_layout.addWidget(user_count_label)
  76. # ---------- 右侧:用户独立话术列表 ----------
  77. right_widget = QWidget()
  78. right_layout = QVBoxLayout(right_widget)
  79. right_layout.setContentsMargins(5, 5, 5, 5)
  80. # 顶部:用户选择下拉框
  81. user_select_layout = QHBoxLayout()
  82. user_select_layout.addWidget(QLabel("选择用户 (快捷键F1-F5):"))
  83. self.user_combo = QComboBox()
  84. self.user_combo.addItems(sample_users)
  85. self.user_combo.currentTextChanged.connect(self.on_user_changed)
  86. user_select_layout.addWidget(self.user_combo)
  87. user_select_layout.addStretch()
  88. right_layout.addLayout(user_select_layout)
  89. # 话术列表标题
  90. script_label = QLabel("📝 话术列表 (当前用户)")
  91. script_label.setStyleSheet("font-weight: bold; font-size: 14px;")
  92. right_layout.addWidget(script_label)
  93. # 话术列表显示
  94. self.script_list_widget = QListWidget()
  95. right_layout.addWidget(self.script_list_widget)
  96. # 话术编辑区域
  97. script_edit_layout = QVBoxLayout()
  98. # 添加话术
  99. add_layout = QHBoxLayout()
  100. self.script_input = QLineEdit()
  101. self.script_input.setPlaceholderText("输入新话术内容...")
  102. add_btn = QPushButton("➕ 添加")
  103. add_btn.clicked.connect(self.add_script)
  104. add_layout.addWidget(self.script_input)
  105. add_layout.addWidget(add_btn)
  106. script_edit_layout.addLayout(add_layout)
  107. # 删除和修改按钮
  108. modify_layout = QHBoxLayout()
  109. delete_btn = QPushButton("🗑️ 删除选中")
  110. delete_btn.clicked.connect(self.delete_script)
  111. modify_btn = QPushButton("✏️ 修改选中")
  112. modify_btn.clicked.connect(self.modify_script)
  113. modify_layout.addWidget(delete_btn)
  114. modify_layout.addWidget(modify_btn)
  115. script_edit_layout.addLayout(modify_layout)
  116. # 保存按钮
  117. save_layout = QHBoxLayout()
  118. save_layout.addStretch()
  119. self.save_scripts_btn = QPushButton("💾 保存话术配置")
  120. self.save_scripts_btn.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold; padding: 8px 20px; border-radius: 5px;")
  121. self.save_scripts_btn.clicked.connect(self.save_user_scripts)
  122. save_layout.addWidget(self.save_scripts_btn)
  123. script_edit_layout.addLayout(save_layout)
  124. right_layout.addLayout(script_edit_layout)
  125. # 发送任务按钮
  126. send_layout = QHBoxLayout()
  127. send_layout.addStretch()
  128. self.send_task_btn = QPushButton("🚀 发送任务")
  129. self.send_task_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 8px 20px; border-radius: 5px;")
  130. self.send_task_btn.clicked.connect(self.send_task)
  131. send_layout.addWidget(self.send_task_btn)
  132. right_layout.addLayout(send_layout)
  133. # ---------- 将三个部件加入分割器 ----------
  134. main_splitter.addWidget(left_widget)
  135. main_splitter.addWidget(middle_widget)
  136. main_splitter.addWidget(right_widget)
  137. main_splitter.setSizes([300, 450, 450])
  138. # 初始化显示第一个用户的话术
  139. if sample_users:
  140. self.current_user = sample_users[0]
  141. self.load_user_scripts(self.current_user)
  142. # ---------- 设置快捷键 F1-F5 ----------
  143. self.setup_shortcuts()
  144. # 窗口样式
  145. self.setStyleSheet("""
  146. QGroupBox {
  147. font-weight: bold;
  148. border: 1px solid #ccc;
  149. border-radius: 5px;
  150. margin-top: 10px;
  151. }
  152. QGroupBox::title {
  153. subcontrol-origin: margin;
  154. left: 10px;
  155. padding: 0 5px 0 5px;
  156. }
  157. QListWidget::item {
  158. padding: 5px;
  159. }
  160. QTextEdit {
  161. background-color: #f8f8f8;
  162. font-family: Consolas, monospace;
  163. }
  164. QComboBox {
  165. padding: 5px;
  166. min-width: 150px;
  167. }
  168. """)
  169. # ---------- 快捷键设置 ----------
  170. def setup_shortcuts(self):
  171. """设置F1-F5快捷键切换用户"""
  172. # F1 选择第一个用户,F2 第二个,以此类推
  173. shortcuts = [
  174. (Qt.Key_F1, 0),
  175. (Qt.Key_F2, 1),
  176. (Qt.Key_F3, 2),
  177. (Qt.Key_F4, 3),
  178. (Qt.Key_F5, 4),
  179. ]
  180. for key, index in shortcuts:
  181. shortcut = QShortcut(QKeySequence(key), self)
  182. # 使用lambda捕获index,并绑定到切换函数
  183. shortcut.activated.connect(lambda idx=index: self.switch_to_user_by_index(idx))
  184. def switch_to_user_by_index(self, index):
  185. """根据索引切换到对应用户"""
  186. if index < self.user_combo.count():
  187. user = self.user_combo.itemText(index)
  188. self.user_combo.setCurrentText(user)
  189. self.log_text.append(f"[快捷键] 切换到用户: {user}")
  190. else:
  191. self.log_text.append(f"[快捷键] 用户索引 {index} 不存在")
  192. # ---------- 用户管理 ----------
  193. def add_user_item(self, username):
  194. """添加一个带复选框的用户项"""
  195. item = QListWidgetItem()
  196. checkbox = QCheckBox(username)
  197. self.user_list_widget.addItem(item)
  198. self.user_list_widget.setItemWidget(item, checkbox)
  199. checkbox.stateChanged.connect(self.on_user_check_changed)
  200. def get_user_checkboxes(self):
  201. """获取所有用户复选框"""
  202. checkboxes = []
  203. for i in range(self.user_list_widget.count()):
  204. item = self.user_list_widget.item(i)
  205. widget = self.user_list_widget.itemWidget(item)
  206. if isinstance(widget, QCheckBox):
  207. checkboxes.append(widget)
  208. return checkboxes
  209. def get_selected_users(self):
  210. """获取所有选中的用户"""
  211. selected = []
  212. for cb in self.get_user_checkboxes():
  213. if cb.isChecked():
  214. selected.append(cb.text())
  215. return selected
  216. def select_all_users(self):
  217. for cb in self.get_user_checkboxes():
  218. cb.setChecked(True)
  219. self.log_text.append("[操作] 已全选所有用户")
  220. def deselect_all_users(self):
  221. for cb in self.get_user_checkboxes():
  222. cb.setChecked(False)
  223. self.log_text.append("[操作] 已取消全选所有用户")
  224. def on_user_check_changed(self):
  225. """复选框状态改变时更新下拉框列表"""
  226. # 获取当前所有用户
  227. current_users = []
  228. for i in range(self.user_list_widget.count()):
  229. item = self.user_list_widget.item(i)
  230. widget = self.user_list_widget.itemWidget(item)
  231. if isinstance(widget, QCheckBox):
  232. current_users.append(widget.text())
  233. # 更新下拉框
  234. current_selection = self.user_combo.currentText()
  235. self.user_combo.clear()
  236. self.user_combo.addItems(current_users)
  237. # 如果之前的用户还在列表中,恢复选择
  238. if current_selection in current_users:
  239. self.user_combo.setCurrentText(current_selection)
  240. elif current_users:
  241. self.user_combo.setCurrentIndex(0)
  242. # ---------- 话术管理 (用户独立) ----------
  243. def load_user_scripts(self, username):
  244. """加载指定用户的话术列表"""
  245. if username in self.user_scripts:
  246. self.script_list_widget.clear()
  247. for script in self.user_scripts[username]:
  248. self.script_list_widget.addItem(script)
  249. self.current_user = username
  250. self.log_text.append(f"[系统] 加载用户 '{username}' 的话术列表")
  251. def on_user_changed(self, username):
  252. """下拉框切换用户"""
  253. if username and username != self.current_user:
  254. # 如果当前用户有修改但未保存,先保存
  255. if self.current_user and self.current_user in self.user_scripts:
  256. # 自动保存当前用户的话术
  257. self.save_current_user_scripts()
  258. self.load_user_scripts(username)
  259. def save_current_user_scripts(self):
  260. """保存当前用户的话术到内存"""
  261. if self.current_user and self.current_user in self.user_scripts:
  262. scripts = []
  263. for i in range(self.script_list_widget.count()):
  264. scripts.append(self.script_list_widget.item(i).text())
  265. self.user_scripts[self.current_user] = scripts
  266. self.log_text.append(f"[系统] 自动保存用户 '{self.current_user}' 的话术配置")
  267. def save_user_scripts(self):
  268. """手动保存当前用户的话术(并持久化)"""
  269. if not self.current_user:
  270. QMessageBox.warning(self, "提示", "请先选择一个用户!")
  271. return
  272. # 保存到内存
  273. self.save_current_user_scripts()
  274. # 持久化保存到文件
  275. try:
  276. with open("user_scripts_backup.json", "w", encoding="utf-8") as f:
  277. json.dump(self.user_scripts, f, ensure_ascii=False, indent=2)
  278. self.log_text.append(f"[系统] 话术配置已保存到文件 user_scripts_backup.json")
  279. QMessageBox.information(self, "保存成功", f"用户 '{self.current_user}' 的话术配置已保存!")
  280. except Exception as e:
  281. QMessageBox.critical(self, "保存失败", f"保存到文件时出错: {str(e)}")
  282. def add_script(self):
  283. """添加话术到当前用户"""
  284. text = self.script_input.text().strip()
  285. if text:
  286. self.script_list_widget.addItem(text)
  287. self.script_input.clear()
  288. # 自动保存
  289. self.save_current_user_scripts()
  290. self.log_text.append(f"[操作] 为用户 '{self.current_user}' 添加话术: {text}")
  291. else:
  292. QMessageBox.information(self, "提示", "话术内容不能为空!")
  293. def delete_script(self):
  294. """删除当前用户选中的话术"""
  295. current_row = self.script_list_widget.currentRow()
  296. if current_row >= 0:
  297. item_text = self.script_list_widget.item(current_row).text()
  298. self.script_list_widget.takeItem(current_row)
  299. # 自动保存
  300. self.save_current_user_scripts()
  301. self.log_text.append(f"[操作] 删除用户 '{self.current_user}' 的话术: {item_text}")
  302. else:
  303. QMessageBox.information(self, "提示", "请先选中一条话术!")
  304. def modify_script(self):
  305. """修改当前用户选中的话术"""
  306. current_row = self.script_list_widget.currentRow()
  307. if current_row >= 0:
  308. old_text = self.script_list_widget.item(current_row).text()
  309. new_text, ok = QMessageBox.getText(self, "修改话术", "请输入新的话术内容:",
  310. text=old_text)
  311. if ok and new_text.strip():
  312. self.script_list_widget.item(current_row).setText(new_text.strip())
  313. # 自动保存
  314. self.save_current_user_scripts()
  315. self.log_text.append(f"[操作] 修改用户 '{self.current_user}' 的话术: {old_text} -> {new_text.strip()}")
  316. elif ok and not new_text.strip():
  317. QMessageBox.information(self, "提示", "话术内容不能为空!")
  318. else:
  319. QMessageBox.information(self, "提示", "请先选中一条话术!")
  320. def clear_log(self):
  321. self.log_text.clear()
  322. self.log_text.append("[系统] 日志已清空")
  323. self.log_text.append("[系统] 快捷键: F1-F5 快速切换用户")
  324. # ---------- 发送任务 ----------
  325. def send_task(self):
  326. """发送任务到选中的用户"""
  327. selected_users = self.get_selected_users()
  328. if not selected_users:
  329. QMessageBox.warning(self, "提示", "请至少选择一个用户!")
  330. return
  331. # 获取每个用户选中的话术 (这里演示:取每个用户的第一条话术)
  332. task_details = []
  333. for user in selected_users:
  334. if user in self.user_scripts and self.user_scripts[user]:
  335. script = self.user_scripts[user][0] # 取第一条
  336. task_details.append(f"{user}: {script}")
  337. else:
  338. task_details.append(f"{user}: (无话术)")
  339. # 记录日志
  340. self.log_text.append(f"[任务] 发送给 {len(selected_users)} 个用户:")
  341. for detail in task_details:
  342. self.log_text.append(f" - {detail}")
  343. self.log_text.append("[任务] 发送完成 (功能待实现)")
  344. # 显示详情
  345. msg = "\n".join(task_details)
  346. QMessageBox.information(self, "发送任务",
  347. f"已发送任务给 {len(selected_users)} 个用户:\n\n{msg}")
  348. # ---------- 窗口关闭时保存 ----------
  349. def closeEvent(self, event):
  350. """关闭窗口时自动保存所有用户话术"""
  351. if self.current_user:
  352. self.save_current_user_scripts()
  353. try:
  354. with open("user_scripts_backup.json", "w", encoding="utf-8") as f:
  355. json.dump(self.user_scripts, f, ensure_ascii=False, indent=2)
  356. self.log_text.append("[系统] 程序退出,已自动保存所有话术配置")
  357. except:
  358. pass
  359. event.accept()
  360. if __name__ == "__main__":
  361. app = QApplication(sys.argv)
  362. window = MainWindow()
  363. window.show()
  364. sys.exit(app.exec_())