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('已取消操作');
+ });
}
}
});