From 4ccbe08332f666275ea3c29db127733726d9f019 Mon Sep 17 00:00:00 2001 From: liuwei Date: Fri, 11 Apr 2025 13:48:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8F=92=E4=BB=B6=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=98=BE=E7=A4=BA=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E7=9B=B8=E5=85=B3=E4=BF=A1=E6=81=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/dashboard/blueprints/plugin_routes.py | 158 ++++++++++++++ admin/dashboard/templates/base.html | 5 + admin/dashboard/templates/plugins_manage.html | 200 ++++++++++++++++++ utils/robot_cmd/robot_command.py | 2 + 4 files changed, 365 insertions(+) create mode 100644 admin/dashboard/blueprints/plugin_routes.py create mode 100644 admin/dashboard/templates/plugins_manage.html diff --git a/admin/dashboard/blueprints/plugin_routes.py b/admin/dashboard/blueprints/plugin_routes.py new file mode 100644 index 0000000..286a47c --- /dev/null +++ b/admin/dashboard/blueprints/plugin_routes.py @@ -0,0 +1,158 @@ +import logging +from flask import Blueprint, request, jsonify, render_template + +from admin.dashboard.blueprints.auth import login_required +from plugin_common.plugin_manager import PluginManager +from plugin_common.plugin_registry import PluginRegistry + +# 创建蓝图 +plugin_routes = Blueprint('plugin_routes', __name__) +LOG = logging.getLogger(__name__) + + +# 机器人管理页面 +@plugin_routes.route('/plugins') +@login_required +def robot_management(): + return render_template('plugins_manage.html') + +@plugin_routes.route('/api/plugins', methods=['GET']) +@login_required +def get_plugins(): + """获取所有插件列表""" + try: + # 获取插件注册表 + plugin_registry = PluginRegistry() + plugins = plugin_registry.get_all_plugins() + + # 转换为前端需要的格式 + plugin_list = [] + for name, plugin in plugins.items(): + # 获取插件模块名 + try: + module_name = plugin.__class__.__module__.split('.')[-2] + except (IndexError, AttributeError): + module_name = "unknown" + + plugin_info = { + "name": plugin.name, + "module_name": module_name, + "version": getattr(plugin, 'version', 'N/A'), + "author": getattr(plugin, 'author', 'N/A'), + "description": getattr(plugin, 'description', 'N/A'), + "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(): + """获取插件详细信息""" + try: + plugin_name = request.args.get('plugin_name') + if not plugin_name: + return jsonify({"success": False, "message": "缺少插件名称参数"}) + + # 获取插件管理器 + plugin_manager = PluginManager().get_instance() + display_name, plugin = 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, + "module_name": module_name, + "version": getattr(plugin, 'version', 'N/A'), + "author": getattr(plugin, 'author', 'N/A'), + "description": getattr(plugin, 'description', 'N/A'), + "status": plugin.status.name if hasattr(plugin, 'status') else 'UNKNOWN', + "command_prefix": getattr(plugin, 'command_prefix', ''), + "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(): + """启用插件""" + try: + data = request.get_json() + plugin_name = data.get('plugin_name') + if not plugin_name: + return jsonify({"success": False, "message": "缺少插件名称参数"}) + + # 获取插件管理器 + plugin_manager = PluginManager().get_instance() + + # 启用插件 + if plugin_manager.start_plugin(plugin_name): + return jsonify({"success": True, "message": f"插件 {plugin_name} 启用成功"}) + else: + return jsonify({"success": False, "message": f"插件 {plugin_name} 启用失败"}) + 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/disable', methods=['POST']) +@login_required +def disable_plugin(): + """禁用插件""" + try: + data = request.get_json() + plugin_name = data.get('plugin_name') + if not plugin_name: + return jsonify({"success": False, "message": "缺少插件名称参数"}) + + # 获取插件管理器 + plugin_manager = PluginManager().get_instance() + + # 禁用插件 + if plugin_manager.stop_plugin(plugin_name): + return jsonify({"success": True, "message": f"插件 {plugin_name} 禁用成功"}) + else: + return jsonify({"success": False, "message": f"插件 {plugin_name} 禁用失败"}) + 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/reload', methods=['POST']) +@login_required +def reload_plugin(): + """重载插件""" + try: + data = request.get_json() + plugin_name = data.get('plugin_name') + if not plugin_name: + return jsonify({"success": False, "message": "缺少插件名称参数"}) + + # 获取插件管理器 + plugin_manager = PluginManager().get_instance() + + # 重载插件 + reloaded_plugin = plugin_manager.reload_plugin(plugin_name) + + if reloaded_plugin: + return jsonify({"success": True, "message": f"插件 {plugin_name} 重载成功"}) + else: + return jsonify({"success": False, "message": f"插件 {plugin_name} 重载失败"}) + 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 diff --git a/admin/dashboard/templates/base.html b/admin/dashboard/templates/base.html index 7fc3c95..ddf069d 100644 --- a/admin/dashboard/templates/base.html +++ b/admin/dashboard/templates/base.html @@ -148,6 +148,11 @@ 通讯录管理 + + + + 插件管理 + diff --git a/admin/dashboard/templates/plugins_manage.html b/admin/dashboard/templates/plugins_manage.html new file mode 100644 index 0000000..20f2345 --- /dev/null +++ b/admin/dashboard/templates/plugins_manage.html @@ -0,0 +1,200 @@ +{% extends "base.html" %} + +{% block title %}插件管理 - 机器人管理后台{% endblock %} + +{% block content %} + +
+ + + +
+ 插件管理 + + 刷新 + +
+ + + + + + + + + + + + + +
+
+
+ + + +
+ + {% raw %}{{ selectedPlugin.name }}{% endraw %} + {% raw %}{{ selectedPlugin.module_name }}{% endraw %} + {% raw %}{{ selectedPlugin.version }}{% endraw %} + {% raw %}{{ selectedPlugin.author }}{% endraw %} + {% raw %}{{ selectedPlugin.description }}{% endraw %} + + + {% raw %}{{ selectedPlugin.status === 'RUNNING' ? '已启用' : '已禁用' }}{% endraw %} + + + + {% raw %}{{ selectedPlugin.command_prefix || '无' }}{% endraw %} + + + + {% raw %}{{ cmd }}{% endraw %} + + + +
{% raw %}{{ JSON.stringify(selectedPlugin.config, null, 2) }}{% endraw %}
+
+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} \ No newline at end of file diff --git a/utils/robot_cmd/robot_command.py b/utils/robot_cmd/robot_command.py index 751723b..8f6d64e 100644 --- a/utils/robot_cmd/robot_command.py +++ b/utils/robot_cmd/robot_command.py @@ -22,6 +22,7 @@ class PermissionStatus(Enum): DISABLED = "disabled" +# 在Feature枚举类中添加新的功能权限 class Feature(Enum): """功能权限枚举,带序号""" ROBOT = 1, "群机器人" @@ -42,6 +43,7 @@ class Feature(Enum): GROUP_ADD = 16, "加群提醒功能" DOUYIN_PARSER = 17, "抖音链接转视频功能" GROUP_MEMBER_CHANGE = 18, "群成员变更提醒功能" + KID_PHOTO_EXTRACT =19, "儿童照片提取转发功能" # 小朋友照片提取功能 def __new__(cls, value, description): obj = object.__new__(cls)