mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-12 23:40:03 +08:00
♻️ refactor(plugin_switch): 重构功能开关与帮助系统并优化 UI 报表渲染 (#2111)
* ♻️ refactor(plugin_switch): 重构功能开关与帮助系统并优化 UI 报表渲染 - 引入策略模式 (Strategy Pattern) 统一插件与被动任务的开关逻辑 - 新增超级用户强制管控功能,支持系统级禁用且群管无法自行开启 - 新增全服群组活跃状态报表与功能全局覆盖率可视化统计图表 - 优化指令解析系统,支持多功能批量开关及更智能的快捷词映射 - 重构帮助系统,支持在帮助页区分展示管理员与超级用户指令 - 细化插件列表状态显示,区分群控、系统管控与全局禁用状态 - UI 组件 UserInfoBlock 新增 extra 扩展插槽支持 - 更新 resources.spec 资源版本要求至 1.1.1 * 🚨 auto fix by pre-commit hooks --------- Co-authored-by: webjoin111 <455457521@qq.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
webjoin111
pre-commit-ci[bot]
parent
ce94f63d9a
commit
0f91ce03e4
@@ -19,7 +19,7 @@ from zhenxun.services.log import logger
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
|
||||
from ._data_source import create_help_img, get_llm_help, get_plugin_help
|
||||
from .data_source import create_help_img, get_llm_help, get_plugin_help
|
||||
|
||||
__plugin_meta__ = PluginMetadata(
|
||||
name="帮助",
|
||||
@@ -75,7 +75,6 @@ _matcher = on_alconna(
|
||||
Alconna(
|
||||
"功能",
|
||||
Args["name?", str],
|
||||
Option("-s|--superuser", action=store_true, help_text="超级用户帮助"),
|
||||
Option("-d|--detail", action=store_true, help_text="详细帮助"),
|
||||
),
|
||||
aliases={"help", "帮助", "菜单"},
|
||||
@@ -98,15 +97,9 @@ async def _(
|
||||
bot: Bot,
|
||||
name: Match[str],
|
||||
session: Uninfo,
|
||||
is_superuser: Query[bool] = AlconnaQuery("superuser.value", False),
|
||||
is_detail: Query[bool] = AlconnaQuery("detail.value", False),
|
||||
):
|
||||
_is_superuser = is_superuser.result if is_superuser.available else False
|
||||
|
||||
if _is_superuser and session.user.id not in bot.config.superusers:
|
||||
await MessageUtils.build_message("权限不足,无法查看超级用户帮助").finish(
|
||||
reply_to=True
|
||||
)
|
||||
_is_superuser = session.user.id in bot.config.superusers
|
||||
|
||||
if name.available:
|
||||
help_style = Config.get_config("help", "HELP_STYLE")
|
||||
@@ -116,11 +109,7 @@ async def _(
|
||||
session.user.id, name.result, _is_superuser, variant=variant
|
||||
)
|
||||
|
||||
is_plugin_found = not (
|
||||
isinstance(traditional_help_result, str)
|
||||
and "没有查找到这个功能噢..." in traditional_help_result
|
||||
)
|
||||
if is_plugin_found:
|
||||
if traditional_help_result is not None:
|
||||
await MessageUtils.build_message(traditional_help_result).send(
|
||||
reply_to=True
|
||||
)
|
||||
@@ -130,7 +119,7 @@ async def _(
|
||||
llm_answer = await get_llm_help(name.result, session.user.id)
|
||||
await MessageUtils.build_message(llm_answer).send(reply_to=True)
|
||||
else:
|
||||
await MessageUtils.build_message(traditional_help_result).send(
|
||||
await MessageUtils.build_message("没有查找到这个功能噢...").send(
|
||||
reply_to=True
|
||||
)
|
||||
logger.info(
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.configs.path_config import DATA_PATH, IMAGE_PATH
|
||||
|
||||
GROUP_HELP_PATH = DATA_PATH / "group_help"
|
||||
GROUP_HELP_PATH.mkdir(exist_ok=True, parents=True)
|
||||
for f in GROUP_HELP_PATH.iterdir():
|
||||
f.unlink()
|
||||
|
||||
SIMPLE_HELP_IMAGE = IMAGE_PATH / "SIMPLE_HELP.png"
|
||||
if SIMPLE_HELP_IMAGE.exists():
|
||||
SIMPLE_HELP_IMAGE.unlink()
|
||||
|
||||
SIMPLE_DETAIL_HELP_IMAGE = IMAGE_PATH / "SIMPLE_DETAIL_HELP.png"
|
||||
if SIMPLE_DETAIL_HELP_IMAGE.exists():
|
||||
SIMPLE_DETAIL_HELP_IMAGE.unlink()
|
||||
|
||||
base_config = Config.get("help")
|
||||
@@ -0,0 +1,3 @@
|
||||
from zhenxun.configs.config import Config
|
||||
|
||||
base_config = Config.get("help")
|
||||
+51
-51
@@ -3,7 +3,6 @@ from nonebot_plugin_uninfo import Uninfo
|
||||
|
||||
from zhenxun import ui
|
||||
from zhenxun.configs.config import BotConfig, Config
|
||||
from zhenxun.configs.path_config import IMAGE_PATH
|
||||
from zhenxun.configs.utils import PluginExtraData
|
||||
from zhenxun.models.bot_console import BotConsole
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
@@ -23,10 +22,7 @@ from zhenxun.utils.common_utils import format_usage_for_markdown
|
||||
from zhenxun.utils.enum import BlockType, PluginType
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
|
||||
from ._utils import classify_plugin
|
||||
|
||||
random_bk_path = IMAGE_PATH / "background" / "help" / "simple_help"
|
||||
background = IMAGE_PATH / "background" / "0.png"
|
||||
from .utils import classify_plugin
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
_HELP_MENU_IMAGE_CACHE = RenderResultMemoryCache(
|
||||
@@ -43,7 +39,7 @@ def _create_plugin_menu_item(
|
||||
is_detail: bool,
|
||||
) -> dict:
|
||||
"""为插件菜单构造一个插件菜单项数据字典"""
|
||||
status = True
|
||||
status_type = 0
|
||||
has_superuser_help = False
|
||||
nb_plugin = nonebot.get_plugin_by_module_name(plugin.module_path)
|
||||
if nb_plugin and nb_plugin.metadata and nb_plugin.metadata.extra:
|
||||
@@ -51,17 +47,21 @@ def _create_plugin_menu_item(
|
||||
if extra_data.superuser_help:
|
||||
has_superuser_help = True
|
||||
|
||||
module_tag = f"<{plugin.module},"
|
||||
|
||||
if not plugin.status:
|
||||
if plugin.block_type == BlockType.ALL:
|
||||
status = False
|
||||
status_type = 3
|
||||
elif group and plugin.block_type == BlockType.GROUP:
|
||||
status = False
|
||||
status_type = 3
|
||||
elif not group and plugin.block_type == BlockType.PRIVATE:
|
||||
status = False
|
||||
elif group and f"{plugin.module}," in group.block_plugin:
|
||||
status = False
|
||||
elif bot and f"{plugin.module}," in bot.block_plugins:
|
||||
status = False
|
||||
status_type = 3
|
||||
elif group and module_tag in (group.superuser_block_plugin or ""):
|
||||
status_type = 2
|
||||
elif bot and module_tag in (bot.block_plugins or ""):
|
||||
status_type = 2
|
||||
elif group and module_tag in (group.block_plugin or ""):
|
||||
status_type = 1
|
||||
|
||||
commands = []
|
||||
if is_detail and nb_plugin and nb_plugin.metadata and nb_plugin.metadata.extra:
|
||||
@@ -71,7 +71,7 @@ def _create_plugin_menu_item(
|
||||
return {
|
||||
"id": str(plugin.id),
|
||||
"name": plugin.name,
|
||||
"status": status,
|
||||
"status": status_type,
|
||||
"has_superuser_help": has_superuser_help,
|
||||
"commands": commands,
|
||||
}
|
||||
@@ -98,13 +98,13 @@ async def create_help_img(
|
||||
main_category_name = "主要功能" if menu_key in ["normal", "功能"] else menu_key
|
||||
categories_for_model.append({"name": main_category_name, "items": max_data})
|
||||
plugin_count += len(max_data)
|
||||
active_count += sum(1 for item in max_data if item["status"])
|
||||
active_count += sum(1 for item in max_data if item["status"] == 0)
|
||||
|
||||
for menu, value in sorted_categories.items():
|
||||
category_name = "主要功能" if menu in ["normal", "功能"] else menu
|
||||
categories_for_model.append({"name": category_name, "items": value})
|
||||
plugin_count += len(value)
|
||||
active_count += sum(1 for item in value if item["status"])
|
||||
active_count += sum(1 for item in value if item["status"] == 0)
|
||||
|
||||
platform = PlatformUtils.get_platform(session)
|
||||
bot_id = BotConfig.get_qbot_uid(session.self_id) or session.self_id
|
||||
@@ -117,7 +117,6 @@ async def create_help_img(
|
||||
PluginMenuCategory(name=category["name"], items=category["items"])
|
||||
)
|
||||
|
||||
# 直接实例化 Data Model
|
||||
menu_data = PluginMenuData(
|
||||
bot_name=BotConfig.self_nickname,
|
||||
bot_avatar_url=bot_avatar_url,
|
||||
@@ -169,29 +168,9 @@ async def get_user_allow_help(user_id: str) -> list[PluginType]:
|
||||
return type_list
|
||||
|
||||
|
||||
def min_leading_spaces(str_list: list[str]) -> int:
|
||||
min_spaces = 9999
|
||||
|
||||
for s in str_list:
|
||||
leading_spaces = len(s) - len(s.lstrip(" "))
|
||||
|
||||
if leading_spaces < min_spaces:
|
||||
min_spaces = leading_spaces
|
||||
|
||||
return min_spaces if min_spaces != 9999 else 0
|
||||
|
||||
|
||||
def split_text(text: str):
|
||||
split_text = text.split("\n")
|
||||
min_spaces = min_leading_spaces(split_text)
|
||||
if min_spaces > 0:
|
||||
split_text = [s[min_spaces:] for s in split_text]
|
||||
return [s.replace(" ", " ") for s in split_text]
|
||||
|
||||
|
||||
async def get_plugin_help(
|
||||
user_id: str, name: str, is_superuser: bool, variant: str | None = None
|
||||
) -> str | bytes:
|
||||
) -> bytes | None:
|
||||
"""获取功能的帮助信息
|
||||
|
||||
参数:
|
||||
@@ -215,10 +194,6 @@ async def get_plugin_help(
|
||||
|
||||
call_count = await Statistics.filter(plugin_name=plugin.module).count()
|
||||
usage = _plugin.metadata.usage
|
||||
if is_superuser:
|
||||
if not extra_data.superuser_help:
|
||||
return "该功能没有超级用户帮助信息"
|
||||
usage = extra_data.superuser_help
|
||||
|
||||
metadata_items = [
|
||||
{"label": "作者", "value": extra_data.author or "未知"},
|
||||
@@ -226,15 +201,40 @@ async def get_plugin_help(
|
||||
{"label": "调用次数", "value": call_count},
|
||||
]
|
||||
|
||||
processed_description = format_usage_for_markdown(
|
||||
_plugin.metadata.description.strip()
|
||||
sections = []
|
||||
sections.append(
|
||||
{
|
||||
"title": "功能简介",
|
||||
"content": [
|
||||
format_usage_for_markdown(_plugin.metadata.description.strip())
|
||||
],
|
||||
"is_admin": False,
|
||||
}
|
||||
)
|
||||
processed_usage = format_usage_for_markdown(usage.strip())
|
||||
|
||||
sections = [
|
||||
{"title": "简介", "content": [processed_description]},
|
||||
{"title": "使用方法", "content": [processed_usage]},
|
||||
]
|
||||
if usage and usage.strip():
|
||||
sections.append(
|
||||
{
|
||||
"title": "管理员指令",
|
||||
"content": [format_usage_for_markdown(usage.strip())],
|
||||
"is_admin": False,
|
||||
}
|
||||
)
|
||||
|
||||
if (
|
||||
is_superuser
|
||||
and extra_data.superuser_help
|
||||
and extra_data.superuser_help.strip()
|
||||
):
|
||||
sections.append(
|
||||
{
|
||||
"title": "超级用户指令",
|
||||
"content": [
|
||||
format_usage_for_markdown(extra_data.superuser_help.strip())
|
||||
],
|
||||
"is_admin": True,
|
||||
}
|
||||
)
|
||||
|
||||
page_data = {
|
||||
"title": _plugin.metadata.name,
|
||||
@@ -246,8 +246,8 @@ async def get_plugin_help(
|
||||
if variant:
|
||||
component.variant = variant
|
||||
return await ui.render(component, use_cache=True, device_scale_factor=2)
|
||||
return "糟糕! 该功能没有帮助喔..."
|
||||
return "没有查找到这个功能噢..."
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
async def get_llm_help(question: str, user_id: str) -> str | bytes:
|
||||
Reference in New Issue
Block a user