[gacha]称号系统热
插件质量报告
插件:
gachaHook 功能范围 循环 使用频率 文件读写 修改系统表 读写系统表 读写自己的表 page.before_render 全站页面输出前 否 5 - - - 读 plugin_gacha_inventory, plugin_gacha_titles page.head 全站页面 head 否 5 - - - - reply.after_render 主题查看页/回帖列表逐条渲染 是 5 - - - 读 plugin_gacha_inventory, plugin_gacha_titles 修正❗️ sidebar.feature_links 首页/侧栏快捷功能 否 5 - - - - topic.after_render 首页/版块列表/主题查看逐条渲染 是 5 - - - 读 plugin_gacha_inventory, plugin_gacha_titles 修正❗️ topic.index_data.loaded 首页/版块/用户主题列表查询后 否 5 - - - 读 plugin_gacha_inventory, plugin_gacha_titles topic.replies_data.loaded 主题查看页回帖查询后 否 4 - - - 读 plugin_gacha_inventory, plugin_gacha_titles user.menu_links 个人卡片/移动端我的菜单(展示位置:个人卡片) 否 4 - - - - user.profile_tab_data 用户资料页标签数据 否 3 - - - - user.profile_tab_header 用户资料页标签内容顶部 否 3 - - - 读 plugin_gacha_titles, plugin_gacha_inventory user.profile_tabs 用户资料页标签栏(展示位置:个人主页Tab) 否 3 - - - - 颜色说明:黄色表示有数据读写,红色表示 Hook 在系统循环中执行,浅蓝色表示有文件写入。“列表跳过”表示回调在列表路径会提前返回,“回调内”表示操作位于回调自身或其帮助函数的循环体内。“文件批处理”表示逐个处理用户一次提交的文件,属于必要操作,不标记修正。只有操作实际处于需要优化的循环路径时,才会标记“修正❗️”。
数据字典
plugin_gacha_titles字段 类型 可空 默认值 约束 id id 否 - 主键、自增 name string 否 - - rarity key 否 - - icon string 否 '' - description string 否 '' - weight uint 否 100 - created_at uint 否 - - plugin_gacha_inventory字段 类型 可空 默认值 约束 id id 否 - 主键、自增 user_id uint 否 - - title_id uint 否 - - source key 否 'gacha' - equipped uint 否 0 - expires_at uint 否 0 - created_at uint 否 - - plugin_gacha_log字段 类型 可空 默认值 约束 id id 否 - 主键、自增 user_id uint 否 - - cost uint 否 - - title_id uint 否 - - created_at uint 否 - - plugin_gacha_daily_free字段 类型 可空 默认值 约束 user_id uint 否 - 主键 claim_date key 否 - 主键 created_at uint 否 - - 版本 1.3.0 更新:
留给大家发挥

- bbs1org2026-08-14
- bbs1org2026-08-14
- bbs1org2026-08-14
- bbs1org2026-08-14
- bbs1org2026-08-14
咋开始抽卡了
- bbs1org2026-08-14
版本 1.3.0 更新:
插件市场无法安装的问题 - 1234567892026-08-14
- bbs1org2026-08-14
- 1234567892026-08-14
更新了,错误:2026-08-14 22:30:14 PDOException: SQLSTATE[HY000]: General error: 1 ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint (index.php:167)
- bbs1org2026-08-14
- 1234567892026-08-14
对。自动停用原因
2026-08-14 22:34:13 PDOException: SQLSTATE[HY000]: General error: 1 ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint (index.php:167) - bbs1org2026-08-14
- 1234567892026-08-14
- bbs1org2026-08-14
版本 1.3.7 更新:
- 优化 gacha 称号查询:列表页作者使用一次
ID IN (...)批量查询;主题页主楼和当页回帖作者合并后一次查询,不再逐条查询。 - 回帖同步展示已装备称号,复用本页预加载结果。
- 称号到期通过查询条件实时过滤,无需计划任务。
- 优化管理页称号持有数:由逐称号统计改为一次
GROUP BY查询。 - 增加抽卡日志索引:
title_id, created_at。 - 移除 MySQL 专用
FIELD()排序,改为通用CASE,兼容 SQLite/MySQL。 - 主题看帖页称号调整为用户名下方、与时间并列,左对齐且无边框、无背景;列表页称号同样无边框、无背景、无固定字体颜色。
最后由 bbs1org 编辑于 2026-08-14 22:27 - 优化 gacha 称号查询:列表页作者使用一次
- bbs1org2026-08-14
版本 1.3.9 更新:
移除 gacha 的旧表字段补齐与历史称号到期时间回填;新安装直接按当前表结构建表,旧安装由用户卸载后重新安装 不错不错
- bbs1org2026-08-15
版本 1.5.0 更新:
后台称号池的添加、编辑、删除改为 AJAX 操作。
称号系统设置改为小卡片分组布局。
后台称号池新增“赠送”,可按用户名直接发放称号。
我的称号页新增“赠送”,可将未过期称号转赠给其他用户。
接收方已有同一称号时,有效期自动累加。 - bbs1org2026-08-15
版本 1.5.1 更新:
后台发放和用户转赠成功后,接收方都会收到站内通知,提示获赠称号并引导查看“我的称号” - 1234567892026-08-15
- 1234567892026-08-15
- 1234567892026-08-16
这个是什么情况

