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