Handoff Document

接手 GameBox 客户端

前任已经走了,没人可问。这份文档是你第一周唯一能依赖的东西。

基线:2026-08-12 的 gameboxclient 工作区快照 (未提交状态,git HEAD 仍是更早的旧基线)。 文中每条实现描述都带 file:line,写的时候逐条核对过。 有人提交代码后行号会漂,文件名和函数名仍然有效。

1. 这是什么,坏了谁受影响

GameBox 是公司内部的游戏配置与发布工具,装在策划、美术、 运营的电脑上。他们每天用它做四件事:

技术上它是一个 Electron 桌面应用: 界面用 Vue 3 写,外壳是 Node.js,还外挂了一堆二进制工具(SVN、Python 脚本、7-Zip 等)。

坏了会怎样

编辑器坏了 → 策划改不了数值,当天的版本内容排期停摆。
发布坏了 → 资源上不去,测试服拿不到新内容,整条链路卡住。
GM 坏了 → 线上玩家问题处理不了,运营直接找你。

换句话说:这个工具没有降级方案。它挂了,相关同事就是完全没法工作。 所以你的第一优先级不是重构,是能快速定位和恢复

2. 十分钟跑起来

2.1 装依赖 —— 直接 npm i 会失败

# ❌ 会因为 peer dependency 冲突失败
npm i

# ✅ 用这个
npm i --legacy-peer-deps

# ✅ 或者用项目自带的脚本(等价,还会顺带跑 cpsvn)
npm run i

原因:仓库里原本有 .npmrc 写着 legacy-peer-deps=true, 但当前工作区里这个文件不见了。 git 历史里能看到当初专门为此做过一次提交 (chore(npm): .npmrc 增加 legacy-peer-deps,让裸 npm i 也能装上)。

建议的第一个提交:.npmrc 加回去。 改动一行,收益是下一个人不用踩这个坑。

2.2 启动

# 开发模式:Vite dev server + Electron 一起起来
npm run dev

# 只做类型检查(不构建)
npm run ts:check

# 打生产包
npm run build:pro

npm run dev 实际是 vite --mode basevite-plugin-electron 会在 dev server 起来后自动拉起 Electron (vite.config.tsonstartoptions.startup(['.', '--no-sandbox']))。 dev server 端口是 4080

2.3 登录之后才算真的跑起来

这一步最容易被低估。在这个项目里,登录不只是「进主界面」, 它还负责下发全部外部服务的凭据 —— SVN 账号密码、 Jenkins 地址和 token、GM 接口地址、项目编码。

没登录 = SVN、Jenkins、COS 全是哑的,而且点了不会报错。 完整链路见架构图 FIG.03「钥匙链」

登录成功后,打开 DevTools 控制台敲这一行确认凭据到位:

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

应该能看到 VITE_SVN_URLVITE_JENKINS_URLVITE_API_BASEPATH 这些键有值。空的就说明服务端没下发, 后面所有外部操作都会静默失败。

2.4 macOS 上会踩到什么

⚠️ 先知道这个

这是一个 Windows 优先的工具。 extend/ 下的可执行文件几乎全是 .exe: Python 转换脚本、地图工具、便携版 nginx 和 node、7-Zip。 Mac 版只有 SVN 一个,而且它没有可执行位-rw-r--r--)。

在 macOS 上你能做的:

做不了的:

登录时还会自动调 initNginx()moveTemp()views/ReLogin/index.vue:256,273),Mac 上必然失败 —— 但不影响登录本身,控制台会有报错,可以先忽略。

SVN 权限问题可以先临时绕过(但这只解决执行位,不保证二进制本身能在你的 macOS 版本上跑):

