按照用户提示,增加了提示,需要在app/Views/thread/show.php加个钩子,所以这个文件也需要覆盖一下。
楼主设置一个积分奖池,用户在该主题回帖即自动获得固定积分,池子发完即止,过期余数退还。
玩法
- 楼主:发帖时勾选「设置回帖奖励」,填「奖池总积分 X」+「每次回帖奖励 N 分」+ 有效期 + 每人限领次数。
- 表单会实时提示「共发放几层、最后一层得多少」(如 100 分 / 每层 3 分 → 34 层,最后一层 1 分)
- 提交后从楼主账户一次性预扣 X 分存进奖池
- 其他用户:在该主题回帖成功 → 自动到账 N 分(无需点击领取)
- 结束:池子发完自动关闭;到期未发完的余数自动退还楼主;楼主也可手动关闭退余
与「积分红包」(red_packet)的区别
| 积分红包 | 回帖奖励(本插件) | |
|---|---|---|
| 核心动作 | 用户点「抢红包」 | 用户回帖即自动到账 |
| 金额 | 随机(二倍均值法) | 固定每层 N 分 |
| 上限 | 按份数 | 按总积分 |
| 关系 | 完全独立,不共享表、不互相调用 | 同左 |
两者都会在帖子详情页渲染卡片(同一 thread_redpacket_area 锚点)。同一主题同时挂两种会显示两张卡片,插件间不做互斥,由运营自行选择。
数据表(独立库 data/reply_reward.sqlite)
| 表 | 用途 |
|---|---|
rr_pools |
奖池主表:总积分 / 每层分 / 限领次数 / 余额 / 状态 / 到期时间 |
rr_claims |
领取计数:UNIQUE(pool_id, user_id) 累加行 + state 两阶段标记 |
rr_settings |
全局配置键值表 |
关键实现说明
发奖时机
挂在 post_create_after(核心 ThreadController.php:175)。
⚠️ 该钩子在回帖事务之外触发(帖子行已 commit)。实测依据见 docs/插件开发规范.md §9.1 的说明块。
⚠️ 钩子的异常会被核心 ThreadController.php:194 的 catch (\Throwable) 吃掉并记日志 → 表现为「回帖成功但没发奖」。因此插件内部自行 try/catch,不让异常逃逸。
跨库一致性:两阶段 + 补偿
插件库与核心库是两个 PDO 连接,SQLite 无法跨库事务。发放流程:
① 原子扣池 UPDATE rr_pools SET remaining = remaining - :got
WHERE id = ? AND status = 0 AND remaining >= :got → rowCount 校验
② 写领取记录 INSERT/UPSERT rr_claims (state = 0 pending, cnt + 1)
③ Points::award(用户, got, ...) ← 核心库,独立写入
④ 置 state = 1 (done)
若 ③ 失败或进程崩溃 → rr_claims 停在 state=0 → route_after_dispatch 里的 compensate() 扫描 5 分钟前仍是 pending 的记录补发。
防超领三层
| 层 | 机制 |
|---|---|
| 池子变负 | UPDATE ... WHERE remaining >= :got + rowCount() |
| 同一用户超领 | UNIQUE(pool_id, user_id) + cnt < K 判定(UPSERT 累加) |
| 跨库丢/超发 | state 列 + 补偿扫描 |
维护任务
route_after_dispatch(index.php:321,响应已产出后触发),session 门控 60 秒:
refundExpired()—— 过期退余(单条失败只记日志并跳过,不整批回滚)compensate()—— 补发 pending 记录
⚠️ 故意不挂 init_after:那是每请求路径,全表扫描 + 退款会拖慢首字节。
目录名含下划线的坑
本插件目录名 reply_reward 含下划线,而核心 app/Helpers/Plugin.php:699/750/846 用目录名硬拼类名 \Plugin\{目录名}\Plugin → class_exists 恒为 false → activate/deactivate/uninstall 静默跳过(不报错、后台还提示成功),典型症状是卸载后表残留。
因此 Plugin.php 末尾必须保留:
\class_alias(Plugin::class, 'Plugin\reply_reward\Plugin', false);
删掉这行会导致卸载不干净。
后台
入口:后台 → 插件 → 回帖奖励(/admin/reply-reward),或在帖子的奖池卡片上点「去后台设置」。
- 全局配置:总开关、是否允许所有用户挂池、默认有效期 / 限领次数、每日挂池上限、数额上下限
- 奖池列表:状态筛选、进度、手动「关闭并退余」
语言包
zh / en / zh_tw 三包,各 81 键,键集合零差异、键序一致。
配置项一览
| 键 | 默认 | 说明 |
|---|---|---|
enabled |
1 |
总开关 |
allow_all_users |
1 |
0 = 仅管理员可挂池 |
default_expire_days |
7 |
默认有效期(天) |
default_per_user_limit |
1 |
默认每人限领次数 |
daily_pool_limit |
3 |
每人每日挂池上限,0 = 不限 |
min_total_points / max_total_points |
10 / 100000 |
单池总积分上下限 |
min_per_reward / max_per_reward |
1 / 1000 |
每次奖励上下限 |