# FC Minigame 技术归档

归档日期：2026-06-26  
适用范围：`frontend-h5`、`frontend-large`、`backend`、互动游戏资源与运行流程  
文档目的：归档 Vue 前端项目、Rust 后端服务、Socket.IO 互动游戏的完整技术、业务、配置、运维信息，防止项目信息遗忘、资源丢失，为后期页面维护、功能迭代、问题排查、样式兼容优化提供技术依据。

## 1. 项目总览

本项目是一个多端互动小游戏系统，包含：

| 模块 | 目录 | 说明 |
| --- | --- | --- |
| H5 玩家端 | `frontend-h5` | 手机端游戏入口，负责玩家登录参数读取、入房、游玩、提交分数、展示个人结果 |
| 大屏/管理端 | `frontend-large` | 大屏展示与管理员控制端，负责登录、创建房间、开始游戏、排行榜展示、关闭房间 |
| 后端服务 | `backend` | Rust 服务，提供 HTTP 管理接口、Socket.IO 实时通信、房间状态、排行榜、数据库落库 |
| 素材资源 | `frontend-h5/src/assets/images`、`frontend-large/src/assets/images` | 各游戏背景、动画帧、音频、二维码、排行榜装饰图等 |

整体交互模型：

1. 管理端登录后建立 Socket.IO 管理员连接。
2. 管理员选择游戏并创建房间。
3. 玩家从 H5 链接携带身份参数进入对应游戏页，建立 Socket.IO 玩家连接并加入当前房间。
4. 管理端开始游戏，后端广播开始事件。
5. 玩家端本地运行游戏逻辑并持续/最终提交分数。
6. 后端维护内存房间状态和排行榜，结束后写入数据库。
7. 管理端与玩家端展示排行或结算结果。

## 2. 技术栈

### 2.1 前端公共技术

| 类型 | 技术 |
| --- | --- |
| 框架 | Vue 3 |
| 构建工具 | Vite |
| 语言 | TypeScript、Vue SFC |
| 路由 | vue-router，Hash 模式 |
| 实时通信 | socket.io-client |
| 二进制协议 | `@msgpack/msgpack` |
| 加密 | crypto-js |
| 调试 | H5 使用 vConsole，大屏端使用浏览器控制台 |
| 包管理 | 仓库同时存在 `package-lock.json` 和 `pnpm-lock.yaml`，现有脚本以 npm 命令为主 |

### 2.2 后端技术

| 类型 | 技术 |
| --- | --- |
| 语言 | Rust 2024 edition |
| HTTP 框架 | Salvo |
| 实时通信 | socketioxide |
| 异步运行时 | Tokio |
| 数据库 | sqlx，支持 PostgreSQL 与 MySQL |
| 序列化 | serde、serde_json、rmp-serde |
| 静态资源嵌入 | rust-embed，debug 模式挂载 `backend/src/web` |
| 跨域 | tower-http `CorsLayer::permissive()` |

## 3. 目录结构

```text
fc_minigame/
  backend/
    Cargo.toml
    config.json
    deploy/
      game.sql
      game_mysql.sql
    src/
      main.rs
      router.rs
      commons/
      db/
      protocols/
      web/
  frontend-h5/
    package.json
    vite.config.ts
    src/
      router/
      commons/
      composables/
      pages/game1..game6/
      assets/images/
  frontend-large/
    package.json
    vite.config.ts
    src/
      router/
      commons/
      composables/
      pages/game1..game6/
      assets/images/
  docs/
    TECHNICAL_ARCHIVE.md
```

说明：

- `node_modules`、`backend/target` 是本地构建产物或依赖目录，不应作为业务维护入口。
- 两套前端代码结构高度相似，但面向角色不同：H5 是玩家端，大屏端是管理员/展示端。
- `backend/src/web` 是后端 debug 模式下可挂载的测试页面和第三方前端库，不是主业务前端。