- bbs1org2026-08-16
- 1234567892026-08-16
- 1234567892026-08-16
- 1234567892026-08-16
这个有点意思
- 1234567892026-08-16
- 1234567892026-08-16
🔍 插件审查报告(对照《AI 开发规则》与开发者文档)
🔒 安全问题
未发现明显问题(积分透支属经济完整性风险,见功能缺陷)。
⚡ 性能问题
- 红区 DB 读回退:
gacha_after_render同时注册于topic.after_render/reply.after_render(红区,plugin.php:1206-1207),其gacha_equipped_title(136-142)在未命中请求级预加载时执行one()查询。快速回复 AJAX 渲染等路径不触发预加载,会落入 DB 读。建议去掉 DB 回退,或确保所有渲染路径先预加载。
🐛 功能/规范缺陷
- 积分可透支(严重):单抽/十连在事务外预检余额(280/302/334),事务内调用
user_points_change(282/306/338),而该函数无余额下限($new=$old+$delta)。并发抽取可把积分扣成负数;且user.points_changed在提交前触发。建议事务内用UPDATE app_users SET points=points-? WHERE id=? AND points>=?原子扣分,提交后再 fire 事件。 - 缺少唯一约束:
gacha_inventory_receive_title(174-186)按 (user_id,title_id) 先查后插/更新,但plugin_gacha_inventory无 UNIQUE(user_id,title_id),并发抽取会重复入库。建议加唯一索引并改用app_db_upsert()。 - UI 规范:CSS 大量写死字号(9px/10px/48px/28px)与十六进制色、圆角数值(1047-1125 等),应改用
var(--font-size-*)、语义色变量与var(--radius)。
✅ 修复优先级
优先修积分透支 → 补唯一约束 → 消除红区 DB 读回退 → 规范化 CSS。
- 红区 DB 读回退:
咋扔着了 我来优化一版吧 积分消耗挺好的
- bbs1org2026-08-22
- bbs1org2026-08-25
版本 1.5.6 更新:
调整字体大小 - bbs1org2026-08-26
版本 1.5.26 更新:
优化UI细节 - bbs1org2026-08-27
版本 1.5.27 更新:
实现每日免费单抽,并防止重复领取。
重复获得称号时延长有效期。
增加“卸下称号”功能。
空称号池与十连抽错误处理更稳健。
修正个人称号卡片圆角变量。 - bbs1org2026-08-27
版本 1.5.27 更新:
优化ui细节 🔍 插件审查报告(AI 自动审查,对照《AI 开发规则》与开发者文档;本插件未被 8/18 楼上 350 的报告覆盖,属独立首次审查)
插件:称号系统(gacha)v1.5.27
结论:已完成命名规范、生命周期(install/uninstall 幂等)、数据库跨库兼容、红区 Hook 零 DB 读、Hook 真实性(含核心与跨插件依赖核对)、SQL 注入风险、CSRF/权限校验、CSS 变量规范等项审查,未发现安全、性能或功能性问题。
- bbs1org2026-08-31
版本 1.5.28 更新:
- 消灭每作者 one()(违规源头)
- gacha_equipped_title($uid) 从「每作者发起 one() 查库」改为纯内存读取预载映射 $GLOBALS['__gacha_equipped_titles'],渲染链里不再有任何逐行查询。
- 渲染钩子 gacha_after_render 重写为「三级无 N+1」
- 已随 .loaded 预载(topic.index_data.loaded / topic.replies_data.loaded 早已做整页一条 IN 批量取回)→ 直接读内存渲染,零查询(这是主流路径,行为不变)。
- 未预载且为 AJAX 局部片段(绕过整页钩子)→ 允许就地单次小批量 preload_equipped_titles([$uid]),不遗留占位符。
- 未预载且为整页 → 插入唯一占位符 <!--gacha-{token}-{kind}-{uid}-->(random_bytes(6) 12 位随机 hex),零 DB 读。
- 新钩子 page.before_render => gacha_on_before_render
- 收集本次 defer 的 uid 去重 → 一条 IN (...) 批量取回 → preg_replace_callback 整页一次性回填:列表位回填称号图标、详情页 post-meta 位回填徽章;无称号替换为空串就地消失。
- 新增辅助函数:gacha_batch_token() / gacha_placeholder_mark() / gacha_defer_render_html() / gacha_on_before_render(),并注册 page.before_render 钩子、版本号递增。
效果
- 主题页 N 个回帖:从「每帖作者一次 one()(N 次)」→ 主流为 topic.replies_data.loaded 整页 1 条 IN;极短兜底路径也被占位符收敛为整页 1 条 IN。渲染循环彻底零逐行 DB 读。
- 残留的 one()(现只剩 9 处)都在安装/抽奖/赠送/路由等非渲染上下文,不违反规则。
- bbs1org2026-09-21
版本 1.5.30 更新:
post-meta 徽章样式自定义(追加 CSS) - bbs1org6天前
版本 1.5.32 更新:
优化布局
