2024-12-10 19:49:11 +08:00
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from pathlib import Path
|
2024-02-25 03:18:34 +08:00
|
|
|
|
import random
|
|
|
|
|
|
import secrets
|
|
|
|
|
|
|
2024-10-18 18:57:55 +08:00
|
|
|
|
from nonebot_plugin_uninfo import Uninfo
|
2024-12-10 19:49:11 +08:00
|
|
|
|
import pytz
|
2024-02-25 03:18:34 +08:00
|
|
|
|
|
2025-08-30 18:13:37 +08:00
|
|
|
|
from zhenxun import ui
|
2024-12-10 19:49:11 +08:00
|
|
|
|
from zhenxun.configs.path_config import IMAGE_PATH
|
|
|
|
|
|
from zhenxun.models.friend_user import FriendUser
|
|
|
|
|
|
from zhenxun.models.group_member_info import GroupInfoUser
|
2024-02-25 03:18:34 +08:00
|
|
|
|
from zhenxun.models.sign_log import SignLog
|
|
|
|
|
|
from zhenxun.models.sign_user import SignUser
|
|
|
|
|
|
from zhenxun.models.user_console import UserConsole
|
2025-09-28 08:53:10 +08:00
|
|
|
|
from zhenxun.services.avatar_service import avatar_service
|
2024-12-10 19:49:11 +08:00
|
|
|
|
from zhenxun.services.log import logger
|
2025-08-30 18:13:37 +08:00
|
|
|
|
from zhenxun.ui.models import ImageCell, TextCell
|
2024-12-10 19:49:11 +08:00
|
|
|
|
from zhenxun.utils.platform import PlatformUtils
|
2024-02-25 03:18:34 +08:00
|
|
|
|
|
2024-09-07 12:46:25 +08:00
|
|
|
|
from ._random_event import random_event
|
2024-12-10 19:49:11 +08:00
|
|
|
|
from .utils import get_card
|
2024-02-25 03:18:34 +08:00
|
|
|
|
|
|
|
|
|
|
ICON_PATH = IMAGE_PATH / "_icon"
|
|
|
|
|
|
|
|
|
|
|
|
PLATFORM_PATH = {
|
|
|
|
|
|
"dodo": ICON_PATH / "dodo.png",
|
|
|
|
|
|
"discord": ICON_PATH / "discord.png",
|
|
|
|
|
|
"kaiheila": ICON_PATH / "kook.png",
|
|
|
|
|
|
"qq": ICON_PATH / "qq.png",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SignManage:
|
|
|
|
|
|
@classmethod
|
2024-07-31 17:30:59 +08:00
|
|
|
|
async def rank(
|
2024-10-18 18:57:55 +08:00
|
|
|
|
cls, session: Uninfo, num: int, group_id: str | None = None
|
2025-08-30 18:13:37 +08:00
|
|
|
|
) -> bytes | str:
|
2024-07-31 17:30:59 +08:00
|
|
|
|
"""好感度排行
|
|
|
|
|
|
|
|
|
|
|
|
参数:
|
2024-10-18 18:57:55 +08:00
|
|
|
|
session: Uninfo
|
2024-07-31 17:30:59 +08:00
|
|
|
|
num: 排行榜数量
|
|
|
|
|
|
group_id: 群组id
|
|
|
|
|
|
|
|
|
|
|
|
返回:
|
2025-08-30 18:13:37 +08:00
|
|
|
|
bytes: 构造图片
|
2024-07-31 17:30:59 +08:00
|
|
|
|
"""
|
|
|
|
|
|
query = SignUser
|
|
|
|
|
|
if group_id:
|
|
|
|
|
|
user_list = await GroupInfoUser.filter(group_id=group_id).values_list(
|
|
|
|
|
|
"user_id", flat=True
|
|
|
|
|
|
)
|
2024-10-18 18:57:55 +08:00
|
|
|
|
if user_list:
|
|
|
|
|
|
query = query.filter(user_id__in=user_list)
|
2024-09-08 11:33:19 +08:00
|
|
|
|
user_list = (
|
2024-07-31 17:30:59 +08:00
|
|
|
|
await query.annotate()
|
2024-07-31 17:14:46 +08:00
|
|
|
|
.order_by("-impression")
|
2024-09-08 11:33:19 +08:00
|
|
|
|
.values_list("user_id", "impression", "sign_count", "platform")
|
2024-02-25 03:18:34 +08:00
|
|
|
|
)
|
2024-10-19 00:36:19 +08:00
|
|
|
|
if not user_list:
|
|
|
|
|
|
return "当前还没有人签到过哦..."
|
2024-09-08 11:33:19 +08:00
|
|
|
|
user_id_list = [user[0] for user in user_list]
|
2024-11-22 10:05:54 +08:00
|
|
|
|
if session.user.id in user_id_list:
|
|
|
|
|
|
index = user_id_list.index(session.user.id) + 1
|
|
|
|
|
|
else:
|
|
|
|
|
|
index = "-1(未统计)"
|
2024-09-08 11:33:19 +08:00
|
|
|
|
user_list = user_list[:num] if num < len(user_list) else user_list
|
2024-02-25 03:18:34 +08:00
|
|
|
|
column_name = ["排名", "-", "名称", "好感度", "签到次数", "平台"]
|
|
|
|
|
|
friend_list = await FriendUser.filter(user_id__in=user_id_list).values_list(
|
|
|
|
|
|
"user_id", "user_name"
|
|
|
|
|
|
)
|
|
|
|
|
|
uid2name = {f[0]: f[1] for f in friend_list}
|
2024-09-08 11:33:19 +08:00
|
|
|
|
if diff_id := set(user_id_list).difference(set(uid2name.keys())):
|
|
|
|
|
|
group_user = await GroupInfoUser.filter(user_id__in=diff_id).values_list(
|
|
|
|
|
|
"user_id", "user_name"
|
|
|
|
|
|
)
|
|
|
|
|
|
for g in group_user:
|
|
|
|
|
|
uid2name[g[0]] = g[1]
|
2024-02-25 03:18:34 +08:00
|
|
|
|
data_list = []
|
2024-10-18 18:57:55 +08:00
|
|
|
|
platform = PlatformUtils.get_platform(session)
|
2024-02-25 03:18:34 +08:00
|
|
|
|
for i, user in enumerate(user_list):
|
2025-09-28 08:53:10 +08:00
|
|
|
|
avatar_path = await avatar_service.get_avatar_path(
|
|
|
|
|
|
platform=user[3] or "qq", identifier=user[0]
|
2024-10-18 18:57:55 +08:00
|
|
|
|
)
|
2024-02-25 03:18:34 +08:00
|
|
|
|
data_list.append(
|
|
|
|
|
|
[
|
2025-08-30 18:13:37 +08:00
|
|
|
|
TextCell(content=f"{i + 1}"),
|
2025-09-28 08:53:10 +08:00
|
|
|
|
ImageCell(
|
|
|
|
|
|
src=avatar_path.as_uri() if avatar_path else "", shape="circle"
|
|
|
|
|
|
)
|
|
|
|
|
|
if avatar_path
|
2025-08-30 18:13:37 +08:00
|
|
|
|
else TextCell(content=""),
|
|
|
|
|
|
TextCell(content=uid2name.get(user[0]) or user[0]),
|
|
|
|
|
|
TextCell(content=str(user[1]), bold=True),
|
|
|
|
|
|
TextCell(content=str(user[2])),
|
2025-09-11 10:31:49 +08:00
|
|
|
|
ImageCell(src=platform_path.resolve().as_uri())
|
2025-08-30 18:13:37 +08:00
|
|
|
|
if (platform_path := PLATFORM_PATH.get(platform))
|
|
|
|
|
|
else TextCell(content=""),
|
2024-02-25 03:18:34 +08:00
|
|
|
|
]
|
|
|
|
|
|
)
|
2024-07-31 17:30:59 +08:00
|
|
|
|
if group_id:
|
|
|
|
|
|
title = "好感度群组内排行"
|
|
|
|
|
|
tip = f"你的排名在本群第 {index} 位哦!"
|
|
|
|
|
|
else:
|
|
|
|
|
|
title = "好感度全局排行"
|
|
|
|
|
|
tip = f"你的排名在全局第 {index} 位哦!"
|
2025-08-30 18:13:37 +08:00
|
|
|
|
from zhenxun.ui.builders import TableBuilder
|
|
|
|
|
|
|
|
|
|
|
|
builder = TableBuilder(title, tip)
|
|
|
|
|
|
builder.set_headers(column_name).add_rows(data_list)
|
|
|
|
|
|
return await ui.render(builder.build())
|
2024-02-25 03:18:34 +08:00
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
async def sign(
|
2024-10-18 18:57:55 +08:00
|
|
|
|
cls, session: Uninfo, nickname: str, is_card_view: bool = False
|
|
|
|
|
|
) -> Path:
|
2024-02-25 03:18:34 +08:00
|
|
|
|
"""签到
|
|
|
|
|
|
|
|
|
|
|
|
参数:
|
2024-10-18 18:57:55 +08:00
|
|
|
|
session: Uninfo
|
2024-02-25 03:18:34 +08:00
|
|
|
|
nickname: 用户昵称
|
2024-07-21 19:06:50 +08:00
|
|
|
|
is_card_view: 是否展示卡片
|
2024-02-25 03:18:34 +08:00
|
|
|
|
|
|
|
|
|
|
返回:
|
|
|
|
|
|
Path: 卡片路径
|
|
|
|
|
|
"""
|
2024-10-18 18:57:55 +08:00
|
|
|
|
platform = PlatformUtils.get_platform(session)
|
2024-02-25 03:18:34 +08:00
|
|
|
|
now = datetime.now(pytz.timezone("Asia/Shanghai"))
|
2024-10-18 18:57:55 +08:00
|
|
|
|
user_console = await UserConsole.get_user(session.user.id, platform)
|
2024-02-25 03:18:34 +08:00
|
|
|
|
user, _ = await SignUser.get_or_create(
|
2024-10-18 18:57:55 +08:00
|
|
|
|
user_id=session.user.id,
|
|
|
|
|
|
defaults={"user_console": user_console, "platform": platform},
|
2024-02-25 03:18:34 +08:00
|
|
|
|
)
|
2024-07-21 19:06:50 +08:00
|
|
|
|
new_log = (
|
2024-10-18 18:57:55 +08:00
|
|
|
|
await SignLog.filter(user_id=session.user.id)
|
|
|
|
|
|
.order_by("-create_time")
|
|
|
|
|
|
.first()
|
2024-07-21 19:06:50 +08:00
|
|
|
|
)
|
2024-07-29 23:31:11 +08:00
|
|
|
|
log_time = None
|
|
|
|
|
|
if new_log:
|
|
|
|
|
|
log_time = new_log.create_time.astimezone(
|
|
|
|
|
|
pytz.timezone("Asia/Shanghai")
|
|
|
|
|
|
).date()
|
2024-09-07 12:46:25 +08:00
|
|
|
|
if not is_card_view and (not new_log or (log_time and log_time != now.date())):
|
|
|
|
|
|
return await cls._handle_sign_in(user, nickname, session)
|
2024-07-21 19:06:50 +08:00
|
|
|
|
return await get_card(
|
2024-10-18 18:57:55 +08:00
|
|
|
|
user,
|
|
|
|
|
|
session,
|
|
|
|
|
|
nickname,
|
|
|
|
|
|
-1,
|
|
|
|
|
|
user_console.gold,
|
|
|
|
|
|
"",
|
|
|
|
|
|
is_card_view=is_card_view,
|
2024-07-21 19:06:50 +08:00
|
|
|
|
)
|
2024-02-25 03:18:34 +08:00
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
async def _handle_sign_in(
|
|
|
|
|
|
cls,
|
|
|
|
|
|
user: SignUser,
|
|
|
|
|
|
nickname: str,
|
2024-10-18 18:57:55 +08:00
|
|
|
|
session: Uninfo,
|
2024-02-25 03:18:34 +08:00
|
|
|
|
) -> Path:
|
|
|
|
|
|
"""签到处理
|
|
|
|
|
|
|
|
|
|
|
|
参数:
|
|
|
|
|
|
user: SignUser
|
|
|
|
|
|
nickname: 用户昵称
|
2024-10-18 18:57:55 +08:00
|
|
|
|
session: Uninfo
|
2024-02-25 03:18:34 +08:00
|
|
|
|
|
|
|
|
|
|
返回:
|
|
|
|
|
|
Path: 卡片路径
|
|
|
|
|
|
"""
|
2024-10-18 18:57:55 +08:00
|
|
|
|
platform = PlatformUtils.get_platform(session)
|
2024-02-25 03:18:34 +08:00
|
|
|
|
impression_added = (secrets.randbelow(99) + 1) / 100
|
|
|
|
|
|
rand = random.random()
|
|
|
|
|
|
add_probability = float(user.add_probability)
|
2025-11-03 16:36:43 +08:00
|
|
|
|
specify_probability = float(user.specify_probability)
|
2024-09-07 12:46:25 +08:00
|
|
|
|
if rand + add_probability > 0.97 or rand < specify_probability:
|
2024-02-25 03:18:34 +08:00
|
|
|
|
impression_added *= 2
|
2024-10-18 18:57:55 +08:00
|
|
|
|
await SignUser.sign(user, impression_added, session.self_id, platform)
|
2024-02-25 03:18:34 +08:00
|
|
|
|
gold = random.randint(1, 100)
|
|
|
|
|
|
gift = random_event(float(user.impression))
|
|
|
|
|
|
if isinstance(gift, int):
|
|
|
|
|
|
gold += gift
|
2024-10-18 18:57:55 +08:00
|
|
|
|
await UserConsole.add_gold(user.user_id, gold + gift, "sign_in", platform)
|
2024-02-25 03:18:34 +08:00
|
|
|
|
gift = f"额外金币 +{gift}"
|
|
|
|
|
|
else:
|
2024-10-18 18:57:55 +08:00
|
|
|
|
await UserConsole.add_gold(user.user_id, gold, "sign_in", platform)
|
|
|
|
|
|
await UserConsole.add_props_by_name(user.user_id, gift, 1, platform)
|
2024-02-25 03:18:34 +08:00
|
|
|
|
gift += " + 1"
|
|
|
|
|
|
logger.info(
|
|
|
|
|
|
f"签到成功. score: {user.impression:.2f} "
|
|
|
|
|
|
f"(+{impression_added:.2f}).获取金币/道具: {gold}",
|
|
|
|
|
|
"签到",
|
|
|
|
|
|
session=session,
|
|
|
|
|
|
)
|
|
|
|
|
|
return await get_card(
|
|
|
|
|
|
user,
|
2024-10-18 18:57:55 +08:00
|
|
|
|
session,
|
2024-02-25 03:18:34 +08:00
|
|
|
|
nickname,
|
|
|
|
|
|
impression_added,
|
|
|
|
|
|
gold,
|
|
|
|
|
|
gift,
|
|
|
|
|
|
rand + add_probability > 0.97 or rand < specify_probability,
|
|
|
|
|
|
)
|