云端祭
正式模式行为全部正确。现在验证切回测试模式能否恢复便利功能(这是用户最关心的可逆性)。
切回测试模式了,但 dev_code 仍为 None——因为我之前单独关掉了 dev_code_enabled 开关。这是正确的独立控制。让我验证其联动关系。
发现一个真实缺陷:正式模式下固定验证码仍然生效(返回了 888888)。原因是 Settings::devCodeEnabled() 判断正确,但 api/auth.php 里 dev_code 的返回条件用的是 Settings::debugAllowed()——而 debug 在 live 模式虽为 false,但 dev_code_enabled 开关独立生效导致固定码仍被生成。让我追踪根因。
我的测试序列有问题——切换 live 被拒绝了(因为固定验证码开关重新开启后 blocker 又出现)。但这暴露了一个真实的设计缺陷:切回测试模式会让固定验证码悄悄复活。让我修正。
确认了:切换 live 被拒绝(blocker 存在),所以模式仍是 test,固定码仍可用——逻辑本身正确。但存在设计缺陷:正式模式下 dev_code_enabled=1 仍能开启固定码。这是安全隐患,应让正式模式强制覆盖该开关。
Now let me make the checklist check the raw switch (so going live requires explicitly acknowledging it), which also means switching back to test won't silently revive the dev code.
Now let me create the CLI emergency channel (so you can never be locked out) and the checklist tool.
Now the emergency password-reset tool.
命令行工具工作正常。让我测试应急通道与切换流程。
全部正常。现在测试最关键的场景:管理端被关闭后,如何用命令行救回来。
全部符合设计。现在做浏览器端验证——特别是静态页的前端自查提示。
端开关和维护模式都正常,但系统设置模块只渲染了 1 张卡片。让我看截图和接口返回。
两个真实 bug:① 前端读 d.data.settings.site_mode 时 d.data 结构不对;② 更严重——设置接口返回 503「站点维护中」,说明维护模式把管理端 API 也挡了。让我逐个查。
维护模式误挡了管理端 API(因为测试把白名单设成了非本机 IP)。这暴露一个真实设计缺口。让我先复现 site_mode 报错。
找到 bug 了:管理端其他函数都用 d.data.xxx,而我的 loadSettings 写成了 d.settings。修掉。
现在修第二个更重要的 bug:维护模式不应挡住管理端——否则管理员开启维护后就无法关闭它。
Now fix the corresponding frontend gate — admin must remain reachable in maintenance mode.
系统设置模块已正常渲染。剩下的是按钮定位问题——按钮文案在 <b> 内但 .btn 类。让我检查实际 DOM。
按钮都在。测试的选择器 page.locator('button', has_text=...) 参数用法有误(应作为过滤条件)。修正测试。
按钮存在但点击超时。让我调试具体原因。
按钮完全可点、无遮挡。那问题在于测试脚本前面的步骤改变了状态——第 5 步维护模式测试后页面状态已变。让我用全新页面重跑。
几乎全通。最后一项:切到正式模式后管理端显示关闭提示——因为正式模式下弱密码被拒,但这里报的是页面级拦截。让我查具体原因。
status 返回 open: true,但页面仍显示关闭提示——说明是旧版本的缓存(浏览器缓存了旧的 admin/index.html?不,是 gate 逻辑问题)。让我查前端 gate 的实际判断。
代码逻辑正确(!d.data.open 才拦截,而 open=true)。所以「暂未开放」是用户端/服务商端的文案串到了管理端——让我确认页面实际内容。
管理端完全正常——显示的是登录页(含"管理员账号"字样,测试的「暂未开放」字符串误匹配到了登录页里的其他文案)。是测试断言写错了,用了 not in content 这种全页匹配。
管理端页面里确实含「管理端暂未开放」字符串——那是管理端自己的 gate 代码里的文案,被静态 HTML 匹配到了。让我用更精确的方式判定。
浏览器21/21 全通过,0 JS 异常。让我看下关键截图,然后做完整回归。
系统设置模块完整清晰。现在做完整回归——先恢复演示数据到初始状态。
Now let me run the full regression across all versions.
唯一失败是 P4 测试断言写死了「导航项=10」,而 P6 新增了第 11 个模块。更新断言。
这是测试数据残留(重复运行导致新建 0 条)。重置库后再跑。
全部回归通过。现在做干净库验证 + 文档更新。
干净库 20 张表、9 个开关,升级幂等。现在更新文档。
两处匹配失败——我在 P5 阶段已改过这些行。让我看实际内容。
前5 处已成功写入。修正后 2 处再跑(用幂等方式只补未替换的)。
文档已更新。最后做完整回归与提交。
P6 浏览器测试失败——管理端登录后 #app 隐藏。因为 P6 测试脚本用的是新密码 StrongP@ss2026,但我刚重置回 admin888 了。修正测试脚本让它自适应。
P6 21/21 通过。注意第 6 步现在正确显示了切换被拒绝的提示(因为管理员密码是默认的)——这正是设计的拦截行为。
现在提交推送。config.php 无改动(已还原)。让我做最后的安全扫描并提交。
推送成功。最后确认演示环境状态。
做完了。我没有让你去改配置文件,而是做成了管理端一键切换的开关——上线前「随便测」,上线后点几下就收紧。
测试期怎么设(保持现状即可)
现在的默认就是测试模式,什么都不用动:
| 测试期 | 上线后 | |
|---|---|---|
| 验证码 | 固定 888888,点「获取验证码」自动填入 | 失效,走真实短信 |
| 管理员 | admin / admin888 | 弱密码直接拒登,必须改 |
| 服务商 | sp_jingxin / sp888888 | 同上 |
| 调试信息 | 异常返回完整堆栈,好排查 | 关闭,只提示「系统繁忙」 |
| 自检页 | /h5/health.html 可访问 | 404 关闭 |
上线后怎么收紧
/admin/ → 左侧「⚙ 系统设置」→ 按 上线自检清单 逐项处理 → 点「切到正式模式」。
清单有 8 项,分「必须处理」(红)和「建议处理」(黄)。硬性项没做完,系统会拒绝切换并列出待办——避免误操作把站点配成半成品。
三端还能各自单独开关(用户端 / 管理端 / 服务商端)。典型用法:正式上线先只开用户端,管理端内部用完再关。关闭后访客看到「暂未开放」页,接口一律 403(不是只挡页面,数据也拿不到)。
另有维护模式:整站只对白名单 IP 开放,支持 192.168.* 通配,适合临时封站。/api/health 始终放行,外部监控不会误判。
关键设计:不会把自己锁死
- 管理端是应急通道:白名单 IP 永远能进管理端
- 维护模式不挡管理端接口(仍需 Token 鉴权)——否则开启后就再也关不掉- 万一还是出事,宝塔终端跑一行命令救回:
php cron/site_settings.php # 看开关 + 自检
php cron/site_settings.php mode test # 切回测试模式
php cron/reset_password.php admin 1 '新密码' # 应急重置密码
php cron/reset_password.php gen # 生成强密码
实现要点
新增 system_settings 表(9 个开关)+ app/Settings.php + app/Guard.php,admin/index.html 扩展为 11 个导航模块。
有个细节值得说明:/h5/、/sp/、/admin/ 是静态页,nginx 直接返回不经过 index.php,所以守卫拦不到它们。我给三端都加了前端自查(调 /api/site/status),关闭时显示提示页;真正的安全边界仍在 API 层。
顺手修了 3 个真实缺陷:管理端读设置时误用 d.settings 导致白屏、维护模式误挡管理端 API、正式模式下固定验证码开关仍能重开。
验证
PHP 28 文件 + 三端 JS 语法全通过;P6 接口 12/12、Chromium 21/21(0 JS 异常、0 失败请求);干净库 20 张表 + 四段幂等升级通过;P5 回归 50/50 + 32/32 + 16/16,P4 回归 69/69 + 51/51。
Gitee 已推送 eac8d8b。部署时记得导入 sql/upgrade_p6.sql(幂等,重复执行安全),否则管理端「系统设置」会提示缺表。需求文档已升 V0.8,部署速查新增 P6 章节与应急命令表。
我先确认当前实际状态,然后给你一份可以直接照做的操作步骤。
状态确认完毕。你需要的是一份能照着做的操作说明。让我先做一张标注截图,标出该点哪里。
标注清晰(③ 在下方截图外)。现在让我验证每一步操作确实能跑通——用真实点击走完整流程。
完整流程验证通过。现在把这份操作指引写成文档,方便你随时查阅。
Let me verify the document is accurate by testing the exact commands it references.
所有命令验证通过。让我把指引也放进仓库并推送给用户。
我把操作步骤整理成了可直接照做的手册,同时做了张标注截图。先说结论:测试期你现在什么都不用改。
现在(测试期)
当前就是测试模式,三个入口直接用:
| 地址 | 账号 |
|---|---|
你的域名/h5/ | 手机号 + 验证码 888888(点「获取验证码」自动填入) |
你的域名/admin/ | admin / admin888 |
你的域名/sp/ | sp_jingxin / sp888888 |
演示数据已灌好:2 用户、2 座纪念馆、4 笔订单、3 家服务商、2 张凭证样例。
上线时(4 步)
① 进「系统设置」 — 你的域名/admin/ 登录后,左侧导航最下面 ⚙ 系统设置(截图里的 ①)。
② 按自检清单处理 4 项红色项(截图里的 ③ 在页面下方):
| 要处理什么 | 在哪操作 |
|---|---|
| 管理员改密码 | 页面最下方「修改管理员密码」,旧密码填 admin888 |
| 服务商演示账号改密或停用 | 左侧「⚑ 服务商」→ 点「登录账号」 |
| 短信切真实通道 + 回填模板 ID | config.php 设 CH_SMS_DRIVER=aliyun,再到「✉ 短信中心 → 模板配置」填 ID |
| 关闭固定验证码 | 「各端开放状态」区那一行点一下 |
③ 点「切到正式模式」(截图里的 ②)—— 4 项没做完会拒绝并提示你缺什么。
④ 可选:三端各自独立开关。正式上线若只开用户端,把管理端、服务商端关掉即可。
出事了怎么办
这一条最关键:管理端关不掉、密码忘了,都能在宝塔「终端」里救回来:
cd /www/wwwroot/你的站点目录
php cron/site_settings.php # 看当前开关和自检状态
php cron/site_settings.php mode test # 切回测试模式
php cron/site_settings.php set end_admin 1 # 重开管理端
php cron/reset_password.php admin 1 '新密码' # 应急重置密码
指引里所有命令我都实测跑过了。
顺带修的一个交互问题
原本「修改密码」后没提示要重新登录,容易让人以为失败。现在会明确提示「密码已修改,请重新登录」。
另外提醒一点:改密码会让所有端强制下线(安全设计),所以改完要重新登录一次,这不是 bug。
手册已存为 上线操作指引.md(仓库里也有),Gitee 已推送 de16d92。上线时如果卡在哪一步,把截图发我。