""" 聊天记录搜索窗口(优化版 — 连接服务器搜索) """ from PyQt5.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QListWidget, QListWidgetItem, QTextEdit, QSplitter, QFrame ) from PyQt5.QtCore import Qt, pyqtSignal from PyQt5.QtGui import QColor import html class SearchResultItem(QListWidgetItem): def __init__(self, message_data, keyword=''): super().__init__() self.message_data = message_data self._update_display(keyword) def _update_display(self, keyword=''): sender = self.message_data.get('sender', '未知') content = self.message_data.get('content', '') timestamp = self.message_data.get('timestamp', '') msg_type = self.message_data.get('msg_type', 'text') if msg_type == 'image': preview = '[图片]' else: preview = content[:60] + '...' if len(content) > 60 else content display_text = f"{sender} {timestamp}\n{preview}" self.setText(display_text) self.setData(Qt.UserRole, self.message_data) def highlight_keyword(self, keyword): """高亮关键词(未来可扩展富文本显示)""" pass class SearchWindow(QWidget): search_requested = pyqtSignal(str, str, str) # chat_type, target_id, keyword def __init__(self, chat_type, target_id, target_name, parent=None): super().__init__(parent) self.chat_type = chat_type self.target_id = target_id self.target_name = target_name self.search_results = [] self._init_ui() def _init_ui(self): self.setWindowTitle(f"搜索聊天记录 - {self.target_name}") self.setGeometry(200, 200, 820, 600) self.setMinimumSize(600, 400) layout = QVBoxLayout(self) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) # 搜索栏 search_frame = QFrame() search_frame.setStyleSheet(""" QFrame { background: #f8fafc; border-bottom: 1px solid #e2e8f0; } """) search_layout = QHBoxLayout(search_frame) search_layout.setContentsMargins(16, 10, 16, 10) search_layout.setSpacing(8) search_icon = QLabel("🔍") search_icon.setStyleSheet("font-size: 16px; border: none;") search_layout.addWidget(search_icon) self.search_input = QLineEdit() self.search_input.setPlaceholderText("输入关键词搜索聊天记录,支持中英文…") self.search_input.setStyleSheet(""" QLineEdit { border: 1px solid #ddd; border-radius: 8px; background: white; font-size: 14px; padding: 8px 12px; } QLineEdit:focus { border: 1px solid #6366f1; } """) self.search_input.returnPressed.connect(self._perform_search) search_layout.addWidget(self.search_input) search_btn = QPushButton("搜索") search_btn.setStyleSheet(""" QPushButton { background: #6366f1; color: white; border: none; border-radius: 8px; padding: 8px 20px; font-size: 13px; font-weight: bold; } QPushButton:hover { background: #4f46e5; } """) search_btn.clicked.connect(self._perform_search) search_layout.addWidget(search_btn) layout.addWidget(search_frame) # 信息栏 info_frame = QFrame() info_frame.setStyleSheet("background: #f1f5f9; border-bottom: 1px solid #e0e0e0;") info_layout = QHBoxLayout(info_frame) info_layout.setContentsMargins(16, 6, 16, 6) chat_type_text = "私聊" if self.chat_type == 'private' else "群聊" info_lbl = QLabel(f"搜索范围:{chat_type_text}「{self.target_name}」") info_lbl.setStyleSheet("font-size: 12px; color: #888;") info_layout.addWidget(info_lbl) layout.addWidget(info_frame) # 分割器 splitter = QSplitter(Qt.Horizontal) self._build_results_panel(splitter) self._build_detail_panel(splitter) splitter.setSizes([320, 500]) layout.addWidget(splitter) def _build_results_panel(self, parent_splitter): results_frame = QFrame() results_frame.setStyleSheet("QFrame { background: white; }") results_layout = QVBoxLayout(results_frame) results_layout.setContentsMargins(0, 0, 0, 0) results_layout.setSpacing(0) # 结果标题 header = QWidget() header.setFixedHeight(36) header.setStyleSheet("background: #fafafa; border-bottom: 1px solid #eee;") hl = QHBoxLayout(header) hl.setContentsMargins(12, 0, 12, 0) self.results_title = QLabel("搜索结果") self.results_title.setStyleSheet("font-size: 13px; font-weight: bold; color: #555;") hl.addWidget(self.results_title) results_layout.addWidget(header) self.results_list = QListWidget() self.results_list.setStyleSheet(""" QListWidget { border: none; background: white; outline: none; } QListWidget::item { padding: 10px 14px; border-bottom: 1px solid #f1f5f9; font-size: 12px; line-height: 1.4; } QListWidget::item:hover { background: #f8fafc; } QListWidget::item:selected { background: #eef2ff; } """) self.results_list.itemClicked.connect(self._show_message_detail) results_layout.addWidget(self.results_list) parent_splitter.addWidget(results_frame) def _build_detail_panel(self, parent_splitter): detail_frame = QFrame() detail_frame.setStyleSheet("QFrame { background: #f8fafc; }") detail_layout = QVBoxLayout(detail_frame) detail_layout.setContentsMargins(0, 0, 0, 0) detail_layout.setSpacing(0) # 详情标题 header = QWidget() header.setFixedHeight(36) header.setStyleSheet("background: #fafafa; border-bottom: 1px solid #eee;") hl = QHBoxLayout(header) hl.setContentsMargins(12, 0, 12, 0) detail_title = QLabel("消息详情") detail_title.setStyleSheet("font-size: 13px; font-weight: bold; color: #555;") hl.addWidget(detail_title) detail_layout.addWidget(header) self.detail_text = QTextEdit() self.detail_text.setReadOnly(True) self.detail_text.setStyleSheet(""" QTextEdit { border: none; background: #f8fafc; font-size: 13px; line-height: 1.6; padding: 16px; } """) self.detail_text.setPlaceholderText("选择左侧一条搜索结果查看消息详情…") detail_layout.addWidget(self.detail_text) parent_splitter.addWidget(detail_frame) def _perform_search(self): keyword = self.search_input.text().strip() if not keyword: return self.results_list.clear() self.detail_text.clear() self.results_title.setText("搜索中…") self.search_requested.emit(self.chat_type, str(self.target_id), keyword) def _show_message_detail(self, item): message_data = item.data(Qt.UserRole) if not message_data: return sender = message_data.get('sender', '未知') content = message_data.get('content', '') timestamp = message_data.get('timestamp', '') msg_type = message_data.get('msg_type', 'text') if msg_type == 'image': content_display = '
[图片消息]
' else: content_display = f'
{html.escape(content).replace(chr(92)+"n", "
")}
' detail_html = f"""
发送者:{html.escape(sender)}
时间:{html.escape(timestamp)}
消息内容:

{content_display}
""" self.detail_text.setHtml(detail_html) def update_search_results(self, results, keyword): self.search_results = results self.results_list.clear() count = len(results) self.results_title.setText(f"搜索结果({count} 条)") if not results: no_result = QListWidgetItem("未找到包含关键词的消息") no_result.setForeground(QColor('#94a3b8')) self.results_list.addItem(no_result) return for message in results: item = SearchResultItem(message, keyword) self.results_list.addItem(item) def closeEvent(self, event): self.search_results.clear() event.accept()