From 45d97b2989d98e9a21cf36728cdea024f3e5f041 Mon Sep 17 00:00:00 2001 From: liuwei Date: Mon, 13 Apr 2026 12:10:37 +0800 Subject: [PATCH] feat: preview emoji media in message list --- admin/dashboard/blueprints/messages.py | 14 ++++++++ admin/dashboard/templates/message_list.html | 36 ++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/admin/dashboard/blueprints/messages.py b/admin/dashboard/blueprints/messages.py index 1b0d298..33fb95b 100644 --- a/admin/dashboard/blueprints/messages.py +++ b/admin/dashboard/blueprints/messages.py @@ -1,4 +1,6 @@ import requests +import html +import re from flask import Blueprint, render_template, jsonify, request, current_app, Response, stream_with_context from .auth import login_required from loguru import logger @@ -31,6 +33,17 @@ def _is_usable_local_media_path(value: str) -> bool: return False +def _extract_emoji_preview_url(xml_text: str) -> str: + if not xml_text: + return '' + patterns = (r'cdnurl="([^"]+)"', r'encrypturl="([^"]+)"', r'externurl="([^"]+)"') + for pattern in patterns: + match = re.search(pattern, xml_text) + if match: + return html.unescape(match.group(1)) + return '' + + def _proxy_remote_media(target_url: str) -> Response: if not target_url: return Response("missing url", status=400) @@ -109,6 +122,7 @@ def get_messages(): if _is_emoji_message(msg): msg['content'] = '[表情]' + msg['emoji_preview_url'] = msg.get('image_path') or _extract_emoji_preview_url(msg.get('attachment_url', '')) continue # 处理消息内容,格式化引用消息 diff --git a/admin/dashboard/templates/message_list.html b/admin/dashboard/templates/message_list.html index 94948319..94bfa96 100644 --- a/admin/dashboard/templates/message_list.html +++ b/admin/dashboard/templates/message_list.html @@ -87,6 +87,16 @@ +
+
【表情消息】
+ +
【表情消息】等待下载完成
+
+
【视频消息】
@@ -138,8 +148,9 @@ {% raw %}{{ getMessageTypeName(selectedMessage.message_type) }}{% endraw %} {% raw %}{{ selectedMessage.content }}{% endraw %} - + + @@ -153,6 +164,7 @@ +
@@ -321,6 +333,10 @@ this.selectedMessage = message; this.imageDialogVisible = true; }, + showEmoji(message) { + this.selectedMessage = message; + this.imageDialogVisible = true; + }, showQuotedImage(url) { const resolvedUrl = this.getQuotedPreviewUrl(url); if (!resolvedUrl) return; @@ -341,6 +357,10 @@ }; return typeMap[type] || `未知类型(${type})`; }, + isEmojiMessage(message) { + if (!message) return false; + return ['47', '1048625', '1090519089'].includes(String(message.message_type)); + }, getImageUrl(imagePath) { if (!imagePath) return ''; @@ -367,6 +387,20 @@ return `/static/images/${fileName}`; }, + getEmojiPreviewUrl(message) { + if (!message) return ''; + if (message.image_path) { + return this.getImageUrl(message.image_path); + } + const previewUrl = message.emoji_preview_url || ''; + if (!previewUrl) { + return ''; + } + if (previewUrl.startsWith('http://') || previewUrl.startsWith('https://')) { + return this.getMediaProxyUrl(previewUrl); + } + return this.getImageUrl(previewUrl); + }, getMediaProxyUrl(url) { if (!url) return ''; if (url.startsWith('/api/messages/media_proxy')) {