Preflight

动手之前,先回答四个问题

这个工具的写操作大多没有目标确认、失败也不明说。 在它变好之前,护栏只能长在你自己的操作习惯里。

基线:2026-08-12 的 gameboxclient 工作区快照。

为什么需要这一页

正常的工具在你点「保存」时会告诉你「即将修改正式服的物品表,确认?」。 这个工具不会。它直接发请求,成功了弹个绿条, 失败了可能什么都不弹(见依赖清单的静默失败一节)。

所以「我在改哪台服」这个问题,只能你自己在动手前查。 下面四条,每条都是一行命令。

第一层 · 写操作前必查(现在就能用)

在 DevTools 控制台里跑。全是只读,不会改任何东西。

① 我在改哪台服?—— 最重要的一条

localStorage.getItem('pCode')
结果 意味着
含 _dev ✅ 打测试 GM
不含 _dev(包括 boxTestLS 这种名字里有 Test 的) 🔴 打正式 GM
null ⚠️ 会往下走 getPcode() 的兜底链, 最终多半落到 .env 的 boxTestLS → 仍然是正式

判定逻辑就一行(src/config/axios/service.ts:79-84): pcode.includes('_dev'),默认分支是正式服。

而 getPcode()(service.ts:30-41)取值有四级兜底, localStorage.pCode 优先级最高 —— 优先于你在界面上选服写进 GameEvn 的值。 所以「我明明切了环境」和「实际打到哪」可能是两回事。

② 双保险:直接看请求打到哪个域名

别只信 pcode 推断。Network 面板看一眼真实的 Request URL:

域名含 环境
common-gm-460qntest ✅ 测试
common-gm-460qnprod 🔴 正式

③ 选服了吗?

localStorage.getItem('defaultServerId')

null 或空 → 请求里的 serverId 会是 undefined,但请求照发 (src/api/game/index.ts:22 的 serverId || getStorage('defaultServerId') 兜底)。 服务端具体怎么响应要看 Network Response。

④ 凭据齐吗?

JSON.parse(localStorage.getItem('GameENV'))

重点看 VITE_SVN_USER / VITE_SVN_PASSWORD —— 这两个在 .env 里是空的,只能靠登录下发, 空的就说明 SVN 链路根本不会工作。 完整分类见环境变量速查卡。

⚠️ 两套工作区,别混

源码仓库(gameboxclient,当前 9401 条未提交改动) 和运行时 SVN 工作副本(<盘符根>/.hidden_resource/<渠道>) 是两个完全无关的东西。

git status 那 9401 条跟发布内容毫无关系。 要知道「有什么要发」,只能看发布页列出的文件列表。详见 Runbook A。

按操作类型的检查项

要做的事 动手前必查 做完必验
改一条配置表数据 ① ② ③ 回读那条数据。界面提示「保存失败」时尤其要查 —— excel_modify 发两个请求,第一个可能已经成功
删配置表数据 ① ② ③ 回读;删除记录会写进 <资源目录>/log/delData.json,可在「最近删除」页找回
GM 操作(发邮件、改玩家数据) ① ② ③,另外确认 VITE_API_GM_PCODE 不为空 去游戏里 / 找运营确认效果
资源发布(SVN) ④,以及数一下弹窗里的文件数量。 另外别把「没提示有任务在跑」当成「确实没有任务在跑」 —— Jenkins 查不通时闸门会静默放行(Runbook A-4), 不确定就去 Jenkins 页面自己看一眼 超过 100 个就别直接提交(会静默截断,见 Runbook A-3)
触发 Jenkins 构建 ④,确认 Jenkins 凭据与 job 名 去 Jenkins 页面看真实状态,别只信客户端的进度条 (轮询有空指针 bug)
更新服务器 🔴 先找运营确认可以踢人的时间窗口 见 Runbook C

第二层 · 代码级护栏提案

📋 以下都是提案,尚未实施

这些是「将来要改」,不是「已经这样」。 现在不动手的理由:gameboxclient 有 9401 条未提交改动、 没有任何测试框架、你也还没拿到可安全操作的环境 —— 此时改写操作路径风险太高。

拿到安全环境、且当前那批未提交改动处置清楚之后,可以照着下面改。 按投入产出比排序。

提案 1 · 写操作前展示目标(收益最大)

改哪里:src/api/gm/index.ts:259 的 excel_modify(),以及同文件的删除类函数。

做什么:发请求前,先算出并展示这五项:

