Files
36-character-flower/docs/36字花-useGameBoardVm-数据层实施说明.md
JiaJun 6aaf90a6ac docs(game): 添加游戏模块数据
- 新增 useGameBoardVm 数据层实施说明文档
- 添加 36字花核心玩法与前端规则摘要
- 创建游戏模块数据与界面分层第一阶段实施稿
- 定义四层架构:api/dto、store、view-model hooks、ui层
- 规范 PC 与 Mobile 共享业务逻辑的改造方案
- 明确各层职责边界和组件改造顺序
2026-05-09 17:52:30 +08:00

249 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 36字花 useGameBoardVm 数据层实施说明
## 1. 目标
本说明只服务下一步开发:实现 `useGameBoardVm.ts`
当前目标很单一:
- 让桌面选号盘从 store 读取真实业务数据
- 让点击格子时真正触发下注动作
- 不在 [desktop-animal.tsx](/Users/jiaunun/Desktop/36-character-flower/src/features/game/components/desktop/desktop-animal.tsx) 内写业务逻辑
- 不同时改造 mobile
本阶段不做:
- 不改造 mobile
- 不新增 `game-ui-store`
- 不重写 `DesktopAnimal` 整个展示结构
- 不处理 auto-spin / modal
---
## 2. 相关文件
本次只围绕以下文件展开:
- [src/features/game/components/desktop/desktop-animal.tsx](/Users/jiaunun/Desktop/36-character-flower/src/features/game/components/desktop/desktop-animal.tsx)
- [src/features/game/entry/pc-entry.tsx](/Users/jiaunun/Desktop/36-character-flower/src/features/game/entry/pc-entry.tsx)
- [src/store/game/game-round-store.ts](/Users/jiaunun/Desktop/36-character-flower/src/store/game/game-round-store.ts)
- [src/features/game/shared/selectors.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/selectors.ts)
将新增:
- `src/features/game/hooks/use-game-board-vm.ts`
---
## 3. 当前问题
当前 [pc-entry.tsx](/Users/jiaunun/Desktop/36-character-flower/src/features/game/entry/pc-entry.tsx) 里虽然已经挂载了 `DesktopAnimal`,但还没有把桌面主玩法接到业务链路。
当前状态:
- `DesktopAnimal` 只是展示组件
- `DesktopAnimal` 支持 `activeId``onSelect`
- `PcEntry` 直接渲染 `<DesktopAnimal />`
- 点击格子不会写入真实下注状态
结果是:
- 控制栏虽然已经接入了部分业务数据
- 状态栏、历史区也开始接入 store
- 但桌面最核心的“点击动物下注”链路还没有打通
---
## 4. useGameBoardVm 的职责
`useGameBoardVm` 只做 3 件事:
1.`game-round-store` 读取选号盘需要的业务数据
2. 组织出桌面选号盘可以直接消费的 view-model
3. 暴露点击格子的业务动作
它不负责:
- 直接渲染 UI
- 做 hover / 动画状态
- 控制 modal
- 处理移动端布局
---
## 5. 数据来源
`useGameBoardVm` 第一版只从 [game-round-store.ts](/Users/jiaunun/Desktop/36-character-flower/src/store/game/game-round-store.ts) 读取:
- `cells`
- `round`
- `selections`
- `trends`
- `placeBet`
可复用的派生逻辑来自 [selectors.ts](/Users/jiaunun/Desktop/36-character-flower/src/features/game/shared/selectors.ts)
- `buildGameCellViewModels`
---
## 6. 第一版输出字段
第一版不追求一步到位,输出保持最小可用。
建议 `useGameBoardVm` 返回:
```ts
{
cells: GameCellViewModel[]
activeId: number | null
canPlaceBets: boolean
onCellPress: (cellId: number) => void
}
```
### 字段说明
#### `cells`
来源:
- `buildGameCellViewModels({ cells, round, selections, trends })`
作用:
- 给未来第二版 board 组件升级时使用
- 即使第一版 `DesktopAnimal` 还没完全吃它,也应该先在 hook 里产出来
#### `activeId`
第一版定义:
- 当前有下注的最后一个格子 id
- 如果没有任何下注,则为 `null`
作用:
- 兼容当前 [desktop-animal.tsx](/Users/jiaunun/Desktop/36-character-flower/src/features/game/components/desktop/desktop-animal.tsx) 现有接口
- 因为这个组件当前只支持单个 `activeId`,还不支持多个已选格子
#### `canPlaceBets`
定义:
- `round.phase === 'betting'`
作用:
- 控制点击是否真正触发下注
- 也为后续 UI 禁用态预留
#### `onCellPress`
定义:
-`canPlaceBets === true` 时,调用 `placeBet(cellId)`
- 否则不执行
---
## 7. 第一版实现规则
### 7.1 不在 DesktopAnimal 内直接读 store
[desktop-animal.tsx](/Users/jiaunun/Desktop/36-character-flower/src/features/game/components/desktop/desktop-animal.tsx) 必须继续保持展示组件定位。
不应该在里面直接写:
- `useGameRoundStore`
- `placeBet`
- `buildGameCellViewModels`
- `round.phase` 判断
### 7.2 业务写在 hookUI 只接 props
推荐接线方式:
在 [pc-entry.tsx](/Users/jiaunun/Desktop/36-character-flower/src/features/game/entry/pc-entry.tsx) 中:
```tsx
const { activeId, onCellPress } = useGameBoardVm()
<DesktopAnimal activeId={activeId} onSelect={onCellPress} />
```
### 7.3 第一版先兼容现有 DesktopAnimal 接口
当前 `DesktopAnimal` 只支持:
- `activeId?: number | null`
- `onSelect?: (animalId: number) => void`
所以第一版不要强行重做它的 props 结构。
先兼容现状,把业务链路打通即可。
---
## 8. 第一版文件改动范围
本次改动建议控制在 2 到 3 个文件:
1. 新增 `src/features/game/hooks/use-game-board-vm.ts`
2. 修改 [pc-entry.tsx](/Users/jiaunun/Desktop/36-character-flower/src/features/game/entry/pc-entry.tsx)
3. 如有必要,微调 [desktop-animal.tsx](/Users/jiaunun/Desktop/36-character-flower/src/features/game/components/desktop/desktop-animal.tsx)
其中第 3 项不是必须,优先争取只改前两个文件。
---
## 9. 第一版完成标准
完成后应满足:
- `PcEntry` 不再裸挂 `<DesktopAnimal />`
- `PcEntry` 通过 `useGameBoardVm` 把选号盘接到 store
- 点击格子会真实调用下注动作
- 控制栏中的总下注额会随点击变化
- `DesktopAnimal` 仍然保持展示组件定位
---
## 10. 第二版演进方向
第一版做完后,下一版再考虑升级 `DesktopAnimal` 接口。
当前限制:
- `DesktopAnimal` 只能高亮一个 `activeId`
第二版建议升级为:
```ts
{
items: GameCellViewModel[]
onSelect: (cellId: number) => void
}
```
这样就可以支持:
- 多个已下注格子同时高亮
- 依据 `status` 区分 `betting / selected / won / lost`
- PC 和 Mobile 共用同一份 board view-model
但这些都不属于当前这一步。
---
## 11. 结论
当前最正确的操作顺序是:
1. 先写 `useGameBoardVm.ts`
2. 再在 `pc-entry.tsx` 中接入
3. 暂时不把业务写进 `desktop-animal.tsx`
这样可以在最小改动范围内把桌面端最核心的“点击格子下注”链路打通并继续保持“数据层在外、UI 层在内”的改造方向。