diff --git a/src/pages/ChatPage.scss b/src/pages/ChatPage.scss index 953341b..4ccdd2b 100644 --- a/src/pages/ChatPage.scss +++ b/src/pages/ChatPage.scss @@ -4132,4 +4132,170 @@ .session-name { font-weight: 500; } +} + +// 消息信息弹窗 +.message-info-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.4); + backdrop-filter: blur(4px); + z-index: 2000; + display: flex; + align-items: center; + justify-content: center; +} + +.message-info-modal { + width: 360px; + max-width: 90vw; + max-height: 80vh; + background: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: 12px; + display: flex; + flex-direction: column; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2); + overflow: hidden; + + .detail-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px; + border-bottom: 1px solid var(--border-color); + + h4 { + font-size: 15px; + font-weight: 600; + color: var(--text-primary); + margin: 0; + } + + .close-btn { + background: none; + border: none; + padding: 4px; + cursor: pointer; + color: var(--text-secondary); + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + background: var(--bg-hover); + color: var(--text-primary); + } + } + } + + .detail-content { + flex: 1; + overflow-y: auto; + padding: 16px; + + &::-webkit-scrollbar { width: 4px; } + &::-webkit-scrollbar-thumb { background: var(--text-tertiary); border-radius: 2px; } + } + + .detail-section { + margin-bottom: 20px; + &:last-child { margin-bottom: 0; } + + .section-title { + display: flex; + align-items: center; + gap: 6px; + font-size: 12px; + font-weight: 600; + color: var(--text-secondary); + margin-bottom: 12px; + letter-spacing: 0.5px; + + svg { opacity: 0.7; } + + .copy-btn { + margin-left: auto; + display: flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + padding: 0; + border: none; + border-radius: 4px; + background: transparent; + color: var(--text-tertiary); + cursor: pointer; + &:hover { background: var(--bg-secondary); color: var(--text-primary); } + } + } + } + + .detail-item { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 0; + border-bottom: 1px solid var(--border-color); + font-size: 13px; + + &:last-child { border-bottom: none; } + + svg { color: var(--text-tertiary); flex-shrink: 0; } + + .label { color: var(--text-secondary); flex-shrink: 0; } + + .value { + flex: 1; + text-align: right; + color: var(--text-primary); + word-break: break-all; + user-select: text; + + &.highlight { color: var(--primary); font-weight: 600; } + &.mono { font-family: 'Consolas', 'Monaco', monospace; font-size: 12px; } + } + + .copy-btn { + display: flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + padding: 0; + border: none; + border-radius: 4px; + background: transparent; + color: var(--text-tertiary); + cursor: pointer; + flex-shrink: 0; + opacity: 0; + transition: opacity 0.15s, color 0.15s, background 0.15s; + + &:hover { background: var(--bg-secondary); color: var(--text-primary); } + svg { color: inherit; } + } + + &:hover .copy-btn { opacity: 1; } + } + + .raw-content-box { + background: var(--bg-tertiary); + border-radius: 8px; + padding: 12px; + max-height: 200px; + overflow: auto; + + pre { + margin: 0; + white-space: pre-wrap; + word-break: break-all; + font-family: 'Consolas', 'Monaco', monospace; + font-size: 12px; + color: var(--text-primary); + user-select: text; + } + } } \ No newline at end of file diff --git a/src/pages/ChatPage.tsx b/src/pages/ChatPage.tsx index b2373dd..b795fe4 100644 --- a/src/pages/ChatPage.tsx +++ b/src/pages/ChatPage.tsx @@ -324,6 +324,7 @@ function ChatPage(_props: ChatPageProps) { // 消息右键菜单 const [contextMenu, setContextMenu] = useState<{ x: number, y: number, message: Message } | null>(null) + const [showMessageInfo, setShowMessageInfo] = useState(null) const [editingMessage, setEditingMessage] = useState<{ message: Message, content: string } | null>(null) // 多选模式 @@ -2735,11 +2736,143 @@ function ChatPage(_props: ChatPageProps) { 删除消息 +
{ setShowMessageInfo(contextMenu.message); setContextMenu(null) }}> + + 查看消息信息 +
, document.body )} + {/* 消息信息弹窗 */} + {showMessageInfo && createPortal( +
setShowMessageInfo(null)}> +
e.stopPropagation()}> +
+

消息详情

+ +
+
+
+
+ + Local ID + {showMessageInfo.localId} + +
+
+ + Server ID + {showMessageInfo.serverId} +
+
+ 消息类型 + {showMessageInfo.localType} +
+
+ 发送者 + {showMessageInfo.senderUsername || '-'} + {showMessageInfo.senderUsername && ( + + )} +
+
+ + 创建时间 + {new Date(showMessageInfo.createTime * 1000).toLocaleString()} +
+
+ 发送状态 + {showMessageInfo.isSend === 1 ? '发送' : '接收'} +
+
+ + {(showMessageInfo.imageMd5 || showMessageInfo.videoMd5 || showMessageInfo.voiceDurationSeconds != null) && ( +
+
+ + 媒体信息 +
+ {showMessageInfo.imageMd5 && ( +
+ Image MD5 + {showMessageInfo.imageMd5} + +
+ )} + {showMessageInfo.imageDatName && ( +
+ DAT 文件 + {showMessageInfo.imageDatName} +
+ )} + {showMessageInfo.videoMd5 && ( +
+ Video MD5 + {showMessageInfo.videoMd5} + +
+ )} + {showMessageInfo.voiceDurationSeconds != null && ( +
+ + 语音时长 + {showMessageInfo.voiceDurationSeconds}秒 +
+ )} +
+ )} + + {(showMessageInfo.emojiMd5 || showMessageInfo.emojiCdnUrl) && ( +
+
+ 表情包信息 +
+ {showMessageInfo.emojiMd5 && ( +
+ MD5 + {showMessageInfo.emojiMd5} +
+ )} + {showMessageInfo.emojiCdnUrl && ( +
+ CDN URL + {showMessageInfo.emojiCdnUrl} +
+ )} +
+ )} + + {showMessageInfo.localType !== 1 && (showMessageInfo.rawContent || showMessageInfo.content) && ( +
+
+ 原始消息内容 + +
+
+
{showMessageInfo.rawContent || showMessageInfo.content}
+
+
+ )} +
+
+
, + document.body + )} + {/* 修改消息弹窗 */} {editingMessage && createPortal(