// 形状示意,不是可直接粘贴的代码
const target = {
  环境:   pcode.includes('_dev') ? 'TEST' : 'PROD',   // ← 显眼地标出来
  pCode:  getPcode(),
  host:   getBaseURL(getPcode()),
  服务器: getStorage('defaultServerId'),
  表名:   data.excel,
}
// PROD 必须二次确认;环境/服务器/pcode 任一缺失则拒绝写入

为什么:当前从点击到落库,没有任何一处告诉用户 他在改哪个环境。而 getPcode() 有四级兜底 (service.ts:30-41),实际生效的是哪一级用户完全无感。

提案 2 · 写后回读

为什么:excel_modify() 用 Promise.all 汇总两个请求,界面报失败时第一步可能已经成功 (见架构图 FIG.04 后的三情况表)。

做什么:写入成功后立刻用 excel_search_DateById 回读同一条,比对关键字段;不一致就明确报「写入结果与预期不符」, 而不是让用户去猜要不要重试。

提案 3 · 给 SVN 提交去掉 100 个上限

改哪里:src/utils/extend/svn.ts:268-284 的 svnCommit()。

现在:commit(commitList.splice(0, 100), …) —— 只提交前 100 个,其余静默丢弃,还 resolve(true)。

改成:循环分批直到列表为空,任一批失败就整体报失败并说明 「已提交 N 批、第 M 批失败」。 这条是纯 bug 修复,风险最低,可以最先做。

提案 4 · 让确认框说清要动哪些服

现状:确认框已经有了 (serveChooseView.vue:125,文案「打包构建会将选择的服修改为 维护状态,并踢人下线」)。问题是它不显示区服名 —— 勾了 1 个服和勾了 8 个服,弹出来的字一模一样。

改哪里:serveChooseView.vue:125 的 confirm 文案。

做什么:把已勾选的区服名拼进文案: 「即将踢出 XX 服、YY 服 全部在线玩家并重启,确认?」。 下游 method.ts:564 是 for (const item of data) 遍历, 名单本来就在手上,拼字符串即可。

提案 5 · 给轮询加超时上限

改哪里:src/api/login/index.ts:105-111 的 checkstartBuild()。

现在:getCurrentJob() 失败时返回 null,而调用方直接取 data.inQueue → 抛 TypeError,定时器永不停止。

改成:先判空;加最大轮询次数或截止时间; 超时后把任务置为「状态未知」并给一个「去 Jenkins 查看」的入口。

提案 6 · 让闸门查询失败时说话

现状:「有构建在跑就不让发布」这道闸门 (见 Runbook A-4) 查不通 Jenkins 时会静默放行:

// jenkins/monitor.ts:99-103
} catch (error) {
  console.error('Error checking active builds:', error)
}
return activeBuilds        // ← 异常时是空数组,跟「真的没构建」长得一模一样

调用方拿到空数组,无法区分「真的没构建在跑」和 「根本没查成」,于是一律放行。

改哪里:getActiveBuilds() 的返回类型 (src/utils/extend/jenkins/monitor.ts:69)。

// 形状示意
async getActiveBuilds(options): Promise<BuildInfo[] | null> {
  try {
    …
  } catch (error) {
    console.error('Error checking active builds:', error)
    return null            // ← 把「查失败」和「查到 0 个」分开
  }
  return activeBuilds
}

四个调用方要跟着改,而且不能一刀切:

调用方 性质 收到 null 时该怎么办
views/Option/index.vue:90 闸门 弹 ElMessageBox.confirm('Jenkins 状态未知,无法确认是否有构建在跑,仍要继续?'),用户取消即中断
Dashboard/method.ts:328 闸门
Dashboard/method.ts:428 闸门
api/login/index.ts:83 不是闸门 它是登录时恢复任务列表用的。 直接跳过恢复即可,别弹框打扰登录流程

为什么不干脆一律拒绝(fail closed): 那样 Jenkins 一挂,全站发布都瘫痪 —— 包括跟 Jenkins 毫无关系的纯本地 SVN 提交, 比现状更糟。这里要去掉的是「静默」,不是「放行」。 判断权交回给人。

顺带的好处:改返回类型会让 TypeScript 直接把这四个调用方全部标红,漏改不了。

动这些之前

先把 gameboxclient 那 9401 条未提交改动搞清楚。 在一个已经有大量未提交改动、又没有测试的仓库里改写操作路径, 出了问题连「是不是我改坏的」都说不清。

提案 3(SVN 分批提交)是唯一一条纯 bug 修复、无行为设计争议的, 如果一定要先做一条,做它。

站点版本 dcc04aa · 2026-08-14 内容基线 gameboxclient @ 2026-08-12