You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
7.2 KiB

"""
全局聊天记录浏览窗口
"""
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QListWidget, QListWidgetItem, QTextEdit,
QSplitter, QFrame, QPushButton, QComboBox
)
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QColor
import html
from datetime import datetime
class HistoryWindow(QWidget):
refresh_requested = pyqtSignal()
search_requested = pyqtSignal(str) # keyword
def __init__(self, username, parent=None):
super().__init__(parent)
self.username = username
self.all_messages = []
self._init_ui()
def _init_ui(self):
self.setWindowTitle("聊天记录浏览器")
self.setGeometry(150, 150, 900, 650)
self.setMinimumSize(650, 450)
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# 顶部工具栏
toolbar = QFrame()
toolbar.setStyleSheet("QFrame { background: #f8fafc; border-bottom: 1px solid #e2e8f0; }")
tl = QHBoxLayout(toolbar)
tl.setContentsMargins(14, 8, 14, 8)
tl.setSpacing(8)
title = QLabel("📜 聊天记录")
title.setStyleSheet("font-size: 15px; font-weight: bold; color: #1e293b;")
tl.addWidget(title)
# 分类筛选
self.filter_combo = QComboBox()
self.filter_combo.addItems(["全部消息", "私聊消息", "群聊消息"])
self.filter_combo.setStyleSheet("""
QComboBox { padding: 4px 10px; border: 1px solid #ddd;
border-radius: 5px; background: white; font-size: 12px; }
""")
self.filter_combo.currentIndexChanged.connect(self._apply_filter)
tl.addWidget(self.filter_combo)
tl.addStretch()
refresh_btn = QPushButton("🔄 刷新")
refresh_btn.setStyleSheet("""
QPushButton { padding: 5px 14px; border: 1px solid #ddd;
border-radius: 5px; background: white; font-size: 12px; }
QPushButton:hover { background: #f0f0f0; }
""")
refresh_btn.clicked.connect(self.refresh_requested.emit)
tl.addWidget(refresh_btn)
layout.addWidget(toolbar)
# 主区域
splitter = QSplitter(Qt.Horizontal)
# 左侧消息列表
left_frame = QFrame()
left_frame.setStyleSheet("QFrame { background: white; }")
ll = QVBoxLayout(left_frame)
ll.setContentsMargins(0, 0, 0, 0)
ll.setSpacing(0)
self.msg_list = QListWidget()
self.msg_list.setStyleSheet("""
QListWidget { border: none; background: white; outline: none; }
QListWidget::item { padding: 8px 12px; border-bottom: 1px solid #f1f5f9; font-size: 12px; }
QListWidget::item:hover { background: #f8fafc; }
QListWidget::item:selected { background: #eef2ff; }
""")
self.msg_list.itemClicked.connect(self._show_detail)
ll.addWidget(self.msg_list)
splitter.addWidget(left_frame)
# 右侧详情
right_frame = QFrame()
right_frame.setStyleSheet("QFrame { background: #fafbfc; }")
rl = QVBoxLayout(right_frame)
rl.setContentsMargins(0, 0, 0, 0)
rl.setSpacing(0)
detail_header = QWidget()
detail_header.setFixedHeight(36)
detail_header.setStyleSheet("background: #fafafa; border-bottom: 1px solid #eee;")
dhl = QHBoxLayout(detail_header)
dhl.setContentsMargins(12, 0, 12, 0)
dhl.addWidget(QLabel("消息详情"))
rl.addWidget(detail_header)
self.detail_view = QTextEdit()
self.detail_view.setReadOnly(True)
self.detail_view.setStyleSheet("""
QTextEdit { border: none; background: #fafbfc;
font-size: 13px; line-height: 1.6; padding: 14px; }
""")
self.detail_view.setPlaceholderText("选择左侧一条消息查看详情...")
rl.addWidget(self.detail_view)
splitter.addWidget(right_frame)
splitter.setSizes([350, 550])
layout.addWidget(splitter)
def load_messages(self, messages):
"""加载消息列表"""
self.all_messages = messages
self._apply_filter()
def _apply_filter(self):
self.msg_list.clear()
filter_idx = self.filter_combo.currentIndex()
filtered = self.all_messages
if filter_idx == 1: # 私聊
filtered = [m for m in self.all_messages if m.get('chat_type') == 'private']
elif filter_idx == 2: # 群聊
filtered = [m for m in self.all_messages if m.get('chat_type') == 'group']
for msg in filtered:
self._add_list_item(msg)
def _add_list_item(self, msg):
sender = msg.get('sender', '?')
content = msg.get('content', '')
timestamp = msg.get('timestamp', '')
chat_type = msg.get('chat_type', 'private')
target = msg.get('target_name', '')
msg_type = msg.get('msg_type', 'text')
icon = "👥" if chat_type == 'group' else "💬"
if msg_type == 'image':
preview = '[图片]'
else:
preview = content[:50] + '...' if len(content) > 50 else content
time_short = timestamp.split(' ')[-1][:5] if ' ' in timestamp else timestamp[:5]
text = f"{icon} {sender}{target} {time_short}\n {preview}"
item = QListWidgetItem(text)
item.setData(Qt.UserRole, msg)
self.msg_list.addItem(item)
def _show_detail(self, item):
msg = item.data(Qt.UserRole)
if not msg:
return
sender = msg.get('sender', '?')
content = msg.get('content', '')
timestamp = msg.get('timestamp', '')
chat_type = msg.get('chat_type', 'private')
target = msg.get('target_name', '?')
msg_type = msg.get('msg_type', 'text')
type_label = "群聊" if chat_type == 'group' else "私聊"
if msg_type == 'image':
content_html = f'<div style="font-size: 14px; color: #6366f1;">[图片消息]</div>'
else:
content_html = f'<div style="font-size: 14px; line-height: 1.7; color: #333;">{html.escape(content)}</div>'
detail_html = f"""
<div style="font-family: 'Microsoft YaHei', sans-serif;">
<div style="background: #eef2ff; padding: 10px 14px; border-radius: 8px; margin-bottom: 12px;">
<table style="width:100%; font-size: 13px;">
<tr><td style="color:#6366f1; width:60px;"><b>发送者:</b></td><td>{html.escape(sender)}</td></tr>
<tr><td style="color:#6366f1;"><b>类型:</b></td><td>{type_label}</td></tr>
<tr><td style="color:#6366f1;"><b>对象:</b></td><td>{html.escape(target)}</td></tr>
<tr><td style="color:#6366f1;"><b>时间:</b></td><td>{html.escape(timestamp)}</td></tr>
</table>
</div>
<div style="background: white; padding: 14px; border-radius: 8px; border: 1px solid #e0e0e0;">
<b style="color:#1e293b;">消息内容:</b><br><br>
{content_html}
</div>
</div>
"""
self.detail_view.setHtml(detail_html)
def closeEvent(self, event):
self.all_messages.clear()
event.accept()