## 4. 前端归档

### 4.1 H5 玩家端 `frontend-h5`

入口：

- `src/main.ts`：Vue 应用入口。
- `src/App.vue`：根组件。
- `src/router/index.ts`：路由配置。

路由：

| 路径 | 页面 | 说明 |
| --- | --- | --- |
| `/loading` | `pages/Loading.vue` | 加载页 |
| `/game1` | `pages/game1/Game.vue` | 游戏 1 |
| `/game2` | `pages/game2/Game.vue` | 游戏 2 |
| `/game3` | `pages/game3/Game3.vue` | 游戏 3 |
| `/game4` | `pages/game4/Game4.vue` | 游戏 4 |
| `/game5` | `pages/game5/Game5.vue` | 游戏 5 |
| `/game6` | `pages/game6/Game.vue` | 游戏 6 |

关键公共模块：

| 文件 | 作用 |
| --- | --- |
| `src/commons/ws.ts` | Socket.IO 初始化、MsgPack 编解码、消息发送与订阅 |
| `src/composables/useGameSocket.ts` | 玩家端房间协议封装：入房、开始、恢复、排名、提交分数 |
| `src/commons/utils.ts` | localStorage、URL 参数、Toast、Confirm、微信/用户参数读取、外部分数上报 |
| `src/commons/assets.ts` | 图片/音频资源 URL 生成，支持本地资源和 OSS/CDN 资源 |
| `src/commons/music.ts` | 音频播放相关工具 |
| `src/commons/debug.ts` | 调试相关工具 |

H5 用户参数：

玩家端通过 URL Query 读取：

| 参数 | 用途 |
| --- | --- |
| `token` | 原始授权 token，用于后续外部接口上报 |
| `nickname` | 玩家昵称 |
| `avatar` | 玩家头像 |
| `userno` | 玩家唯一标识，代码中会作为 Socket 鉴权 `userid` |

当处于 debug 模式时，H5 会生成模拟玩家信息，便于本地调试。

### 4.2 大屏/管理端 `frontend-large`

入口：

- `src/main.ts`：Vue 应用入口。
- `src/App.vue`：根组件。
- `src/router/index.ts`：路由配置。

路由：

| 路径 | 页面 | 权限 |
| --- | --- | --- |
| `/` | 重定向 | 有 token 到 `/main`，否则到 `/login` |
| `/login` | `pages/Login.vue` | 无需登录 |
| `/main` | `pages/Main.vue` | 需要管理员 token |
| `/game1` 到 `/game6` | 对应大屏游戏页 | 需要管理员 token |

关键公共模块：

| 文件 | 作用 |
| --- | --- |
| `src/composables/useAdminGameSocket.ts` | 管理端 Socket 协议封装：房间状态、建房、回退、开始、关房、排行榜 |
| `src/commons/ws.ts` | Socket.IO 初始化、MsgPack 编解码、连接复用与关闭 |
| `src/commons/utils.ts` | localStorage、登录态、通知、Toast、Confirm、运行模式工具 |
| `src/commons/assets.ts` | 素材 URL 统一生成 |
| `src/commons/player.ts` | 玩家展示相关逻辑 |
| `src/components/DesignStage.vue` | 大屏适配容器 |

管理员登录态字段存储在 localStorage：

| 字段 | 来源 | 说明 |
| --- | --- | --- |
| `token` | `/manager/login` | 管理员 token |
| `passphrase` | `/manager/login` | AES 加密短语，用于 Socket 鉴权 |
| `socket_path` | `/manager/login` | Socket.IO path |
| `client_ns` | `/manager/login` | Socket.IO namespace |
| `domain` | 前端逻辑写入 | 连接域名，开发时可为空或本地域名 |

### 4.3 前端资源策略

两套前端都使用 `src/commons/assets.ts` 生成资源 URL。

资源路径规则：

