""" 消息格式化模块 - 抽卡、成就、统计等所有用户可见输出 提供所有用户可见消息的格式化函数,包括: - 抽卡结果消息 - 三连抽结果消息 - 成就通知消息 - 统计查询消息 - 排行榜消息 - 每日统计消息 所有函数返回NoneBot的Message对象,可直接用于matcher.send()。 """ from typing import List, Dict, Any, Optional, Tuple from nonebot.adapters.onebot.v11 import Message, MessageSegment from .utils import format_user_mention, get_image_path import os # 稀有度显示配置(单一数据源,消除重复模式) RARITY_DISPLAY = { "SSR": {"congrats": ("🌟✨", "✨🌟"), "card": "🎊", "desc": "SSR", "tail": "💫"}, "SP": {"congrats": ("🌈🎆", "🎆🌈"), "card": "🎉", "desc": "SP", "tail": "🔥"}, "SR": {"congrats": ("⭐", "⭐"), "card": "✨", "desc": "SR", "tail": ""}, "R": {"congrats": ("🍀", "🍀"), "card": "📜", "desc": "R", "tail": ""}, } def format_gacha_result(rarity: str, name: str, user_id: str, user_name: str, image_url: str) -> Message: """ 格式化单次抽卡结果消息。 Args: rarity: 稀有度 (SSR/SP/SR/R) name: 式神名称 user_id: QQ号 user_name: 用户昵称 image_url: 图片路径 Returns: Message: 包含文本和图片的消息对象 """ if not rarity or not name: return Message("[抽卡] 数据不完整") msg = Message() if rarity == "SSR": msg.append(f"🌟✨ 恭喜 {format_user_mention(user_id, user_name)} ✨🌟\n") msg.append(f"🎊 抽到了 SSR 式神:{name} 🎊\n") msg.append(f"💫 真是太幸运了!💫") elif rarity == "SP": msg.append(f"🌈🎆 恭喜 {format_user_mention(user_id, user_name)} 🎆🌈\n") msg.append(f"🎉 抽到了 SP 式神:{name} 🎉\n") msg.append(f"🔥 这是传说中的SP!🔥") elif rarity == "SR": msg.append(f"⭐ 恭喜 {format_user_mention(user_id, user_name)} ⭐\n") msg.append(f"✨ 抽到了 SR 式神:{name} ✨") else: # R msg.append(f"🍀 {format_user_mention(user_id, user_name)} 🍀\n") msg.append(f"📜 抽到了 R 式神:{name}") if image_url and os.path.exists(image_url): msg.append(MessageSegment.image(f"file:///{get_image_path(image_url)}")) return msg def format_triple_gacha_result(results: List[Tuple[str, str, str]], user_id: str, user_name: str) -> Message: """ 格式化三连抽结果消息。 Args: results: 三连抽结果列表,每个元素为(稀有度, 式神名, 图片路径) user_id: QQ号 user_name: 用户昵称 Returns: Message: 包含三连抽结果的消息对象 """ msg = Message() msg.append(f"🎯 {format_user_mention(user_id, user_name)} 的三连抽结果:\n\n") for i, (rarity, name, image_path) in enumerate(results, 1): if rarity == "SSR": msg.append(f"🌟 第{i}抽:SSR - {name}\n") elif rarity == "SP": msg.append(f"🌈 第{i}抽:SP - {name}\n") elif rarity == "SR": msg.append(f"⭐ 第{i}抽:SR - {name}\n") else: # R msg.append(f"📜 第{i}抽:R - {name}\n") return msg def format_achievement_notify( achievements_data: List[Dict[str, Any]], user_id: str, ) -> Message: """ 格式化成就解锁通知消息。 纯格式化函数,不执行任何业务逻辑(奖励发放等)。 调用方负责解析成就数据和处理奖励。 Args: achievements_data: 已解析的成就数据列表,每项含 name/reward/claimed/reward_msg 等字段 user_id: 用户ID Returns: Message: 格式化的成就通知消息 Note: 纯函数,无副作用,无外部调用。 """ if not achievements_data: return Message() msg = Message() if achievements_data: msg.append("\n\n🏆 恭喜解锁新成就!\n") for ach in achievements_data: name = ach.get("name", "未知成就") reward = ach.get("reward", 0) reward_msg = ach.get("reward_msg", "") claimed = ach.get("claimed", False) if claimed and reward_msg: msg.append(f"🎖️ {name} 重复奖励 (奖励:{reward}) {reward_msg}\n") else: msg.append(f"🎖️ {name}\n") return msg def format_achievement_progress( consecutive_days: int, no_ssr_streak: int, user_id: str ) -> Message: """ 格式化成就进度消息。 Args: consecutive_days: 连续抽卡天数 no_ssr_streak: 连续未出SSR/SP次数 user_id: 用户ID Returns: Message: 包含成就进度的消息对象 """ from .gacha import get_achievement_definition msg = Message() msg.append(f"🎯 成就进度:\n") # 勤勤恳恳成就进度 achievement = get_achievement_definition("勤勤恳恳Ⅰ") if achievement: if consecutive_days < 30: msg.append(f"📅 勤勤恳恳Ⅰ:{consecutive_days}/30天 🎯\n") elif consecutive_days < 60: msg.append(f"📅 勤勤恳恳Ⅱ:{consecutive_days}/60天 🎯\n") elif consecutive_days < 90: msg.append(f"📅 勤勤恳恳Ⅲ:{consecutive_days}/90天 🎯\n") elif consecutive_days < 120: msg.append(f"📅 勤勤恳恳Ⅳ:{consecutive_days}/120天 ⭐\n") elif consecutive_days < 150: msg.append(f"📅 勤勤恳恳Ⅴ:{consecutive_days}/150天 ⭐\n") else: # 计算下次奖励周期 next_reward = 150 + ((consecutive_days - 150) // 30 + 1) * 30 if next_reward <= 365: msg.append(f"📅 勤勤恳恳Ⅴ (满级):{consecutive_days}天,距离下次奖励{next_reward}天 🎯\n") else: msg.append(f"📅 勤勤恳恳Ⅴ (满级):{consecutive_days}天,可获得奖励!🎉\n") # 非酋成就进度 if no_ssr_streak > 0: if no_ssr_streak < 60: msg.append(f"💔 非酋进度:{no_ssr_streak}/60次 😭\n") elif no_ssr_streak < 120: msg.append(f"💔 顶级非酋:{no_ssr_streak}/120次 😱\n") elif no_ssr_streak < 180: msg.append(f"💔 月见黑:{no_ssr_streak}/180次 🌙\n") return msg def format_user_stats(stats: Dict[str, Any], user_id: str, user_name: str) -> Message: """ 格式化用户抽卡统计消息。 Args: stats: 用户统计数据字典 user_id: 用户ID user_name: 用户昵称 Returns: Message: 包含统计信息的消息对象 """ msg = Message() msg.append(f"📊 {format_user_mention(user_id, user_name)} 的抽卡统计:\n") msg.append(f"🎲 总抽卡次数:{stats['total_draws']}次\n") total = stats['total_draws'] if total > 0: msg.append(f"\n稀有度分布:\n") msg.append(f"📜 R:{stats.get('R_count',0)}张 ({stats.get('R_count',0)/total*100:.1f}%)\n") msg.append(f"⭐ SR:{stats.get('SR_count',0)}张 ({stats.get('SR_count',0)/total*100:.1f}%)\n") msg.append(f"✨ SSR:{stats.get('SSR_count',0)}张 ({stats.get('SSR_count',0)/total*100:.1f}%)\n") msg.append(f"🌈 SP:{stats.get('SP_count',0)}张 ({stats.get('SP_count',0)/total*100:.1f}%)") return msg def format_user_detail_stats( stats: Dict[str, Any], user_id: str, user_name: str, recent_draws: List[Dict[str, Any]] ) -> Message: """ 格式化用户详细抽卡统计消息。 Args: stats: 用户统计数据字典 user_id: 用户ID user_name: 用户昵称 recent_draws: 最近抽卡记录列表 Returns: Message: 包含详细统计信息的消息对象 """ msg = Message() msg.append(f"{format_user_mention(user_id, user_name)} 的抽卡统计:\n") msg.append(f"总抽卡次数:{stats['total_draws']}次\n") total = stats['total_draws'] if total > 0: msg.append(f"R:{stats.get('R_count',0)}张 ({stats.get('R_count',0)/total*100:.1f}%)\n") msg.append(f"SR:{stats.get('SR_count',0)}张 ({stats.get('SR_count',0)/total*100:.1f}%)\n") msg.append(f"SSR:{stats.get('SSR_count',0)}张 ({stats.get('SSR_count',0)/total*100:.1f}%)\n") msg.append(f"SP:{stats.get('SP_count',0)}张 ({stats.get('SP_count',0)/total*100:.1f}%)") if recent_draws: msg.append(f"\n最近{len(recent_draws)}次抽卡:\n") for draw in recent_draws: msg.append(f"• {draw}\n") return msg def format_rank_list(rank_data: List[Dict[str, Any]], page: int, total_pages: int) -> Message: """ 格式化抽卡排行榜消息。 Args: rank_data: 排行榜数据列表 page: 当前页码 total_pages: 总页数 Returns: Message: 包含排行榜的消息对象 """ msg = Message() msg.append(f"🏆 抽卡排行榜 (第{page}页/共{total_pages}页)\n\n") for idx, entry in enumerate(rank_data, 1): msg.append(f"{idx}. {entry.get('user_name', '未知')} - {entry.get('total_draws', 0)}次\n") return msg def format_daily_stats(daily_stats: Dict[str, Any]) -> Message: """ 格式化今日抽卡统计消息。 Args: daily_stats: 今日统计数据字典 Returns: Message: 包含今日统计的消息对象 """ msg = Message() msg.append(f"📅 今日抽卡统计\n") msg.append(f"总抽卡次数:{daily_stats.get('today_total',0)}次\n") msg.append(f"\n稀有度分布:\n") msg.append(f"R:{daily_stats.get('R_count',0)}张\n") msg.append(f"SR:{daily_stats.get('SR_count',0)}张\n") msg.append(f"SSR:{daily_stats.get('SSR_count',0)}张\n") msg.append(f"SP:{daily_stats.get('SP_count',0)}张\n") top = daily_stats.get("top_users", []) if top: msg.append("\n今日TOP5:\n") for idx, u in enumerate(top[:5], 1): msg.append(f"{idx}. {u.get('user_name','未知')} - {u.get('draws',0)}次\n") return msg