Files
DanDingNoneBot/danding_bot/plugins/danding_points/README.md
Mr.Xia 0fd011fa1e 功能:实现 Danding_Points 积分系统插件
- 新增积分系统插件,支持积分查询、签到、转账等核心功能
- 包含对应的测试脚本

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 00:24:00 +08:00

6.0 KiB
Raw Permalink Blame History

Danding Points 插件

全局积分/虚拟货币服务层,为其他插件提供统一的积分管理能力。用户在一个插件中获得的积分可以在另一个插件中消费。

本插件不包含任何用户交互命令(无 NoneBot matcher纯 API 服务层,供其他插件直接 import 调用。

目录结构

danding_points/
├── __init__.py     # 插件元数据 & points_api 单例导出
├── config.py       # 配置类
├── database.py     # SQLite 数据库操作
└── api.py          # PointsAPI 核心

配置选项

.env 文件或 NoneBot 配置文件中添加(均带 DANDING_ 前缀):

配置项 类型 默认值 说明
DANDING_POINTS_DB_FILE str data/danding_points/points.db 数据库文件路径
DANDING_POINTS_MAX_BALANCE int 0 用户积分余额上限,0 = 无限制
DANDING_POINTS_MAX_PER_OPERATION int 0 单次操作积分上限,0 = 无限制
DANDING_POINTS_LOG_RETENTION_DAYS int 365 流水日志保留天数

API 接口

所有方法均为 async,通过 points_api 单例调用。

get_balance(user_id: str) -> int

查询用户积分余额。用户不存在时自动返回 0,不会创建账户。

balance = await points_api.get_balance("123456")

add_points(user_id, amount, source, reason=None) -> Tuple[bool, int]

为用户增加积分。用户不存在时自动建户。

  • amount: 正整数,必须 > 0
  • source: 来源标识,不能为空(用于流水追踪)
  • reason: 变动原因,可选
  • 返回 (success, new_balance),失败时 success=False

触发校验:操作上限 → 余额上限。任一校验失败均返回 (False, 当前余额)

ok, balance = await points_api.add_points("123456", 100, "gacha", "抽卡奖励")
if ok:
    print(f"充值成功,当前余额: {balance}")

spend_points(user_id, amount, source, reason=None) -> Tuple[bool, int]

消费用户积分。余额不足时返回 (False, 当前余额)

  • amount: 正整数,必须 > 0
  • 流水中 amount 记录为负数
ok, balance = await points_api.spend_points("123456", 30, "shop", "购买道具")
if not ok:
    print("余额不足")

set_points(user_id, amount, source, reason=None) -> Tuple[bool, int]

直接设定用户积分。绕过 操作上限和余额上限约束。

  • amount: 非负整数,必须 >= 0
  • 新值等于旧值时不写流水,直接返回 (True, amount)
  • total_earned 仅累加正向差额(设低不影响)
ok, balance = await points_api.set_points("123456", 500, "admin", "管理员调整")

get_transactions(user_id, limit=20, offset=0) -> List[dict]

查询用户积分流水记录,按时间倒序。

  • limit: 1~100超出范围自动裁剪
  • offset: 分页偏移量,>= 0

返回字段:id, user_id, amount, balance_after, source, reason, created_at

txs = await points_api.get_transactions("123456", limit=10, offset=0)
for tx in txs:
    print(f"{tx['created_at']}  {tx['amount']:+d}  余额:{tx['balance_after']}")

get_ranking(limit=10, order_by="points") -> List[dict]

查询积分排行榜。

  • limit: 1~100
  • order_by: "points"(按余额)或 "total_earned"(按累计获得),其他值回退为 "points"
  • 使用 RANK() 窗口函数,同分并列,次级排序按 user_id 字母序

返回字段:rank, user_id, points, total_earned, total_spent

ranking = await points_api.get_ranking(limit=10, order_by="points")
for r in ranking:
    print(f"#{r['rank']}  {r['user_id']}  {r['points']}分")

其他插件对接

基本用法

在需要积分功能的插件中 import 单例即可:

from nonebot import require

require("danding_points")
from danding_bot.plugins.danding_points import points_api

示例:抽卡插件发放奖励

# 在 onmyoji_gacha 插件中
from danding_bot.plugins.danding_points import points_api

async def reward_user(user_id: str):
    ok, balance = await points_api.add_points(
        user_id, 50, "onmyoji_gacha", "SSR 抽到奖励"
    )
    return balance

示例:商店插件消费积分

# 在 shop 插件中
from danding_bot.plugins.danding_points import points_api

async def buy_item(user_id: str, cost: int):
    ok, balance = await points_api.spend_points(
        user_id, cost, "shop", "购买商品"
    )
    if not ok:
        return "积分不足"
    return f"购买成功,剩余 {balance} 积分"

示例:管理员插件调整积分

# 在 danding_api 插件中
from danding_bot.plugins.danding_points import points_api

async def admin_set(user_id: str, amount: int):
    ok, balance = await points_api.set_points(
        user_id, amount, "danding_api", "管理员手动调整"
    )
    return balance

source 命名建议

source 参数用于标识积分变动来源,建议各插件使用自身插件名作为 source

插件 source 值
onmyoji_gacha "onmyoji_gacha"
danding_api "danding_api"
shop "shop"
sign_in "sign_in"

数据库

使用 SQLite数据文件位于 data/danding_points/points.db,无需额外配置。

表结构

user_points — 用户积分账户

字段 类型 说明
user_id TEXT PK 用户 ID
points INTEGER 当前余额,>= 0
total_earned INTEGER 累计获得
total_spent INTEGER 累计消费
created_at TEXT 创建时间
updated_at TEXT 最后更新时间

point_transactions — 积分变动流水

字段 类型 说明
id INTEGER PK 自增 ID
user_id TEXT 用户 ID
amount INTEGER 变动数额(消费为负)
balance_after INTEGER 变动后余额
source TEXT 来源标识
reason TEXT 变动原因
created_at TEXT 创建时间