| 场景 | 行为 |
| --- | --- |
| 开发环境 | 默认读取 `/src/assets/images/...` |
| 生产环境且配置 `VITE_ASSET_BASE_URL` | 读取 OSS/CDN 资源 |
| 生产环境未配置 OSS/CDN | 读取构建产物中的 `/assets/images/...` |
| `VITE_ASSET_BUILD_LOCAL=true` | 强制把 `src/assets/images` 复制到 `dist/assets/images` |

相关环境变量：

| 变量 | 说明 |
| --- | --- |
| `VITE_ASSET_BASE_URL` | 生产静态资源基础路径 |
| `VITE_ASSET_DEV_LOCAL` | 开发环境是否优先本地资源，`false` 时可直接测试 OSS/CDN |
| `VITE_ASSET_BUILD_LOCAL` | 是否构建本地资源包 |

当前已见配置：

- H5 生产资源前缀：`https://xjfcoss.guocai365.org.cn/games/h5/assets/images/`
- 大屏生产资源前缀：`https://xjfcoss.guocai365.org.cn/games/pc/assets/images/`

注意：

- 修改素材文件后，如走 OSS/CDN，需要同步上传远程资源。
- 如走本地资源构建，需要使用 `build:local` 或设置 `VITE_ASSET_BUILD_LOCAL=true`。
- 音频文件也放在 `assets/images` 下，资源工具同样适用。

## 5. 前端构建与运行

### 5.1 H5

```bash
cd frontend-h5
npm install
npm run dev
npm run build:oss
npm run build:local
npm run preview
```

脚本说明：

| 脚本 | 说明 |
| --- | --- |
| `dev` | 启动 Vite 开发服务 |
| `build:oss` | 类型检查后按 production 模式构建，优先使用 OSS/CDN 资源 |
| `build:local` | 类型检查后按 local-assets 模式构建，并打包本地素材 |
| `preview` | 预览生产构建 |
| `serve:local` | H5 特有，`vite preview --host 0.0.0.0` |
| `type-check` | `vue-tsc --build` |

H5 Vite 配置要点：

- 开发代理 `/socket.io` 与 `/manager` 到 `http://localhost:8082`。
- 使用 `@vitejs/plugin-basic-ssl`，开发服务可支持 HTTPS。
- build 时 `base` 为 `/h5/`。
- build 时注入 `__APP_DOMAIN__ = https://hddp.guocai365.org.cn`。
- serve 时注入 `__DEBUG__ = true`。

### 5.2 大屏/管理端

```bash
cd frontend-large
npm install
npm run dev
npm run build:oss
npm run build:local
npm run preview
```

大屏 Vite 配置要点：

- 开发代理 `/socket.io` 与 `/manager` 到 `http://localhost:8082`。
- build 时当前 `base` 为 `/`。
- build 时注入 `__APP_DOMAIN__ = https://hddp.guocai365.org.cn`。
- 支持 OSS/CDN 或本地素材两种构建方式。

### 5.3 Node 版本要求

两个前端项目 `package.json` 中均要求：

```text
node ^20.19.0 || >=22.12.0
```

建议归档锁定：

- Node：20.19+ 或 22.12+
- npm：随 Node 安装版本即可
- TypeScript：项目依赖约束为 `~6.0.0`

## 6. 后端归档

### 6.1 后端入口

| 文件 | 作用 |
| --- | --- |
| `src/main.rs` | 初始化数据库、配置路由、启动 Salvo HTTP 服务 |
| `src/router.rs` | HTTP 路由、Socket.IO layer、404/405 处理 |
| `src/protocols/socket_io.rs` | 核心业务协议、房间状态机、管理员/玩家 Socket 消息处理 |
| `src/commons/config.rs` | `config.json` 配置加载 |
| `src/commons/utils.rs` | AES 加解密、时间工具、全局配置 |
| `src/db/mod.rs` | 数据库驱动选择与统一查询入口 |
| `src/db/pg.rs` | PostgreSQL 驱动 |
| `src/db/mysql.rs` | MySQL 驱动 |
| `src/db/models/*` | 房间、游戏成绩、日志、管理员模型 |

