XIUNOX 更新记录贴 202600716

管理

  • [逻辑错误] 修复后台帖子列表「移动」操作无版块选择弹窗

    • 原设计用内联 <select> 下拉框(d-none 切换),点击「移动」按钮同时触发 doBatch toast 提示与 toggleClass 显示下拉框,用户感知为「提示选版块但无弹窗可选」

    • 改为 Bootstrap Modal 弹窗:点击「移动」打开 modal 选择目标版块,modal 内「确认」直接提交(跳过 XN.confirm 二次确认,避免双重确认啰嗦)

    • 必测: admin/?thread-list.htm(勾选帖子→点移动→弹窗选版块→确认→帖子移动成功)

    • 回归: admin/?thread-list.htm(未勾选帖子点移动 toast 提示;弹窗内未选版块点确认 toast 提示;其他批量操作 close/open/delete/top/digest/announcement 正常走 XN.confirm)

  • [逻辑错误] 限制在线升级「检查更新」24 小时仅允许一次(前端 localStorage + 后端 cache 双层)

    • 改动: admin/route/online_upgrade.php(check action 加 cache_get/set,cleanup 步骤清缓存)

    • 改动: admin/view/htm/online_upgrade.htm(checkUpdate 前置拦截 + 弹窗 Modal + disable 按钮,refreshCheckBtnState 统一状态)

    • 改动: lang/{zh-cn,zh-tw,en-us}/bbs_admin.php 新增 7 个语言键

    • 必测: admin/?online_upgrade.htm 首次检查→disable+提醒;24h 内重复点击→弹窗+不发请求;升级完成→清缓存恢复按钮

    • 回归: admin/?index.htm 仪表盘自动检查不受影响

  • [配置不同步] 插件启用/安装状态从 conf.json 双写改为 db 单一权威

    • 改动: model/plugin.func.php

      • plugin_init(): 批量读 bbs_plugin 表覆盖 $plugins[dir] 的 enable/installed;db 无记录的老插件自动平移 conf.json 状态到 db

      • plugin_paths_enabled(): 编译入口改读 db enable/installed;db 异常时回退 conf.json 兜底

      • 删除 plugin_enable/disable/install/unstall 4 处 file_replace_var,conf.json 不再被运行时改写

    • 效果: conf.json 回归纯声明文件(git 跟踪不再被污染);多实例状态一致;双源漂移消除

    • 兜底: db 不可用时 try/catch 回退 conf.json,避免白屏

    • 必测: admin/?plugin-local.htm 列表状态正确;启用/禁用/安装/卸载后状态正确且 conf.json 不变;插件 hook 正常内联(清 tmp 后首次访问触发重编译)

    • 回归: 前台插件功能正常;install 阶段 db 表不存在时 plugin_paths_enabled 走兜底

    • 修复: plugin_db_get_all() 用了不存在的 db−>findall()方法(db类只有find),导致try/catch吞掉Error异常返回空数组,所有插件走else平移分支用conf.json旧值覆盖db,状态永远不变。改用db->find(..., 1000000, "dir") 修复

    • 根因: 该函数此前只在 plugin_db_init_all 升级场景调用,从未被真正触发,bug 一直潜伏;本次改造将其用于 plugin_init 关键路径后暴露

  • [功能完善] 后台导航设置左侧导航 Tab 新增总开关 sidebar_nav_enable(与 mobile_nav_enable 对称)

    • 默认开启(1),未配置视为 1 保持向前兼容;关闭(0)后前台 sidebar_left.inc.htm 整个左侧栏(含 .sidebar-left 卡片容器)不输出

    • 改动文件: admin/route/setting.php(GET/POST/message 返回)、admin/view/htm/setting_nav.htm(form-switch + JS 回填)、view/htm/sidebar_left.inc.htm(if 包裹)、conf/conf.default.php、lang/{zh-cn,zh-tw,en-us}/bbs_admin.php

    • 必测: admin/?setting-nav.htm#sideNav 开关切换 + 保存 + 前台首页/版块页验证

    • 回归: 前台首页左侧栏默认仍显示;关闭后主区可占满宽度

    • 缓存: 已清 tmp/admin_route_setting.php、tmp/admin_view_htm_setting_nav.htm、tmp/view_htm_sidebar_left.inc.htm、tmp/lang_bbs.php、tmp/lang_bbs_admin.php

  • [功能完善] xnx_moments_theme 主题优化:dock 菜单用后台 nav_items + 首页/版块页帖子列表改新卡片布局

    • 需求1: 左侧 dock 菜单上方使用后台顶部导航设置的数据($conf['nav_items']),搜索和消息按钮放菜单后边

      • 改动: overwrite/view/htm/header.inc.htm 的 dock-nav 区域改为遍历 $conf['nav_items'](按 rank+type 排序),搜索/消息按钮固定放末尾

    • 需求2: 首页和版块页帖子列表改为左头像+右内容(用户名/等级+分类标题+简介+原文链接+时间评论点赞)

      • 新增: hook/thread_list_inc_start.htm(拦截 index/forum 路由,批量查首楼正文+图片附件避免 N+1,预处理摘要/首图/版主权限后 include 新模板并 return 终止原模板渲染)

      • 新增: view/htm/thread_list_moments.inc.htm(新卡片布局:左头像 avatar_component_from_data + 右内容用户名着色/用户组badge/分类badge/标题/摘要2行省略/首图缩略80px+数量角标/原文链接/时间评论点赞浏览)

      • 改动: conf.json hooks_rank 新增 thread_list_inc_start.htm:100

      • 改动: static/css/moments.css 追加新卡片样式(列表项hover/摘要省略/缩略图/角标/原文链接/移动端适配)

      • 改动: setting.php + install.php 默认配置新增 excerpt_len=120/show_image_thumb=1,POST 保存逻辑同步

      • 改动: view/htm/setting.htm 新增「列表样式」区块(摘要字数输入+首图缩略开关)

      • 改动: hook/lang_{zh_cn,zh_tw,en_us}_bbs.php 新增 4 个语言键(moments_view_original/excerpt_len/show_image_thumb/settings_list)

    • 技术决策: 仅覆盖 index+forum 路由(用 hook 拦截路由判断,user_thread/search 等页面仍用原版);批量查询 1 次 SQL 拿所有 firstpid 的 post + 1 次 SQL 拿所有 tid 的图片附件;用 attach__find 而非 attach_find 仅对首图手动 attach_format(性能优化)

    • 必测: 前台首页帖子列表新卡片布局(头像/用户名/等级/分类/标题/摘要/首图/原文链接/时间评论点赞);forum/13 版块页同样新布局;dock 菜单显示后台导航项+搜索+消息

    • 回归: user_thread/my_thread/search 等页面仍用原版 thread_list.inc.htm;后台插件设置页新增「列表样式」区块可配置摘要字数和首图开关

    • 缓存: 已清 tmp/view_htm_thread_list.inc.htm、tmp/view_htm_header.inc.htm、tmp/view_htm_index.htm、tmp/view_htm_forum.htm、tmp/view_htm_forum_index.htm、tmp/view_htm_layout_three_column.inc.htm、tmp/plugin_xnx_moments_theme_view_htm_thread_list_moments.inc.htm、tmp/lang_zh-cn_bbs.php

  • [功能增强] xnx_ad_selfbuy 广告位插件补充购买入口

    • 新增广告位购买大厅页(adselfbuy-list.htm),列出所有广告位+占用状态+价格表,作为统一购买入口

    • route/ad.php 默认 action 从 my 改为 list,访问 adselfbuy.htm 直接进大厅页

    • ad_my.htm 空状态加"去购买广告位"引导按钮,指向大厅页

    • 新增 forum_threadlist_after.htm hook,移动端版块帖子列表下方显示广告位区块(d-xl-none 仅移动端可见)

    • 三语言包补充 8 个新键(去购买/立即购买/登录后购买/已占用/可购买/价格表/暂无可用广告位等)

    • conf.json version 1.1.0 -> 1.2.0,注册新 hook forum_threadlist_after.htm

    • 必测: adselfbuy-list.htm(大厅页)、adselfbuy.htm(默认跳大厅)、adselfbuy-my.htm(空状态引导)

    • 必测: 移动端访问 forum 页帖子列表下方应有广告位区块

    • 回归: forum_mod_after.htm / index_site_brief_after.htm / thread_user_after.htm 侧栏广告位不受影响

  • [GET表单路由丢失] 修复 install 默认导航项 URL 为 ?xxx.htm 查询格式(原 url=index/forum-1 渲染为相对路径导致链接失效)

    • 顶部导航: 首页(?index.htm) + 版块(?forums.htm) + 排行(?rank.htm)

    • 左侧导航: 默认版块(?forum-1.htm),移除原首页项

    • 新增 rank_page 语言键(zh-cn/zh-tw/en-us)

    • 必测: 重新安装后前台顶部/左侧导航链接可正常跳转

    • 回归: admin/?setting-nav.htm 导航项展示

  • [变量冲突] 修复 ad_list.htm 大厅页 $settings 被 header.inc.htm 中 xnx_hidden 插件 hook 覆盖导致 Undefined array key price_day

    • 根因: header.inc.htm 编译缓存第106行有 xnx_hidden 插件注入的 $settings = HiddenService::getSettings(),覆盖了 route/ad.php 中设置的 $settings

    • 修复: route/ad.php 和 ad_list.htm 中 $settings 变量名改为 $ad_settings,避免与其他插件冲突

    • 必测: adselfbuy-list.htm 大厅页价格表正常显示

    • 必测: adselfbuy.htm 默认跳大厅页无报错

  • [HTMX事件冲突] 修复发帖页抽奖校验失败后按钮卡在"正在提交..."无法再次提交

    • 根因: post.htm submit 捕获阶段立即禁用按钮,抽奖 htmx:confirm 校验失败时 dropRequest 阻止请求,htmx:after:request 不触发导致 resetPostSubmit 永不执行

    • 修复: post.htm 新增 htmx:confirm 监听器,setTimeout(0) 检查 defaultPrevented,被阻止则恢复按钮(核心层修复,所有插件受益)

    • 必测: 发帖页启用抽奖填中奖人数=1(低于下限)发帖→提示后按钮应恢复可点击;改正确人数后能正常发帖

    • 回归: 发帖页不开抽奖正常发帖;抽奖扣费确认弹窗取消后按钮恢复;确认后正常提交

  • [HTMX事件冲突] 修复抽奖扣费确认弹窗未点确认请求已发出

    • 根因: post.htm 第735行积分确认 htmx:confirm 与抽奖 htmx:confirm 冲突,confirmCreditsDeduct 无扣减时直接 issueRequest 放行,不等待抽奖 XN.confirm 异步确认

    • 修复: 抽奖改为 dropRequest 彻底放弃当前请求 + 用户确认后设 lotteryConfirmed=true + htmx.trigger(form,submit) 重新提交;post.htm setTimeout(0) 加 window._htmxConfirmAsync 排除异步确认场景

    • 必测: 发帖页启用抽奖选积分奖品→发帖→弹扣费确认→不点确认时请求不应发出;点确认后正常提交;点取消按钮恢复

    • 回归: 校验失败(中奖人数<min)按钮恢复可再次提交;不开抽奖正常发帖;抽奖+发帖积分双重确认场景

  • [逻辑错误] 修复楼中楼回复图片点击无反应(容器缺 .message class 导致 lightbox 选择器不匹配)

    • 必测: 帖子详情页楼中楼回复中的图片点击应弹出灯箱

    • 回归: 主帖/一级评论图片点击仍正常;快速回复后新评论图片也能点击

  • [逻辑错误] 修复 ad_list.htm 大厅页触发 http_404 导致 headers already sent 错误

    • 根因: route/ad.php 中 list 块是独立 if,第56行 if($action==buy) 开启新的 if-elseif-else 链,当 action=list 时走到 else http_404(),此时 header 已发送,http_response_code 失败

    • 修复: list 块末尾加 return,避免继续执行后续 if-elseif-else 链

    • 必测: adselfbuy-list.htm 和 adselfbuy.htm 不再报 headers already sent

  • [逻辑错误] 修复点击回复评论A后再点高级回复,提交后变成一级评论(高级回复按钮跳转未携带 quotepid)

    • 必测: 帖子详情页点评论A的回复 → 点高级回复 → 提交后应在评论A下显示为楼中楼

    • 回归: 直接点高级回复(未选评论)仍为一级评论;关闭引用条后再点高级回复为一级评论

  • [逻辑错误] 修复 xnx_ad_selfbuy 初始化广告位始终为 0 的问题

    • 根因: bbs_xnx_ad_selfbuy_slot 表不存在(历史卸载/重装未正确执行 install.php),initDefaultSlots 检测表不存在时 include install.php 建表+插数据,但随后再次 db_count 得到 9 返回 ok=false 提示"广告位标识已存在",对用户误导

    • 修复: initDefaultSlots 在 include install.php 后,若已有数据则直接返回 ok=true 成功提示,不再走"已存在"分支

    • 已手动为数据库补建 bbs_xnx_ad_selfbuy_slot 表并插入 9 条默认广告位数据

    • 必测: admin/?plugin-setting-xnx_ad_selfbuy.htm&tab=slots 刷新应看到 9 条广告位

    • 必测: 前台 adselfbuy-list.htm 大厅页应显示广告位卡片

  • [逻辑错误] 修复搜索频率限制误拦纯访问搜索页:kv_set 计时点在 keyword_safe 判断之前,导致无关键词访问 search.htm 也被计时,随后真实搜索被误拦

    • 必测: search.htm 无关键词访问后再立即搜索关键词

    • 必测: 搜索结果翻第二页(page=2)不被拦截

    • 回归: 间隔内重复搜索关键词仍被正确拦截

  • [配置不同步] 修复 xnx_ad_selfbuy install.php 三个潜在问题

    • setting_set 改为幂等:仅在配置不存在时写入默认值,避免重装或 initDefaultSlots include 时覆盖用户已配置的价格/审核等设置

    • 末尾新增清理 model.min.php 合并缓存(符合 project_memory 硬约束:生产环境走合并加载,旧缓存不含 Service 类)

    • global 声明补充 $conf(用于读取 tmp_path)

    • 建表 SQL 本身正确(slot 和 order 两张表字段与数据库实际结构一致),未改动

    • 必测: 卸载后重装,install.php 应正确建表+插数据+写配置,且不覆盖已有配置

  • [变量覆盖] 全局修复 xnx_ad_selfbuy 中 $settings 被 xnx_hidden 插件 hook 覆盖的问题(遗漏的 buy/edit 页面)

    • 根因: 上一轮只修复了 ad_list.htm,遗漏了 ad_buy.htm 和 ad_edit.htm(route/ad.php 的 buy/edit action 中 $settings 同样被 header.inc.htm 第106行 xnx_hidden 注入的 $settings = HiddenService::getSettings() 覆盖)

    • 修复范围: route/ad.php(3处 $settings→$ad_settings)、view/htm/ad_buy.htm(11处)、view/htm/ad_edit.htm(8处)

    • 防御性修复: admin/route/ad_selfbuy.php 和 admin/view/htm/ad_selfbuy.htm 中的 $settings 统一改为 $ad_settings(虽然 admin header 无 xnx_hidden hook,但避免未来其他插件注入冲突)

    • 必测: adselfbuy-buy-{slot_id}.htm 购买页价格表和 data 属性正常

    • 必测: adselfbuy-edit-{order_id}.htm 编辑/续费页价格表正常

    • 必测: admin/?plugin-setting-xnx_ad_selfbuy.htm&tab=rules 后台规则配置页正常

  • [类型误用] 修复 xnx_appcenter 详情页"添加新版本"下载包上传成功却提示失败

    • 根因:appcenter_detail.js L91 用 res.code === 0(数字严格相等),但后端 message() 返回的 code 是字符串 "0"(misc.func.php L285 $arr[code] = $code.''),导致 0 === "0" 永远为 false,走入失败分支

    • 修复:改为 String(res.code) === '0',与 appcenter_publish.js L212、appcenter_desc_editor.js L59 判断方式统一

    • 必测: ?appcenter-{app_id} 详情页"添加新版本"上传 zip 下载包

    • 回归: ?appcenter-publish 发布页上传图标/截图/下载包(已用 String() 不受影响)

    • 同类检查: 已 grep 验证 appcenter_desc_editor.js、appcenter_publish.js 均用 String(res.code) === '0',无同类 bug

  • [逻辑错误] 修复找回密码第 3 步 resetpw_complete 绕过后台密码策略校验(security_password_min_length / security_password_complexity 未生效)

    • 必测: 找回密码走完整流程到第 3 步,输入弱密码应被拦截

    • 回归: 正常改密流程不受影响

    • 根因: resetpw 第 1 步和 my/password 均调用 SecurityConfigService::checkPasswordPolicy,但 resetpw_complete 只调用旧版 is_password,与后台 security-account.htm 配置脱钩

