From db08a4a15e106711441f70f275e2255f834499d5 Mon Sep 17 00:00:00 2001 From: liuwei Date: Mon, 20 Apr 2026 14:13:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=92=E4=BB=B6=E7=BE=A4=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E6=94=AF=E6=8C=81=E6=8C=89=E7=BE=A4=E5=BC=80?= =?UTF-8?q?=E5=90=AF/=E5=85=B3=E9=97=AD=EF=BC=8C=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E5=8E=9F=E6=9C=89=E7=BE=A4=E6=9D=83=E9=99=90=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/dashboard/blueprints/plugin_routes.py | 49 +++++++++++++ admin/dashboard/templates/plugins_manage.html | 73 ++++++++++++++++++- 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/admin/dashboard/blueprints/plugin_routes.py b/admin/dashboard/blueprints/plugin_routes.py index 211b47b..c8a31f7 100644 --- a/admin/dashboard/blueprints/plugin_routes.py +++ b/admin/dashboard/blueprints/plugin_routes.py @@ -134,6 +134,55 @@ def get_plugin_group_status(): return jsonify({"success": False, "message": f"获取插件群状态失败: {str(e)}"}) +@plugin_routes.route('/api/plugins/group_status/toggle', methods=['POST']) +@login_required +def toggle_plugin_group_status(): + """切换插件在指定群的启用状态(开启/关闭)""" + try: + server = current_app.dashboard_server + data = request.get_json() or {} + plugin_name = (data.get('plugin_name') or '').strip() + group_id = (data.get('group_id') or '').strip() + status = (data.get('status') or '').strip().lower() + + # 参数校验:保证前端传入完整且合法的切换目标。 + if not plugin_name: + return jsonify({"success": False, "message": "缺少插件名称参数"}) + if not group_id: + return jsonify({"success": False, "message": "缺少群ID参数"}) + if status not in ('enabled', 'disabled'): + return jsonify({"success": False, "message": "状态参数非法,仅支持 enabled / disabled"}) + + # 查找插件实例,沿用现有查找逻辑,兼容模块名与展示名。 + display_name, plugin = server.plugin_manager.find_plugin_by_name(plugin_name) + if not plugin: + return jsonify({"success": False, "message": f"未找到插件: {plugin_name}"}) + + # 插件必须注册了 feature 才能进行群级开关;否则无法映射到权限系统。 + plugin_feature = getattr(plugin, "feature", None) + if plugin_feature is None: + return jsonify({"success": False, "message": "该插件未接入群级开关能力,无法直接切换"}) + + # 将字符串状态映射到统一权限枚举,然后写入群权限缓存与Redis。 + target_status = PermissionStatus.ENABLED if status == 'enabled' else PermissionStatus.DISABLED + GroupBotManager.set_group_permission(group_id, plugin_feature, target_status) + + # 返回简洁确认信息,方便前端即时提示与二次渲染。 + return jsonify({ + "success": True, + "message": f"已将群 {group_id} 的插件“{plugin.name}”设置为{'开启' if target_status == PermissionStatus.ENABLED else '关闭'}", + "data": { + "plugin_name": plugin.name, + "group_id": group_id, + "status": target_status.value, + "feature_key": getattr(plugin_feature, "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/info', methods=['GET']) @login_required def get_plugin_info(): diff --git a/admin/dashboard/templates/plugins_manage.html b/admin/dashboard/templates/plugins_manage.html index c6def9e..94c6e3c 100644 --- a/admin/dashboard/templates/plugins_manage.html +++ b/admin/dashboard/templates/plugins_manage.html @@ -194,6 +194,18 @@ + + + @@ -214,6 +226,18 @@ + + + @@ -240,7 +264,8 @@ configFormat: 'toml', pluginGroupStatusVisible: false, groupStatusLoading: false, - pluginGroupStatusData: null + pluginGroupStatusData: null, + currentGroupStatusPlugin: null } }, computed: { @@ -425,9 +450,11 @@ this.pluginGroupStatusVisible = true; this.groupStatusLoading = true; this.pluginGroupStatusData = null; + // 记录当前正在查看群状态的插件,供“开启/关闭后刷新”复用。 + this.currentGroupStatusPlugin = plugin; // 统一使用插件模块名查询,和启用/禁用/重载接口参数保持一致。 - axios.get('/api/plugins/group_status', { + return axios.get('/api/plugins/group_status', { params: { plugin_name: plugin.module_name } @@ -456,6 +483,48 @@ .finally(() => { this.groupStatusLoading = false; }); + }, + togglePluginGroupSwitch(group, enable) { + if (!this.currentGroupStatusPlugin || !group || !group.group_id) { + this.$message.error('缺少必要参数,无法切换'); + return; + } + + const actionText = enable ? '开启' : '关闭'; + const pluginName = this.currentGroupStatusPlugin.name || this.currentGroupStatusPlugin.module_name; + const groupName = group.group_name || group.group_id; + + this.$confirm(`确定要${actionText}群 "${groupName}" 的插件 "${pluginName}" 吗?`, '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + this.groupStatusLoading = true; + // 调用后端切换接口,后端内部复用 GroupBotManager 的原有缓存+Redis策略。 + axios.post('/api/plugins/group_status/toggle', { + plugin_name: this.currentGroupStatusPlugin.module_name, + group_id: group.group_id, + status: enable ? 'enabled' : 'disabled' + }) + .then(response => { + if (response.data.success) { + this.$message.success(`${actionText}成功`); + // 切换后重新拉取当前插件群状态,保证统计与列表一致。 + return this.showPluginGroupStatus(this.currentGroupStatusPlugin); + } else { + this.$message.error(response.data.message || `${actionText}失败`); + } + }) + .catch(error => { + console.error(`${actionText}插件群状态出错:`, error); + this.$message.error(`${actionText}插件群状态出错`); + }) + .finally(() => { + this.groupStatusLoading = false; + }); + }).catch(() => { + this.$message.info('已取消操作'); + }); } } });