### 6.2 后端启动

```bash
cd backend
cargo run
```

发布构建：

```bash
cd backend
cargo build --release
```

Linux musl 目标构建备注：

```bash
cargo zigbuild --release --target x86_64-unknown-linux-musl
```

`Cargo.toml` 中二进制名：

```text
hddpServer
```

### 6.3 后端配置

后端启动时读取 `backend/config.json`。如果文件不存在，会生成默认配置并 panic，提示配置后再运行。

配置字段：

| 字段 | 说明 |
| --- | --- |
| `host` | 服务监听地址，例如 `0.0.0.0:8082` |
| `client_ns` | Socket.IO namespace，默认 `/ws` |
| `socket_path` | Socket.IO path，默认 `/socket.io` |
| `aes_passphrase` | 管理员 Socket 鉴权用 AES 短语, ***发生泄漏时请更改配置及管理员登录密码token等信息*** |
| `db.kind` | 数据库类型，支持 `postgresql`、`mysql` |
| `db.uri` | 数据库连接串 |


### 6.4 HTTP 接口

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| POST | `/manager/login` | 管理员登录，返回 token、passphrase、socket_path、client_ns |
| POST | `/manager/getConn` | 获取 Socket 连接配置 |
| POST | `/manager/getTop10Rank` | 根据 `batch_no` 查询历史前十排行榜 |
| GET | `/socket.io` | Socket.IO path，由 socketioxide layer 接管 |
| GET | `/web/{path}` | debug 模式挂载 `backend/src/web` 静态测试页 |

统一响应形态：

```json
{
  "state": 1,
  "msg": "",
  "data": {}
}
```

失败响应：

```json
{
  "state": 0,
  "msg": "错误信息",
  "data": null
}
```

### 6.5 数据库

初始化 SQL：

- PostgreSQL：`backend/deploy/game.sql`
- MySQL：`backend/deploy/game_mysql.sql`

数据表：

| 表 | 说明 |
| --- | --- |
| `tb_room` | 游戏房间批次记录 |
| `tb_game` | 玩家游戏成绩记录 |
| `tb_log` | 后端错误日志 |
| `tb_manager` | 管理员账号与 token |

`tb_room` 关键字段：

| 字段 | 说明 |
| --- | --- |
| `batch_no` | 批次号，主键 |
| `item_num` | 游戏编号，1 到 6 |
| `player_count` | 房间人数 |
| `create_date` | 创建时间 |

`tb_game` 关键字段：

| 字段 | 说明 |
| --- | --- |
| `wechat_id` | 玩家原始身份 token 或微信标识 |
| `nickname` | 昵称 |
| `avatar` | 头像 |
| `game_rank` | 排名 |
| `item_num` | 游戏编号 |
| `score` | 分数 |
| `create_date` | 创建时间 |
| `batch_no` | 所属房间批次 |

默认管理员初始化 SQL：

```sql
INSERT INTO tb_manager(username, password/token字段, token)
VALUES ('admin', '123456', '88236aeb-8d3f-6d56-fdf5-3adca3961dfb');
```

注意：PostgreSQL 与 MySQL 对 `password` 字段转义方式不同，以各自 SQL 文件为准。

## 7. Socket.IO 互动协议

### 7.1 连接参数

Socket.IO 统一配置：

| 参数 | 值 |
| --- | --- |
| path | `/socket.io` |
| namespace | `/ws` |
| transports | `['websocket']` |
| upgrade | `false` |
| timeout | `10000` ms |
| payload 编码 | MsgPack |

前端发送消息：

```ts
socket.send(encode({ cmd, data }))
```

后端响应事件：

```json
{
  "state": 1,
  "msg": "",
  "data": {}
}
```

