Files
cursor/plans/monthly cashback-215d598c.plan.md
ray zhou 2dd9f17da9 ok
2026-06-29 14:51:55 +08:00

8.9 KiB
Raw Permalink Blame History

月返水Monthly Cashback实现方案

与周返水完全同构,仅「周」改「月」。需求见 月返水.md;结构镜像 DailyRebateLogic.php 与周返水两份计划(核心 + 统计)。

需要改动的服务

  • slot_lib常量。
  • slot_console表 / 模型 / 服务 / Logic / Controller / Validator / 命令 / 路由 / 活动配置入口 / 部署文档。
  • backend/slot_admin+ vue后台「每月返水统计」页。
  • slot_wallet仅确认流水类型 69 打码归【活动赠送 Y3】。
  • slot_pwa无需改动复用 rebate_bet)。

周期与口径(与周返水差异)

  • 统计月:每月 1 日 00:00:00 ~ 月末 23:59:59服务器时区。
  • month_start = date('Y-m-01');上月 = first day of last month;上上月 = first day of 2 months ago;过期时间 = 下月 1 日。
  • 月有效投注 = 当月每日 rebate_bet 之和(仅充值用户,沿用 pwa 现有口径)。
  • VIP 取月末最后一刻(结算下月 1 日读当前 VIPfloor 取整到厘。

数据流

flowchart TD
  pwa["slot_pwa 已累加 rebate_bet"] --> redis["redis user:profit:Ymd TTL7天"]
  accrue["monthlyRebateAccrue 每天00:05 处理昨日"] --> redis
  accrue --> rec["monthly_rebate_record 当月Pending bet累加 + vip/rate快照"]
  settle["monthlyRebateSettle 每月1日00:15"] --> rec
  settle --> vip["读当前VIP rate=vip_rates level"]
  settle --> expirePrev["上上月 Claimable -> Expired"]
  claim["C端 claim 上月"] --> wallet["WalletService gift 类型69 打码Y3"]
  admin["后台 每月返水统计"] --> rec

落库方案 B幂等

  • monthly_rebate_recordlast_accrued_datedate
  • monthlyRebateAccrue(每天)处理昨日key 仅 1 天,在 TTL 内):遍历昨日 profit 哈希,充值用户且 rebate_bet>0 → 定位昨日所属月记录(无则建 Pending→ 若 last_accrued_date < 昨日bet_amount += rebate_bet 且更新 last_accrued_date;同时写入当前 vip_level/rate_snapshot(供后台对待定行展示费率)。
  • C 端 This Month = record.bet_amount + 今日 redis 实时 rebate_bet

结算/过期(每月 1 日)

  • monthlyRebateSettle:上月 Pending → 读当前 VIP → rebate=floor(bet*rate/100)rebate>0 置 Claimableclaimable_at=本月1日expire_at=下月1日;同次将上上月 Claimable 且 expire_at<=now 置 Expired。
  • monthlyRebateExpire:兜底,Claimable 且 expire_at<=now -> Expired
  • 顺序accrue 先于 settle。

复用 vs 新建(计费 = VIP 费率单乘,不复用 tiers

  • 复用骨架:领取短事务 CAS + 钱包入账失败回滚 + 结算结构化日志 + RechargedUidSetService/UserProfitEntity/四态 + statusLabel/Controller/Validator 形态。
  • 新建:MonthlyRebateCalcService::calcRebateLi(betLi, ratePercent)=floor(betLi*ratePercent/100)MonthlyRebateConfigService(解析 vip_rates/maxRate/rateForVip/canonicalExtConfigForStorage)。

文件清单

slot_lib

  • Consts.phpACTIVITY_TYPE_MONTHLY_REBATE=14TRANSACTION_TYPE_MONTHLY_REBATE=69(若周返水未先上,取下一空位即可)。

slot_console

  • 模型 app/model/common/MonthlyRebateRecordModel.php(四态 + findByUidAndMonth)。
  • RechargeGiftConfigModel.phpTYPE_MONTHLY_REBATE=14 + getMonthlyRebateActiveInfo/...ByExactSource(镜像每日返水方法)。
  • 服务 app/service/MonthlyRebateCalcService.phpapp/service/MonthlyRebateConfigService.php
  • Logic app/api/logic/MonthlyRebateLogic.phpinfo/claim/accrue/settle/expire
  • Controller app/api/controller/MonthlyRebateController.php、Validator app/api/validator/MonthlyRebateValidator.phpclaim 场景,可选 month_start
  • 命令 app/command/MonthlyRebateAccrue.phpMonthlyRebateSettle.phpMonthlyRebateExpire.php
  • 路由:注册 monthly-rebate info/claim。
  • SQL db/monthly_rebate.sql(含 month_start datelast_accrued_date、唯一键 uniq_uid_monthvip_levelrate_snapshot)。
  • 活动配置入口 ActivityConfigEntity.phpTYPE_MONTHLY_REBATEMonthlyRebateConfigService::canonicalExtConfigForStorage
  • 部署文档 doc/monthly_rebate_deploy.md

backend/slot_admin后台统计镜像 FreeCreditsStatsLogic.php

  • 模型 app/game/model/common/MonthlyRebateRecordModel.phpconnection='s_common'、四态 + statusLabel)。
  • DTO app/game/dto/MonthlyRebateStatsQueryDTO.php、校验 app/game/validate/MonthlyRebateStatsValidate.phpuid/source/status/stat_range[]/orderBy(in:bet_amount,rebate_amount)/orderType/page/limit)。
  • 控制器 app/game/controller/MonthlyRebateStatsController.phpindex 返回 list + otherData
  • Logic app/game/logic/MonthlyRebateStatsLogic.php
    • buildQueryuid 精确、source 精确、status whereIn、时间范围 snap 整月(month_start >= 月初(start)month_start <= 月初(end))、排序白名单默认 month_start desc
    • list:行补 rate(=rate_snapshot)month_start/month_endis_current_monthstatus_label,金额 getNumberFormat
    • statistics:总领取/总待领取/总过期/领取率(分母 0→02 位小数)/待定(仅当筛选含本月)。
  • 菜单 db/menu-monthly-rebate-stats.sql(挂「综合统计」父菜单,镜像 menu-free-credits-stats.sqlcomponent=game/monthlyRebateStats/index + sm_system_group_menu 授权)。