xnx_feeds 动态 Feed 插件修复(审核通过才显示 + 评论动态 + 弹出间隔)

  • [审核泄露] 修复 thread_new 在帖子待审状态(audit_status=0)时就写入 feed 的问题

    • 修改: plugin/xnx_feeds/hook/thread_create_thread_end.php 加 audit_status 检查

    • 必测: 开启发帖审核的版块发帖,feed 不应立即显示,审核通过后才显示

  • [功能增强] 新增 post_new 评论动态类型,展示用户回帖行为

    • 新增: plugin/xnx_feeds/hook/model_post_create_end.php(跳过首帖,检查 audit_status)

    • 必测: 审核通过的评论出现在 feed,点击跳转到帖子对应评论锚点 #pid-xxx

  • [审核不同步] 新增 audit_approve_end hook,审核通过后补写 thread_new/post_new feed

    • 修改: lib/security/AuditService.php approve() 末尾用 plugin_hook() 运行时分发

    • 新增: plugin/xnx_feeds/hook/audit_approve_end.php(thread 补写 thread_new,post 补写 post_new)

    • 必测: 待审帖子/评论审核通过后立即出现在 feed

  • [配置不同步] 新增 pop_interval 弹出间隔后台可配置,避免一打开页面弹一堆

    • 修改: FeedsService/setting.php/setting.htm/footer_js_after.htm 加 pop_interval 配置

    • 必测: 后台设置弹出间隔为 0/1500/3000,前端 toast 按间隔依次弹出

  • [语言包不同步] 三种语言包同步新增 post_new 和 pop_interval 相关键

    • 必测: 后台设置页 zh-cn/zh-tw/en-us 显示正确标签

  • 版本递增: conf.json 1.1.0 → 1.2.0

  • 清理编译缓存: route_thread/model_post.func/view_htm_footer.inc/lang_zh-cn_bbs/FeedsService