所有后端业务响应都通过 MsgPack 编码后按事件名 emit。

### 7.2 管理员 Socket 鉴权

管理员连接 `auth`：

| 字段 | 说明 |
| --- | --- |
| `userid` | 管理员 token |
| `validuser` | `CryptoJS.AES.encrypt(token, passphrase).toString()` |

后端校验：

1. 解密 `validuser`。
2. 解密结果必须等于 `userid`。
3. 使用 token 查询 `tb_manager`。
4. 同一时间只允许一个管理员在线；新管理员登录会顶掉旧管理员。

### 7.3 玩家 Socket 鉴权

玩家连接 `auth`：

| 字段 | 说明 |
| --- | --- |
| `userid` | 玩家唯一标识，H5 中来自 `userno` |

玩家不使用 `validuser` 字段。若没有管理员在线，后端允许连接记录但返回 `connect_result` 失败，提示房间未开启。

### 7.4 管理端命令

| cmd | data | 说明 | 主要响应事件 |
| --- | --- | --- | --- |
| `room_state` | `{}` | 获取当前房间状态 | `room_state_result` |
| `room_create` | 游戏序号数字，如 `1` | 创建游戏房间，进入 Loading 状态 | `room_create_result` |
| `room_back` | 游戏序号数字 | 回到指定游戏 Loading 状态 | `room_back_result` |
| `game_start` | 游戏 ID 字符串，如 `game1` | 开始当前游戏 | `game_start_result` |
| `room_rank` | `{}` | 获取当前排行榜 | `room_rank_result` |
| `room_close` | `{}` | 关闭房间，断开玩家连接 | `room_close_result` |

### 7.5 玩家端命令

| cmd | data | 说明 | 主要响应事件 |
| --- | --- | --- | --- |
| `room_join` | `{ nickname, token, avatar, gameId }` | 玩家加入房间 | `room_join_result`、`room_recover_result`、`room_rank_result` |
| `submit_score` | `{ score }` | 游戏中提交/刷新分数 | `submit_score_result` |
| `submit_score_save` | `{ item_num, wechat, nickname, avatar, rank, score }` | 结算后保存成绩到数据库 | `submit_score_save_result` |

### 7.6 后端主动事件

| event | 接收端 | 说明 |
| --- | --- | --- |
| `connect_result` | 玩家端 | 连接失败或无管理员时提示 |
| `login_result` | 管理端 | token 失效或管理员登录异常 |
| `new_admin_result` | 管理端 | 被其他管理员登录顶下线 |
| `room_join_result` | 管理端、玩家端 | 玩家入房或房间人数/列表变化 |
| `room_recover_result` | 玩家端 | 玩家断线重连后恢复游戏状态 |
| `game_start_result` | 管理端、玩家端 | 游戏开始 |
| `submit_score_result` | 玩家端 | 当前玩家分数/名次结果 |
| `submit_score_save_result` | 玩家端 | 成绩保存结果和最终排行榜 |
| `room_rank_result` | 管理端、玩家端 | 排行榜 |
| `room_close_result` | 管理端、玩家端 | 房间关闭 |
| `player_offline_result` | 管理端 | 玩家离线通知，当前代码中部分广播逻辑保留但未启用 |

## 8. 房间状态与游戏流程

### 8.1 房间状态

后端内存状态 `RoomStatus`：

| 状态 | 数值 | 说明 |
| --- | --- | --- |
| `Closed` | 0 | 房间关闭 |
| `Loading` | 1 | 已创建房间，等待玩家加入 |
| `Running` | 2 | 游戏进行中 |
| `Submit` | 3 | 分数提交/结果等待阶段 |
| `Ended` | 4 | 游戏结束 |

### 8.2 时间控制

后端常量：

