This commit is contained in:
ray zhou
2026-06-29 14:51:55 +08:00
parent 225fb2bd28
commit 2dd9f17da9
319 changed files with 29461 additions and 9412 deletions

View File

@@ -0,0 +1,253 @@
<!-- c1c00f01-351c-4b81-9a07-dec92aaf4ae2 -->
---
todos:
- id: "phase0-prep"
content: "Phase 0确认 minus() 死代码、补 PHPDoc、更新 README 入口索引"
status: pending
- id: "phase1-base-query-register"
content: "Phase 1新建 AbstractWalletMutationLogic + WalletQueryLogic + WalletRegisterLogicWalletLogic 委托 register/query"
status: pending
- id: "phase2-bet-win"
content: "Phase 2新建 WalletBetWinLogic迁移 bet/win 及 Redis round 辅助逻辑"
status: pending
- id: "phase3-recharge"
content: "Phase 3新建 WalletRechargeLogic迁移 inc/recharge/reward 与 Trial Pool 充值链"
status: pending
- id: "phase4-withdraw-trial"
content: "Phase 4新建 WalletWithdrawLogic + WalletTrialLogic修复 switchBonus 路由(如需要)"
status: pending
isProject: false
---
# WalletLogic 分阶段拆分方案
## 现状诊断
[`slot-wallet/app/api/logic/WalletLogic.php`](slot-wallet/app/api/logic/WalletLogic.php) 当前 **1885 行**,承担了钱包服务几乎全部资金用例编排:
| 域 | 主要方法 | 约行数 | 已有下沉 |
|---|---|---|---|
| 路由门面 | `run`, `runRechargeOrder`, `ACTION_METHOD_MAP` | ~80 | — |
| 注册 | `register`, `initWalletWithoutMoney` | ~120 | [`RegisterService`](slot-wallet/app/service/wallet/RegisterService.php) |
| 下注/派奖 | `bet`, `win`, pending win Redis, bet split | ~450 | [`BetService`](slot-wallet/app/service/wallet/BetService.php), [`WinService`](slot-wallet/app/service/wallet/WinService.php) |
| 入账/充值 | `inc`, `recharge`, `rechargeSign`, `reward`, Trial Pool | ~400 | [`RechargeFundLotService`](slot-wallet/app/service/wallet/RechargeFundLotService.php) |
| 提现/Bonus 转换 | `withdraw*`, `rollbackWithdraw`, `bonusToDeposit`, `switchBonus` | ~350 | [`WithdrawTaskService`](slot-wallet/app/service/wallet/WithdrawTaskService.php) |
| Trial 体验金 | `grantTrial`, `expireTrial` | ~250 | — |
| 查询 | `query`, `queryBizLog` (static) | ~70 | — |
| 公共能力 | `addLog`, `maxRetry`, `sendConsoleBus`, `getBalance` 等 | ~200 | — |
**问题**:单文件混合 6+ 业务域事务边界、幂等、Redis 辅助状态交织Review 和改动风险都高。
**已有良好先例**:同目录 [`GrantLogic`](slot-wallet/app/api/logic/GrantLogic.php)、[`PlayerTaskLogic`](slot-wallet/app/api/logic/PlayerTaskLogic.php) 已是「一用例一 Logic」核心扣款/派奖细节已在 Service 层Logic 层再拆是合理下一步。
**额外发现**(非本次必做):`minus()` 未出现在 `ACTION_METHOD_MAP` 且无调用方,疑似历史遗留,可在 Phase 0 确认后删除。
---
## 目标架构
```mermaid
flowchart TB
subgraph controller [Controller 不变]
WC[WalletController]
end
subgraph facade [门面层]
WL[WalletLogic]
end
subgraph domain [子 Logic 按域]
WQ[WalletQueryLogic]
WRg[WalletRegisterLogic]
WBw[WalletBetWinLogic]
WRe[WalletRechargeLogic]
WWd[WalletWithdrawLogic]
WTr[WalletTrialLogic]
end
subgraph shared [共享]
Base[AbstractWalletMutationLogic]
end
subgraph service [已有 Service 不动]
BS[BetService]
WS[WinService]
RS[RegisterService]
end
WC --> WL
WL --> WRg & WBw & WRe & WWd & WTr
GrantLogic --> WQ
WL --> WQ
WRg & WBw & WRe & WWd & WTr --> Base
WBw --> BS & WS
WRg --> RS
```
**原则**(对齐 [`backend-layering`](.cursor/rules/backend-layering.mdc)
- **Logic 拆用例、Service 保公共能力**:不再新建「只做 Model 转发」的 Service。
- **WalletLogic 只做分发 + 缓存清理**:保留 `run()` / `runRechargeOrder()` 对外签名;`ACTION_METHOD_MAP` 改为指向子 Logic 方法。
- **Controller 不改**:继续只注入 `WalletLogic`(你已确认)。
- **共享状态收敛**:子 Logic 继承抽象基类,统一持有 `WalletUpdateRequestDTO``rechargeOrderDto` 仅留在 `WalletRechargeLogic`
---
## 共享基类设计
新建 [`slot-wallet/app/api/logic/AbstractWalletMutationLogic.php`](slot-wallet/app/api/logic/AbstractWalletMutationLogic.php)
```php
abstract class AbstractWalletMutationLogic
{
protected WalletUpdateRequestDTO $requestDTO;
/** 绑定本次 mutation 请求上下文 */
protected function bindRequest(WalletUpdateRequestDTO $requestDTO): void { ... }
/** 写 wallet_log、PWA 流水、乐观锁重试、Console Bus 等 */
protected function addLog(...): int { ... }
protected function addTransactionRecord(...): void { ... }
protected function getBalance(WalletAccountModel $model): int { ... }
protected function maxRetry(callable $callback, int $retryCount = 3): WalletEntity { ... }
protected function sendConsoleBus(string $type, int $amount): void { ... }
protected function initWalletWithoutMoney(): ?WalletAccountModel { ... }
}
```
- 从现有 `WalletLogic` **原样迁移**上述 protected/private 方法,避免行为变化。
- 子 Logic 方法签名改为显式接收 DTO 或在门面 `bindRequest()` 后调用,**不再依赖 `$this->requestDTO` 隐式全局状态跨文件散落**。
---
## 子 Logic 划分
| 新类 | 职责 | 从 WalletLogic 迁出的方法 |
|---|---|---|
| `WalletQueryLogic` | 只读查询 | `query`, `queryBizLog` |
| `WalletRegisterLogic` | 注册赠金 | `register` |
| `WalletBetWinLogic` | 游戏下注/派奖编排 | `bet`, `win`, `executeTrialBet/Win`, `executeFreeSpinPaidBet`, pending win / bet split Redis, `getWinAllocationByRound`, `buildBetSplitRemark` |
| `WalletRechargeLogic` | 入账/充值 | `inc`, `executeIncWithTransaction`, `recharge`, `rechargeSign`, `reward`, Trial Pool 扣减链, `resolveRechargeOrderDtoForLots`, `insertRechargeFundLotsIfNeeded` |
| `WalletWithdrawLogic` | 提现与 Bonus 桶转换 | `withdraw`, `withdrawFrozen`, `rollbackWithdraw`, `doneWithdraw`, `bonusToDeposit`, `switchBonus` |
| `WalletTrialLogic` | Trial 体验金生命周期 | `grantTrial`, `expireTrial`, `resolveTrialAmount`, `makeTrialPoolBizId`, `buildTrialPoolRemark`, `deductTrialPoolInRechargeTransaction`(若仍被 Recharge 调用则保留在 Recharge 或抽 `TrialPoolSupport` trait |
**Trial Pool 边界**`planTrialPoolDeductionForRecharge` / `finalizeTrialPoolAfterRechargeInc` 与充值事务强耦合,建议 **Phase 3 随 RechargeLogic 一起迁**Trial 发放/过期独立进 `WalletTrialLogic`
---
## 门面 WalletLogic拆分后 ~150 行)
```php
class WalletLogic
{
public function __construct(
private WalletRegisterLogic $registerLogic,
private WalletBetWinLogic $betWinLogic,
private WalletRechargeLogic $rechargeLogic,
private WalletWithdrawLogic $withdrawLogic,
private WalletTrialLogic $trialLogic,
) {}
public function run(WalletUpdateRequestDTO $requestDTO) { /* 分发 + deleteWalletCache */ }
public function runRechargeOrder(WalletRechargeRequestDTO $dto) { /* 委托 rechargeLogic */ }
// 兼容 GrantLogic / 外部 static 调用
public static function query(...) { return WalletQueryLogic::query(...); }
public static function queryBizLog(...) { return WalletQueryLogic::queryBizLog(...); }
}
```
`ACTION_METHOD_MAP` 改为 **Logic 实例 + 方法名****callable 数组**,例如:
```php
WalletLogModel::BIZ_TYPE_BET => [$this->betWinLogic, 'bet'],
```
Webman DI 需在 [`config/`](slot-wallet/config/) 或现有容器绑定中注册子 Logic若项目无自动注入门面构造函数内 `new` 亦可,与当前 `GrantLogic` 风格一致)。
---
## 分阶段实施(你已选 phased + facade
### Phase 0准备低风险
-`WalletLogic` 现有 public 方法补全/核对中文 PHPDoc拆分时会移动代码趁此对齐 [`php-clean-code`](.cursor/rules/php-clean-code.mdc))。
- 确认 `minus()` 无调用后删除(或加 `@deprecated` 注释待下一版删)。
- 更新 [`README.md`](slot-wallet/README.md)「实现入口」一节,列出子 Logic 索引。
### Phase 1Query + Register + 基类
- 新建 `AbstractWalletMutationLogic``WalletQueryLogic``WalletRegisterLogic`
- `WalletLogic::query/queryBizLog` 改为委托;[`GrantLogic`](slot-wallet/app/api/logic/GrantLogic.php) 可继续 `WalletLogic::query()` 不动。
- `register` 从 WalletLogic 迁出;`run()` 分发到 `WalletRegisterLogic`
- **验收**注册接口、余额查询、Grant 通知链路回归。
### Phase 2BetWin最高复杂度
- 新建 `WalletBetWinLogic`,迁移 `bet`/`win` 及 Redis round 状态方法。
- `WalletController``bet`/`win` 专用入口仍走 `walletLogic->run()`,行为不变。
- **注意**`win()` 内对 `$requestDTO->fee` 的临时修改必须在 BetWinLogic 内用 `try/finally` 保持,避免泄漏到其他域。
- **验收**:下注/派奖、Trial 阶段 bet/win、FreeSpin 代付、中间派奖 `is_end=0`、幂等 hit。
### Phase 3Recharge / Inc
- 新建 `WalletRechargeLogic`,迁移 `inc` 全链路 + `recharge`/`rechargeSign`/`reward`
- `runRechargeOrder` 委托给 RechargeLogic`rechargeOrderDto` 生命周期)。
- **验收**:充值主链路、首充 Trial Pool 扣减、Fund Lot 落库、签到充值 `sign`
### Phase 4Withdraw + Trial
- 新建 `WalletWithdrawLogic``WalletTrialLogic`
- 补齐 `ACTION_METHOD_MAP` 中缺失的 `switchBonus` 映射(若 slot-sdk 仍在调 `type=switchBonus`,当前可能未路由到方法——拆分时可一并修复)。
- **验收**:提现冻结/成功/失败回滚、Bonus 转 Deposit、Trial 发放/过期。
---
## 不建议的做法
- **不要把子用例再拆成 Logic 型 Service**(如 `WithdrawLogicService`),违反分层红线。
- **不要一次性改 Controller 注入多个 Logic**,你已选 facade保持对外稳定。
- **不要把 BetService/WinService 的业务编排再搬回 Logic 后又复制一份**——子 Logic 只做事务、幂等、流水、MQ核心算法继续调用现有 Service。
---
## 预期收益
- 单文件从 ~1900 行降至 **门面 ~150 行 + 各子 Logic 200500 行**
- 改动 bet 不再误触 recharge 事务代码Review 范围清晰。
-`GrantLogic` 风格统一,新人可按域定位代码。
- 对外 API、`WalletLogic::run()` 签名、SDK 调用路径 **零破坏**
---
## 风险与缓解
| 风险 | 缓解 |
|---|---|
| 拆分引入行为回归 | 每 Phase 独立 PR优先复制代码再删旧代码不做顺手重构 |
| `$requestDTO` 可变状态 | 基类 `bindRequest()` + 子 Logic 不跨用例复用实例 |
| Webman 构造注入 | 若无 DIPhase 1 先在 WalletLogic 内 `new` 子 Logic后续再接线 |
| Trial Pool 跨 Recharge/Trial | Phase 3 完成 Recharge 后再动 Trial必要时抽 `TrialPoolDeductionSupport` trait 供 Recharge 专用 |
---
## 涉及文件
**新建**(均在 `slot-wallet/app/api/logic/`
- `AbstractWalletMutationLogic.php`
- `WalletQueryLogic.php`
- `WalletRegisterLogic.php`
- `WalletBetWinLogic.php`
- `WalletRechargeLogic.php`
- `WalletWithdrawLogic.php`
- `WalletTrialLogic.php`
**修改**
- [`WalletLogic.php`](slot-wallet/app/api/logic/WalletLogic.php) — 瘦身为门面
- [`README.md`](slot-wallet/README.md) — 更新入口索引(可选 `.cursor/rules/slot-wallet-prd-and-money.mdc` 一行指向)
**不改**
- [`WalletController.php`](slot-wallet/app/api/controller/WalletController.php)
- 现有 `app/service/wallet/*Service.php`