From 94e0c16e7b90ece5b0af695b69762e7cde6faedc Mon Sep 17 00:00:00 2001 From: liuwei Date: Wed, 4 Jun 2025 17:52:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/dashboard/blueprints/auth.py | 12 ++- admin/dashboard/blueprints/contacts.py | 19 +++-- admin/dashboard/blueprints/file_browser.py | 31 ++++--- admin/dashboard/blueprints/main.py | 3 +- admin/dashboard/blueprints/messages.py | 2 +- admin/dashboard/blueprints/plugin_routes.py | 70 ++++++++------- admin/dashboard/blueprints/stats.py | 13 ++- admin/dashboard/blueprints/system.py | 13 ++- admin/dashboard/blueprints/virtual_group.py | 95 +++++++++++---------- 9 files changed, 148 insertions(+), 110 deletions(-) diff --git a/admin/dashboard/blueprints/auth.py b/admin/dashboard/blueprints/auth.py index 5e6b330..e16157a 100644 --- a/admin/dashboard/blueprints/auth.py +++ b/admin/dashboard/blueprints/auth.py @@ -4,6 +4,7 @@ from functools import wraps # 创建认证蓝图 auth_bp = Blueprint('auth', __name__) + # 登录检查装饰器 def login_required(f): @wraps(f) @@ -11,8 +12,10 @@ def login_required(f): if not session.get('logged_in'): return redirect(url_for('auth.login')) return f(*args, **kwargs) + return decorated_function + # 登录页面 @auth_bp.route('/login', methods=['GET', 'POST']) def login(): @@ -20,20 +23,21 @@ def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] - + # 从应用上下文获取服务器实例,而不是从蓝图对象 server = current_app.dashboard_server - + if username == server.username and password == server.password: session['logged_in'] = True return redirect(url_for('main.index')) else: error = '用户名或密码错误' - + return render_template('login.html', error=error) + # 登出 @auth_bp.route('/logout') def logout(): session.pop('logged_in', None) - return redirect(url_for('auth.login')) \ No newline at end of file + return redirect(url_for('auth.login')) diff --git a/admin/dashboard/blueprints/contacts.py b/admin/dashboard/blueprints/contacts.py index 6e96bbc..c3b4bbb 100644 --- a/admin/dashboard/blueprints/contacts.py +++ b/admin/dashboard/blueprints/contacts.py @@ -7,15 +7,17 @@ from loguru import logger # 创建联系人管理蓝图 contacts_bp = Blueprint('contacts', __name__, url_prefix='/contacts') + def send_message_in_thread(func, *args, **kwargs): """在独立线程中发送消息""" + def run(): loop = None try: # 创建新的事件循环 loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) - + # 创建异步任务 async def send(): try: @@ -25,13 +27,13 @@ def send_message_in_thread(func, *args, **kwargs): finally: # 发送完成后停止事件循环 loop.stop() - + # 创建并运行任务 asyncio.run_coroutine_threadsafe(send(), loop) - + # 运行事件循环直到停止 loop.run_forever() - + except Exception as e: logger.error(f"线程执行失败: {e}") finally: @@ -42,23 +44,24 @@ def send_message_in_thread(func, *args, **kwargs): pending = asyncio.all_tasks(loop) for task in pending: task.cancel() - + # 运行事件循环直到所有任务都被取消 loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True)) - + # 停止事件循环 loop.stop() - + # 关闭事件循环 loop.close() except Exception as e: logger.error(f"清理资源失败: {e}") - + # 创建并启动线程 thread = threading.Thread(target=run) thread.daemon = True # 设置为守护线程,这样主程序退出时线程会自动结束 thread.start() + # 联系人管理页面 @contacts_bp.route('/') @login_required diff --git a/admin/dashboard/blueprints/file_browser.py b/admin/dashboard/blueprints/file_browser.py index 6e3e562..fd4f92f 100644 --- a/admin/dashboard/blueprints/file_browser.py +++ b/admin/dashboard/blueprints/file_browser.py @@ -4,11 +4,13 @@ from loguru import logger file_browser_bp = Blueprint('file_browser', __name__) + @file_browser_bp.route('/file_browser') def file_browser(): """文件浏览器页面""" return render_template('file_browser.html') + @file_browser_bp.route('/api/list_files') def list_files(): """获取指定目录下的文件列表""" @@ -18,14 +20,14 @@ def list_files(): project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # 构建完整路径 full_path = os.path.join(project_root, path) - + # 安全检查:确保路径在项目根目录内 if not os.path.abspath(full_path).startswith(project_root): return jsonify({"success": False, "message": "访问被拒绝:路径超出项目范围"}) - + if not os.path.exists(full_path): return jsonify({"success": False, "message": "目录不存在"}) - + # 需要隐藏的目录列表 hidden_dirs = { '__pycache__', @@ -44,30 +46,30 @@ def list_files(): '.eggs', '*.egg-info' } - + items = [] for item in os.listdir(full_path): # 跳过隐藏文件和目录 if item.startswith('.'): continue - + item_path = os.path.join(full_path, item) is_dir = os.path.isdir(item_path) - + # 跳过隐藏目录 if is_dir and item in hidden_dirs: continue - + items.append({ "name": item, "is_dir": is_dir, "size": os.path.getsize(item_path) if not is_dir else 0, "modified": os.path.getmtime(item_path) }) - + # 对文件列表进行排序:目录在前,同类型按名称排序 items.sort(key=lambda x: (not x["is_dir"], x["name"].lower())) - + return jsonify({ "success": True, "data": { @@ -79,6 +81,7 @@ def list_files(): logger.error(f"列出文件失败: {e}") return jsonify({"success": False, "message": str(e)}) + @file_browser_bp.route('/api/download_file') def download_file(): """下载指定文件""" @@ -88,17 +91,17 @@ def download_file(): project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # 构建完整路径 full_path = os.path.join(project_root, path) - + # 安全检查:确保路径在项目根目录内 if not os.path.abspath(full_path).startswith(project_root): return jsonify({"success": False, "message": "访问被拒绝:路径超出项目范围"}) - + if not os.path.exists(full_path): return jsonify({"success": False, "message": "文件不存在"}) - + if os.path.isdir(full_path): return jsonify({"success": False, "message": "不能下载目录"}) - + return send_file( full_path, as_attachment=True, @@ -106,4 +109,4 @@ def download_file(): ) except Exception as e: logger.error(f"下载文件失败: {e}") - return jsonify({"success": False, "message": str(e)}) \ No newline at end of file + return jsonify({"success": False, "message": str(e)}) diff --git a/admin/dashboard/blueprints/main.py b/admin/dashboard/blueprints/main.py index a2d84c0..41d3f0b 100644 --- a/admin/dashboard/blueprints/main.py +++ b/admin/dashboard/blueprints/main.py @@ -4,7 +4,8 @@ from .auth import login_required # 创建主页蓝图 main_bp = Blueprint('main', __name__) + @main_bp.route('/') @login_required def index(): - return render_template('index.html') \ No newline at end of file + return render_template('index.html') diff --git a/admin/dashboard/blueprints/messages.py b/admin/dashboard/blueprints/messages.py index 94d5651..44a0bfb 100644 --- a/admin/dashboard/blueprints/messages.py +++ b/admin/dashboard/blueprints/messages.py @@ -127,4 +127,4 @@ def get_hourly_message_trend(): }) except Exception as e: logger.error(f"获取按小时聊天趋势数据失败: {e}") - return jsonify({'success': False, 'error': str(e)}), 500 \ No newline at end of file + return jsonify({'success': False, 'error': str(e)}), 500 diff --git a/admin/dashboard/blueprints/plugin_routes.py b/admin/dashboard/blueprints/plugin_routes.py index 73972fa..d71f140 100644 --- a/admin/dashboard/blueprints/plugin_routes.py +++ b/admin/dashboard/blueprints/plugin_routes.py @@ -18,6 +18,7 @@ LOG = logger def robot_management(): return render_template('plugins_manage.html') + @plugin_routes.route('/api/plugins', methods=['GET']) @login_required def get_plugins(): @@ -26,7 +27,7 @@ def get_plugins(): server = current_app.dashboard_server # 获取插件注册表 plugins = server.plugin_registry.get_all_plugins() - + # 转换为前端需要的格式 plugin_list = [] for name, plugin in plugins.items(): @@ -35,7 +36,7 @@ def get_plugins(): module_name = plugin.__class__.__module__.split('.')[-2] except (IndexError, AttributeError): module_name = "unknown" - + plugin_info = { "name": plugin.name, "module_name": module_name, @@ -45,12 +46,13 @@ def get_plugins(): "status": plugin.status.name if hasattr(plugin, 'status') else 'UNKNOWN' } plugin_list.append(plugin_info) - + return jsonify({"success": True, "data": plugin_list}) except Exception as e: LOG.error(f"获取插件列表失败: {str(e)}", exc_info=True) return jsonify({"success": False, "message": f"获取插件列表失败: {str(e)}"}) + @plugin_routes.route('/api/plugins/info', methods=['GET']) @login_required def get_plugin_info(): @@ -60,19 +62,19 @@ def get_plugin_info(): plugin_name = request.args.get('plugin_name') if not plugin_name: return jsonify({"success": False, "message": "缺少插件名称参数"}) - + # 获取插件管理器 display_name, plugin = server.plugin_manager.find_plugin_by_name(plugin_name) - + if not plugin: return jsonify({"success": False, "message": f"未找到插件: {plugin_name}"}) - + # 获取插件模块名 try: module_name = plugin.__class__.__module__.split('.')[-2] except (IndexError, AttributeError): module_name = "unknown" - + # 构建详细信息 plugin_info = { "name": plugin.name, @@ -85,12 +87,13 @@ def get_plugin_info(): "commands": getattr(plugin, 'commands', []), "config": getattr(plugin, '_config', {}) } - + return jsonify({"success": True, "data": plugin_info}) except Exception as e: LOG.error(f"获取插件详情失败: {str(e)}", exc_info=True) return jsonify({"success": False, "message": f"获取插件详情失败: {str(e)}"}) + @plugin_routes.route('/api/plugins/enable', methods=['POST']) @login_required def enable_plugin(): @@ -101,7 +104,7 @@ def enable_plugin(): plugin_name = data.get('plugin_name') if not plugin_name: return jsonify({"success": False, "message": "缺少插件名称参数"}) - + # 获取插件管理器 # 启用插件 if server.plugin_manager.start_plugin(plugin_name): @@ -112,6 +115,7 @@ def enable_plugin(): LOG.error(f"启用插件失败: {str(e)}", exc_info=True) return jsonify({"success": False, "message": f"启用插件失败: {str(e)}"}) + @plugin_routes.route('/api/plugins/disable', methods=['POST']) @login_required def disable_plugin(): @@ -122,7 +126,7 @@ def disable_plugin(): plugin_name = data.get('plugin_name') if not plugin_name: return jsonify({"success": False, "message": "缺少插件名称参数"}) - + # 禁用插件 if server.plugin_manager.stop_plugin(plugin_name): return jsonify({"success": True, "message": f"插件 {plugin_name} 禁用成功"}) @@ -132,6 +136,7 @@ def disable_plugin(): LOG.error(f"禁用插件失败: {str(e)}", exc_info=True) return jsonify({"success": False, "message": f"禁用插件失败: {str(e)}"}) + @plugin_routes.route('/api/plugins/reload', methods=['POST']) @login_required def reload_plugin(): @@ -142,10 +147,10 @@ def reload_plugin(): plugin_name = data.get('plugin_name') if not plugin_name: return jsonify({"success": False, "message": "缺少插件名称参数"}) - + # 重载插件 reloaded_plugin = server.plugin_manager.reload_plugin(plugin_name) - + if reloaded_plugin: return jsonify({"success": True, "message": f"插件 {plugin_name} 重载成功"}) else: @@ -164,34 +169,34 @@ def get_raw_plugin_config(): plugin_name = request.args.get('plugin_name') if not plugin_name: return jsonify({"success": False, "message": "缺少插件名称参数"}) - + # 获取插件管理器 - + # 查找插件 display_name, plugin = server.plugin_manager.find_plugin_by_name(plugin_name) - + if not plugin: return jsonify({"success": False, "message": f"未找到插件: {plugin_name}"}) - + # 获取配置文件路径 config_path = plugin.get_config_path() - + if not os.path.exists(config_path): return jsonify({"success": False, "message": f"配置文件不存在: {config_path}"}) - + # 读取配置文件内容 with open(config_path, 'r', encoding='utf-8') as f: config_text = f.read() - + # 确定配置文件格式 format_type = 'toml' if config_path.endswith('.json'): format_type = 'json' elif config_path.endswith('.yaml') or config_path.endswith('.yml'): format_type = 'yaml' - + return jsonify({ - "success": True, + "success": True, "data": config_text, "format": format_type }) @@ -199,6 +204,7 @@ def get_raw_plugin_config(): LOG.error(f"获取插件配置文件失败: {str(e)}", exc_info=True) return jsonify({"success": False, "message": f"获取配置文件失败: {str(e)}"}) + @plugin_routes.route('/api/plugins/config/update', methods=['POST']) @login_required def update_plugin_config(): @@ -209,27 +215,27 @@ def update_plugin_config(): plugin_name = data.get('plugin_name') config_text = data.get('config_text') format_type = data.get('format', 'toml') - + if not plugin_name or config_text is None: return jsonify({"success": False, "message": "缺少必要参数"}) - + # 查找插件 # 获取插件管理器 display_name, plugin = server.plugin_manager.find_plugin_by_name(plugin_name) - + if not plugin: return jsonify({"success": False, "message": f"未找到插件: {plugin_name}"}) - + # 获取配置文件路径 config_path = plugin.get_config_path() - + # 确保配置目录存在 os.makedirs(os.path.dirname(config_path), exist_ok=True) - + # 写入配置文件 with open(config_path, 'w', encoding='utf-8') as f: f.write(config_text) - + # 解析配置并更新插件内部配置 try: if format_type == 'toml': @@ -238,15 +244,15 @@ def update_plugin_config(): config_obj = json.loads(config_text) else: return jsonify({"success": False, "message": f"不支持的配置格式: {format_type}"}) - + # 更新插件内部配置 plugin._config = config_obj - + return jsonify({"success": True, "message": "配置已保存"}) except Exception as e: LOG.error(f"解析配置失败: {str(e)}", exc_info=True) return jsonify({"success": False, "message": f"配置已保存,但解析失败: {str(e)}"}) - + except Exception as e: LOG.error(f"更新插件配置失败: {str(e)}", exc_info=True) - return jsonify({"success": False, "message": f"更新配置失败: {str(e)}"}) \ No newline at end of file + return jsonify({"success": False, "message": f"更新配置失败: {str(e)}"}) diff --git a/admin/dashboard/blueprints/stats.py b/admin/dashboard/blueprints/stats.py index 95a8bd8..74ceaf1 100644 --- a/admin/dashboard/blueprints/stats.py +++ b/admin/dashboard/blueprints/stats.py @@ -7,27 +7,32 @@ from flask import current_app # 创建统计数据蓝图 stats_bp = Blueprint('stats', __name__) + # 页面路由 @stats_bp.route('/plugins') @login_required def plugins(): return render_template('plugins.html') + @stats_bp.route('/users') @login_required def users_page(): return render_template('users.html') + @stats_bp.route('/groups') @login_required def groups(): return render_template('groups.html') + @stats_bp.route('/errors') @login_required def errors(): return render_template('errors.html') + # API路由 @stats_bp.route('/api/user_stats') @login_required @@ -49,6 +54,7 @@ def api_user_stats(): logger.error(f"获取用户统计失败: {e}") return jsonify({"success": False, "error": str(e)}), 500 + @stats_bp.route('/api/group_stats') @login_required def api_group_stats(): @@ -69,6 +75,7 @@ def api_group_stats(): logger.error(f"获取群组统计失败: {e}") return jsonify({"success": False, "error": str(e)}), 500 + @stats_bp.route('/api/plugin_stats') @login_required def api_plugin_stats(): @@ -81,6 +88,7 @@ def api_plugin_stats(): logger.error(f"获取插件统计失败: {e}") return jsonify({"success": False, "error": str(e)}), 500 + @stats_bp.route('/api/error_logs') @login_required def api_error_logs(): @@ -94,6 +102,7 @@ def api_error_logs(): logger.error(f"获取错误日志失败: {e}") return jsonify({"success": False, "error": str(e)}), 500 + @stats_bp.route('/api/dashboard_summary') @login_required def api_dashboard_summary(): @@ -118,6 +127,7 @@ def api_dashboard_summary(): logger.error(f"获取仪表盘摘要数据出错: {e}") return jsonify({"success": False, "error": str(e)}), 500 + @stats_bp.route('/api/plugin_trend') @login_required def api_plugin_trend(): @@ -131,6 +141,7 @@ def api_plugin_trend(): logger.error(f"获取插件趋势失败: {e}") return jsonify({"success": False, "error": str(e)}), 500 + @stats_bp.route('/api/error_detail/') @login_required def api_error_detail(error_id): @@ -140,4 +151,4 @@ def api_error_detail(error_id): return jsonify({"success": True, "data": detail}) except Exception as e: logger.error(f"获取错误详情失败: {e}") - return jsonify({"success": False, "error": str(e)}), 500 \ No newline at end of file + return jsonify({"success": False, "error": str(e)}), 500 diff --git a/admin/dashboard/blueprints/system.py b/admin/dashboard/blueprints/system.py index bdd246c..6119855 100644 --- a/admin/dashboard/blueprints/system.py +++ b/admin/dashboard/blueprints/system.py @@ -13,20 +13,27 @@ system_bp = Blueprint('system', __name__) # 记录应用启动时间 APP_START_TIME = time.time() + + @system_bp.route('/api_docs') @login_required def api_docs(): return render_template('api_docs.html') + + @system_bp.route('/system_status') @login_required def system_status(): return render_template('system_status.html') + + # 页面路由 @system_bp.route('/wx_logs') @login_required def wx_logs(): return render_template('wx_logs.html') + # API路由 @system_bp.route('/api/system_info') @login_required @@ -50,6 +57,7 @@ def api_system_info(): logger.error(f"获取系统信息失败: {e}") return jsonify({"success": False, "error": str(e)}), 500 + @system_bp.route('/api/wx_logs') @login_required def api_wx_logs(): @@ -59,14 +67,14 @@ def api_wx_logs(): # 修正日志文件路径计算,获取项目根目录 project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) - + if log_type == 'error': log_file = os.path.join(project_root, 'wx_error.log') elif log_type == 'debug': log_file = os.path.join(project_root, 'wx_debug.log') else: log_file = os.path.join(project_root, 'wx_info.log') - + # 读取日志文件 log_content = [] if os.path.exists(log_file): @@ -95,6 +103,7 @@ def api_wx_logs(): logger.error(f"获取微信日志失败: {e}") return jsonify({"success": False, "error": str(e)}), 500 + # 在现有路由下添加 @system_bp.route('/api/current_user_info', methods=['GET']) @login_required diff --git a/admin/dashboard/blueprints/virtual_group.py b/admin/dashboard/blueprints/virtual_group.py index bce4404..82a60f4 100644 --- a/admin/dashboard/blueprints/virtual_group.py +++ b/admin/dashboard/blueprints/virtual_group.py @@ -3,15 +3,16 @@ import uuid from flask import Blueprint, jsonify, request, current_app, render_template from .auth import login_required - virtual_group_bp = Blueprint('virtual_group', __name__) + # 添加虚拟群组管理视图 @virtual_group_bp.route('/') @login_required def virtual_group(): return render_template('virtual_group_management.html') - + + @virtual_group_bp.route('/api/virtual_groups', methods=['GET']) @login_required def get_virtual_groups(): @@ -19,15 +20,15 @@ def get_virtual_groups(): try: server = current_app.dashboard_server redis_client = server.db_manager.get_redis_connection() - + # 从Redis获取虚拟群组数据 chat_groups_json = redis_client.get("group_virtual:chat_groups") if not chat_groups_json: return jsonify({"success": True, "data": {"chatGroups": []}}) - + import json chat_groups = json.loads(chat_groups_json) - + # 确保群组名称是最新的 for chat_group in chat_groups.get("chatGroups", []): for group in chat_group.get("groups", []): @@ -36,7 +37,7 @@ def get_virtual_groups(): group_name = server.contact_manager.get_nickname(group_id) if group_name: group["name"] = group_name - + return jsonify({"success": True, "data": chat_groups}) except Exception as e: logger.error(f"获取虚拟群组失败: {e}") @@ -51,11 +52,11 @@ def create_virtual_group(): server = current_app.dashboard_server redis_client = server.db_manager.get_redis_connection() data = request.json - + group_name = data.get('name') if not group_name: return jsonify({"success": False, "error": "群组名称不能为空"}), 400 - + # 从Redis获取现有虚拟群组 import json chat_groups_json = redis_client.get("group_virtual:chat_groups") @@ -63,21 +64,21 @@ def create_virtual_group(): chat_groups = json.loads(chat_groups_json) else: chat_groups = {"chatGroups": []} - + # 创建新的虚拟群组 new_group = { "id": str(uuid.uuid4()), "name": group_name, "groups": [] } - + chat_groups["chatGroups"].append(new_group) - + # 保存回Redis redis_client.set("group_virtual:chat_groups", json.dumps(chat_groups, ensure_ascii=False)) - + return jsonify({ - "success": True, + "success": True, "message": f"虚拟群组 {group_name} 创建成功", "data": new_group }) @@ -93,15 +94,15 @@ def delete_virtual_group(group_id): try: server = current_app.dashboard_server redis_client = server.db_manager.get_redis_connection() - + # 从Redis获取现有虚拟群组 import json chat_groups_json = redis_client.get("group_virtual:chat_groups") if not chat_groups_json: return jsonify({"success": False, "error": "虚拟群组不存在"}), 404 - + chat_groups = json.loads(chat_groups_json) - + # 查找并删除指定的虚拟群组 found = False for i, group in enumerate(chat_groups.get("chatGroups", [])): @@ -109,15 +110,15 @@ def delete_virtual_group(group_id): del chat_groups["chatGroups"][i] found = True break - + if not found: return jsonify({"success": False, "error": "虚拟群组不存在"}), 404 - + # 保存回Redis redis_client.set("group_virtual:chat_groups", json.dumps(chat_groups, ensure_ascii=False)) - + return jsonify({ - "success": True, + "success": True, "message": "虚拟群组删除成功" }) except Exception as e: @@ -133,24 +134,24 @@ def add_group_to_virtual(group_id): server = current_app.dashboard_server redis_client = server.db_manager.get_redis_connection() data = request.json - + wx_group_id = data.get('wx_group_id') if not wx_group_id: return jsonify({"success": False, "error": "微信群ID不能为空"}), 400 - + # 检查微信群是否存在 group_name = server.contact_manager.get_nickname(wx_group_id) if not group_name: return jsonify({"success": False, "error": "微信群不存在或未被机器人识别"}), 404 - + # 从Redis获取现有虚拟群组 import json chat_groups_json = redis_client.get("group_virtual:chat_groups") if not chat_groups_json: return jsonify({"success": False, "error": "虚拟群组不存在"}), 404 - + chat_groups = json.loads(chat_groups_json) - + # 查找指定的虚拟群组 found = False for chat_group in chat_groups.get("chatGroups", []): @@ -159,7 +160,7 @@ def add_group_to_virtual(group_id): for group in chat_group.get("groups", []): if group.get("id") == wx_group_id: return jsonify({"success": False, "error": "该微信群已在虚拟群组中"}), 400 - + # 添加微信群到虚拟群组 chat_group["groups"].append({ "id": wx_group_id, @@ -167,15 +168,15 @@ def add_group_to_virtual(group_id): }) found = True break - + if not found: return jsonify({"success": False, "error": "虚拟群组不存在"}), 404 - + # 保存回Redis redis_client.set("group_virtual:chat_groups", json.dumps(chat_groups, ensure_ascii=False)) - + return jsonify({ - "success": True, + "success": True, "message": f"微信群 {group_name} 已添加到虚拟群组", "data": { "id": wx_group_id, @@ -194,15 +195,15 @@ def remove_group_from_virtual(group_id, wx_group_id): try: server = current_app.dashboard_server redis_client = server.db_manager.get_redis_connection() - + # 从Redis获取现有虚拟群组 import json chat_groups_json = redis_client.get("group_virtual:chat_groups") if not chat_groups_json: return jsonify({"success": False, "error": "虚拟群组不存在"}), 404 - + chat_groups = json.loads(chat_groups_json) - + # 查找指定的虚拟群组和微信群 found_group = False found_wx_group = False @@ -215,18 +216,18 @@ def remove_group_from_virtual(group_id, wx_group_id): found_wx_group = True break break - + if not found_group: return jsonify({"success": False, "error": "虚拟群组不存在"}), 404 - + if not found_wx_group: return jsonify({"success": False, "error": "该微信群不在虚拟群组中"}), 404 - + # 保存回Redis redis_client.set("group_virtual:chat_groups", json.dumps(chat_groups, ensure_ascii=False)) - + return jsonify({ - "success": True, + "success": True, "message": "微信群已从虚拟群组移除" }) except Exception as e: @@ -242,19 +243,19 @@ def update_virtual_group(group_id): server = current_app.dashboard_server redis_client = server.db_manager.get_redis_connection() data = request.json - + group_name = data.get('name') if not group_name: return jsonify({"success": False, "error": "群组名称不能为空"}), 400 - + # 从Redis获取现有虚拟群组 import json chat_groups_json = redis_client.get("group_virtual:chat_groups") if not chat_groups_json: return jsonify({"success": False, "error": "虚拟群组不存在"}), 404 - + chat_groups = json.loads(chat_groups_json) - + # 查找并更新指定的虚拟群组 found = False for chat_group in chat_groups.get("chatGroups", []): @@ -262,15 +263,15 @@ def update_virtual_group(group_id): chat_group["name"] = group_name found = True break - + if not found: return jsonify({"success": False, "error": "虚拟群组不存在"}), 404 - + # 保存回Redis redis_client.set("group_virtual:chat_groups", json.dumps(chat_groups, ensure_ascii=False)) - + return jsonify({ - "success": True, + "success": True, "message": "虚拟群组更新成功", "data": { "id": group_id, @@ -279,4 +280,4 @@ def update_virtual_group(group_id): }) except Exception as e: logger.error(f"更新虚拟群组失败: {e}") - return jsonify({"success": False, "error": str(e)}), 500 \ No newline at end of file + return jsonify({"success": False, "error": str(e)}), 500