| 常量 | 值 | 说明 |
| --- | --- | --- |
| `ROOM_ENTRY_LIMIT` | 20 | 等待阶段最多展示前 20 个入房玩家 |
| `ROOM_SCORE_RANK_LIMIT` | 10 | 结算排行榜前 10 |
| `GAME_START_COUNTDOWN_SECS` | 3 | 开始倒计时 |
| `GAME_RESULT_WAIT_SECS` | 2 | 结果等待时间 |
| `GAME_RUNNING_SECS` | 60 | 游戏运行时间 |
| `ADMIN_ABSENT_DEACTIVATE_PLAYER_SECS` | 300 | 管理员离线后玩家连接失效等待 |

### 8.3 排行规则

后端规则：

- 分数越高排名越靠前。
- 分数相同时按玩家标识排序。
- 只取前 10 名作为最终榜单展示。
- 已进入历史前十的玩家，本轮不再进入可领奖前十展示。
- `submit_score_save` 落库时使用后端内存中的分数与排名为准，避免客户端篡改最终排名。

### 8.4 房间生命周期

```text
Closed
  -> 管理员 room_create
Loading
  -> 玩家 room_join
  -> 管理员 game_start
Running
  -> 玩家 submit_score
  -> 后端 60 秒倒计时
Submit
  -> 玩家 submit_score_save
  -> 后端推送排行榜
Ended
  -> 管理员 room_close 或重新创建房间
Closed
```

## 9. 游戏清单

代码中存在 6 个游戏，H5 和大屏均有对应页面。

| 编号 | ID | H5 页面 | 大屏页面 | 备注 |
| --- | --- | --- | --- | --- |
| 1 | `game1` | `frontend-h5/src/pages/game1/Game.vue` | `frontend-large/src/pages/game1/Game.vue` | 素材目录 `game1` |
| 2 | `game2` | `frontend-h5/src/pages/game2/Game.vue` | `frontend-large/src/pages/game2/Game.vue` | 素材目录 `game2` |
| 3 | `game3` | `frontend-h5/src/pages/game3/Game3.vue` | `frontend-large/src/pages/game3/Game3.vue` | 素材目录 `game3` |
| 4 | `game4` | `frontend-h5/src/pages/game4/Game4.vue` | `frontend-large/src/pages/game4/Game4.vue` | 素材目录 `game4` |
| 5 | `game5` | `frontend-h5/src/pages/game5/Game5.vue` | `frontend-large/src/pages/game5/Game5.vue` | 素材目录 `game5` |
| 6 | `game6` | `frontend-h5/src/pages/game6/Game.vue` | `frontend-large/src/pages/game6/Game.vue` | 素材目录 `game6` |

后端历史注释中的游戏中文名映射：

| ID | 名称 |
| --- | --- |
| `game1` | 击鼓齐福 |
| `game2` | 聚宝接福 |
| `game3` | 马上有福 |
| `game4` | 策马迎福 |
| `game5` | 圈彩纳福 |
| `game6` | 福运当头 |

外部分数上报中曾出现的游戏代码：

| 游戏 | code |
| --- | --- |
| 击鼓齐福 | `JGQF` |
| 聚宝接福 | `JBJF` |
| 马上有福 | `MSYF` |
| 策马迎福 | `CMYF` |
| 圈彩纳福 | `QCNF` |
| 福运当头 | `FYDT` |

H5 成绩保存成功后，若存在原始 token，会调用外部接口：

```text
POST https://api.guocai365.org.cn/api/offline_clearance/user/screen_game_score
Authorization: 玩家原始 token
Content-Type: application/json
```

请求体字段：

| 字段 | 说明 |
| --- | --- |
| `game_code` | 游戏代码 |
| `score` | 分数 |
| `batch_no` | 当前批次号 |
| `rank_no` | 排名 |

## 10. 部署与运维

### 10.1 推荐部署顺序