chmod +x extend/Svn/Mac/Arm64/1.14.2/bin/*

3. 三个进程,三种调试方式

出问题时的第一个判断永远是:这是哪个进程的问题? 判断错了,你会在错误的控制台里找一下午。

进程 跑什么代码 怎么看日志 典型症状
渲染进程 src/** 全部 Shift+Cmd/Ctrl+I 打开 DevTools (快捷键注册在 electron/main/config/menu.tsdebugMenu,由 src/App.vue:50debug IPC 触发注册) 页面白屏、按钮点了没反应、请求 404
主进程 electron/main/** electron-log注意只在非 development 下才初始化handler/ready.ts:24-26), 开发时日志只在启动 Electron 的那个终端 窗口起不来、自动更新失败、IPC 无响应
子进程 extend/worker/*.js process.send() 把消息发回主进程,主进程再转发到渲染层。 子进程自己的 console 看不到 下载/解压进度条卡住不动

最快的分诊问题

「这个功能在浏览器里能复现吗?」 如果症状只在打包后的应用里出现、dev 模式正常,那多半是主进程或路径问题 (process.env.DISTDIST_EXTENDready.ts:10-20 里按打包与否算了两套值)。

反过来,如果 DevTools 控制台里有红色报错,那就老老实实是渲染层的事, 别去翻主进程。

4. 代码地图速览

详细内容在文件结构地图, 这里只给最小必要的四条:

改配置字段src/store/config/<表名>.ts。 页面组件不用动,通用表单引擎 PropEditor 会按 schema 自己渲染。

改接口地址 / 凭据src/utils/extend/envOption.ts不是 .env —— 那里只有 11 个键, 真正的配置由 /user/info 下发。

加页面src/router/index.ts + src/locales/zh-CN.ts

加主进程能力electron/main/handler/channel.ts 加一个 ipcMain.handle

5. 改一个需求的标准动作

5.1 「给物品表加个字段」

  1. 确认后端那张表已经有这个字段了 —— 前端 schema 只是描述, 不会凭空创造字段。
  2. 打开 src/store/config/Item.ts,照着旁边的字段加一段: type(String/Number)、summary(界面标签)、 desc(悬浮说明)、必要时 editoroptions
  3. npm run dev,登录,选服,进 /game/item, 点进一条数据,确认新字段出现在表单里。
  4. 改一个值点保存,看 Network 里 excel_modify 的 payload 带上了新字段。
  5. npm run ts:check,确认错误数没有增加

5.2 「加一个新页面」

  1. src/views/GameEditor/ 下建目录,照抄一个结构最简单的模块 (Box/ 只有 445 行,是个好模板)。
  2. src/router/index.ts/game children 里加路由, meta 至少要有 showMenu: truetitleicon(iconify 名)。
  3. src/locales/zh-CN.tsrouter.future 加标题键。
  4. 要编辑页就再加一条 xxx_editmetahidden: true 让它不出现在菜单里。

5.3 「加一个主进程能力」

// 1. electron/main/handler/channel.ts
ipcMain.handle('my-thing', async (_event, arg) => {
  return doSomething(arg)
})

// 2. 渲染层任意位置
import { ipcRenderer } from 'electron'
const result = await ipcRenderer.invoke('my-thing', payload)

✅ 照做

新代码要用主进程能力,走 IPC,不要走 @electron/remote 项目里现有的 src/utils/extend/electron.ts 那条路虽然更省事, 但它把整个主进程对象暴露给了渲染层,边界完全不可控。

IPC 的每个通道都是显式的、可枚举的、可以在 channel.ts 里一眼看完的。这是唯一能让边界不继续恶化的做法。

5.4 提交前的固定检查

npm run ts:check   # 错误数不能比改动前多
npm run lint:eslint
关于 ts:check这个项目没有单元测试vue-tsc 是唯一的整体校验。它本身就带着大量历史错误, 所以验收标准是「不新增」而不是「零错误」。 改动前先跑一次记下数字,改完再跑一次对比。
提交钩子目前是失效的package.json"prepare": "husky install"lint:lint-staged 都指向 .husky/, 但这个目录在当前工作区里已经不存在。别指望自动检查,手动跑。

6. 发版

发布页在 /expert/release(专家模式 → 发布)。 完整分叉见架构图 FIG.05。 这里只讲操作要点。

6.1 两种任务,一道全局闸门

闸门:只要 Jenkins 上有任何构建在跑, 所有发布卡片都点不动,包括纯本地的 SVN 提交 (views/Option/index.vue:89-111)。 看到「当前有打包任务在进行中」不是 bug,是设计如此。

SVN 型 Jenkins 型
动了什么 本地磁盘 + 远端 SVN 仓库 远端构建服务器
有没有确认步骤 ✅ 有。弹窗列出所有改动文件,可逐个勾选、可单独还原 ❌ 没有。点了直接触发
怎么停 提交前关掉弹窗即可;提交后只能 svn revert Jenkins.stopBuild(jobName, buildNumber), 页面上也有停止入口
失败了会怎样 命令行报错,界面有提示 弹「构建失败」,不会自动重试

6.2 卡住了怎么办

⚠️ 最常见的一类报障

「发布卡在进行中不动了」几乎总是同一个原因: Jenkins 那边早就结束了,客户端的轮询没收到

轮询是 src/api/login/index.ts:105-107 里一个裸 setInterval,只在拿到明确结束态时才停。 Jenkins 中途不可达、返回结构变了、job 被删了 —— 它都会一直转下去。

处理顺序:

  1. 先去 Jenkins 页面看那个 job 的真实状态。
  2. Jenkins 那边已完成 → 让用户重新登录。 登录会 taskStore.reset(),是最快的自救。
  3. Jenkins 那边真的在跑 → 就是正常等待,告诉用户等。

7. 已知坑清单

下面每一条都是在源码里逐条核对过的,不是猜测。 按「会不会咬到你」排序。

7.1 会直接咬到你的

❌ 改错文件

src/config/axios/serviceold.tssrc/config/axios/service.ts 内容高度相似, 在用的是后者。 同理 src/utils/extend/jenkins_old.ts vs src/utils/extend/jenkins/

改之前先确认 import 路径指向哪个。这是本项目最经典的浪费时间方式。

❌ 静默失败

凭据缺失时,所有外部操作都不报错。 src/utils/extend/jenkins/index.ts 全用 _buildService?.start(...) 这种可选链 —— 客户端没初始化时返回 undefined,一切正常。 COS_Handler.init()catch 直接 return false,没人检查。

所以:排查任何「点了没反应」,第一条命令永远是 JSON.parse(localStorage.getItem('GameENV'))

❌ 断链

Python 工具链找不到解释器。 src/utils/extend/python.ts:34-41 指向 extend/Python/Win/3.11/python.exeextend/Python/Mac/3.8/bin/python3, 但 extend/Python/这两个目录都不存在

影响地图转换、动画转换、lua 读写、nginx 初始化。 在问清楚之前不要自己改路径 —— 很可能这些 exe 已经是独立可执行文件,那段拼接是死代码, 你改了反而会把「明显坏掉」变成「悄悄坏掉」。

❌ 权限位

extend/Svn/Mac/Arm64/1.14.2/bin/svn 权限是 -rw-r--r--没有可执行位。 Mac 上任何 SVN 操作都会在 exec 那一步失败。

chmod +x 能解决执行位,但不保证这个二进制在你的 macOS 版本上真的能跑起来。

7.2 架构层面的,短期别动但要知道

⚠️ 隔离

渲染层全开 Node 权限,没有 preload。 electron/main/config/options.ts:6-8nodeIntegration: truecontextIsolation: falsewebSecurity: falsevite.config.ts:58-72 把 preload 构建整段注释掉了。

代价是渲染层加载的任何内容都拥有读写整台机器的能力。 短期绝不能动(几百个文件建立在这之上), 但新代码不要继续扩散 @electron/remote

⚠️ 隔离

凭据明文落在 localStorage。 src/store/modules/GameEvn.ts:44-49 的深度 watch 会把整个 ENV(含 svn_passwordjenkins_token) 写进 localStorage 的 GameENV 键。

规范做法是凭据只留主进程,渲染层通过 IPC 请求主进程代为执行, 并用 Electron safeStorage 加密存储。这是你跟安全或运维对话时必须能说清楚的一条。

⚠️ 隔离

generateRoutes() 不做权限过滤。 src/store/modules/permission.ts:37-56 只是 [...DynamicRouterMap] 加一条 404,全部注册。 菜单里藏起来的页面(meta.hidden)不代表无权访问, 手敲 hash 地址照样能进。真正的授权只可能在服务端。

7.3 明确的小 bug,可以顺手修

问题 位置 后果
小窗的 setWindowOpenHandler 解构了不存在的 docUrl(同文件主窗口写的是 url electron/main/helpers/window.ts:91(对照 48 行) Excel 小窗里点外链,传给 shell.openExternal 的是 undefined
smallWindow 一个变量同时当窗口引用和共享数据用 helpers/window.ts:71 vs setSharedData() 103 行 调过 setSharedDatagetSmallWindow() 拿到的不是窗口
守卫里 needConfirm 分支调完 next(false) 没有 return src/permission.tsbeforeEach 后续逻辑继续执行并可能再次调 next(),Vue Router 会告警
tableConfigMapbox: 'Nox', 但配置文件叫 Box.ts src/store/modules/table.ts 疑似打字错误。先查清有没有代码真的走这条路再改
stylelint 同时在 dependenciesdevDependencies,且前者写着 "latest" package.json lint 工具被打进生产包;latest 让依赖树不可复现。 改动风险最低,适合当第一个提交
仓库里躺着 hs_err_pid15992.lognpminstall-debug.logupdate.log 仓库根目录 开发机产生的垃圾文件被提交了(update.log 里能看到路径 E:\project\tool-demo)。应该加进 .gitignore

7.4 疑似废弃但不能乱删

完整清单在功能点清单第四节。 最需要注意的一条:src/views/Database/index.vue 虽然不在路由里,但这个目录之外还有 10 个在用文件引用它

删任何东西前必须 grep,而且要知道本项目大量使用动态引入 (() => import()import.meta.glob), 静态分析会漏报 —— src/store/config/*.ts 尤其危险, 它们没有任何显式 import,全靠 glob 扫进来。

8. 必须问人的清单

这一节的优先级高于任何技术学习

下面这些问题只能问人,代码里找不到答案。 在拿到答案之前,所有涉及写操作的链路都只做代码追踪, 不要真跑

8.1 组织与流程

8.2 环境与权限

8.3 技术问题

⚠️ 单独说:Windows 机器

这不是个人偏好问题。把依赖清单里那几行连起来看: SVN 提交、地图转换、动画转换、图片转换、本地预览、打正式包 —— 六项核心职责在 macOS 上全部无法执行。

你可以在 Mac 上完成开发和调试,但无法完整履行这个岗位。 这条应该明确写进你的第一周汇报,越早提越好。

9. 校验手段与它们的边界

手段 命令 能保证什么 不能保证什么
类型检查 npm run ts:check 没有新增类型错误 不保证零错误(本来就有一大堆历史错误); 不检查模板里的类型
ESLint npm run lint:eslint 代码风格与部分低级错误 不检查业务逻辑
生产构建 npm run build:pro 依赖能解析、能打出包 不保证运行时正确
手动真机验证 唯一能验证业务正确性的手段 覆盖不全,靠人

❌ 现状

这个项目没有任何单元测试或集成测试框架。 package.json 里没有 test 脚本,没有 vitest / jest, 没有 __tests__ 目录。

这意味着每一次改动的正确性都只能靠人工点。 接手初期这是最大的风险来源 —— 你改的东西没人告诉你坏了, 直到策划来找你。

可以做的第一步(不需要大改造):给 src/utils/ 下的纯函数补几个 Vitest 用例。 那些函数没有 Electron 依赖,测起来最容易,也最能给你安全感。

10. 第一周建议路线

Day 1 —— 跑起来,登录成功,把 GameENV 打出来看一眼。 读架构图的前三张。

Day 2 —— 跟着课 02 走一次完整请求。在 Network 里认出 cmd 字段。

Day 3 —— 补 Vue 3 和 Pinia (课 03 / 课 04), 用项目里的真实页面练。

Day 4 —— 做第一个改动:给某张配置表加一个字段,走完 5.1 的五步。

Day 5 —— 把「必须问人」那一节的问题实际问出去。 这一步比多读一天代码有价值得多。