Handoff Document
前任已经走了,没人可问。这份文档是你第一周唯一能依赖的东西。
gameboxclient 工作区快照
(未提交状态,git HEAD 仍是更早的旧基线)。
文中每条实现描述都带 file:line,写的时候逐条核对过。
有人提交代码后行号会漂,文件名和函数名仍然有效。
GameBox 是公司内部的游戏配置与发布工具,装在策划、美术、 运营的电脑上。他们每天用它做四件事:
技术上它是一个 Electron 桌面应用: 界面用 Vue 3 写,外壳是 Node.js,还外挂了一堆二进制工具(SVN、Python 脚本、7-Zip 等)。
坏了会怎样
编辑器坏了 →
策划改不了数值,当天的版本内容排期停摆。
发布坏了 →
资源上不去,测试服拿不到新内容,整条链路卡住。
GM 坏了 → 线上玩家问题处理不了,运营直接找你。
换句话说:这个工具没有降级方案。它挂了,相关同事就是完全没法工作。 所以你的第一优先级不是重构,是能快速定位和恢复。
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 加回去。
改动一行,收益是下一个人不用踩这个坑。
# 开发模式:Vite dev server + Electron 一起起来
npm run dev
# 只做类型检查(不构建)
npm run ts:check
# 打生产包
npm run build:pro
npm run dev 实际是 vite --mode base。
vite-plugin-electron 会在 dev server 起来后自动拉起 Electron
(vite.config.ts 的 onstart 里
options.startup(['.', '--no-sandbox']))。 dev server 端口是
4080。
这一步最容易被低估。在这个项目里,登录不只是「进主界面」, 它还负责下发全部外部服务的凭据 —— SVN 账号密码、 Jenkins 地址和 token、GM 接口地址、项目编码。
没登录 = SVN、Jenkins、COS 全是哑的,而且点了不会报错。 完整链路见架构图 FIG.03「钥匙链」。
登录成功后,打开 DevTools 控制台敲这一行确认凭据到位:
JSON.parse(localStorage.getItem('GameENV'))
应该能看到 VITE_SVN_URL、VITE_JENKINS_URL、
VITE_API_BASEPATH 这些键有值。空的就说明服务端没下发,
后面所有外部操作都会静默失败。
⚠️ 先知道这个
这是一个 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/*
出问题时的第一个判断永远是:这是哪个进程的问题? 判断错了,你会在错误的控制台里找一下午。
| 进程 | 跑什么代码 | 怎么看日志 | 典型症状 |
|---|---|---|---|
| 渲染进程 | src/** 全部 |
Shift+Cmd/Ctrl+I 打开 DevTools
(快捷键注册在 electron/main/config/menu.ts 的
debugMenu,由 src/App.vue:50 发
debug IPC 触发注册)
|
页面白屏、按钮点了没反应、请求 404 |
| 主进程 | electron/main/** |
electron-log。注意只在非 development 下才初始化
(handler/ready.ts:24-26), 开发时日志只在启动 Electron 的那个终端里
|
窗口起不来、自动更新失败、IPC 无响应 |
| 子进程 | extend/worker/*.js |
process.send()
把消息发回主进程,主进程再转发到渲染层。
子进程自己的 console 看不到
|
下载/解压进度条卡住不动 |
最快的分诊问题
「这个功能在浏览器里能复现吗?」
如果症状只在打包后的应用里出现、dev 模式正常,那多半是主进程或路径问题
(process.env.DIST、DIST_EXTEND 在
ready.ts:10-20 里按打包与否算了两套值)。
反过来,如果 DevTools 控制台里有红色报错,那就老老实实是渲染层的事, 别去翻主进程。
详细内容在文件结构地图, 这里只给最小必要的四条:
改配置字段 →
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。
src/store/config/Item.ts,照着旁边的字段加一段:
type(String/Number)、summary(界面标签)、
desc(悬浮说明)、必要时 editor 和
options。
npm run dev,登录,选服,进 /game/item,
点进一条数据,确认新字段出现在表单里。
excel_modify 的 payload
带上了新字段。
npm run ts:check,确认错误数没有增加。
src/views/GameEditor/ 下建目录,照抄一个结构最简单的模块
(Box/ 只有 445 行,是个好模板)。
src/router/index.ts 的 /game children
里加路由, meta 至少要有
showMenu: true、title、
icon(iconify 名)。
src/locales/zh-CN.ts 的
router.future 加标题键。
xxx_edit, meta 加
hidden: true 让它不出现在菜单里。
// 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 里一眼看完的。这是唯一能让边界不继续恶化的做法。
npm run ts:check # 错误数不能比改动前多
npm run lint:eslint
ts:check:这个项目没有单元测试,
vue-tsc 是唯一的整体校验。它本身就带着大量历史错误,
所以验收标准是「不新增」而不是「零错误」。
改动前先跑一次记下数字,改完再跑一次对比。
package.json 里
"prepare": "husky install" 和
lint:lint-staged 都指向 .husky/,
但这个目录在当前工作区里已经不存在。别指望自动检查,手动跑。
发布页在 /expert/release(专家模式 → 发布)。 完整分叉见架构图 FIG.05。 这里只讲操作要点。
闸门:只要 Jenkins 上有任何构建在跑,
所有发布卡片都点不动,包括纯本地的 SVN 提交
(views/Option/index.vue:89-111)。
看到「当前有打包任务在进行中」不是 bug,是设计如此。
| SVN 型 | Jenkins 型 | |
|---|---|---|
| 动了什么 | 本地磁盘 + 远端 SVN 仓库 | 远端构建服务器 |
| 有没有确认步骤 | ✅ 有。弹窗列出所有改动文件,可逐个勾选、可单独还原 | ❌ 没有。点了直接触发 |
| 怎么停 | 提交前关掉弹窗即可;提交后只能 svn revert |
Jenkins.stopBuild(jobName, buildNumber),
页面上也有停止入口
|
| 失败了会怎样 | 命令行报错,界面有提示 | 弹「构建失败」,不会自动重试 |
⚠️ 最常见的一类报障
「发布卡在进行中不动了」几乎总是同一个原因: Jenkins 那边早就结束了,客户端的轮询没收到。
轮询是 src/api/login/index.ts:105-107 里一个裸
setInterval,只在拿到明确结束态时才停。 Jenkins
中途不可达、返回结构变了、job 被删了 —— 它都会一直转下去。
处理顺序:
taskStore.reset(),是最快的自救。
下面每一条都是在源码里逐条核对过的,不是猜测。 按「会不会咬到你」排序。
❌ 改错文件
src/config/axios/serviceold.ts 和
src/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.exe 和
extend/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
版本上真的能跑起来。
⚠️ 隔离
渲染层全开 Node 权限,没有 preload。
electron/main/config/options.ts:6-8:
nodeIntegration: true、contextIsolation: false、 webSecurity: false。
vite.config.ts:58-72 把 preload 构建整段注释掉了。
代价是渲染层加载的任何内容都拥有读写整台机器的能力。
短期绝不能动(几百个文件建立在这之上),
但新代码不要继续扩散 @electron/remote。
⚠️ 隔离
凭据明文落在 localStorage。
src/store/modules/GameEvn.ts:44-49 的深度 watch 会把整个
ENV(含
svn_password、jenkins_token) 写进
localStorage 的 GameENV 键。
规范做法是凭据只留主进程,渲染层通过 IPC 请求主进程代为执行, 并用 Electron safeStorage 加密存储。这是你跟安全或运维对话时必须能说清楚的一条。
⚠️ 隔离
generateRoutes() 不做权限过滤。
src/store/modules/permission.ts:37-56 只是
[...DynamicRouterMap] 加一条 404,全部注册。
菜单里藏起来的页面(meta.hidden)不代表无权访问, 手敲 hash
地址照样能进。真正的授权只可能在服务端。
| 问题 | 位置 | 后果 |
|---|---|---|
小窗的 setWindowOpenHandler 解构了不存在的
docUrl(同文件主窗口写的是 url)
|
electron/main/helpers/window.ts:91(对照 48 行)
|
Excel 小窗里点外链,传给 shell.openExternal 的是
undefined
|
smallWindow 一个变量同时当窗口引用和共享数据用 |
helpers/window.ts:71 vs
setSharedData() 103 行
|
调过 setSharedData 后
getSmallWindow() 拿到的不是窗口
|
守卫里 needConfirm 分支调完 next(false)
没有 return
|
src/permission.ts 的 beforeEach |
后续逻辑继续执行并可能再次调 next(),Vue Router
会告警
|
tableConfigMap 里 box: 'Nox',
但配置文件叫 Box.ts
|
src/store/modules/table.ts |
疑似打字错误。先查清有没有代码真的走这条路再改 |
stylelint 同时在 dependencies 和
devDependencies,且前者写着 "latest"
|
package.json |
lint 工具被打进生产包;latest 让依赖树不可复现。
改动风险最低,适合当第一个提交
|
仓库里躺着 hs_err_pid15992.log、
npminstall-debug.log、update.log
|
仓库根目录 |
开发机产生的垃圾文件被提交了(update.log 里能看到路径
E:\project\tool-demo)。应该加进
.gitignore
|
完整清单在功能点清单第四节。
最需要注意的一条:src/views/Database/index.vue
虽然不在路由里,但这个目录之外还有 10 个在用文件引用它。
删任何东西前必须 grep,而且要知道本项目大量使用动态引入 (() => import()、import.meta.glob), 静态分析会漏报 ——
src/store/config/*.ts 尤其危险, 它们没有任何显式
import,全靠 glob 扫进来。
这一节的优先级高于任何技术学习
下面这些问题只能问人,代码里找不到答案。 在拿到答案之前,所有涉及写操作的链路都只做代码追踪, 不要真跑。
/user/info
下发的凭据是按人区分的吗?
extend/Python/ 下那些 exe 还需要 Python
解释器吗?
如果不需要,python.ts 里的 command 拼接就是死代码。
这条影响四条功能链路,优先级最高。
/animation/animate 这个动画编辑器还在用吗?
它有 2585 行代码,但路由写着 showMenu: false,
任何菜单里都到不了。是从别处编程跳转,还是已经废弃?
/base 和
/preload 这两组路由是什么?
在做的新功能,还是废弃的实验?
update.log 里出现的路径 E:\project\tool-demo
说明原开发环境是 Windows。
⚠️ 单独说:Windows 机器
这不是个人偏好问题。把依赖清单里那几行连起来看: SVN 提交、地图转换、动画转换、图片转换、本地预览、打正式包 —— 六项核心职责在 macOS 上全部无法执行。
你可以在 Mac 上完成开发和调试,但无法完整履行这个岗位。 这条应该明确写进你的第一周汇报,越早提越好。
| 手段 | 命令 | 能保证什么 | 不能保证什么 |
|---|---|---|---|
| 类型检查 | npm run ts:check |
没有新增类型错误 | 不保证零错误(本来就有一大堆历史错误); 不检查模板里的类型 |
| ESLint | npm run lint:eslint |
代码风格与部分低级错误 | 不检查业务逻辑 |
| 生产构建 | npm run build:pro |
依赖能解析、能打出包 | 不保证运行时正确 |
| 手动真机验证 | — | 唯一能验证业务正确性的手段 | 覆盖不全,靠人 |
❌ 现状
这个项目没有任何单元测试或集成测试框架。
package.json 里没有 test 脚本,没有 vitest / jest, 没有
__tests__ 目录。
这意味着每一次改动的正确性都只能靠人工点。 接手初期这是最大的风险来源 —— 你改的东西没人告诉你坏了, 直到策划来找你。
可以做的第一步(不需要大改造):给
src/utils/ 下的纯函数补几个 Vitest 用例。 那些函数没有
Electron 依赖,测起来最容易,也最能给你安全感。