1. 准备数据库，执行对应 SQL。
2. 准备 `backend/config.json`，确认 `host`、`client_ns`、`socket_path`、`aes_passphrase`、数据库连接。
3. 构建并启动后端，确认 `http://host:port` 可访问。
4. 构建 H5 前端。
5. 构建大屏/管理端。
6. 上传或同步 `assets/images` 素材到 OSS/CDN，或使用本地资源构建。
7. 配置 Nginx/网关：
   - H5 静态目录。
   - 大屏静态目录。
   - `/manager/*` 反向代理到后端。
   - `/socket.io` 反向代理到后端并支持 WebSocket Upgrade。
8. 用管理端登录创建房间。
9. 用 H5 测试链接进入房间，验证入房、开始、提交分数、排行榜、落库。

### 10.2 Nginx 代理要点

必须保证：

- `/socket.io` 代理到后端 `host`。
- 代理支持 WebSocket。
- `client_ns` 保持 `/ws`。
- H5 构建 `base` 当前为 `/h5/`，部署路径应匹配。
- 大屏构建 `base` 当前为 `/`，如部署到子路径需要同步调整 Vite `base` 与路由资源路径。

WebSocket 代理关键头：

```nginx
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
```

### 10.3 上线检查清单

| 检查项 | 说明 |
| --- | --- |
| 后端端口 | `config.json.host` 与网关代理一致 |
| Socket path | 前端、后端、Nginx 均为 `/socket.io` |
| namespace | 前端、后端均为 `/ws` |
| AES 短语 | 后端 `aes_passphrase` 与登录返回一致 |
| 数据库 | `tb_manager` 有管理员账号，`tb_game` 可写入 |
| 素材 | OSS/CDN 路径或本地 `dist/assets/images` 可访问 |
| H5 URL 参数 | `token`、`nickname`、`avatar`、`userno` 完整 |
| 排行榜 | 管理端和玩家端均能收到 `room_rank_result` |
| 外部接口 | H5 可访问 `api.guocai365.org.cn` 成绩上报接口 |

## 11. 排障指南

### 11.1 管理端登录失败

检查：

- `/manager/login` 是否 200。
- `tb_manager` 是否存在对应账号。
- 后端 `config.json` 是否配置数据库。
- `aes_passphrase` 是否为空；为空时登录接口会失败。
- 浏览器 localStorage 中旧 token 是否需要清理。

### 11.2 Socket 连接失败

检查：

- 浏览器 Network 中 `/socket.io` 是否 101 或 WebSocket 连接成功。
- Vite 开发代理是否指向 `http://localhost:8082`。
- 生产 Nginx 是否支持 WebSocket Upgrade。
- 前端 `socket_path` 与后端 `config.socket_path` 是否一致。
- 前端 `client_ns` 与后端 `config.client_ns` 是否一致。

### 11.3 玩家提示房间未开启

可能原因：

- 管理端未登录或管理员 Socket 已断开。
- 管理端未创建房间。
- H5 进入的 `gameId` 与当前房间 `current_game_id` 不一致。
- 管理员离线超过保护时间，后端已将玩家连接标记失效。

### 11.4 排行榜不更新

检查：

- 玩家是否成功发送 `submit_score`。
- 后端房间状态是否为 `Running` 或 `Submit`。
- 管理端是否订阅 `room_rank_result`。
- 玩家是否已经进入历史前十，导致本轮不再进入可领奖榜单。
- 分数相同时排序会按玩家标识兜底，可能看起来顺序固定。

### 11.5 成绩未落库

检查：

- H5 是否发送 `submit_score_save`。
- 后端数据库连接是否正常。
- `tb_game` 表结构是否已初始化。
- `submit_score_save` 必需字段是否完整：`item_num`、`wechat`、`nickname`、`avatar`、`rank`、`score`。
- 后端会用内存中的 server_score/server_rank 覆盖客户端上报结果，排查时应看后端状态而不是只看前端 payload。
- 如插入失败，后端会尝试写 `tb_log`。

### 11.6 素材加载失败

检查：