xnx_feeds 动态 Feed 插件增强(用户组升级动态)

  • [功能增强] 新增 user_levelup 用户组升级动态类型

    • 新增: plugin/xnx_feeds/hook/model_user_update_group_success.php(升级 return TRUE 之前写 feed)

    • 修改: model/user.func.php 在 user_update_group() return TRUE 前新增 model_user_update_group_success.php hook 点(原 end hook 在 return 之后不可达)

    • 修改: FeedsService/setting.php/setting.htm/install.php 加 user_levelup 默认开关

    • 必测: 用户积分达到升级阈值触发 user_update_group() 时 feed 显示"升级到了 XX 组"

    • 回归: 已是最高组/积分未变化不重复写 feed;gid<100 管理员组不触发

  • [语言包不同步] 三种语言包同步新增 user_levelup 相关键(action + settings label)

  • 版本递增: conf.json 1.2.0 → 1.3.0

  • 清理编译缓存: tmp/model_user.func.php、tmp/lang_zh-cn_bbs.php、tmp/lang_zh-tw_bbs.php、tmp/lang_en-us_bbs.php

xnx_appcenter v1.3.0 — 5 项需求开发

  • [配置不同步] 需求1: 后台新增「发布准入勋章」单选配置,发布应用需同时满足在允许用户组+拥有指定勋章;xnx_medal 未启用时自动跳过勋章校验;管理员(gid=1,2)豁免

    • 必测: admin/?plugin-setting-xnx_appcenter.htm 选勋章 → 非管理员无勋章时进 ?appcenter-publish 应被拦截

    • 回归: 管理员发布应用不受影响

  • [逻辑错误] 需求2: 开发者资料编辑页新增「官方站点」字段;4 字段(介绍/联系方式/品牌前缀/官方站点)全部必填;brand_prefix 禁止以 xn/xnx 开头(不区分大小写)+ 唯一性校验(排除自己)+ URL 格式校验

    • 必测: ?appcenter-developer-edit 填写 4 字段保存;brand_prefix 填 xn_xxx 应报错;填已存在前缀应报错

  • [逻辑错误] 需求3: 发布应用前强制校验开发者资料已完善,未完善时进入发布页显示警告+跳转按钮(管理员豁免)

    • 必测: 清空开发者资料后访问 ?appcenter-publish 应显示完善资料提示

  • [语言包不同步] 需求4: 修复分类管理和标签库共用文案 bug — 标签库原来 placeholder 用了「分类键名/分类名称」、按钮文字用「添加分类」,已拆分为独立语言键 xnx_appcenter_setting_tag_key/tag_name/add_tag

    • 必测: admin/?plugin-setting-xnx_appcenter.htm 标签库区按钮应显示「添加标签」、placeholder 应显示「标签键名/标签名称」

  • [逻辑错误] 需求5: 付费逻辑修复 — 原购买扣积分后直接蒸发,现改为实时分账:扣买家→开发者得(1-抽成)→系统抽成部分销毁(只记账)→写入 bbs_xnx_appcenter_earnings 收益流水表;后台新增「系统抽成比例」(默认10%)、「最大价格」(默认1000) 全局配置

    • 必测: 设置抽成 10% → 用户购买 100 金币应用 → 开发者应得 90 金币 → earnings 表应有 1 条流水记录

    • 回归: 免费应用购买不受影响

  • [边界未校验] 发布/编辑应用价格上限校验:超过后台配置的 max_price 时拦截

    • 必测: max_price=1000 时发布价格 1001 应报错

  • 数据库变更: developer 表加 official_site varchar(200);新增 earnings 收益流水表;conf.json 版本 1.2.0→1.3.0

  • 同步更新 install.php/uninstall.php/upgrade.php 三个脚本

  • 三语言包 zh-cn/zh-tw/en-us 同步新增 21 个语言键

  • 清理 tmp/ 编译缓存(route_appcenter/model_AppCenterService/model_PurchaseService/lang_/view_htm_

  • [逻辑错误] 修复 xnx_appcenter 后台设置页静态调用 MedalService::getMedalList() 报错

    • 根因: getMedalList() 是实例方法(非静态),且返回 [list,count] 分页结构,模板却直接遍历;表主键是 id 而模板用 medal_id

    • 改动: plugin/xnx_appcenter/setting.php 改用 MedalService::getInstance()->getAllMedals()(带缓存的 id=>medal 数组)

    • 改动: plugin/xnx_appcenter/view/htm/setting.htm 模板 m[medalid]→_m[id]

    • 清缓存: tmp/plugin_xnx_appcenter_setting.php + tmp/plugin_xnx_appcenter_view_htm_setting.htm

    • 必测: admin/?plugin-setting-xnx_appcenter.htm(xnx_medal 已启用时勋章下拉单选正常显示+选中)

    • 回归: xnx_medal 未启用时下拉隐藏不报错

  • [逻辑错误] 修复 xnx_appcenter 分类/标签名显示 lang[xxx] 问题

    • 根因: 模板和路由把用户输入的分类/标签名当作 lang key 调用 lang(),当输入中文时 $lang[中文] 不存在,返回 lang[中文] 字面量

    • 改动: plugin/xnx_appcenter/ 下 5 个文件共 11 处去掉 lang() 包裹,直接输出用户输入值

      • route/appcenter.php(5 处: cat_name_map/$_cat_map/detail_cat_map 等)

      • model/AppCenterService.php(1 处: getTagMap)

      • view/htm/appcenter_publish.htm(2 处: 分类下拉/标签 checkbox)

      • view/htm/setting.htm(1 处: 分类名输入框回显)

      • view/htm/appcenter_list.htm(2 处: 分类导航/标签按钮)

    • 清缓存: tmp/plugin_xnx_appcenter_route_appcenter.php + model_AppCenterService.php + view_htm_appcenter_publish.htm + view_htm_appcenter_list.htm

    • 必测: admin/?plugin-setting-xnx_appcenter.htm(分类/标签名输入中文保存后回显正常)

    • 必测: ?appcenter-list.htm(分类导航/标签按钮显示中文名不出现 lang[xxx])

    • 必测: ?appcenter-publish.htm(分类下拉/标签 checkbox 显示中文名)

  • [变量未定义] xnx_appcenter 后台发布准入勋章改为 radio 列表+详情跳转

    • 根因: 原下拉只显示勋章名称,用户无法区分是哪个勋章,也无法查看勋章详情

    • 改动: plugin/xnx_appcenter/view/htm/setting.htm 将 select 改为 radio 列表,每项显示 图标+名称+描述,并提供「查看详情」外链按钮跳转到 ?medal-{id}.htm

    • 改动: plugin/xnx_appcenter/hook/lang_{zh_cn,zh_tw,en_us}_bbs.php 新增 xnx_appcenter_setting_require_medal_view_detail 语言键

    • 清缓存: tmp/lang_zh-cn_bbs.php + tmp/plugin_xnx_appcenter_view_htm_setting.htm

    • 必测: admin/?plugin-setting-xnx_appcenter.htm(xnx_medal 已启用 → 准入勋章区显示 radio 列表+图标+名称+描述+详情按钮;点详情按钮新标签打开 ?medal-{id}.htm)

    • 回归: xnx_medal 未启用时该区域隐藏不报错;保存设置后选中状态保留

  • [信息泄露] 修复 xnx_appcenter 发布应用缺勋章时只提示「需要拥有指定勋章」不告知是哪个勋章

    • 根因: AppCenterService::checkPublishPrerequisite 勋章校验失败时只返回固定语言键,未带勋章名和详情链接

    • 改动: plugin/xnx_appcenter/model/AppCenterService.php 校验失败时查勋章名、构造 url(medal-id) 详情链接,返回 medal_name/medal_url

    • 改动: plugin/xnx_appcenter/route/appcenter.php 发布页前置校验失败时渲染 alert + 「查看勋章详情」按钮

    • 改动: plugin/xnx_appcenter/hook/lang_{zh-cn,zh-tw,en-us}_bbs.php xnx_appcenter_need_medal 加 {medal_name} 占位符,新增 xnx_appcenter_view_medal_detail 键

    • 清缓存: tmp/plugin_xnx_appcenter_route_appcenter.php + model_AppCenterService.php + lang_zh-cn_bbs.php

    • 必测: 后台设置发布准入勋章后,无该勋章用户访问 ?appcenter-publish.htm 看到提示「发布应用需要拥有勋章:xxx」+ 查看详情按钮,点击跳转勋章详情页

    • 回归: 管理员(gid=1,2)仍豁免;未设置准入勋章(require_medal_id=0)时不拦截

  • [逻辑错误] xnx_feeds 拆分「加载条数」(display_count, 1-30) 与「同时显示条数」(max_visible, 1-5) 两个独立配置,原 display_count 含义混淆且 MAX_VISIBLE=3 硬编码

    • 改: FeedsService/setting.php/setting.htm/install.php/footer_js_after.htm/3 个语言包

    • 必测: admin/?plugin-setting-xnx_feeds.htm(新增 max_visible 输入框)

    • 必测: 前台页面 toast 弹窗,设置 max_visible=1 时同时只显示 1 条

    • 回归: realtime_only 模式过滤逻辑不变

  • [GET表单路由丢失] 修复 xnx_appcenter 发布前置校验「去完善开发者资料」按钮跳转 404

    • 根因: AppCenterService::checkPublishPrerequisite 用 route_url(appcenter_developer, [], [sub=>edit]) 生成 query string 形式 /appcenter/developer?sub=edit,但路由分发用 param(2) 读 path 第 2 段,sub 为空走 else 分支(开发者主页),param(uid,0)=0 触发 xnx_appcenter_no_app 报错

    • 改动: plugin/xnx_appcenter/model/AppCenterService.php:125 改用 route_url(appcenter_developer_edit) 生成 /appcenter/developer/edit,与 appcenter_developer.htm/appcenter_my.htm 等其他位置保持一致

    • 清缓存: tmp/plugin_xnx_appcenter_model_AppCenterService.php

    • 必测: 未完善开发者资料的用户访问 ?appcenter-publish.htm → 点「去完善开发者资料」→ 正常打开编辑表单页

    • 回归: 开发者资料保存后跳转回开发者主页正常

  • [文档补充] 为 7 个插件创建中文 README.md(xnx_ad_selfbuy/xnx_api_tester/xnx_appcenter/xnx_attach_access/xnx_checkin/xnx_demo_data/xnx_dice),含功能/文件结构/配置流程三章节,仅 xnx_api_tester 含扩展说明

    • 必测: 各插件根目录 README.md 存在性校验

    • 回归: 无代码变更

  • [文档补充] 为 7 个插件创建中文 README.md(xnx_oauth/xnx_read/xnx_register_notice/xnx_report/xnx_status/xnx_tag/xnx_verify)

    • 含功能/文件结构/配置流程三章节

    • xnx_oauth/xnx_status/xnx_tag/xnx_verify 含扩展说明(OAuthService::registerProvider / StatusService / TagService / VerifyService + medal_condition_* hook)

    • xnx_read 原有 readme.md 被按统一规范重写为 README.md(macOS 大小写不敏感,同文件)

    • 必测: 各插件根目录 README.md 存在性校验

    • 回归: 无代码变更

  • [新功能] xnx_appcenter v1.4.0: 开发者资料审核机制 + 管理员站内信通知

    • 需求: 开发者资料需管理员审核通过才能发布应用;资料待审核 + 应用待审核两个场景均站内信通知超管(gid=1)

    • DB 改动: xnx_appcenter_developer 表加 4 字段(audit_status/audit_time/audit_uid/audit_reason),存量开发者默认 audit_status=1(避免历史用户被锁死);conf.json version 1.3.0 → 1.4.0

    • 升级: 后台插件列表会显示「需升级」红色按钮,点击执行 upgrade.php 幂等迁移

    • AppCenterService 改动:

      • saveDeveloper() 保存后重置 audit_status=0,通知超管

      • checkPublishPrerequisite() 新增 audit_status=1 检查

      • 新增 getPendingDevelopers()/auditDeveloper()/notifyAdminsPendingDeveloper()/notifyAdminsPendingApp()

      • createApp()/updateApp() 进入待审核状态时通知超管

    • 后台改动: setting.php 加 POST audit_developer action;setting.htm 加 Tab 切换,新增「开发者审核」tab 展示待审核列表(头像/昵称/介绍/联系方式/品牌前缀/官方站点/提交时间 + 通过/拒绝按钮)

    • 通知机制: notify_create(type=system/audit_approve/audit_reject) 向 gid=1 用户批量发送,url 指向后台审核 tab 或应用详情页

    • 语言包: 三套(zh-cn/zh-tw/en-us)同步新增 19 个语言键

    • 清缓存: tmp/ 下所有 plugin_xnx_appcenter_* 和 lang_*_bbs.php 编译缓存 + model.min.php

    • 必测:

      • 新开发者提交资料 → 超管收到站内信「有新的开发者资料待审核」

      • 后台「开发者审核」tab 显示待审核列表 + 数量徽章

      • 点通过/拒绝按钮 → 开发者收到站内信通知结果

      • 未通过审核的开发者访问 ?appcenter-publish.htm 被拦截,提示「尚未通过审核」

      • 开发者修改资料后 audit_status 重置为 0,需重新审核

      • need_audit=1 时开发者发布/编辑应用 → 超管收到站内信「有新的应用待审核」

      • 回归: 存量开发者(升级后 audit_status=1)仍可正常发布应用;管理员(gid=1,2)豁免所有前置校验

  • [文档补充] 为 8 个插件创建中文 README.md(xnx_duel/xnx_edgeone/xnx_fcomment/xnx_feeds/xnx_fields/xnx_friendlink/xnx_fusers/xnx_hidden),含功能/文件结构/配置流程三章节,xnx_feeds 与 xnx_hidden 含扩展说明

    • 必测: 各插件根目录 README.md 存在性校验

    • 回归: 无代码变更

  • [文档补充] 补齐 xnx_medal、xnx_moments_theme 两个插件 README.md(含扩展说明:medal_grant_end hook + 条件扩展 hook;moments_theme 覆盖模板清单 + dock 导航 hook 点)

  • [文档补充] xnx_checkin README 补充扩展说明章节(事件 hook xnx_checkin_do_checkin_end,签到成功后触发,列出可用变量)

  • [文档补充] xnx_read/readme.md 重命名为 README.md 统一命名(macOS 大小写不敏感,内容为按规范重写的沉浸阅读说明)

    • 必测: 31 个插件根目录均存在大写 README.md

    • 回归: xnx_ai_reply/README.md 未改动;无代码变更

  • [新增插件] 创建 xnx_need_avatar 默认头像发帖拦截插件(共 12 个文件)

    • 文件: plugin/xnx_need_avatar/{conf.json,install.php,uninstall.php,setting.php}

    • 文件: plugin/xnx_need_avatar/model/NeedAvatarService.php

    • 文件: plugin/xnx_need_avatar/hook/{model_inc_file,thread_create_thread_before,post_post_start,lang_zh_cn_bbs,lang_zh_tw_bbs,lang_en_us_bbs}.php

    • 文件: plugin/xnx_need_avatar/view/htm/setting.htm

    • 必测: admin/?plugin-setting-xnx_need_avatar.htm(后台开关与豁免用户组)

    • 必测: thread-create.htm(默认头像用户发帖被拦截,显示去设置头像链接)

    • 必测: post-create-{tid}.htm(默认头像用户回帖被拦截)

    • 必测: 管理员 gid=1,2 豁免可正常发帖回帖

  • [变量覆盖] xnx_ad_selfbuy 积分类型显示改为读取后台设置的名称(credits_name/golds_name/rmbs),不再硬编码 golds 等字面量

    • 必测: admin/?plugin-setting-xnx_ad_selfbuy.htm&tab=audit(审核列表费用列显示金币)

    • 必测: admin/?plugin-setting-xnx_ad_selfbuy.htm&tab=list(广告列表费用列)

    • 必测: admin/?plugin-setting-xnx_ad_selfbuy.htm&tab=rules(积分类型下拉显示中文名)

    • 必测: adselfbuy/buy/2(购买页价格计算显示金币)

    • 必测: adselfbuy/edit/{id}(编辑/续费页价格计算)

  • [逻辑错误] 修复 xnx_ad_selfbuy 后台广告位管理/编辑 Modal 无响应:内联 script 在 bootstrap.bundle.min.js 加载前执行导致 bootstrap.Modal 为 null,改为 DOMContentLoaded 后初始化

    • 必测: admin/?plugin-setting-xnx_ad_selfbuy.htm&tab=slots(点击创建/编辑按钮弹出 Modal)

  • [新功能] xnx_ad_selfbuy 新增购买提示(buy_tips)设置和展示

    • 必测: admin/?plugin-setting-xnx_ad_selfbuy.htm&tab=rules(底部新增购买提示 textarea)

    • 必测: adselfbuy-list.htm(侧栏显示 tips alert)

    • 必测: adselfbuy/buy/{slot_id}(侧栏显示 tips alert)

    • 必测: adselfbuy/edit/{order_id}(侧栏显示 tips alert)

    • 回归: buy_tips 留空时三个页面不显示 alert

  • [逻辑错误] 修复 xnx_need_avatar 默认头像判断漏判「曾上传后恢复默认」场景

    • 根因: isDefaultAvatar 只检查 avatar==0,漏掉 avatar>0 但文件已删除的场景(user_format 会把 avatar_url 回落到 default_avatar_url,但 avatar 字段仍为旧时间戳)

    • 修复: 改用 $user['avatar_url'] === default_avatar_url() 字符串比较,覆盖三种默认头像场景(从未设置/预设文件删除/上传文件丢失)

    • 修复: setting.htm 补引入 ADMIN_PATH header.inc.htm 和 footer.inc.htm(后台设置页缺头尾导致无导航无样式)

    • 修复: 清理开发环境独立编译缓存 tmp/plugin_xnx_need_avatar_model_NeedAvatarService.php(之前只清了 model.min.php 生产缓存,开发环境 DEBUG=1 走独立缓存导致旧逻辑仍生效)

    • 必测: 曾上传头像后恢复默认的普通用户发帖应被拦截

    • 必测: admin/?plugin-setting-xnx_need_avatar.htm 设置页显示后台导航和样式

    • 回归: 从未设置头像的用户仍被拦截;已设置头像用户正常发帖

  • [逻辑错误] 修复 post.htm 中 post_ref_thread_after.htm hook 重复导致插件 ID 冲突

    • 根因: 手机端(表单内 第172行)和桌面端(表单外 第243行)共用 hook 名, 插件渲染两份 DOM 导致 ID 重复, JS getElementById 只绑定第一个

    • 修复: 第172行 hook 改名为 post_ref_thread_after_mobile.htm, 桌面端第243行保持原名

    • 必测: ?post-create.htm 发帖页手机端+桌面端各插件卡片

  • [逻辑错误] xnx_attach_access 附件权限卡片上传附件后无响应

    • 卡片模板加全局计数器 m/d 后缀区分实例, hidden input 只在表单内(m)实例渲染

    • JS init 改为查找 offsetParent 非空的可见卡片实例, 所有 getElementById 用后缀拼接

    • 必测: 发帖页上传附件后权限卡片生成选择行(手机端+桌面端)

    • 回归: 权限配置保存正常

  • [逻辑错误] xnx_tag/xnx_hidden/xnx_lottery 同步注册 mobile hook

    • 三个插件 conf.json 新增 post_ref_thread_after_mobile.htm + 复制 hook 文件

    • xnx_tag/xnx_hidden JS 用 querySelectorAll 遍历所有实例, xnx_lottery 已有全局计数器, 均无需改 JS

    • 必测: 发帖页手机端三个插件卡片正常显示

  • [缓存失效] 修复 xnx_attach_access JS 浏览器缓存导致修复不生效

    • 根因: post_js.htm 用 $conf[version] (固定核心版本号) 作为 JS 缓存版本号, 修改 JS 文件后版本号不变, 浏览器加载旧 JS

    • 修复: 改用 filemtime 生成动态版本号 (参考 xnx_lottery 方案)

    • 必测: 发帖页上传附件后权限卡片生成选择行

  • [功能增强] 缓存配置页支持自定义缓存前缀(cachepre),便于和其他系统共享 Redis/Memcached 时区分键名空间

    • 改: admin/route/other.php cachepre 从硬编码 bbs_ 改为用户输入,带格式校验(1-32位字母数字下划线短横线)

    • 改: admin/view/htm/other_cache_setting.htm 新增缓存前缀输入框

    • 改: lib/CacheService.php init() 比较 cachepre 变化触发实例重建(file/redis/memcached/mysql 四驱动)

    • 安全: 改前缀前自动用旧前缀 cache_delete_prefix 清空数据缓存,避免孤儿键;session 用独立 sess: 前缀不受影响

    • 必测: admin/?other-cache_setting.htm 修改前缀保存后前台正常访问

  • [功能增强] 缓存配置页支持核心缓存键 TTL 自定义,可针对不同类型缓存设置独立过期时间

    • 改: lib/CacheHelper.php 新增 getTtl/getCoreTtlKeys/getTtlConfig/saveTtlConfig 方法,remember 内部自动用用户配置覆盖默认 TTL

    • 改: admin/route/other.php 保存 TTL 配置到 setting(bbs_kv 表,不受 cachepre 影响)

    • 改: admin/view/htm/other_cache_setting.htm 新增核心缓存键 TTL 配置表格(9项,支持通配符匹配动态键)

    • 改: lang/zh-cn/zh-tw/en-us bbs_admin.php 新增 7 个语言键

    • 必测: admin/?other-cache_setting.htm 修改某项 TTL 保存后前台对应缓存按新 TTL 过期

    • 必测: 留空自定义 TTL 表示恢复系统默认值

xnx_attach_access 插件修复(发帖附件权限无响应 + 购买接口空白 + 积分名称)

  • [逻辑错误] 修复核心 post.htm 中 post_ref_thread_after.htm hook 重复(手机端表单内 + 桌面端表单外各一处)导致插件 DOM ID 重复、JS getElementById 只绑定到隐藏副本

    • 必测: 发帖页上传附件后权限卡片生成选择行(手机端 + 桌面端)

    • 拆分 hook: 第172行改为 post_ref_thread_after_mobile.htm(手机端专用,表单内)

    • 同步处理 xnx_tag / xnx_hidden / xnx_lottery 三个插件的 conf.json + hook 文件

  • [组件混用] 修复附件上传走 AIEditor 内置 uploader,附件添加到 #editor-attachment-list 而非插件监听的 #upload-attachment-list / #upload-preview-grid,导致 MutationObserver 不触发

    • 必测: 发帖页点击附件按钮上传文件,权限卡片生成选择行

    • 修复: scanExistingCards / observeContainers 增加 #editor-attachment-list 容器

    • extractAttachData 增加对 AIEditor 附件项结构 .att-name a 的解析

  • [伪静态路径] 修复 attach/access/purchase 请求空白:路由路径用连字符 attach-access,在 url_rewrite_on=3(路径风格)时 url() 把 - 替换成 /,导致 param(0)=attach 匹配到错误的 route/attach.php

    • 必测: 帖子详情页点击购买按钮,确认 Modal 中显示金额和积分类型,点击确认后扣费成功

    • 修复: 路由路径改为下划线 attach_access(url() 不会替换下划线)

    • 涉及: model_route_table_end.php / index_route_case_end.php / thread_js.htm 的 URL 生成

  • [变量覆盖] 修复积分类型显示用固定语言包(积分/金币/人民币),未从后台配置读取 credits_name/golds_name/rmbs_name

    • 必测: 后台修改积分名称后,发帖卡片 / 帖子详情徽章 / 购买 Modal / 后台购买记录页都显示新名称

    • 修复: model_post_file_list_html_end.php / attach_access_post_card.htm / setting.htm / thread_js.htm / thread_attach_access.js 全部改为优先读 $conf['credits_name'] 等

  • [缓存失效] 修复 upload-service.js / thread_attach_access.js / post_attach_access.js 用固定 $conf['version'] 作为缓存版本号,修改后浏览器加载旧版本

    • 必测: 修改 JS 文件后普通刷新即可加载新版本(无需强制刷新)

    • 修复: EditorService.php / thread_js.htm 改用 filemtime 生成动态版本号

最新回复

请先登录后再回复 登录

uid:1 管理
关注
随遇而安,随缘而行
发帖 90
评论 356
粉丝 11
关注 1
发新帖
目录
XIUNOX 更新记录贴 202600716