[开发]猜题对决(quiz_duel)插件说明

👑Lv.11 元老 🌞 骨干会员
2026-10-25 01:13:02

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:WWW/update/30/plugins/quiz_duel/说明.md。

猜题对决(quiz_duel)插件说明

版本:1.0.0 | 作者:SoSite | 状态:⛔ 未启用

功能:一对一猜题对赌——出题人设题并押注,应战人猜出题人的答案,猜中者赢家通吃(拿走双倍注额)。


一、功能简介

  • 出题(挑战):填写问题、选项 A / B、自己的答案,并押注一笔积分 → 生成一条 open 状态的挑战
  • 应战:他人选择 A 或 B 并押上同等注额 → 立即结算
  • 应战人选的答案 == 出题人设的答案 → 应战人赢
  • 否则 → 出题人赢
  • 赢家通吃:赢家获得 stake × 2(双方的注额之和)
  • 三个页面:等待应战列表(/duel)、创建挑战(/duel/create)、我的对决(/duel/my)、对决详情(/duel/detail/{id})
  • 侧栏:/duel 页面右栏输出「导航 + 赢家榜 + 最近对决」三块面板(桌面走钩子,移动端走视图内兜底)
  • 前端交互:htmx 局部刷新(成功响应携带 data-redirect 时延迟跳转),零内联 JS

二、目录结构

plugins/quiz_duel/
├── plugin.json                      # 插件清单(4 个钩子;无 admin_url / permissions)
├── Plugin.php                       # 主类:建表、赢家榜、最近历史、今日应战数、总盈亏、生命周期
├── QuizDuelController.php           # 前台:列表 / 创建 / 我的 / 详情 / 应战结算
├── hook/
│   ├── init_after.php               # 幂等建表兜底(缓存标记 protected/.quiz_duel_table_cache)
│   ├── route_register.php           # 前台路由注册
│   ├── nav_plugin_links.php         # 应用下拉菜单入口
│   └── right_sidebar_after.php      # 右栏「导航 / 赢家榜 / 最近对决」(仅 /duel 前缀页面输出)
├── views/
│   ├── index.php                    # 等待应战列表
│   ├── create.php                   # 创建挑战
│   ├── detail.php                   # 详情 / 应战
│   └── my.php                       # 我的对决
├── assets/                          # style.css / script.js(零内联)
├── data/                            # quiz_duel.sqlite(独立库)+ .htaccess / web.config
└── lang/                            # zh.php / en.php / zh_tw.php(各 64 键,三语零差异)

三、数据表

插件独立库:plugins/quiz_duel/data/quiz_duel.sqlite

表用途
quiz_duels对决记录(creator_id / opponent_id / question / option_a / option_b / creator_choice / opponent_choice / stake / status / winner_id / created_at / accepted_at / completed_at)

  • 索引:idx_quiz_duels_status、idx_quiz_duels_creator、idx_quiz_duels_opponent
  • status 状态机:open(等待应战)→ completed(已结算)
  • 建表:activate() + init_after 双保险;卸载:uninstall() 删表

四、路由

方法路径说明
GET/duel等待应战的挑战列表(需登录)
GET/duel/create创建挑战页(需登录)
POST/duel/create提交挑战(需登录 + CSRF)
GET/duel/my我的对决(需登录)
GET/duel/detail/{id}对决详情(需登录)
POST/duel/accept应战并结算(需登录 + CSRF)

本插件无后台页,故 plugin.json 不声明 admin_url 与 permissions(二者均为可选字段)。

五、核心规则

创建挑战的字段校验(store())

字段规则
question长度 4 ~ 200 字
option_a / option_b长度 1 ~ 50 字
creator_choice必须是 A 或 B
stakeduel_bet_min ~ duel_bet_max

校验通过 → Points::deduct() 扣押注 → 写 quiz_duels(status = 'open')。

写库失败自动退款(Points::award,理由「猜题对决退款」)。

应战结算(accept())

① 校验 choice ∈ {A, B}
② 取对决记录,必须存在且 status = 'open'(否则「已关闭」)
③ 不能应战自己的挑战
④ 扣应战人积分(Points::deduct,理由「猜题对决押注」)
⑤ 判定:opponent_choice == creator_choice → 应战人赢,否则出题人赢
⑥ 更新记录(opponent_id / opponent_choice / status='completed' / winner_id / accepted_at / completed_at)
⑦ 发奖:Points::award(winnerId, stake * 2)

  • 结算与发奖在同一个 try 块内:任一步抛异常 → 退还应战人积分(理由「猜题对决退款」)并返回错误
  • Points::award() 外层再套一层 try/catch:封装内异常降级为日志,不阻断「已结算、即将返回 JSON」的响应

配置项(核心 settings 表,惰性默认)

键默认说明
duel_bet_min10最低押注额
duel_bet_max500最高押注额

统计接口(Plugin.php)

方法说明
getLeaderboard($limit)赢家榜(按 SUM(stake) 降序,仅 completed)
getRecentHistory($limit)最近对决(按 completed_at 降序)
getTodayJoinCount($userId)今日应战次数(status IN ('accepted','completed'))
getUserProfit($userId)用户总盈亏 = 赢得的 SUM(stake*2) − 输掉的 SUM(stake)

跨库无法 JOIN:用户名 / 头像经 User::batchGetUsers() / User::batchGetNames() 从核心库批量补全。

六、注意事项

  • ⚠️ 需要登录才能查看与参与,游客访问会被 requireLogin() 重定向
  • ⚠️ 依赖核心积分体系:Points::deduct() / Points::award()
  • ⚠️ 只有 status = 'open' 的挑战可被应战,已结算的挑战再次应战返回「已关闭」;不能应战自己的挑战
  • ⚠️ 一次应战即终局:没有「出题人反悔」「超时作废」机制——open 状态的挑战会一直挂着,直到有人应战
  • ⚠️ 出题人与应战人各扣一次注额,赢家拿 stake × 2,平台不抽成(零和)
  • ⚠️ 本插件目录名含下划线,核心 Plugin::activate/deactivate/uninstall() 的类名推导

("\\Plugin\\{$name}\\Plugin")会拼出 \Plugin\quiz_duel\Plugin 而无法命中 \Plugin\QuizDuel\Plugin

→ 已在 Plugin.php 末尾用 class_alias 补别名(否则卸载时数据表不会被删除)

  • 当前状态:quiz_duels 1 行;插件未启用(activated: false)
轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 瀏覽 5 次 | 回覆 0 次

全部回覆 (0)

暫無回覆

請 登入