## 周返水(Weekly Cashback)实现方案 ### 已定决策(来自本轮确认) - 二、三:按评审意见修订需求文档、计费/配置与每日返水解耦。 - 四:方案 B —— 周有效投注每日落库,规避 `user:profit:Ymd` 的 7 天 TTL。 - 五.1:VIP 费率存活动配置 `ext_config.vip_rates`(type=13),不放 VIP 表。 - 五.2:VIP 取「周末最后一刻」(结算下周一读当前 VIP 即可)。 - 五.3:结算上周的同时把「上上周」未领取的置过期。 - 五.4:VIP0 不进页面,不处理。 - 五.5/6/7:倒计时对齐周界;四周记录入库;返水 `floor` 取整到厘。 ### 计费模型(与每日返水的关键差异) - 每日返水 = 下注累进分段(`tiers`);周返水 = `周有效投注 × rate(vip%)` 单乘,按 `floor` 取整。 - 统计周:周一 00:00:00 ~ 周日 23:59:59,**服务器时区**(统一口径,修订文档里"美国时间"表述)。 - 周有效投注 = 当周 7 天 `rebate_bet` 之和(仅充值用户累加,沿用 `slot_pwa` 现有口径,pwa 无需改动)。 ### 数据流 ```mermaid flowchart TD pwa["slot_pwa incBet 仅充值用户累加 rebate_bet"] --> redis["redis user:profit:Ymd TTL7天"] accrue["weeklyRebateAccrue 每天00:05 处理昨日"] --> redis accrue --> rec["weekly_rebate_record 当周Pending bet_amount累加"] settle["weeklyRebateSettle 周一00:15"] --> rec settle --> vip["读当前VIP rate=vip_rates level"] settle --> expirePrev["上上周 Claimable -> Expired"] claim["C端 claim 上周"] --> wallet["WalletService gift 类型68 打码Y3"] ``` ### 落库方案 B(幂等) - 新表 `weekly_rebate_record` 增加 `last_accrued_date`(date)。 - `weeklyRebateAccrue`(每天)处理**昨日**(key 仅 1 天,必在 TTL 内):遍历昨日 `user:profit:` 哈希,充值用户且 `rebate_bet>0` → 定位昨日所属周的记录(无则建 Pending)→ 若 `last_accrued_date < 昨日` 则 `bet_amount += rebate_bet` 且更新 `last_accrued_date`(重跑不重复累加)。 - C 端「This Week」展示 = `record.bet_amount`(昨日及之前)+ 今日 redis 实时 `rebate_bet`,`rebate = floor(weekBet * rate /100)`(镜像每日返水 `syncTodayPending` 思路)。 ### 结算/过期(周一) - `weeklyRebateSettle`:对上周 `week_start` 的 Pending 记录,读当前 VIP → `rate=vip_rates[level]` → `rebate=floor(bet*rate/100)`;`rebate>0` 置 `Claimable`,写 `vip_level`/`rate_snapshot`/`claimable_at=本周一`/`expire_at=下周一`;同一次把「上上周」`Claimable 且 expire_at<=now` 置 `Expired`。 - `weeklyRebateExpire`:兜底,`status=Claimable AND expire_at<=now -> Expired`(镜像 `expireDueRecords`)。 - 顺序:accrue 先于 settle。 ### 复用 vs 新建 - 复用骨架:领取短事务 CAS + 钱包入账失败回滚 + 结算结构化日志(镜像 [DailyRebateLogic](slot_console/app/api/logic/DailyRebateLogic.php));`RechargedUidSetService`、`UserProfitEntity`、四态 + `statusLabel`、Controller/Validator 形态。 - 新建(VIP 费率,不复用 tiers 累进):`WeeklyRebateCalcService::calcRebateLi(betLi, ratePercent)`、`WeeklyRebateConfigService`(解析 `vip_rates`、`maxRate`、`rateForVip`、`canonicalExtConfigForStorage`)。 ### 文件清单 slot_lib: - [Consts.php](slot_lib/src/common/const/Consts.php) 新增 `ACTIVITY_TYPE_WEEKLY_REBATE=13`、`TRANSACTION_TYPE_WEEKLY_REBATE=68`。 slot_console: - 模型 `app/model/common/WeeklyRebateRecordModel.php`(四态 + `findByUidAndWeek`)。 - `RechargeGiftConfigModel` 加 `TYPE_WEEKLY_REBATE=13` 与 `getWeeklyRebateActiveInfo/...ByExactSource`(镜像每日返水方法)。 - 服务 `app/service/WeeklyRebateCalcService.php`、`app/service/WeeklyRebateConfigService.php`。 - Logic `app/api/logic/WeeklyRebateLogic.php`(info/claim/accrue/settle/expire)。 - Controller `app/api/controller/WeeklyRebateController.php`、Validator `app/api/validator/WeeklyRebateValidator.php`。 - 命令 `app/command/WeeklyRebateAccrue.php`、`WeeklyRebateSettle.php`、`WeeklyRebateExpire.php`。 - 路由:在 api 路由注册 weekly-rebate info/claim(与每日返水同处)。 - SQL `db/weekly_rebate.sql`(含 `last_accrued_date`、唯一键 `uniq_uid_week`)。 - 活动配置入口 [ActivityConfigEntity.php](slot_console/app/entity/activity/ActivityConfigEntity.php) 读写处对 `TYPE_WEEKLY_REBATE` 调 `WeeklyRebateConfigService::canonicalExtConfigForStorage`。 - 部署文档 `doc/weekly_rebate_deploy.md`(镜像 daily_rebate_deploy)。 backend/slot_admin(+ vue): - 字典 `activity_type` 增「周返水」value=13;菜单「周返水统计」;活动 type=13 编辑页 VIP 费率(16 档)配置 UI;周返水统计页。 slot_wallet: - 确认 `TRANSACTION_TYPE_WEEKLY_REBATE=68` 打码归类为 活动赠送 Y3(`SOURCE_TYPE_ACTIVITY_REWARD=3`),与每日返水一致;如有类型白名单需补 68。 ### 需求文档修订(周返水.md) - 领取按钮「昨天返水金额」→「上一周返水金额」。 - 规则文案「refreshes daily」改为「本周累计实时刷新、每周一结算」。 - 时区统一为服务器时区(删「美国时间」歧义)。 - `No Btes` → `No Bets`。 ### ext_config 标准格式(type=13) ```json { "vip_rates": [ {"vip_level": 0, "rate_percent": 0}, {"vip_level": 1, "rate_percent": 0.5}, {"vip_level": 15, "rate_percent": 2.0} ], "banner_image": "" } ``` ### cron - `weeklyRebateAccrue` 每天 00:05;`weeklyRebateSettle` 每周一 00:15;`weeklyRebateExpire` 每周一 00:20(兜底)。 ### 收尾门禁 - 改 `app/**/*.php` 后按 `slot-backend-completion-report` Skill 跑 `verify-slot-backend.sh` + docker `php -l`,回复附「检测结果」章节。 [ {"id": "doc-fix", "content": "修订 周返水.md 笔误(昨天->上周、daily->weekly、时区统一、No Bets)"}, {"id": "consts", "content": "slot_lib Consts 新增 ACTIVITY_TYPE_WEEKLY_REBATE=13、TRANSACTION_TYPE_WEEKLY_REBATE=68"}, {"id": "sql-model", "content": "建 weekly_rebate.sql 与 WeeklyRebateRecordModel(含 last_accrued_date、四态、findByUidAndWeek)"}, {"id": "config-model-methods", "content": "RechargeGiftConfigModel 加 TYPE_WEEKLY_REBATE 与 getWeeklyRebateActiveInfo 系列方法"}, {"id": "services", "content": "WeeklyRebateCalcService(VIP费率单乘) 与 WeeklyRebateConfigService(解析 vip_rates/maxRate/rateForVip/canonical)"}, {"id": "logic", "content": "WeeklyRebateLogic:info/claim(短事务CAS+钱包回滚)/accrue/settle(读VIP+过期上上周)/expire"}, {"id": "controller-route", "content": "WeeklyRebateController + WeeklyRebateValidator + 路由注册"}, {"id": "commands", "content": "命令 WeeklyRebateAccrue/Settle/Expire + cron 配置"}, {"id": "activity-entry", "content": "ActivityConfigEntity 读写 type=13 走 canonicalExtConfigForStorage"}, {"id": "admin", "content": "slot_admin 字典/菜单/type=13 VIP费率配置页/周返水统计页"}, {"id": "wallet-verify", "content": "slot_wallet 确认流水类型68 打码归 活动赠送Y3"}, {"id": "deploy-doc", "content": "编写 weekly_rebate_deploy.md 部署文档"}, {"id": "verify-gate", "content": "跑 verify-slot-backend.sh + php -l,输出检测结果章节"} ]