游戏门户是 Qbao 的附属静态站点(形态与下载站 /dl 一致):独立网页 /games/,
与主站同源共享登录状态,按账号保存并隔离游戏数据,为未来联机预留数据层与契约。
tb-pill,侧栏不再重复)。/games/index.html(window.open('...','_blank','noopener'));qbao:open-games IPC 打开独立子窗口(webPreferences 与主窗口一致,含 preload)。aiTaskWorker 执行,浏览器侧轮询在后台标签被节流只会减慢进度刷新,回前台即恢复)。aiTaskQueue 存在 pending/running 任务(与侧栏 AI 行徽标同源)。成绩保存在服务端 user_games_stats(迁移 014):user_id 主键 + data JSONB,按账号强隔离。
| 端点 | 说明 |
|---|---|
GET /api/v1/games |
当前用户全部游戏数据 { data: { [gameId]: { best, level, plays, lastAt } } } |
POST /api/v1/games |
上报/合并单游戏成绩:{ gameId, score?, level?, plays? } |
合并规则(服务端权威,防篡改):
best / level 只升不降(取最大值);plays 每次成功上报至少 +1(上限 100000,仅统计不参与权益);app/src/services/gamesManifest.js 联动(CI 断言防漂移)。前端上报实现:app/public/games/common/qbao-hook.js(游戏页调用
window.__qbaoGame.report(...),3 秒合并窗口后 POST)。钩子仅读取凭据
(网页:同源 localStorage qbao_token 混淆值,只读不写;桌面:既有 qbao:secret-load IPC)。
派对桌游「狼人杀」经开源项目 xiong35/werewolf(MIT, commit 26a77c0) 自托管接入,不依赖任何外部服务:
/games/ 卡片 → /games/werewolf/(与主站同源,Caddy 静态直出 + SPA 兜底)。qbao-werewolf,监听 127.0.0.1:3011):
/games/werewolf/api/* → Caddy uri strip_prefix 剥前缀 → 3011(建房/加入/行动);/games/werewolf/werewolf-ws → 3011 原样透传(不剥前缀,含 Upgrade 头)。user_games_stats、不参与积分(桌游按局结算,后续再议)。party/werewolf/README.md):同源子路径接线、运行时资源前缀、
「Day N」→「第N天」等全中文界面、构建链现代化(Vite 5 + Vue 3 官方插件、TS 4.9)。party/werewolf/README.md(构建、闭包依赖、systemd 均归档在
party/werewolf/deploy/;Caddy 路由片段见 docs/ARCHITECTURE.md §2.4)。后续联机扩展(预留方向不变)——房间制异步对战(复用现有账号体系与 REST,不做 WebSocket, 保持服务器低负载):
user_games_stats 同 schema 族新增 game_rooms(id, owner_id, game_id, state jsonb, rev, created_at)
与 game_moves(room_id, seq, user_id, move jsonb);GET /api/v1/games/rooms/:id;弹猪乐(marble,同学自研微信小游戏 Web 移植,个人授权)是首个打通「游戏 ↔ Qbao 积分」的游戏; 其余游戏仍只记录成绩(user_games_stats),不产生积分。
user_marble_profiles(迁移 017),服务端权威(本地无法篡改/重置刷);游客自动回退 localStorage 本地模式(成绩照常按账号上报 best/plays)。POST /api/v1/games/marble/round/start 扣押珠并由服务端随机倍率(×2/×3/×5/×10)与亮灯槽位 → 客户端做物理表现 → round/result 上报落槽,服务端判定输赢。user_marble_rounds 保证单开一局(防双重结算/重放),10 分钟未结算自动退回押珠。marble_in / marble_diamond_out;弹珠不可兑积分、积分不可购钻石;GET /points/rules 与积分页自动展示新规则。routes/marble.routes.js、services/marbleService.js、schemas/marble.schema.js、config/points.js(MARBLE_* 常量)、迁移 sql/017_v3.40_marble.sql;客户端 app/public/games/marble/(webwx.js 适配层/云桥 + 上游 game.js 补丁,见 marble/SOURCE.md(移植补丁清单;上游只读镜像 party/marble-wx-game/ 已于 2026-09 移除);测试 server/test/marble.routes.test.js(25 例,假池;全量 228 例)。长线观察项:user_games_stats 单行 JSONB 体积随游戏数增长,警戒线为单行 >64KB (当前 6 款 × 4 字段远低于此,狼人杀为联机桌游不写成绩;弹猪乐另有独立钱包表 user_marble_profiles,不占本表;超限时拆列为游戏独立列)。
配合 docs/ENVIRONMENTS.md(L0/L1/L2 概念)与 docs/DEVELOPMENT_FLOW.md(流程纪律)。 占位符说明:{BETA_HOST}=内测域名、{DOMAIN}=生产入口;真实值见本机 local/ENV.md。
?qa=1&token=)仅在 {BETA_HOST} 与 localhost/127.0.0.1 主机名放行;生产主机名({DOMAIN})代码层忽略。门禁纯函数与单测:app/src/games/qa-gate.js(qaAllowedByHost);移植新游戏时把同一逻辑内联进其适配层,注释互指(与 secureStore 两端同步模式一致)。http://127.0.0.1:8124/games/ 静态调试(访客本地模式 + localhost QA 钩子;静态根为 app/public,游戏入口在 games/index.html;与 ENVIRONMENTS.md 的写法保持一致);scripts/qa/smoke-stage.ps1 -Env beta|prod,游戏专项断言随接入补齐(弹猪乐 API E2E 为样板)。server/sql/ 编号迁移(先内测库、验收后生产库);gameId 白名单更新须同时改 games.schema 与 gamesManifest(CI 断言防漂移)。