mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 14:22:55 +08:00
Merge branch 'main' into feature/webui-config
This commit is contained in:
commit
922ca71e7d
@ -1,4 +1,5 @@
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
from nonebot.plugin import PluginMetadata
|
from nonebot.plugin import PluginMetadata
|
||||||
from nonebot_plugin_alconna import (
|
from nonebot_plugin_alconna import (
|
||||||
@ -14,35 +15,38 @@ from nonebot_plugin_alconna import (
|
|||||||
from nonebot_plugin_session import EventSession
|
from nonebot_plugin_session import EventSession
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from zhenxun.configs.utils import Command, PluginExtraData
|
from zhenxun.configs.config import Config
|
||||||
|
from zhenxun.configs.utils import Command, PluginExtraData, RegisterConfig
|
||||||
from zhenxun.models.chat_history import ChatHistory
|
from zhenxun.models.chat_history import ChatHistory
|
||||||
from zhenxun.models.group_member_info import GroupInfoUser
|
from zhenxun.models.group_member_info import GroupInfoUser
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
from zhenxun.utils.enum import PluginType
|
from zhenxun.utils.enum import PluginType
|
||||||
from zhenxun.utils.image_utils import ImageTemplate
|
from zhenxun.utils.image_utils import BuildImage, ImageTemplate
|
||||||
from zhenxun.utils.message import MessageUtils
|
from zhenxun.utils.message import MessageUtils
|
||||||
|
from zhenxun.utils.platform import PlatformUtils
|
||||||
|
|
||||||
__plugin_meta__ = PluginMetadata(
|
__plugin_meta__ = PluginMetadata(
|
||||||
name="消息统计",
|
name="消息统计",
|
||||||
description="消息统计查询",
|
description="消息统计查询",
|
||||||
usage="""
|
usage="""
|
||||||
格式:
|
格式:
|
||||||
消息排行 ?[type [日,周,月,年]] ?[--des]
|
消息排行 ?[type [日,周,月,季,年]] ?[--des]
|
||||||
|
|
||||||
快捷:
|
快捷:
|
||||||
[日,周,月,年]消息排行 ?[数量]
|
[日,周,月,季,年]消息排行 ?[数量]
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
消息排行 : 所有记录排行
|
消息排行 : 所有记录排行
|
||||||
日消息排行 : 今日记录排行
|
日消息排行 : 今日记录排行
|
||||||
周消息排行 : 今日记录排行
|
周消息排行 : 本周记录排行
|
||||||
月消息排行 : 今日记录排行
|
月消息排行 : 本月记录排行
|
||||||
年消息排行 : 今日记录排行
|
季消息排行 : 本季度记录排行
|
||||||
|
年消息排行 : 本年记录排行
|
||||||
消息排行 周 --des : 逆序周记录排行
|
消息排行 周 --des : 逆序周记录排行
|
||||||
""".strip(),
|
""".strip(),
|
||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
version="0.1",
|
version="0.2",
|
||||||
plugin_type=PluginType.NORMAL,
|
plugin_type=PluginType.NORMAL,
|
||||||
menu_type="数据统计",
|
menu_type="数据统计",
|
||||||
commands=[
|
commands=[
|
||||||
@ -50,8 +54,19 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
Command(command="日消息统计"),
|
Command(command="日消息统计"),
|
||||||
Command(command="周消息排行"),
|
Command(command="周消息排行"),
|
||||||
Command(command="月消息排行"),
|
Command(command="月消息排行"),
|
||||||
|
Command(command="季消息排行"),
|
||||||
Command(command="年消息排行"),
|
Command(command="年消息排行"),
|
||||||
],
|
],
|
||||||
|
configs=[
|
||||||
|
RegisterConfig(
|
||||||
|
module="chat_history",
|
||||||
|
key="SHOW_QUIT_MEMBER",
|
||||||
|
value=True,
|
||||||
|
help="是否在消息排行中显示已退群用户",
|
||||||
|
default_value=True,
|
||||||
|
type=bool,
|
||||||
|
)
|
||||||
|
],
|
||||||
).to_dict(),
|
).to_dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -60,7 +75,7 @@ _matcher = on_alconna(
|
|||||||
Alconna(
|
Alconna(
|
||||||
"消息排行",
|
"消息排行",
|
||||||
Option("--des", action=store_true, help_text="逆序"),
|
Option("--des", action=store_true, help_text="逆序"),
|
||||||
Args["type?", ["日", "周", "月", "年"]]["count?", int, 10],
|
Args["type?", ["日", "周", "月", "季", "年"]]["count?", int, 10],
|
||||||
),
|
),
|
||||||
aliases={"消息统计"},
|
aliases={"消息统计"},
|
||||||
priority=5,
|
priority=5,
|
||||||
@ -68,7 +83,7 @@ _matcher = on_alconna(
|
|||||||
)
|
)
|
||||||
|
|
||||||
_matcher.shortcut(
|
_matcher.shortcut(
|
||||||
r"(?P<type>['日', '周', '月', '年'])?消息(排行|统计)\s?(?P<cnt>\d+)?",
|
r"(?P<type>['日', '周', '月', '季', '年'])?消息(排行|统计)\s?(?P<cnt>\d+)?",
|
||||||
command="消息排行",
|
command="消息排行",
|
||||||
arguments=["{type}", "{cnt}"],
|
arguments=["{type}", "{cnt}"],
|
||||||
prefix=True,
|
prefix=True,
|
||||||
@ -96,20 +111,57 @@ async def _(
|
|||||||
date_scope = (time_now - timedelta(days=7), time_now)
|
date_scope = (time_now - timedelta(days=7), time_now)
|
||||||
elif date in ["月"]:
|
elif date in ["月"]:
|
||||||
date_scope = (time_now - timedelta(days=30), time_now)
|
date_scope = (time_now - timedelta(days=30), time_now)
|
||||||
column_name = ["名次", "昵称", "发言次数"]
|
elif date in ["季"]:
|
||||||
|
date_scope = (time_now - timedelta(days=90), time_now)
|
||||||
|
column_name = ["名次", "头像", "昵称", "发言次数"]
|
||||||
|
show_quit_member = Config.get_config("chat_history", "SHOW_QUIT_MEMBER", True)
|
||||||
|
|
||||||
|
fetch_count = count.result
|
||||||
|
if not show_quit_member:
|
||||||
|
fetch_count = count.result * 2
|
||||||
|
|
||||||
if rank_data := await ChatHistory.get_group_msg_rank(
|
if rank_data := await ChatHistory.get_group_msg_rank(
|
||||||
group_id, count.result, "DES" if arparma.find("des") else "DESC", date_scope
|
group_id, fetch_count, "DES" if arparma.find("des") else "DESC", date_scope
|
||||||
):
|
):
|
||||||
idx = 1
|
idx = 1
|
||||||
data_list = []
|
data_list = []
|
||||||
|
|
||||||
for uid, num in rank_data:
|
for uid, num in rank_data:
|
||||||
if user := await GroupInfoUser.filter(
|
if len(data_list) >= count.result:
|
||||||
|
break
|
||||||
|
|
||||||
|
user_in_group = await GroupInfoUser.filter(
|
||||||
user_id=uid, group_id=group_id
|
user_id=uid, group_id=group_id
|
||||||
).first():
|
).first()
|
||||||
user_name = user.user_name
|
|
||||||
|
if not user_in_group and not show_quit_member:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if user_in_group:
|
||||||
|
user_name = user_in_group.user_name
|
||||||
else:
|
else:
|
||||||
user_name = uid
|
user_name = f"{uid}(已退群)"
|
||||||
data_list.append([idx, user_name, num])
|
|
||||||
|
avatar_size = 40
|
||||||
|
try:
|
||||||
|
avatar_bytes = await PlatformUtils.get_user_avatar(str(uid), "qq")
|
||||||
|
if avatar_bytes:
|
||||||
|
avatar_img = BuildImage(
|
||||||
|
avatar_size, avatar_size, background=BytesIO(avatar_bytes)
|
||||||
|
)
|
||||||
|
await avatar_img.circle()
|
||||||
|
avatar_tuple = (avatar_img, avatar_size, avatar_size)
|
||||||
|
else:
|
||||||
|
avatar_img = BuildImage(avatar_size, avatar_size, color="#CCCCCC")
|
||||||
|
await avatar_img.circle()
|
||||||
|
avatar_tuple = (avatar_img, avatar_size, avatar_size)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"获取用户头像失败: {e}", "chat_history")
|
||||||
|
avatar_img = BuildImage(avatar_size, avatar_size, color="#CCCCCC")
|
||||||
|
await avatar_img.circle()
|
||||||
|
avatar_tuple = (avatar_img, avatar_size, avatar_size)
|
||||||
|
|
||||||
|
data_list.append([idx, avatar_tuple, user_name, num])
|
||||||
idx += 1
|
idx += 1
|
||||||
if not date_scope:
|
if not date_scope:
|
||||||
if date_scope := await ChatHistory.get_group_first_msg_datetime(group_id):
|
if date_scope := await ChatHistory.get_group_first_msg_datetime(group_id):
|
||||||
@ -132,13 +184,3 @@ async def _(
|
|||||||
)
|
)
|
||||||
await MessageUtils.build_message(A).finish(reply_to=True)
|
await MessageUtils.build_message(A).finish(reply_to=True)
|
||||||
await MessageUtils.build_message("群组消息记录为空...").finish()
|
await MessageUtils.build_message("群组消息记录为空...").finish()
|
||||||
|
|
||||||
|
|
||||||
# # @test.handle()
|
|
||||||
# # async def _(event: MessageEvent):
|
|
||||||
# # print(await ChatHistory.get_user_msg(event.user_id, "private"))
|
|
||||||
# # print(await ChatHistory.get_user_msg_count(event.user_id, "private"))
|
|
||||||
# # print(await ChatHistory.get_user_msg(event.user_id, "group"))
|
|
||||||
# # print(await ChatHistory.get_user_msg_count(event.user_id, "group"))
|
|
||||||
# # print(await ChatHistory.get_group_msg(event.group_id))
|
|
||||||
# # print(await ChatHistory.get_group_msg_count(event.group_id))
|
|
||||||
|
|||||||
252
zhenxun/builtin_plugins/mahiro_bank/__init__.py
Normal file
252
zhenxun/builtin_plugins/mahiro_bank/__init__.py
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from nonebot.plugin import PluginMetadata
|
||||||
|
from nonebot_plugin_alconna import Alconna, Args, Arparma, Match, Subcommand, on_alconna
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
from nonebot_plugin_uninfo import Uninfo
|
||||||
|
from nonebot_plugin_waiter import prompt_until
|
||||||
|
|
||||||
|
from zhenxun.configs.utils import PluginExtraData, RegisterConfig
|
||||||
|
from zhenxun.services.log import logger
|
||||||
|
from zhenxun.utils.depends import UserName
|
||||||
|
from zhenxun.utils.message import MessageUtils
|
||||||
|
from zhenxun.utils.utils import is_number
|
||||||
|
|
||||||
|
from .data_source import BankManager
|
||||||
|
|
||||||
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
name="小真寻银行",
|
||||||
|
description="""
|
||||||
|
小真寻银行,提供高品质的存款!当好感度等级达到指初识时,小真寻会偷偷的帮助你哦。
|
||||||
|
存款额度与好感度有关,每日存款次数有限制。
|
||||||
|
基础存款提供基础利息
|
||||||
|
每日存款提供高额利息
|
||||||
|
""".strip(),
|
||||||
|
usage="""
|
||||||
|
指令:
|
||||||
|
存款 [金额]
|
||||||
|
取款 [金额]
|
||||||
|
银行信息
|
||||||
|
我的银行信息
|
||||||
|
""".strip(),
|
||||||
|
extra=PluginExtraData(
|
||||||
|
author="HibiKier",
|
||||||
|
version="0.1",
|
||||||
|
menu_type="群内小游戏",
|
||||||
|
configs=[
|
||||||
|
RegisterConfig(
|
||||||
|
key="sign_max_deposit",
|
||||||
|
value=100,
|
||||||
|
help="好感度换算存款金额比例,当值是100时,最大存款金额=好感度*100,存款的最低金额是100(强制)",
|
||||||
|
default_value=100,
|
||||||
|
type=int,
|
||||||
|
),
|
||||||
|
RegisterConfig(
|
||||||
|
key="max_daily_deposit_count",
|
||||||
|
value=3,
|
||||||
|
help="每日最大存款次数",
|
||||||
|
default_value=3,
|
||||||
|
type=int,
|
||||||
|
),
|
||||||
|
RegisterConfig(
|
||||||
|
key="rate_range",
|
||||||
|
value=[0.0005, 0.001],
|
||||||
|
help="小时利率范围",
|
||||||
|
default_value=[0.0005, 0.001],
|
||||||
|
type=list[float],
|
||||||
|
),
|
||||||
|
RegisterConfig(
|
||||||
|
key="impression_event",
|
||||||
|
value=25,
|
||||||
|
help="到达指定好感度时随机提高或降低利率",
|
||||||
|
default_value=25,
|
||||||
|
type=int,
|
||||||
|
),
|
||||||
|
RegisterConfig(
|
||||||
|
key="impression_event_range",
|
||||||
|
value=[0.00001, 0.0003],
|
||||||
|
help="到达指定好感度时随机提高或降低利率",
|
||||||
|
default_value=[0.00001, 0.0003],
|
||||||
|
type=list[float],
|
||||||
|
),
|
||||||
|
RegisterConfig(
|
||||||
|
key="impression_event_prop",
|
||||||
|
value=0.3,
|
||||||
|
help="到达指定好感度时随机提高或降低利率触发概率",
|
||||||
|
default_value=0.3,
|
||||||
|
type=float,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).to_dict(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_matcher = on_alconna(
|
||||||
|
Alconna(
|
||||||
|
"mahiro-bank",
|
||||||
|
Subcommand("deposit", Args["amount?", int]),
|
||||||
|
Subcommand("withdraw", Args["amount?", int]),
|
||||||
|
Subcommand("user-info"),
|
||||||
|
Subcommand("bank-info"),
|
||||||
|
# Subcommand("loan", Args["amount?", int]),
|
||||||
|
# Subcommand("repayment", Args["amount?", int]),
|
||||||
|
),
|
||||||
|
priority=5,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_matcher.shortcut(
|
||||||
|
r"存款\s*(?P<amount>\d+)?",
|
||||||
|
command="mahiro-bank",
|
||||||
|
arguments=["deposit", "{amount}"],
|
||||||
|
prefix=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_matcher.shortcut(
|
||||||
|
r"取款\s*(?P<withdraw>\d+)?",
|
||||||
|
command="mahiro-bank",
|
||||||
|
arguments=["withdraw", "{withdraw}"],
|
||||||
|
prefix=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_matcher.shortcut(
|
||||||
|
r"我的银行信息",
|
||||||
|
command="mahiro-bank",
|
||||||
|
arguments=["user-info"],
|
||||||
|
prefix=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
_matcher.shortcut(
|
||||||
|
r"银行信息",
|
||||||
|
command="mahiro-bank",
|
||||||
|
arguments=["bank-info"],
|
||||||
|
prefix=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_amount(handle_type: str) -> int:
|
||||||
|
amount_num = await prompt_until(
|
||||||
|
f"请输入{handle_type}金币数量",
|
||||||
|
lambda msg: is_number(msg.extract_plain_text()),
|
||||||
|
timeout=60,
|
||||||
|
retry=3,
|
||||||
|
retry_prompt="输入错误,请输入数字。剩余次数:{count}",
|
||||||
|
)
|
||||||
|
if not amount_num:
|
||||||
|
await MessageUtils.build_message(
|
||||||
|
"输入超时了哦,小真寻柜员以取消本次存款操作..."
|
||||||
|
).finish()
|
||||||
|
return int(amount_num.extract_plain_text())
|
||||||
|
|
||||||
|
|
||||||
|
@_matcher.assign("deposit")
|
||||||
|
async def _(session: Uninfo, arparma: Arparma, amount: Match[int]):
|
||||||
|
amount_num = amount.result if amount.available else await get_amount("存款")
|
||||||
|
if result := await BankManager.deposit_check(session.user.id, amount_num):
|
||||||
|
await MessageUtils.build_message(result).finish(reply_to=True)
|
||||||
|
_, rate, event_rate = await BankManager.deposit(session.user.id, amount_num)
|
||||||
|
result = (
|
||||||
|
f"存款成功!\n此次存款金额为: {amount.result}\n"
|
||||||
|
f"当前小时利率为: {rate * 100:.2f}%"
|
||||||
|
)
|
||||||
|
effective_hour = int(24 - datetime.now().hour)
|
||||||
|
if event_rate:
|
||||||
|
result += f"(小真寻偷偷将小时利率给你增加了 {event_rate:.2f}% 哦)"
|
||||||
|
result += (
|
||||||
|
f"\n预计总收益为: {int(amount.result * rate * effective_hour) or 1} 金币。"
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
f"小真寻银行存款:{amount_num},当前存款数:{amount.result},存款小时利率: {rate}",
|
||||||
|
arparma.header_result,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
|
await MessageUtils.build_message(result).finish(at_sender=True)
|
||||||
|
|
||||||
|
|
||||||
|
@_matcher.assign("withdraw")
|
||||||
|
async def _(session: Uninfo, arparma: Arparma, amount: Match[int]):
|
||||||
|
amount_num = amount.result if amount.available else await get_amount("取款")
|
||||||
|
if result := await BankManager.withdraw_check(session.user.id, amount_num):
|
||||||
|
await MessageUtils.build_message(result).finish(reply_to=True)
|
||||||
|
try:
|
||||||
|
user = await BankManager.withdraw(session.user.id, amount_num)
|
||||||
|
result = (
|
||||||
|
f"取款成功!\n当前取款金额为: {amount_num}\n当前存款金额为: {user.amount}"
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
f"小真寻银行取款:{amount_num}, 当前存款数:{user.amount},"
|
||||||
|
f" 存款小时利率:{user.rate}",
|
||||||
|
arparma.header_result,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
|
await MessageUtils.build_message(result).finish(reply_to=True)
|
||||||
|
except ValueError:
|
||||||
|
await MessageUtils.build_message("你的银行内的存款数量不足哦...").finish(
|
||||||
|
reply_to=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@_matcher.assign("user-info")
|
||||||
|
async def _(session: Uninfo, arparma: Arparma, uname: str = UserName()):
|
||||||
|
result = await BankManager.get_user_info(session, uname)
|
||||||
|
await MessageUtils.build_message(result).send()
|
||||||
|
logger.info("查看银行个人信息", arparma.header_result, session=session)
|
||||||
|
|
||||||
|
|
||||||
|
@_matcher.assign("bank-info")
|
||||||
|
async def _(session: Uninfo, arparma: Arparma):
|
||||||
|
result = await BankManager.get_bank_info()
|
||||||
|
await MessageUtils.build_message(result).send()
|
||||||
|
logger.info("查看银行信息", arparma.header_result, session=session)
|
||||||
|
|
||||||
|
|
||||||
|
# @_matcher.assign("loan")
|
||||||
|
# async def _(session: Uninfo, arparma: Arparma, amount: Match[int]):
|
||||||
|
# amount_num = amount.result if amount.available else await get_amount("贷款")
|
||||||
|
# if amount_num <= 0:
|
||||||
|
# await MessageUtils.build_message("贷款数量必须大于 0 啊笨蛋!").finish()
|
||||||
|
# try:
|
||||||
|
# user, event_rate = await BankManager.loan(session.user.id, amount_num)
|
||||||
|
# result = (
|
||||||
|
# f"贷款成功!\n当前贷金额为: {user.loan_amount}"
|
||||||
|
# f"\n当前利率为: {user.loan_rate * 100}%"
|
||||||
|
# )
|
||||||
|
# if event_rate:
|
||||||
|
# result += f"(小真寻偷偷将利率给你降低了 {event_rate}% 哦)"
|
||||||
|
# result += f"\n预计每小时利息为:{int(user.loan_amount * user.loan_rate)}金币。"
|
||||||
|
# logger.info(
|
||||||
|
# f"小真寻银行贷款: {amount_num}, 当前贷款数: {user.loan_amount}, "
|
||||||
|
# f"贷款利率: {user.loan_rate}",
|
||||||
|
# arparma.header_result,
|
||||||
|
# session=session,
|
||||||
|
# )
|
||||||
|
# except ValueError:
|
||||||
|
# await MessageUtils.build_message(
|
||||||
|
# "贷款数量超过最大限制,请签到提升好感度获取更多额度吧..."
|
||||||
|
# ).finish(reply_to=True)
|
||||||
|
|
||||||
|
|
||||||
|
# @_matcher.assign("repayment")
|
||||||
|
# async def _(session: Uninfo, arparma: Arparma, amount: Match[int]):
|
||||||
|
# amount_num = amount.result if amount.available else await get_amount("还款")
|
||||||
|
# if amount_num <= 0:
|
||||||
|
# await MessageUtils.build_message("还款数量必须大于 0 啊笨蛋!").finish()
|
||||||
|
# user = await BankManager.repayment(session.user.id, amount_num)
|
||||||
|
# result = (f"还款成功!\n当前还款金额为: {amount_num}\n"
|
||||||
|
# f"当前贷款金额为: {user.loan_amount}")
|
||||||
|
# logger.info(
|
||||||
|
# f"小真寻银行还款:{amount_num},当前贷款数:{user.amount}, 贷款利率:{user.rate}",
|
||||||
|
# arparma.header_result,
|
||||||
|
# session=session,
|
||||||
|
# )
|
||||||
|
# await MessageUtils.build_message(result).finish(at_sender=True)
|
||||||
|
|
||||||
|
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
"cron",
|
||||||
|
hour=0,
|
||||||
|
minute=0,
|
||||||
|
)
|
||||||
|
async def _():
|
||||||
|
await BankManager.settlement()
|
||||||
|
logger.info("小真寻银行结算", "定时任务")
|
||||||
450
zhenxun/builtin_plugins/mahiro_bank/data_source.py
Normal file
450
zhenxun/builtin_plugins/mahiro_bank/data_source.py
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
import asyncio
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import random
|
||||||
|
|
||||||
|
from nonebot_plugin_htmlrender import template_to_pic
|
||||||
|
from nonebot_plugin_uninfo import Uninfo
|
||||||
|
from tortoise.expressions import RawSQL
|
||||||
|
from tortoise.functions import Count, Sum
|
||||||
|
|
||||||
|
from zhenxun.configs.config import Config
|
||||||
|
from zhenxun.configs.path_config import TEMPLATE_PATH
|
||||||
|
from zhenxun.models.mahiro_bank import MahiroBank
|
||||||
|
from zhenxun.models.mahiro_bank_log import MahiroBankLog
|
||||||
|
from zhenxun.models.sign_user import SignUser
|
||||||
|
from zhenxun.models.user_console import UserConsole
|
||||||
|
from zhenxun.utils.enum import BankHandleType, GoldHandle
|
||||||
|
from zhenxun.utils.platform import PlatformUtils
|
||||||
|
|
||||||
|
base_config = Config.get("mahiro_bank")
|
||||||
|
|
||||||
|
|
||||||
|
class BankManager:
|
||||||
|
@classmethod
|
||||||
|
async def random_event(cls, impression: float):
|
||||||
|
"""随机事件"""
|
||||||
|
impression_event = base_config.get("impression_event")
|
||||||
|
impression_event_prop = base_config.get("impression_event_prop")
|
||||||
|
impression_event_range = base_config.get("impression_event_range")
|
||||||
|
if impression >= impression_event and random.random() < impression_event_prop:
|
||||||
|
"""触发好感度事件"""
|
||||||
|
return random.uniform(impression_event_range[0], impression_event_range[1])
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def deposit_check(cls, user_id: str, amount: int) -> str | None:
|
||||||
|
"""检查存款是否合法
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 存款金额
|
||||||
|
|
||||||
|
返回:
|
||||||
|
str | None: 存款信息
|
||||||
|
"""
|
||||||
|
if amount <= 0:
|
||||||
|
return "存款数量必须大于 0 啊笨蛋!"
|
||||||
|
user, sign_user, bank_user = await asyncio.gather(
|
||||||
|
*[
|
||||||
|
UserConsole.get_user(user_id),
|
||||||
|
SignUser.get_user(user_id),
|
||||||
|
cls.get_user(user_id),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
sign_max_deposit: int = base_config.get("sign_max_deposit")
|
||||||
|
max_deposit = max(int(float(sign_user.impression) * sign_max_deposit), 100)
|
||||||
|
if user.gold < amount:
|
||||||
|
return f"金币数量不足,当前你的金币为:{user.gold}."
|
||||||
|
if bank_user.amount + amount > max_deposit:
|
||||||
|
return (
|
||||||
|
f"存款超过上限,存款上限为:{max_deposit},"
|
||||||
|
f"当前你的还可以存款金额:{max_deposit - bank_user.amount}。"
|
||||||
|
)
|
||||||
|
max_daily_deposit_count: int = base_config.get("max_daily_deposit_count")
|
||||||
|
today_deposit_count = len(await cls.get_user_deposit(user_id))
|
||||||
|
if today_deposit_count >= max_daily_deposit_count:
|
||||||
|
return f"存款次数超过上限,每日存款次数上限为:{max_daily_deposit_count}。"
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def withdraw_check(cls, user_id: str, amount: int) -> str | None:
|
||||||
|
"""检查取款是否合法
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 取款金额
|
||||||
|
|
||||||
|
返回:
|
||||||
|
str | None: 取款信息
|
||||||
|
"""
|
||||||
|
if amount <= 0:
|
||||||
|
return "取款数量必须大于 0 啊笨蛋!"
|
||||||
|
user = await cls.get_user(user_id)
|
||||||
|
data_list = await cls.get_user_deposit(user_id)
|
||||||
|
lock_amount = sum(data.amount for data in data_list)
|
||||||
|
if user.amount - lock_amount < amount:
|
||||||
|
return (
|
||||||
|
"取款金额不足,当前你的存款为:"
|
||||||
|
f"{user.amount}({lock_amount}已被锁定)!"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_user_deposit(
|
||||||
|
cls, user_id: str, is_completed: bool = False
|
||||||
|
) -> list[MahiroBankLog]:
|
||||||
|
"""获取用户今日存款次数
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
|
||||||
|
返回:
|
||||||
|
list[MahiroBankLog]: 存款列表
|
||||||
|
"""
|
||||||
|
return await MahiroBankLog.filter(
|
||||||
|
user_id=user_id,
|
||||||
|
handle_type=BankHandleType.DEPOSIT,
|
||||||
|
is_completed=is_completed,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_user(cls, user_id: str) -> MahiroBank:
|
||||||
|
"""查询余额
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
|
||||||
|
返回:
|
||||||
|
MahiroBank
|
||||||
|
"""
|
||||||
|
user, _ = await MahiroBank.get_or_create(user_id=user_id)
|
||||||
|
return user
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_user_data(
|
||||||
|
cls,
|
||||||
|
user_id: str,
|
||||||
|
data_type: BankHandleType,
|
||||||
|
is_completed: bool = False,
|
||||||
|
count: int = 5,
|
||||||
|
) -> list[MahiroBankLog]:
|
||||||
|
return (
|
||||||
|
await MahiroBankLog.filter(
|
||||||
|
user_id=user_id, handle_type=data_type, is_completed=is_completed
|
||||||
|
)
|
||||||
|
.order_by("-id")
|
||||||
|
.limit(count)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def complete_projected_revenue(cls, user_id: str) -> int:
|
||||||
|
"""预计收益
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
|
||||||
|
返回:
|
||||||
|
int: 预计收益金额
|
||||||
|
"""
|
||||||
|
deposit_list = await cls.get_user_deposit(user_id)
|
||||||
|
if not deposit_list:
|
||||||
|
return 0
|
||||||
|
return int(
|
||||||
|
sum(
|
||||||
|
deposit.rate * deposit.amount * deposit.effective_hour
|
||||||
|
for deposit in deposit_list
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_user_info(cls, session: Uninfo, uname: str) -> bytes:
|
||||||
|
"""获取用户数据
|
||||||
|
|
||||||
|
参数:
|
||||||
|
session: Uninfo
|
||||||
|
uname: 用户id
|
||||||
|
|
||||||
|
返回:
|
||||||
|
bytes: 图片数据
|
||||||
|
"""
|
||||||
|
user_id = session.user.id
|
||||||
|
user = await cls.get_user(user_id=user_id)
|
||||||
|
(
|
||||||
|
rank,
|
||||||
|
deposit_count,
|
||||||
|
user_today_deposit,
|
||||||
|
projected_revenue,
|
||||||
|
sum_data,
|
||||||
|
) = await asyncio.gather(
|
||||||
|
*[
|
||||||
|
MahiroBank.filter(amount__gt=user.amount).count(),
|
||||||
|
MahiroBankLog.filter(user_id=user_id).count(),
|
||||||
|
cls.get_user_deposit(user_id),
|
||||||
|
cls.complete_projected_revenue(user_id),
|
||||||
|
MahiroBankLog.filter(
|
||||||
|
user_id=user_id, handle_type=BankHandleType.INTEREST
|
||||||
|
)
|
||||||
|
.annotate(sum=Sum("amount"))
|
||||||
|
.values("sum"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
now = datetime.now()
|
||||||
|
end_time = (
|
||||||
|
now
|
||||||
|
+ timedelta(days=1)
|
||||||
|
- timedelta(hours=now.hour, minutes=now.minute, seconds=now.second)
|
||||||
|
)
|
||||||
|
today_deposit_amount = sum(deposit.amount for deposit in user_today_deposit)
|
||||||
|
deposit_list = [
|
||||||
|
{
|
||||||
|
"id": deposit.id,
|
||||||
|
"date": now.date(),
|
||||||
|
"start_time": str(deposit.create_time).split(".")[0],
|
||||||
|
"end_time": end_time.replace(microsecond=0),
|
||||||
|
"amount": deposit.amount,
|
||||||
|
"rate": f"{deposit.rate * 100:.2f}",
|
||||||
|
"projected_revenue": int(
|
||||||
|
deposit.amount * deposit.rate * deposit.effective_hour
|
||||||
|
)
|
||||||
|
or 1,
|
||||||
|
}
|
||||||
|
for deposit in user_today_deposit
|
||||||
|
]
|
||||||
|
platform = PlatformUtils.get_platform(session)
|
||||||
|
data = {
|
||||||
|
"name": uname,
|
||||||
|
"rank": rank + 1,
|
||||||
|
"avatar_url": PlatformUtils.get_user_avatar_url(
|
||||||
|
user_id, platform, session.self_id
|
||||||
|
),
|
||||||
|
"amount": user.amount,
|
||||||
|
"deposit_count": deposit_count,
|
||||||
|
"today_deposit_count": len(user_today_deposit),
|
||||||
|
"cumulative_gain": sum_data[0]["sum"] or 0,
|
||||||
|
"projected_revenue": projected_revenue,
|
||||||
|
"today_deposit_amount": today_deposit_amount,
|
||||||
|
"deposit_list": deposit_list,
|
||||||
|
"create_time": now.replace(microsecond=0),
|
||||||
|
}
|
||||||
|
return await template_to_pic(
|
||||||
|
template_path=str((TEMPLATE_PATH / "mahiro_bank").absolute()),
|
||||||
|
template_name="user.html",
|
||||||
|
templates={"data": data},
|
||||||
|
pages={
|
||||||
|
"viewport": {"width": 386, "height": 700},
|
||||||
|
"base_url": f"file://{TEMPLATE_PATH}",
|
||||||
|
},
|
||||||
|
wait=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_bank_info(cls) -> bytes:
|
||||||
|
now = datetime.now()
|
||||||
|
now_start = now - timedelta(
|
||||||
|
hours=now.hour, minutes=now.minute, seconds=now.second
|
||||||
|
)
|
||||||
|
(
|
||||||
|
bank_data,
|
||||||
|
today_count,
|
||||||
|
interest_amount,
|
||||||
|
active_user_count,
|
||||||
|
date_data,
|
||||||
|
) = await asyncio.gather(
|
||||||
|
*[
|
||||||
|
MahiroBank.annotate(
|
||||||
|
amount_sum=Sum("amount"), user_count=Count("id")
|
||||||
|
).values("amount_sum", "user_count"),
|
||||||
|
MahiroBankLog.filter(
|
||||||
|
create_time__gt=now_start, handle_type=BankHandleType.DEPOSIT
|
||||||
|
).count(),
|
||||||
|
MahiroBankLog.filter(handle_type=BankHandleType.INTEREST)
|
||||||
|
.annotate(amount_sum=Sum("amount"))
|
||||||
|
.values("amount_sum"),
|
||||||
|
MahiroBankLog.filter(
|
||||||
|
create_time__gte=now_start - timedelta(days=7),
|
||||||
|
handle_type=BankHandleType.DEPOSIT,
|
||||||
|
)
|
||||||
|
.annotate(count=Count("user_id", distinct=True))
|
||||||
|
.values("count"),
|
||||||
|
MahiroBankLog.filter(
|
||||||
|
create_time__gte=now_start - timedelta(days=7),
|
||||||
|
handle_type=BankHandleType.DEPOSIT,
|
||||||
|
)
|
||||||
|
.annotate(date=RawSQL("DATE(create_time)"), total_amount=Sum("amount"))
|
||||||
|
.group_by("date")
|
||||||
|
.values("date", "total_amount"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
date2cnt = {str(date["date"]): date["total_amount"] for date in date_data}
|
||||||
|
date = now.date()
|
||||||
|
e_date, e_amount = [], []
|
||||||
|
for _ in range(7):
|
||||||
|
if str(date) in date2cnt:
|
||||||
|
e_amount.append(date2cnt[str(date)])
|
||||||
|
else:
|
||||||
|
e_amount.append(0)
|
||||||
|
e_date.append(str(date)[5:])
|
||||||
|
date -= timedelta(days=1)
|
||||||
|
e_date.reverse()
|
||||||
|
e_amount.reverse()
|
||||||
|
date = 1
|
||||||
|
lasted_log = await MahiroBankLog.annotate().order_by("create_time").first()
|
||||||
|
if lasted_log:
|
||||||
|
date = now.date() - lasted_log.create_time.date()
|
||||||
|
date = (date.days or 1) + 1
|
||||||
|
data = {
|
||||||
|
"amount_sum": bank_data[0]["amount_sum"],
|
||||||
|
"user_count": bank_data[0]["user_count"],
|
||||||
|
"today_count": today_count,
|
||||||
|
"day_amount": int(bank_data[0]["amount_sum"] / date),
|
||||||
|
"interest_amount": interest_amount[0]["amount_sum"] or 0,
|
||||||
|
"active_user_count": active_user_count[0]["count"] or 0,
|
||||||
|
"e_data": e_date,
|
||||||
|
"e_amount": e_amount,
|
||||||
|
"create_time": now.replace(microsecond=0),
|
||||||
|
}
|
||||||
|
return await template_to_pic(
|
||||||
|
template_path=str((TEMPLATE_PATH / "mahiro_bank").absolute()),
|
||||||
|
template_name="bank.html",
|
||||||
|
templates={"data": data},
|
||||||
|
pages={
|
||||||
|
"viewport": {"width": 450, "height": 750},
|
||||||
|
"base_url": f"file://{TEMPLATE_PATH}",
|
||||||
|
},
|
||||||
|
wait=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def deposit(
|
||||||
|
cls, user_id: str, amount: int
|
||||||
|
) -> tuple[MahiroBank, float, float | None]:
|
||||||
|
"""存款
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 存款数量
|
||||||
|
|
||||||
|
返回:
|
||||||
|
tuple[MahiroBank, float, float]: MahiroBank,利率,增加的利率
|
||||||
|
"""
|
||||||
|
rate_range = base_config.get("rate_range")
|
||||||
|
rate = random.uniform(rate_range[0], rate_range[1])
|
||||||
|
sign_user = await SignUser.get_user(user_id)
|
||||||
|
random_add_rate = await cls.random_event(float(sign_user.impression))
|
||||||
|
if random_add_rate:
|
||||||
|
rate += random_add_rate
|
||||||
|
await UserConsole.reduce_gold(user_id, amount, GoldHandle.PLUGIN, "bank")
|
||||||
|
return await MahiroBank.deposit(user_id, amount, rate), rate, random_add_rate
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def withdraw(cls, user_id: str, amount: int) -> MahiroBank:
|
||||||
|
"""取款
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 取款数量
|
||||||
|
|
||||||
|
返回:
|
||||||
|
MahiroBank
|
||||||
|
"""
|
||||||
|
await UserConsole.add_gold(user_id, amount, "bank")
|
||||||
|
return await MahiroBank.withdraw(user_id, amount)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def loan(cls, user_id: str, amount: int) -> tuple[MahiroBank, float | None]:
|
||||||
|
"""贷款
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 贷款数量
|
||||||
|
|
||||||
|
返回:
|
||||||
|
tuple[MahiroBank, float]: MahiroBank,贷款利率
|
||||||
|
"""
|
||||||
|
rate_range = base_config.get("rate_range")
|
||||||
|
rate = random.uniform(rate_range[0], rate_range[1])
|
||||||
|
sign_user = await SignUser.get_user(user_id)
|
||||||
|
user, _ = await MahiroBank.get_or_create(user_id=user_id)
|
||||||
|
if user.loan_amount + amount > sign_user.impression * 150:
|
||||||
|
raise ValueError("贷款数量超过最大限制,请签到提升好感度获取更多额度吧...")
|
||||||
|
random_reduce_rate = await cls.random_event(float(sign_user.impression))
|
||||||
|
if random_reduce_rate:
|
||||||
|
rate -= random_reduce_rate
|
||||||
|
await UserConsole.add_gold(user_id, amount, "bank")
|
||||||
|
return await MahiroBank.loan(user_id, amount, rate), random_reduce_rate
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def repayment(cls, user_id: str, amount: int) -> MahiroBank:
|
||||||
|
"""还款
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 还款数量
|
||||||
|
|
||||||
|
返回:
|
||||||
|
MahiroBank
|
||||||
|
"""
|
||||||
|
await UserConsole.reduce_gold(user_id, amount, GoldHandle.PLUGIN, "bank")
|
||||||
|
return await MahiroBank.repayment(user_id, amount)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def settlement(cls):
|
||||||
|
"""结算每日利率"""
|
||||||
|
bank_user_list = await MahiroBank.filter(amount__gt=0).all()
|
||||||
|
log_list = await MahiroBankLog.filter(
|
||||||
|
is_completed=False, handle_type=BankHandleType.DEPOSIT
|
||||||
|
).all()
|
||||||
|
user_list = await UserConsole.filter(
|
||||||
|
user_id__in=[user.user_id for user in bank_user_list]
|
||||||
|
).all()
|
||||||
|
user_data = {user.user_id: user for user in user_list}
|
||||||
|
bank_data: dict[str, list[MahiroBankLog]] = {}
|
||||||
|
for log in log_list:
|
||||||
|
if log.user_id not in bank_data:
|
||||||
|
bank_data[log.user_id] = []
|
||||||
|
bank_data[log.user_id].append(log)
|
||||||
|
log_create_list = []
|
||||||
|
log_update_list = []
|
||||||
|
# 计算每日默认金币
|
||||||
|
for bank_user in bank_user_list:
|
||||||
|
if user := user_data.get(bank_user.user_id):
|
||||||
|
amount = bank_user.amount
|
||||||
|
if logs := bank_data.get(bank_user.user_id):
|
||||||
|
amount -= sum(log.amount for log in logs)
|
||||||
|
if not amount:
|
||||||
|
continue
|
||||||
|
# 计算每日默认金币
|
||||||
|
gold = int(amount * bank_user.rate)
|
||||||
|
user.gold += gold
|
||||||
|
log_create_list.append(
|
||||||
|
MahiroBankLog(
|
||||||
|
user_id=bank_user.user_id,
|
||||||
|
amount=gold,
|
||||||
|
rate=bank_user.rate,
|
||||||
|
handle_type=BankHandleType.INTEREST,
|
||||||
|
is_completed=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# 计算每日存款金币
|
||||||
|
for user_id, logs in bank_data.items():
|
||||||
|
if user := user_data.get(user_id):
|
||||||
|
for log in logs:
|
||||||
|
gold = int(log.amount * log.rate * log.effective_hour) or 1
|
||||||
|
user.gold += gold
|
||||||
|
log.is_completed = True
|
||||||
|
log_update_list.append(log)
|
||||||
|
log_create_list.append(
|
||||||
|
MahiroBankLog(
|
||||||
|
user_id=user_id,
|
||||||
|
amount=gold,
|
||||||
|
rate=log.rate,
|
||||||
|
handle_type=BankHandleType.INTEREST,
|
||||||
|
is_completed=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if log_create_list:
|
||||||
|
await MahiroBankLog.bulk_create(log_create_list, 10)
|
||||||
|
if log_update_list:
|
||||||
|
await MahiroBankLog.bulk_update(log_update_list, ["is_completed"], 10)
|
||||||
|
await UserConsole.bulk_update(user_list, ["gold"], 10)
|
||||||
@ -141,7 +141,7 @@ async def _(
|
|||||||
group_id = str(event.group_id)
|
group_id = str(event.group_id)
|
||||||
if event.sub_type == "kick_me":
|
if event.sub_type == "kick_me":
|
||||||
"""踢出Bot"""
|
"""踢出Bot"""
|
||||||
await GroupManager.kick_bot(bot, user_id, group_id)
|
await GroupManager.kick_bot(bot, group_id, str(event.operator_id))
|
||||||
elif event.sub_type in ["leave", "kick"]:
|
elif event.sub_type in ["leave", "kick"]:
|
||||||
result = await GroupManager.run_user(
|
result = await GroupManager.run_user(
|
||||||
bot, user_id, group_id, str(event.operator_id), event.sub_type
|
bot, user_id, group_id, str(event.operator_id), event.sub_type
|
||||||
|
|||||||
@ -110,7 +110,7 @@ async def enable_plugin(
|
|||||||
)
|
)
|
||||||
await BotConsole.enable_plugin(None, plugin.module)
|
await BotConsole.enable_plugin(None, plugin.module)
|
||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
f"已禁用全部 bot 的插件: {plugin_name.result}"
|
f"已开启全部 bot 的插件: {plugin_name.result}"
|
||||||
).finish()
|
).finish()
|
||||||
elif bot_id.available:
|
elif bot_id.available:
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@ -92,7 +92,7 @@ async def enable_task(
|
|||||||
)
|
)
|
||||||
await BotConsole.enable_task(None, task.module)
|
await BotConsole.enable_task(None, task.module)
|
||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
f"已禁用全部 bot 的被动: {task_name.available}"
|
f"已开启全部 bot 的被动: {task_name.available}"
|
||||||
).finish()
|
).finish()
|
||||||
elif bot_id.available:
|
elif bot_id.available:
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
123
zhenxun/models/mahiro_bank.py
Normal file
123
zhenxun/models/mahiro_bank.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from tortoise import fields
|
||||||
|
|
||||||
|
from zhenxun.services.db_context import Model
|
||||||
|
|
||||||
|
from .mahiro_bank_log import BankHandleType, MahiroBankLog
|
||||||
|
|
||||||
|
|
||||||
|
class MahiroBank(Model):
|
||||||
|
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||||
|
"""自增id"""
|
||||||
|
user_id = fields.CharField(255, description="用户id")
|
||||||
|
"""用户id"""
|
||||||
|
amount = fields.BigIntField(default=0, description="存款")
|
||||||
|
"""用户存款"""
|
||||||
|
rate = fields.FloatField(default=0.0005, description="小时利率")
|
||||||
|
"""小时利率"""
|
||||||
|
loan_amount = fields.BigIntField(default=0, description="贷款")
|
||||||
|
"""用户贷款"""
|
||||||
|
loan_rate = fields.FloatField(default=0.0005, description="贷款利率")
|
||||||
|
"""贷款利率"""
|
||||||
|
update_time = fields.DatetimeField(auto_now=True)
|
||||||
|
"""修改时间"""
|
||||||
|
create_time = fields.DatetimeField(auto_now_add=True)
|
||||||
|
"""创建时间"""
|
||||||
|
|
||||||
|
class Meta: # pyright: ignore [reportIncompatibleVariableOverride]
|
||||||
|
table = "mahiro_bank"
|
||||||
|
table_description = "小真寻银行"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def deposit(cls, user_id: str, amount: int, rate: float) -> Self:
|
||||||
|
"""存款
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 金币数量
|
||||||
|
rate: 小时利率
|
||||||
|
|
||||||
|
返回:
|
||||||
|
Self: MahiroBank
|
||||||
|
"""
|
||||||
|
effective_hour = int(24 - datetime.now().hour)
|
||||||
|
user, _ = await cls.get_or_create(user_id=user_id)
|
||||||
|
user.amount += amount
|
||||||
|
await user.save(update_fields=["amount", "rate"])
|
||||||
|
await MahiroBankLog.create(
|
||||||
|
user_id=user_id,
|
||||||
|
amount=amount,
|
||||||
|
rate=rate,
|
||||||
|
effective_hour=effective_hour,
|
||||||
|
handle_type=BankHandleType.DEPOSIT,
|
||||||
|
)
|
||||||
|
return user
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def withdraw(cls, user_id: str, amount: int) -> Self:
|
||||||
|
"""取款
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 金币数量
|
||||||
|
|
||||||
|
返回:
|
||||||
|
Self: MahiroBank
|
||||||
|
"""
|
||||||
|
if amount <= 0:
|
||||||
|
raise ValueError("取款金额必须大于0")
|
||||||
|
user, _ = await cls.get_or_create(user_id=user_id)
|
||||||
|
if user.amount < amount:
|
||||||
|
raise ValueError("取款金额不能大于存款金额")
|
||||||
|
user.amount -= amount
|
||||||
|
await user.save(update_fields=["amount"])
|
||||||
|
await MahiroBankLog.create(
|
||||||
|
user_id=user_id, amount=amount, handle_type=BankHandleType.WITHDRAW
|
||||||
|
)
|
||||||
|
return user
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def loan(cls, user_id: str, amount: int, rate: float) -> Self:
|
||||||
|
"""贷款
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 贷款金额
|
||||||
|
rate: 贷款利率
|
||||||
|
|
||||||
|
返回:
|
||||||
|
Self: MahiroBank
|
||||||
|
"""
|
||||||
|
user, _ = await cls.get_or_create(user_id=user_id)
|
||||||
|
user.loan_amount += amount
|
||||||
|
user.loan_rate = rate
|
||||||
|
await user.save(update_fields=["loan_amount", "loan_rate"])
|
||||||
|
await MahiroBankLog.create(
|
||||||
|
user_id=user_id, amount=amount, rate=rate, handle_type=BankHandleType.LOAN
|
||||||
|
)
|
||||||
|
return user
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def repayment(cls, user_id: str, amount: int) -> Self:
|
||||||
|
"""还款
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user_id: 用户id
|
||||||
|
amount: 还款金额
|
||||||
|
|
||||||
|
返回:
|
||||||
|
Self: MahiroBank
|
||||||
|
"""
|
||||||
|
if amount <= 0:
|
||||||
|
raise ValueError("还款金额必须大于0")
|
||||||
|
user, _ = await cls.get_or_create(user_id=user_id)
|
||||||
|
if user.loan_amount < amount:
|
||||||
|
raise ValueError("还款金额不能大于贷款金额")
|
||||||
|
user.loan_amount -= amount
|
||||||
|
await user.save(update_fields=["loan_amount"])
|
||||||
|
await MahiroBankLog.create(
|
||||||
|
user_id=user_id, amount=amount, handle_type=BankHandleType.REPAYMENT
|
||||||
|
)
|
||||||
|
return user
|
||||||
31
zhenxun/models/mahiro_bank_log.py
Normal file
31
zhenxun/models/mahiro_bank_log.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
from tortoise import fields
|
||||||
|
|
||||||
|
from zhenxun.services.db_context import Model
|
||||||
|
from zhenxun.utils.enum import BankHandleType
|
||||||
|
|
||||||
|
|
||||||
|
class MahiroBankLog(Model):
|
||||||
|
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||||
|
"""自增id"""
|
||||||
|
user_id = fields.CharField(255, description="用户id")
|
||||||
|
"""用户id"""
|
||||||
|
amount = fields.BigIntField(default=0, description="存款")
|
||||||
|
"""金币数量"""
|
||||||
|
rate = fields.FloatField(default=0, description="小时利率")
|
||||||
|
"""小时利率"""
|
||||||
|
handle_type = fields.CharEnumField(
|
||||||
|
BankHandleType, null=True, description="处理类型"
|
||||||
|
)
|
||||||
|
"""处理类型"""
|
||||||
|
is_completed = fields.BooleanField(default=False, description="是否完成")
|
||||||
|
"""是否完成"""
|
||||||
|
effective_hour = fields.IntField(default=0, description="有效小时")
|
||||||
|
"""有效小时"""
|
||||||
|
update_time = fields.DatetimeField(auto_now=True)
|
||||||
|
"""修改时间"""
|
||||||
|
create_time = fields.DatetimeField(auto_now_add=True)
|
||||||
|
"""创建时间"""
|
||||||
|
|
||||||
|
class Meta: # pyright: ignore [reportIncompatibleVariableOverride]
|
||||||
|
table = "mahiro_bank_log"
|
||||||
|
table_description = "小真寻银行日志"
|
||||||
@ -13,6 +13,19 @@ class PriorityLifecycleType(StrEnum):
|
|||||||
"""关闭"""
|
"""关闭"""
|
||||||
|
|
||||||
|
|
||||||
|
class BankHandleType(StrEnum):
|
||||||
|
DEPOSIT = "DEPOSIT"
|
||||||
|
"""存款"""
|
||||||
|
WITHDRAW = "WITHDRAW"
|
||||||
|
"""取款"""
|
||||||
|
LOAN = "LOAN"
|
||||||
|
"""贷款"""
|
||||||
|
REPAYMENT = "REPAYMENT"
|
||||||
|
"""还款"""
|
||||||
|
INTEREST = "INTEREST"
|
||||||
|
"""利息"""
|
||||||
|
|
||||||
|
|
||||||
class GoldHandle(StrEnum):
|
class GoldHandle(StrEnum):
|
||||||
"""
|
"""
|
||||||
金币处理
|
金币处理
|
||||||
|
|||||||
@ -23,7 +23,6 @@ async def get_fastest_raw_formats() -> list[str]:
|
|||||||
formats: dict[str, str] = {
|
formats: dict[str, str] = {
|
||||||
"https://raw.githubusercontent.com/": RAW_CONTENT_FORMAT,
|
"https://raw.githubusercontent.com/": RAW_CONTENT_FORMAT,
|
||||||
"https://ghproxy.cc/": f"https://ghproxy.cc/{RAW_CONTENT_FORMAT}",
|
"https://ghproxy.cc/": f"https://ghproxy.cc/{RAW_CONTENT_FORMAT}",
|
||||||
"https://mirror.ghproxy.com/": f"https://mirror.ghproxy.com/{RAW_CONTENT_FORMAT}",
|
|
||||||
"https://gh-proxy.com/": f"https://gh-proxy.com/{RAW_CONTENT_FORMAT}",
|
"https://gh-proxy.com/": f"https://gh-proxy.com/{RAW_CONTENT_FORMAT}",
|
||||||
"https://cdn.jsdelivr.net/": "https://cdn.jsdelivr.net/gh/{owner}/{repo}@{branch}/{path}",
|
"https://cdn.jsdelivr.net/": "https://cdn.jsdelivr.net/gh/{owner}/{repo}@{branch}/{path}",
|
||||||
}
|
}
|
||||||
@ -36,7 +35,6 @@ async def get_fastest_archive_formats() -> list[str]:
|
|||||||
formats: dict[str, str] = {
|
formats: dict[str, str] = {
|
||||||
"https://github.com/": ARCHIVE_URL_FORMAT,
|
"https://github.com/": ARCHIVE_URL_FORMAT,
|
||||||
"https://ghproxy.cc/": f"https://ghproxy.cc/{ARCHIVE_URL_FORMAT}",
|
"https://ghproxy.cc/": f"https://ghproxy.cc/{ARCHIVE_URL_FORMAT}",
|
||||||
"https://mirror.ghproxy.com/": f"https://mirror.ghproxy.com/{ARCHIVE_URL_FORMAT}",
|
|
||||||
"https://gh-proxy.com/": f"https://gh-proxy.com/{ARCHIVE_URL_FORMAT}",
|
"https://gh-proxy.com/": f"https://gh-proxy.com/{ARCHIVE_URL_FORMAT}",
|
||||||
}
|
}
|
||||||
return await __get_fastest_formats(formats)
|
return await __get_fastest_formats(formats)
|
||||||
@ -48,7 +46,6 @@ async def get_fastest_release_formats() -> list[str]:
|
|||||||
formats: dict[str, str] = {
|
formats: dict[str, str] = {
|
||||||
"https://objects.githubusercontent.com/": RELEASE_ASSETS_FORMAT,
|
"https://objects.githubusercontent.com/": RELEASE_ASSETS_FORMAT,
|
||||||
"https://ghproxy.cc/": f"https://ghproxy.cc/{RELEASE_ASSETS_FORMAT}",
|
"https://ghproxy.cc/": f"https://ghproxy.cc/{RELEASE_ASSETS_FORMAT}",
|
||||||
"https://mirror.ghproxy.com/": f"https://mirror.ghproxy.com/{RELEASE_ASSETS_FORMAT}",
|
|
||||||
"https://gh-proxy.com/": f"https://gh-proxy.com/{RELEASE_ASSETS_FORMAT}",
|
"https://gh-proxy.com/": f"https://gh-proxy.com/{RELEASE_ASSETS_FORMAT}",
|
||||||
}
|
}
|
||||||
return await __get_fastest_formats(formats)
|
return await __get_fastest_formats(formats)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user