From 59898621f5406541866b35e725420e1742abe4d1 Mon Sep 17 00:00:00 2001 From: liuwei Date: Tue, 1 Apr 2025 15:28:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E6=B6=88=E6=81=AF=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/dashboard/server.py | 76 +++++++++++++++++++------------- message_storage/message_to_db.py | 22 +++++---- utils/message_formatter.py | 38 ++++++++++++++++ 3 files changed, 97 insertions(+), 39 deletions(-) create mode 100644 utils/message_formatter.py diff --git a/admin/dashboard/server.py b/admin/dashboard/server.py index dfa249c..65daf33 100644 --- a/admin/dashboard/server.py +++ b/admin/dashboard/server.py @@ -4,20 +4,19 @@ import sys import threading from datetime import datetime import time - +import xml.etree.ElementTree as ET from db.message_storage import MessageStorageDB from db.stats_db import StatsDBOperator -from utils.wechat.contact_manager import ContactManager +from flask import Flask, render_template, request, jsonify, redirect, url_for, session, send_from_directory +from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus +# 导入消息格式化工具 +from utils.message_formatter import format_quote_message +# 导入toml用于配置文件 +import toml # 添加项目根目录到系统路径,确保可以导入项目模块 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) -from flask import Flask, render_template, request, jsonify, redirect, url_for, session, send_from_directory -from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus - -# 导入toml用于配置文件 -import toml - class DashboardServer: """统计看板服务器""" @@ -152,12 +151,12 @@ class DashboardServer: def errors(): return render_template('errors.html') - @app.route('/messages') @login_required def message_list_page(): """消息列表页面""" return render_template('message_list.html') + # 在_create_app方法中添加新的路由 @app.route('/robot_management') @login_required @@ -170,31 +169,31 @@ class DashboardServer: try: # 获取所有群组列表 groups = GroupBotManager.get_group_list() - + # 如果方法返回None或发生异常,使用本地缓存 if groups is None and hasattr(GroupBotManager, "local_cache"): groups = GroupBotManager.local_cache.get("group_list", set()) - + # 如果仍然为None,则初始化为空集合 if groups is None: groups = set() - + self.logger.info(f"获取到 {len(groups)} 个群组") group_data = [] - + for group_id in groups: try: # 获取群名称,如果失败则使用默认值 group_name = self.contact_manager.get_nickname(group_id) if not group_name: group_name = f"未知群组({group_id})" - + # 获取机器人状态,如果失败则使用默认值 try: robot_status = GroupBotManager.get_group_permission(group_id, Feature.ROBOT) except: robot_status = PermissionStatus.UNKNOWN - + group_data.append({ "group_id": group_id, "group_name": group_name, @@ -208,7 +207,7 @@ class DashboardServer: "group_name": "获取失败", "robot_status": "unknown" }) - + return jsonify({"success": True, "data": group_data}) except Exception as e: self.logger.error(f"获取群组列表失败: {e}") @@ -220,7 +219,7 @@ class DashboardServer: try: permissions = GroupBotManager.list_group_permissions(group_id) permission_data = [] - + for feature, status in permissions.items(): permission_data.append({ "feature_id": feature.value, @@ -228,7 +227,7 @@ class DashboardServer: "feature_description": feature.description, "status": status.value }) - + return jsonify({"success": True, "data": permission_data}) except Exception as e: self.logger.error(f"获取群组权限失败: {e}") @@ -241,11 +240,11 @@ class DashboardServer: data = request.json feature_id = data.get('feature_id') status = data.get('status') - + try: feature = Feature(int(feature_id)) new_status = PermissionStatus(status) - + # 特殊处理ROBOT功能 if feature == Feature.ROBOT: r = self.db_manager.get_redis_connection() @@ -255,7 +254,7 @@ class DashboardServer: else: GroupBotManager.local_cache["group_list"].remove(group_id) r.srem("group:list", group_id) - + GroupBotManager.set_group_permission(group_id, feature, new_status) return jsonify({"success": True}) except Exception as e: @@ -269,15 +268,15 @@ class DashboardServer: data = request.json operation = data.get('operation') group_ids = data.get('group_ids', []) - + results = {} - + try: if operation == 'remove_groups': for group_id in group_ids: result = GroupBotManager.remove_group(group_id) results[group_id] = result - + return jsonify({"success": True, "results": results}) else: return jsonify({"success": False, "error": "不支持的操作类型"}), 400 @@ -486,7 +485,6 @@ class DashboardServer: self.logger.error(f"添加群组失败: {e}") return jsonify({"success": False, "error": str(e)}), 500 - @app.route('/api/messages', methods=['GET']) @login_required def get_messages(): @@ -499,7 +497,7 @@ class DashboardServer: search_text = request.args.get('search_text') page = int(request.args.get('page', 1)) page_size = int(request.args.get('page_size', 20)) - + # 调用数据库方法获取消息 result = self.message_storage.get_messages_by_filter( group_id=group_id, @@ -509,15 +507,31 @@ class DashboardServer: page=page, page_size=page_size ) - - # 处理消息数据,添加群组名称和发送者昵称 + + # 处理消息数据,添加群组名称和发送者昵称,并格式化引用消息 for msg in result['messages']: # 获取群组名称 msg['group_name'] = self.contact_manager.get_nickname(msg['group_id']) or msg['group_id'] - + # 获取发送者昵称 msg['sender_name'] = self.contact_manager.get_nickname(msg['sender']) or msg['sender'] - + + # 处理消息内容,格式化引用消息 + if msg['message_type'] == 49 and msg['content']: # 应用消息类型 + try: + # 检查是否为引用消息 + if '' in msg['content']: + # 使用格式化工具处理引用消息 + msg['content'] = format_quote_message(msg['content']) + else: + # 其他类型的应用消息,解析 XML 提取标题 + root = ET.fromstring(msg['content']) + title_elem = root.find('.//title') + if title_elem is not None: + msg['content'] = title_elem.text + except Exception as e: + self.logger.error(f"解析消息类型49出错: {e}") + return jsonify(result) except Exception as e: self.logger.error(f"获取消息列表失败: {e}") @@ -536,7 +550,7 @@ class DashboardServer: 'group_id': group_id, 'group_name': self.contact_manager.get_nickname(group_id) or group_id }) - + return jsonify({'groups': groups}) except Exception as e: self.logger.error(f"获取群组列表失败: {e}") diff --git a/message_storage/message_to_db.py b/message_storage/message_to_db.py index 344e054..f21a634 100644 --- a/message_storage/message_to_db.py +++ b/message_storage/message_to_db.py @@ -7,6 +7,8 @@ from wcferry import WxMsg from db.connection import DBConnectionManager from db.message_storage import MessageStorageDB +# 导入消息格式化工具 +from utils.message_formatter import format_quote_message # 配置日志 logging.basicConfig( @@ -209,18 +211,22 @@ class MessageStorage: hours_ago = int( (current_time - datetime.strptime(last_summary_time, '%Y-%m-%d %H:%M:%S')).total_seconds() / 3600) + 1 messages = self.message_db.get_recent_messages(group_id, hours_ago=hours_ago) - # 构建最终的结果字符串 result = [] for msg in messages: - timestamp, sender, content, message_type = msg['timestamp'], msg['sender'], msg['content'], msg[ - 'message_type'] + timestamp, sender, content, message_type = msg['timestamp'], msg['sender'], msg['content'], msg['message_type'] try: - if message_type == 49: # 注意这里是整数类型 - # 解析 XML 字符串 - root = ET.fromstring(content) - # 提取 title 内容 - content = root.find('.//title').text + if message_type == 49: # 应用消息类型 + # 检查是否为引用消息 + if '' in content: + # 使用格式化工具处理引用消息 + content = format_quote_message(content) + else: + # 其他类型的应用消息,解析 XML 提取标题 + root = ET.fromstring(content) + title_elem = root.find('.//title') + if title_elem is not None: + content = title_elem.text except Exception as e: logger.error(f"解析消息类型49出错: {e}") diff --git a/utils/message_formatter.py b/utils/message_formatter.py new file mode 100644 index 0000000..c2e9957 --- /dev/null +++ b/utils/message_formatter.py @@ -0,0 +1,38 @@ +import xml.etree.ElementTree as ET +import html + + +def format_quote_message(xml_content): + """ + 格式化引用消息 + + Args: + xml_content: XML格式的消息内容 + + Returns: + 格式化后的消息文本 + """ + try: + # 解析XML + root = ET.fromstring(xml_content) + + # 获取主消息内容 + title_elem = root.find('.//title') + main_content = title_elem.text if title_elem is not None else "" + + # 获取引用消息信息 + refer_msg = root.find('.//refermsg') + if refer_msg is not None: + display_name = refer_msg.find('displayname').text if refer_msg.find('displayname') is not None else "未知用户" + quoted_content = refer_msg.find('content').text if refer_msg.find('content') is not None else "" + + # 解码HTML实体 + quoted_content = html.unescape(quoted_content) + + # 构建格式化的引用消息 + formatted_message = f"┌─────────────────────────────────\n│ 引用 {display_name}:{quoted_content}\n└─────────────────────────────────\n{main_content}" + return formatted_message + + return main_content + except Exception as e: + return f"解析引用消息失败: {str(e)}"