mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-04 03:10:01 +08:00
重构webui适配 (#1801)
* ♻️ 使用Uninfo重构PlatformUtils基础方法 * 🩹 优化插件加载与模块格式转换逻辑 * 🚑 修复商店道具无法使用 * 🚑 修复道具无法正常使用 * 🔧 增加Bot状态管理及模块禁用功能 * 🎨 优化Web UI代码结构,修改target方法 * 🚨 auto fix by pre-commit hooks * 🎨 添加菜单API及优化异常处理 * 🐛 优化菜单API及模型结构,修复WebUi插件列表Api * 📝 更新仓库readme * 🚨 add mdlint file * 📝 Add help chapter. * 🐛 修复优化AuthChecker逻辑 * 🐛 优化数据库API,移除冗余导入及修正SQL_DICT引用 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: BalconyJH <balconyjh@gmail.com>
This commit is contained in:
co-authored by
pre-commit-ci[bot]
BalconyJH
parent
ebf05fd884
commit
35014e4048
@@ -1,7 +1,5 @@
|
||||
import asyncio
|
||||
import contextlib
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
import time
|
||||
|
||||
from fastapi import APIRouter
|
||||
@@ -9,28 +7,26 @@ from fastapi.responses import JSONResponse
|
||||
import nonebot
|
||||
from nonebot.config import Config
|
||||
from starlette.websockets import WebSocket, WebSocketDisconnect, WebSocketState
|
||||
from tortoise.functions import Count
|
||||
from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK
|
||||
|
||||
from zhenxun.models.bot_connect_log import BotConnectLog
|
||||
from zhenxun.models.chat_history import ChatHistory
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
from zhenxun.models.statistics import Statistics
|
||||
from zhenxun.models.bot_console import BotConsole
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.common_utils import CommonUtils
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
|
||||
from ....base_model import Result
|
||||
from ....config import AVA_URL, GROUP_AVA_URL, QueryDateType
|
||||
from ....config import QueryDateType
|
||||
from ....utils import authentication, get_system_status
|
||||
from .data_source import bot_live
|
||||
from .data_source import ApiDataSource
|
||||
from .model import (
|
||||
ActiveGroup,
|
||||
BaseInfo,
|
||||
BotBlockModule,
|
||||
BotManageUpdateParam,
|
||||
BotStatusParam,
|
||||
HotPlugin,
|
||||
NonebotData,
|
||||
QueryCount,
|
||||
TemplateBaseInfo,
|
||||
)
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
@@ -56,64 +52,14 @@ async def _(bot_id: str | None = None) -> Result[list[BaseInfo]]:
|
||||
返回:
|
||||
Result: 获取指定bot信息与bot列表
|
||||
"""
|
||||
global run_time
|
||||
bot_list: list[TemplateBaseInfo] = []
|
||||
if bots := nonebot.get_bots():
|
||||
select_bot: BaseInfo
|
||||
for _, bot in bots.items():
|
||||
login_info = await bot.get_login_info()
|
||||
bot_list.append(
|
||||
TemplateBaseInfo(
|
||||
bot=bot, # type: ignore
|
||||
self_id=bot.self_id,
|
||||
nickname=login_info["nickname"],
|
||||
ava_url=AVA_URL.format(bot.self_id),
|
||||
)
|
||||
)
|
||||
# 获取指定qq号的bot信息,若无指定 则获取第一个
|
||||
if _bl := [b for b in bot_list if b.self_id == bot_id]:
|
||||
select_bot = _bl[0]
|
||||
else:
|
||||
select_bot = bot_list[0]
|
||||
select_bot.is_select = True
|
||||
now = datetime.now()
|
||||
# 今日累计接收消息
|
||||
select_bot.received_messages = await ChatHistory.filter(
|
||||
bot_id=select_bot.self_id,
|
||||
create_time__gte=now - timedelta(hours=now.hour),
|
||||
).count()
|
||||
# 群聊数量
|
||||
select_bot.group_count = len(await select_bot.bot.get_group_list())
|
||||
# 好友数量
|
||||
select_bot.friend_count = len(await select_bot.bot.get_friend_list())
|
||||
for bot in bot_list:
|
||||
bot.bot = None # type: ignore
|
||||
# 插件加载数量
|
||||
select_bot.plugin_count = await PluginInfo.all().count()
|
||||
fail_count = await PluginInfo.filter(load_status=False).count()
|
||||
select_bot.fail_plugin_count = fail_count
|
||||
select_bot.success_plugin_count = (
|
||||
select_bot.plugin_count - select_bot.fail_plugin_count
|
||||
)
|
||||
# 连接时间
|
||||
select_bot.connect_time = bot_live.get(select_bot.self_id) or 0
|
||||
if select_bot.connect_time:
|
||||
connect_date = datetime.fromtimestamp(select_bot.connect_time)
|
||||
select_bot.connect_date = connect_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
version_file = Path() / "__version__"
|
||||
if version_file.exists():
|
||||
if text := version_file.open().read():
|
||||
if ver := text.replace("__version__: ", "").strip():
|
||||
select_bot.version = ver
|
||||
day_call = await Statistics.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour)
|
||||
).count()
|
||||
select_bot.day_call = day_call
|
||||
select_bot.connect_count = await BotConnectLog.filter(
|
||||
bot_id=select_bot.self_id
|
||||
).count()
|
||||
return Result.ok([BaseInfo(**e.dict()) for e in bot_list], "拿到信息啦!")
|
||||
return Result.warning_("无Bot连接...")
|
||||
try:
|
||||
result = await ApiDataSource.get_base_info(bot_id)
|
||||
if not result:
|
||||
Result.warning_("无Bot连接...")
|
||||
return Result.ok(result, "拿到信息啦!")
|
||||
except Exception as e:
|
||||
logger.error(f"{router.prefix}/get_base_info 调用错误", "WebUi", e=e)
|
||||
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.get(
|
||||
@@ -124,32 +70,11 @@ async def _(bot_id: str | None = None) -> Result[list[BaseInfo]]:
|
||||
description="获取接收消息数量",
|
||||
)
|
||||
async def _(bot_id: str | None = None) -> Result[QueryCount]:
|
||||
now = datetime.now()
|
||||
query = ChatHistory
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
all_count = await query.annotate().count()
|
||||
day_count = await query.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
week_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
month_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
year_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
return Result.ok(
|
||||
QueryCount(
|
||||
num=all_count,
|
||||
day=day_count,
|
||||
week=week_count,
|
||||
month=month_count,
|
||||
year=year_count,
|
||||
)
|
||||
)
|
||||
try:
|
||||
return Result.ok(await ApiDataSource.get_all_chat_count(bot_id), "拿到信息啦!")
|
||||
except Exception as e:
|
||||
logger.error(f"{router.prefix}/get_all_chat_count 调用错误", "WebUi", e=e)
|
||||
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.get(
|
||||
@@ -160,32 +85,11 @@ async def _(bot_id: str | None = None) -> Result[QueryCount]:
|
||||
description="获取调用次数",
|
||||
)
|
||||
async def _(bot_id: str | None = None) -> Result[QueryCount]:
|
||||
now = datetime.now()
|
||||
query = Statistics
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
all_count = await query.annotate().count()
|
||||
day_count = await query.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
week_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
month_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
year_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
return Result.ok(
|
||||
QueryCount(
|
||||
num=all_count,
|
||||
day=day_count,
|
||||
week=week_count,
|
||||
month=month_count,
|
||||
year=year_count,
|
||||
)
|
||||
)
|
||||
try:
|
||||
return Result.ok(await ApiDataSource.get_all_call_count(bot_id), "拿到信息啦!")
|
||||
except Exception as e:
|
||||
logger.error(f"{router.prefix}/get_all_call_count 调用错误", "WebUi", e=e)
|
||||
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.get(
|
||||
@@ -196,19 +100,18 @@ async def _(bot_id: str | None = None) -> Result[QueryCount]:
|
||||
description="好友/群组数量",
|
||||
)
|
||||
async def _(bot_id: str) -> Result[dict[str, int]]:
|
||||
if bots := nonebot.get_bots():
|
||||
if bot_id not in bots:
|
||||
return Result.warning_("指定Bot未连接...")
|
||||
bot = bots[bot_id]
|
||||
platform = PlatformUtils.get_platform(bot)
|
||||
if platform == "qq":
|
||||
data = {
|
||||
"friend_count": len(await bot.get_friend_list()),
|
||||
"group_count": len(await bot.get_group_list()),
|
||||
}
|
||||
return Result.ok(data)
|
||||
return Result.warning_("暂不支持该平台...")
|
||||
return Result.warning_("无Bot连接...")
|
||||
try:
|
||||
bot = nonebot.get_bot(bot_id)
|
||||
data = {
|
||||
"friend_count": len(await PlatformUtils.get_friend_list(bot)),
|
||||
"group_count": len(await PlatformUtils.get_group_list(bot)),
|
||||
}
|
||||
return Result.ok(data, "拿到信息啦!")
|
||||
except (ValueError, KeyError):
|
||||
return Result.warning_("指定Bot未连接...")
|
||||
except Exception as e:
|
||||
logger.error(f"{router.prefix}/get_fg_count 调用错误", "WebUi", e=e)
|
||||
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.get(
|
||||
@@ -219,6 +122,7 @@ async def _(bot_id: str) -> Result[dict[str, int]]:
|
||||
description="获取nb数据",
|
||||
)
|
||||
async def _() -> Result[NonebotData]:
|
||||
global run_time
|
||||
return Result.ok(NonebotData(config=driver.config, run_time=int(run_time)))
|
||||
|
||||
|
||||
@@ -241,6 +145,7 @@ async def _() -> Result[Config]:
|
||||
description="获取nb运行时间",
|
||||
)
|
||||
async def _() -> Result[int]:
|
||||
global run_time
|
||||
return Result.ok(int(run_time))
|
||||
|
||||
|
||||
@@ -254,48 +159,13 @@ async def _() -> Result[int]:
|
||||
async def _(
|
||||
date_type: QueryDateType | None = None, bot_id: str | None = None
|
||||
) -> Result[list[ActiveGroup]]:
|
||||
query = ChatHistory
|
||||
now = datetime.now()
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
if date_type == QueryDateType.DAY:
|
||||
query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
|
||||
if date_type == QueryDateType.WEEK:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=7))
|
||||
if date_type == QueryDateType.MONTH:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=30))
|
||||
if date_type == QueryDateType.YEAR:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=365))
|
||||
data_list = (
|
||||
await query.annotate(count=Count("id"))
|
||||
.filter(group_id__not_isnull=True)
|
||||
.group_by("group_id")
|
||||
.order_by("-count")
|
||||
.limit(5)
|
||||
.values_list("group_id", "count")
|
||||
)
|
||||
id2name = {}
|
||||
if data_list:
|
||||
if info_list := await GroupConsole.filter(
|
||||
group_id__in=[x[0] for x in data_list]
|
||||
).all():
|
||||
for group_info in info_list:
|
||||
id2name[group_info.group_id] = group_info.group_name
|
||||
active_group_list = [
|
||||
ActiveGroup(
|
||||
group_id=data[0],
|
||||
name=id2name.get(data[0]) or data[0],
|
||||
chat_num=data[1],
|
||||
ava_img=GROUP_AVA_URL.format(data[0], data[0]),
|
||||
try:
|
||||
return Result.ok(
|
||||
await ApiDataSource.get_active_group(date_type, bot_id), "拿到信息啦!"
|
||||
)
|
||||
for data in data_list
|
||||
]
|
||||
active_group_list = sorted(
|
||||
active_group_list, key=lambda x: x.chat_num, reverse=True
|
||||
)
|
||||
if len(active_group_list) > 5:
|
||||
active_group_list = active_group_list[:5]
|
||||
return Result.ok(active_group_list)
|
||||
except Exception as e:
|
||||
logger.error(f"{router.prefix}/get_active_group 调用错误", "WebUi", e=e)
|
||||
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.get(
|
||||
@@ -308,37 +178,66 @@ async def _(
|
||||
async def _(
|
||||
date_type: QueryDateType | None = None, bot_id: str | None = None
|
||||
) -> Result[list[HotPlugin]]:
|
||||
query = Statistics
|
||||
now = datetime.now()
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
if date_type == QueryDateType.DAY:
|
||||
query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
|
||||
if date_type == QueryDateType.WEEK:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=7))
|
||||
if date_type == QueryDateType.MONTH:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=30))
|
||||
if date_type == QueryDateType.YEAR:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=365))
|
||||
data_list = (
|
||||
await query.annotate(count=Count("id"))
|
||||
.group_by("plugin_name")
|
||||
.order_by("-count")
|
||||
.limit(5)
|
||||
.values_list("plugin_name", "count")
|
||||
)
|
||||
hot_plugin_list = []
|
||||
module_list = [x[0] for x in data_list]
|
||||
plugins = await PluginInfo.filter(module__in=module_list).all()
|
||||
module2name = {p.module: p.name for p in plugins}
|
||||
for data in data_list:
|
||||
module = data[0]
|
||||
name = module2name.get(module) or module
|
||||
hot_plugin_list.append(HotPlugin(module=module, name=name, count=data[1]))
|
||||
hot_plugin_list = sorted(hot_plugin_list, key=lambda x: x.count, reverse=True)
|
||||
if len(hot_plugin_list) > 5:
|
||||
hot_plugin_list = hot_plugin_list[:5]
|
||||
return Result.ok(hot_plugin_list)
|
||||
try:
|
||||
return Result.ok(
|
||||
await ApiDataSource.get_hot_plugin(date_type, bot_id), "拿到信息啦!"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"{router.prefix}/get_hot_plugin 调用错误", "WebUi", e=e)
|
||||
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.post(
|
||||
"/change_bot_status",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="修改bot全局开关",
|
||||
)
|
||||
async def _(param: BotStatusParam):
|
||||
try:
|
||||
await BotConsole.set_bot_status(param.status, param.bot_id)
|
||||
return Result.ok(info="修改bot全局开关成功!")
|
||||
except (ValueError, KeyError):
|
||||
return Result.fail("Bot未初始化...")
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_bot_block_module",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[BotBlockModule],
|
||||
response_class=JSONResponse,
|
||||
description="获取bot层面的禁用模块",
|
||||
)
|
||||
async def _(bot_id: str) -> Result[BotBlockModule]:
|
||||
try:
|
||||
return Result.ok(
|
||||
await ApiDataSource.get_bot_block_module(bot_id), "拿到信息啦!"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"{router.prefix}/get_bot_block_module 调用错误", "WebUi", e=e)
|
||||
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.post(
|
||||
"/update_bot_manage",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="修改bot全局开关",
|
||||
)
|
||||
async def _(param: BotManageUpdateParam):
|
||||
try:
|
||||
bot_data = await BotConsole.get_or_none(bot_id=param.bot_id)
|
||||
if not bot_data:
|
||||
return Result.fail("Bot数据不存在...")
|
||||
bot_data.block_plugins = CommonUtils.convert_module_format(param.block_plugins)
|
||||
bot_data.block_tasks = CommonUtils.convert_module_format(param.block_tasks)
|
||||
await bot_data.save(update_fields=["block_plugins", "block_tasks"])
|
||||
return Result.ok()
|
||||
except Exception as e:
|
||||
logger.error(f"{router.prefix}/update_bot_manage 调用错误", "WebUi", e=e)
|
||||
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
|
||||
|
||||
|
||||
@ws_router.websocket("/system_status")
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
import time
|
||||
|
||||
import nonebot
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.drivers import Driver
|
||||
from tortoise.functions import Count
|
||||
|
||||
from zhenxun.models.bot_connect_log import BotConnectLog
|
||||
from zhenxun.models.bot_console import BotConsole
|
||||
from zhenxun.models.chat_history import ChatHistory
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
from zhenxun.models.statistics import Statistics
|
||||
from zhenxun.models.task_info import TaskInfo
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.common_utils import CommonUtils
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
|
||||
from ....config import AVA_URL, GROUP_AVA_URL, QueryDateType
|
||||
from .model import (
|
||||
ActiveGroup,
|
||||
BaseInfo,
|
||||
BotBlockModule,
|
||||
HotPlugin,
|
||||
QueryCount,
|
||||
TemplateBaseInfo,
|
||||
)
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
@@ -33,3 +58,313 @@ async def _(bot: Bot):
|
||||
@driver.on_bot_disconnect
|
||||
async def _(bot: Bot):
|
||||
bot_live.remove(bot.self_id)
|
||||
|
||||
|
||||
class ApiDataSource:
|
||||
@classmethod
|
||||
async def __build_bot_info(cls, bot: Bot) -> TemplateBaseInfo:
|
||||
"""构建bot信息
|
||||
|
||||
参数:
|
||||
bot: bot实例
|
||||
|
||||
返回:
|
||||
TemplateBaseInfo: bot信息
|
||||
"""
|
||||
login_info = None
|
||||
try:
|
||||
login_info = await bot.get_login_info()
|
||||
except Exception as e:
|
||||
logger.warning("调用接口get_login_info失败", "WebUi", e=e)
|
||||
return TemplateBaseInfo(
|
||||
bot=bot,
|
||||
self_id=bot.self_id,
|
||||
nickname=login_info["nickname"] if login_info else bot.self_id,
|
||||
ava_url=AVA_URL.format(bot.self_id),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def __get_bot_version(cls) -> str:
|
||||
"""获取bot版本
|
||||
|
||||
返回:
|
||||
str | None: 版本
|
||||
"""
|
||||
version_file = Path() / "__version__"
|
||||
if version_file.exists():
|
||||
if text := version_file.open().read():
|
||||
return text.replace("__version__: ", "").strip()
|
||||
return "unknown"
|
||||
|
||||
@classmethod
|
||||
async def __init_bot_base_data(cls, select_bot: TemplateBaseInfo):
|
||||
"""初始化bot的基础数据
|
||||
|
||||
参数:
|
||||
select_bot: bot
|
||||
"""
|
||||
now = datetime.now()
|
||||
# 今日累计接收消息
|
||||
select_bot.received_messages = await ChatHistory.filter(
|
||||
bot_id=select_bot.self_id,
|
||||
create_time__gte=now - timedelta(hours=now.hour),
|
||||
).count()
|
||||
# 群聊数量
|
||||
select_bot.group_count = len(await PlatformUtils.get_group_list(select_bot.bot))
|
||||
# 好友数量
|
||||
select_bot.friend_count = len(
|
||||
await PlatformUtils.get_friend_list(select_bot.bot)
|
||||
)
|
||||
select_bot.status = await BotConsole.get_bot_status(select_bot.self_id)
|
||||
# 连接时间
|
||||
select_bot.connect_time = bot_live.get(select_bot.self_id) or 0
|
||||
if select_bot.connect_time:
|
||||
connect_date = datetime.fromtimestamp(select_bot.connect_time)
|
||||
select_bot.connect_date = connect_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
select_bot.version = cls.__get_bot_version()
|
||||
day_call = await Statistics.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour)
|
||||
).count()
|
||||
select_bot.day_call = day_call
|
||||
select_bot.connect_count = await BotConnectLog.filter(
|
||||
bot_id=select_bot.self_id
|
||||
).count()
|
||||
|
||||
@classmethod
|
||||
async def get_base_info(cls, bot_id: str | None) -> list[BaseInfo] | None:
|
||||
"""获取bot信息
|
||||
|
||||
参数:
|
||||
bot_id: bot id
|
||||
|
||||
返回:
|
||||
list[BaseInfo] | None: bot列表
|
||||
"""
|
||||
bots = nonebot.get_bots()
|
||||
if not bots:
|
||||
return None
|
||||
select_bot: BaseInfo
|
||||
bot_list = [await cls.__build_bot_info(bot) for _, bot in bots.items()]
|
||||
# 获取指定qq号的bot信息,若无指定 则获取第一个
|
||||
if _bl := [b for b in bot_list if b.self_id == bot_id]:
|
||||
select_bot = _bl[0]
|
||||
else:
|
||||
select_bot = bot_list[0]
|
||||
await cls.__init_bot_base_data(select_bot)
|
||||
for bot in bot_list:
|
||||
bot.bot = None # type: ignore
|
||||
select_bot.is_select = True
|
||||
return [BaseInfo(**e.dict()) for e in bot_list]
|
||||
|
||||
@classmethod
|
||||
async def get_all_chat_count(cls, bot_id: str | None) -> QueryCount:
|
||||
"""获取年/月/周/日聊天次数
|
||||
|
||||
参数:
|
||||
bot_id: bot id
|
||||
|
||||
返回:
|
||||
QueryCount: 数据内容
|
||||
"""
|
||||
now = datetime.now()
|
||||
query = ChatHistory
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
all_count = await query.annotate().count()
|
||||
day_count = await query.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
week_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
month_count = await query.filter(
|
||||
create_time__gte=now
|
||||
- timedelta(days=30, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
year_count = await query.filter(
|
||||
create_time__gte=now
|
||||
- timedelta(days=365, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
return QueryCount(
|
||||
num=all_count,
|
||||
day=day_count,
|
||||
week=week_count,
|
||||
month=month_count,
|
||||
year=year_count,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_all_call_count(cls, bot_id: str | None) -> QueryCount:
|
||||
"""获取年/月/周/日调用次数
|
||||
|
||||
参数:
|
||||
bot_id: bot id
|
||||
|
||||
返回:
|
||||
QueryCount: 数据内容
|
||||
"""
|
||||
now = datetime.now()
|
||||
query = Statistics
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
all_count = await query.annotate().count()
|
||||
day_count = await query.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
week_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
month_count = await query.filter(
|
||||
create_time__gte=now
|
||||
- timedelta(days=30, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
year_count = await query.filter(
|
||||
create_time__gte=now
|
||||
- timedelta(days=365, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
return QueryCount(
|
||||
num=all_count,
|
||||
day=day_count,
|
||||
week=week_count,
|
||||
month=month_count,
|
||||
year=year_count,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def __get_query(
|
||||
cls,
|
||||
base_query: type[ChatHistory | Statistics],
|
||||
date_type: QueryDateType | None = None,
|
||||
bot_id: str | None = None,
|
||||
):
|
||||
"""构建日期查询条件
|
||||
|
||||
参数:
|
||||
date_type: 日期类型.
|
||||
bot_id: bot id.
|
||||
"""
|
||||
query = base_query
|
||||
now = datetime.now()
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
if date_type == QueryDateType.DAY:
|
||||
query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
|
||||
if date_type == QueryDateType.WEEK:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=7))
|
||||
if date_type == QueryDateType.MONTH:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=30))
|
||||
if date_type == QueryDateType.YEAR:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=365))
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
async def get_active_group(
|
||||
cls, date_type: QueryDateType | None = None, bot_id: str | None = None
|
||||
) -> list[ActiveGroup]:
|
||||
"""获取活跃群组
|
||||
|
||||
参数:
|
||||
date_type: 日期类型.
|
||||
bot_id: bot id.
|
||||
|
||||
返回:
|
||||
list[ActiveGroup]: 活跃群组列表
|
||||
"""
|
||||
query = cls.__get_query(ChatHistory, date_type, bot_id)
|
||||
data_list = (
|
||||
await query.annotate(count=Count("id"))
|
||||
.filter(group_id__not_isnull=True)
|
||||
.group_by("group_id")
|
||||
.order_by("-count")
|
||||
.limit(5)
|
||||
.values_list("group_id", "count")
|
||||
)
|
||||
id2name = {}
|
||||
if data_list:
|
||||
if info_list := await GroupConsole.filter(
|
||||
group_id__in=[x[0] for x in data_list]
|
||||
).all():
|
||||
for group_info in info_list:
|
||||
id2name[group_info.group_id] = group_info.group_name
|
||||
active_group_list = [
|
||||
ActiveGroup(
|
||||
group_id=data[0],
|
||||
name=id2name.get(data[0]) or data[0],
|
||||
chat_num=data[1],
|
||||
ava_img=GROUP_AVA_URL.format(data[0], data[0]),
|
||||
)
|
||||
for data in data_list
|
||||
]
|
||||
active_group_list = sorted(
|
||||
active_group_list, key=lambda x: x.chat_num, reverse=True
|
||||
)
|
||||
if len(active_group_list) > 5:
|
||||
active_group_list = active_group_list[:5]
|
||||
return active_group_list
|
||||
|
||||
@classmethod
|
||||
async def get_hot_plugin(
|
||||
cls, date_type: QueryDateType | None = None, bot_id: str | None = None
|
||||
) -> list[HotPlugin]:
|
||||
"""获取热门插件
|
||||
|
||||
参数:
|
||||
date_type: 日期类型.
|
||||
bot_id: bot id.
|
||||
|
||||
返回:
|
||||
list[HotPlugin]: 热门插件列表
|
||||
"""
|
||||
query = cls.__get_query(Statistics, date_type, bot_id)
|
||||
data_list = (
|
||||
await query.annotate(count=Count("id"))
|
||||
.group_by("plugin_name")
|
||||
.order_by("-count")
|
||||
.limit(5)
|
||||
.values_list("plugin_name", "count")
|
||||
)
|
||||
hot_plugin_list = []
|
||||
module_list = [x[0] for x in data_list]
|
||||
plugins = await PluginInfo.filter(module__in=module_list).all()
|
||||
module2name = {p.module: p.name for p in plugins}
|
||||
for data in data_list:
|
||||
module = data[0]
|
||||
name = module2name.get(module) or module
|
||||
hot_plugin_list.append(HotPlugin(module=module, name=name, count=data[1]))
|
||||
hot_plugin_list = sorted(hot_plugin_list, key=lambda x: x.count, reverse=True)
|
||||
if len(hot_plugin_list) > 5:
|
||||
hot_plugin_list = hot_plugin_list[:5]
|
||||
return hot_plugin_list
|
||||
|
||||
@classmethod
|
||||
async def get_bot_block_module(cls, bot_id: str) -> BotBlockModule | None:
|
||||
"""获取bot层面的禁用模块
|
||||
|
||||
参数:
|
||||
bot_id: bot id
|
||||
|
||||
返回:
|
||||
BotBlockModule | None: 数据内容
|
||||
"""
|
||||
bot_data = await BotConsole.get_or_none(bot_id=bot_id)
|
||||
if not bot_data:
|
||||
return None
|
||||
block_tasks = []
|
||||
block_plugins = []
|
||||
all_plugins = await PluginInfo.filter(
|
||||
load_status=True, plugin_type=PluginType.NORMAL
|
||||
).values("module", "name")
|
||||
all_task = await TaskInfo.annotate().values("module", "name")
|
||||
if bot_data.block_tasks:
|
||||
tasks = CommonUtils.convert_module_format(bot_data.block_tasks)
|
||||
block_tasks = [t["module"] for t in all_task if t["module"] in tasks]
|
||||
if bot_data.block_plugins:
|
||||
plugins = CommonUtils.convert_module_format(bot_data.block_plugins)
|
||||
block_plugins = [t["module"] for t in all_plugins if t["module"] in plugins]
|
||||
return BotBlockModule(
|
||||
bot_id=bot_id,
|
||||
block_tasks=block_tasks,
|
||||
block_plugins=block_plugins,
|
||||
all_plugins=all_plugins,
|
||||
all_tasks=all_task,
|
||||
)
|
||||
|
||||
@@ -1,8 +1,45 @@
|
||||
from typing import Any
|
||||
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.config import Config
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class BotManageUpdateParam(BaseModel):
|
||||
"""bot更新参数"""
|
||||
|
||||
bot_id: str
|
||||
"""bot id"""
|
||||
block_plugins: list[str]
|
||||
"""禁用插件"""
|
||||
block_tasks: list[str]
|
||||
"""禁用被动"""
|
||||
|
||||
|
||||
class BotStatusParam(BaseModel):
|
||||
"""bot状态参数"""
|
||||
|
||||
bot_id: str
|
||||
"""bot id"""
|
||||
status: bool
|
||||
"""状态"""
|
||||
|
||||
|
||||
class BotBlockModule(BaseModel):
|
||||
"""bot禁用模块参数"""
|
||||
|
||||
bot_id: str
|
||||
"""bot id"""
|
||||
block_plugins: list[str]
|
||||
"""禁用插件"""
|
||||
block_tasks: list[str]
|
||||
"""禁用被动"""
|
||||
all_plugins: list[dict[str, Any]]
|
||||
"""所有插件"""
|
||||
all_tasks: list[dict[str, Any]]
|
||||
"""所有被动"""
|
||||
|
||||
|
||||
class SystemStatus(BaseModel):
|
||||
"""
|
||||
系统状态
|
||||
@@ -36,13 +73,8 @@ class BaseInfo(BaseModel):
|
||||
"""连接日期"""
|
||||
connect_count: int = 0
|
||||
"""连接次数"""
|
||||
|
||||
plugin_count: int = 0
|
||||
"""加载插件数量"""
|
||||
success_plugin_count: int = 0
|
||||
"""加载成功插件数量"""
|
||||
fail_plugin_count: int = 0
|
||||
"""加载失败插件数量"""
|
||||
status: bool = False
|
||||
"""全局状态"""
|
||||
|
||||
is_select: bool = False
|
||||
"""当前选择"""
|
||||
|
||||
Reference in New Issue
Block a user