backend/slot_admin_vue镜像 freeCreditsStats/index.vue

  • src/api/game/monthlyRebateStats.jssrc/views/game/monthlyRebateStats/index.vue:筛选(ID/渠道/状态/按日范围)、#tableAfterButtons 顶部总计、可排序列(有效下注额/返水金额)、统计周期列显示「本月」或 month_start - month_end

slot_wallet

  • 确认流水类型 69 打码归类为 活动赠送 Y3SOURCE_TYPE_ACTIVITY_REWARD=3),如有类型白名单补 69。

ext_config 标准格式type=14

{
  "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

  • monthlyRebateAccrue 每天 00:05monthlyRebateSettle 每月 1 日 00:15monthlyRebateExpire 每月 1 日 00:20。

与周返水共用注意

  • 月返水与周返水各自独立表/配置/命令/流水类型,互不影响;同一用户同期可同时拥有日/周/月三套返水记录。
  • 若日/周/月三套都上,建议抽取「曾充值判断 + profit 哈希解码 + 月/周边界」公共片段,避免三处复制(可选优化,不阻塞)。

收尾门禁

  • app/**/*.php 后按 slot-backend-completion-report Skill 跑 verify-slot-backend.sh + docker php -l,回复附「检测结果」章节(含 PHPDoc:checked。 [ {"id": "consts", "content": "slot_lib Consts 新增 ACTIVITY_TYPE_MONTHLY_REBATE=14、TRANSACTION_TYPE_MONTHLY_REBATE=69"}, {"id": "sql-model", "content": "monthly_rebate.sql + MonthlyRebateRecordModel(month_start/last_accrued_date/vip_level/rate_snapshot/四态/findByUidAndMonth)"}, {"id": "config-model-methods", "content": "RechargeGiftConfigModel 加 TYPE_MONTHLY_REBATE 与 getMonthlyRebateActiveInfo 系列方法"}, {"id": "services", "content": "MonthlyRebateCalcService(VIP费率单乘) 与 MonthlyRebateConfigService(vip_rates/maxRate/rateForVip/canonical)"}, {"id": "logic", "content": "MonthlyRebateLogicinfo/claim(CAS+钱包回滚)/accrue(写vip/rate快照)/settle(读VIP+过期上上月)/expire"}, {"id": "controller-route", "content": "MonthlyRebateController + MonthlyRebateValidator + 路由注册"}, {"id": "commands", "content": "命令 MonthlyRebateAccrue/Settle/Expire + cron"}, {"id": "activity-entry", "content": "ActivityConfigEntity 读写 type=14 走 canonicalExtConfigForStorage"}, {"id": "admin-stats", "content": "slot_admin 每月返水统计Model(s_common)/DTO/Validate/Controller/Logic(buildQuery月snap+list+statistics)"}, {"id": "admin-vue", "content": "slot_admin_vue monthlyRebateStats api.js + index.vue(筛选/总计/排序/统计周期)"}, {"id": "admin-menu-sql", "content": "menu-monthly-rebate-stats.sql 挂综合统计父菜单 + 分组授权"}, {"id": "wallet-verify", "content": "slot_wallet 确认流水类型69 打码归 活动赠送Y3"}, {"id": "deploy-doc", "content": "编写 monthly_rebate_deploy.md"}, {"id": "verify-gate", "content": "跑 verify-slot-backend.sh + php -l 输出检测结果章节"} ]