- 当前构建是 `build:oss` 还是 `build:local`。
- `VITE_ASSET_BASE_URL` 是否指向正确目录。
- OSS/CDN 是否存在对应文件。
- 文件大小写是否一致，Windows 本地不敏感，Linux/OSS 通常敏感。
- H5 的 build base 是 `/h5/`，资源相对路径需匹配部署路径。

### 11.7 中文显示乱码

源码中部分历史中文注释或字符串显示为乱码，可能是历史编码保存问题。维护时建议：

- 不要批量自动转码整个仓库，避免引入大规模 diff。
- 只在需要改动的文件中逐段确认编码和运行表现。
- 用户可见文案优先通过浏览器实际页面确认，不只看源码显示。

## 12. 后续维护建议

### 12.1 新增游戏

需要同步修改：

1. H5 新增 `src/pages/gameN`。
2. 大屏新增 `src/pages/gameN`。
3. 两端路由新增 `/gameN`。
4. 两端素材目录新增 `assets/images/gameN`。
5. 后端允许 `item_num` 范围或 SQL check 约束扩展。
6. 后端游戏名映射扩展。
7. 外部分数上报 code 映射扩展。
8. 管理端主页面游戏入口扩展。
9. OSS/CDN 上传新增素材。

### 12.2 修改游戏时长

后端统一控制：

- `GAME_RUNNING_SECS`
- `GAME_START_COUNTDOWN_SECS`
- `GAME_RESULT_WAIT_SECS`

前端如果有本地倒计时、动画节奏或结算弹窗，也必须同步调整，否则会出现前后端状态不一致。

### 12.3 修改排行榜规则

重点文件：

- `backend/src/protocols/socket_io.rs`
- `frontend-h5/src/composables/useGameSocket.ts`
- `frontend-large/src/composables/useAdminGameSocket.ts`

需要确认：

- 前 10 名限制。
- 已上榜玩家是否可重复上榜。
- 同分排序规则。
- 玩家个人排名和大屏展示排名是否一致。
- `tb_game.game_rank` 落库规则是否同步。

### 12.4 修改部署路径

需要同步：

- H5 `vite.config.ts` 中 `base`。
- 大屏 `vite.config.ts` 中 `base`。
- Nginx 静态路径。
- OSS/CDN `VITE_ASSET_BASE_URL`。
- H5 分享/入口链接。
- 大屏登录和管理入口。

## 13. 重要风险记录

| 风险 | 说明 | 建议 |
| --- | --- | --- |
| 配置含敏感信息 | `backend/config.json` 可能包含数据库账号和 AES 短语 | 生产配置单独托管，不公开 |
| 内存房间状态 | 房间状态在后端进程内存中，服务重启会丢失当前房间 | 活动前避免重启，必要时设计持久化 |
| 单管理员限制 | 后端只允许一个管理员在线 | 多人运维时约定唯一控制端 |
| 素材体积大 | 游戏动画帧、音频较多 | 上线前确认 CDN 缓存、首屏加载和移动端流量 |
| 锁文件并存 | npm 与 pnpm 锁文件同时存在 | 后续维护固定一种包管理器，避免依赖漂移 |
| 编码历史问题 | 部分中文注释/文案显示乱码 | 小范围修复，避免批量误伤 |

## 14. 归档结论

本项目核心是“管理端控制房间 + H5 玩家互动 + Rust 后端实时排行与落库”的活动型小游戏系统。后续维护最重要的边界是：

- 页面样式与游戏交互在两套 Vue 前端中维护。
- 房间状态、排行、管理员唯一在线、成绩落库在后端维护。
- 前后端实时协议统一使用 Socket.IO + MsgPack。
- 素材资源由 `assetUrl/cssAssetUrl` 统一管理，可走 OSS/CDN 或本地打包。
- 生产配置、数据库和 OSS/CDN 路径是运维交接重点，需单独安全保管。
