8.5 KiB
8.5 KiB
todos:
- id: "ddl" content: "编写 reward_pool / reward_pool_item 建表 DDL(AUTO_INCREMENT 主键、status 1/2、可选审计字段)" status: pending
- id: "constants" content: "新建 RewardPoolConstants / RewardPoolRewardType(钱包类复用 foundation 数值,新增 COUPON=3)" status: pending
- id: "models" content: "新建 RewardPoolModel、RewardPoolItemModel(完整类 PHPDoc + @property + 查询方法)" status: pending
- id: "draw-shared" content: "下沉加权随机算法为可复用方法,供奖池与 TrialPrizeDrawService 共用" status: pending
- id: "entity" content: "新建 RewardPoolDrawResultEntity 及列表/汇总 Entity(禁止 Logic 返回 array)" status: pending
- id: "draw-logic" content: "实现 app/innerapi/logic/RewardPoolDrawLogic::drawByPoolCode(只读、无副作用)" status: pending
- id: "admin-crud" content: "slot-activity app/admin:RewardPool(Item)Controller/Logic/Validate(saithink 范式)+ admin 路由" status: pending
- id: "validate" content: "奖池/奖项校验:reward_type 约束 + 优惠券模板存在性 + 启用校验 + pool_code 不可改" status: pending
- id: "sdk" content: "ActivityService 增 admin/reward-pool(-item)/* SDK 方法(adminXxx 同套路)" status: pending
- id: "admin" content: "saas6.x/server operation RewardPoolController + RewardPoolGatewayService 代理(#[Permission])" status: pending
- id: "admin-vue" content: "admin-vue 增奖池管理页面与菜单(奖池列表/编辑/启停 + 奖项配置页)" status: pending
- id: "verify" content: "运行 slot-backend-completion-report 门禁并粘贴检测结果" status: pending isProject: false
通用奖池 V1 实施方案
落点服务:slot-activity(核心 + 数据)、slot-sdk(跨服务客户端)、saas6.x/server(运营后台代理)+ saas6.x/admin-vue(后台前端)。沿用现有「活动管理」后台范式(operation 控制器 + *GatewayService 封装 slotsdk)。
注意:后台代码不在
slot-admin,而在独立仓库~/Documents/project/www/tenant/saas6.x(用户明确指定)。
子需求文档(SSOT 拆分):docs/requirements/generic_reward_pool/README.md(01 表结构 / 02 抽奖 / 03 后台)。
关键决策(已确认 + 需注意的派生项)
- 奖励类型按《奖池.md V1》原口径:
reward_type=1 可提现释放 / 2 Bonus / 3 充值优惠券,券用coupon_template_id(不对齐 foundation 数值、不引入 FS)。- 新建
app/constants/RewardPoolRewardType(WITHDRAWABLE_RELEASE=1/BONUS=2/COUPON=3)。 - 业务方按抽奖结果发奖时,由业务侧显式把
reward_type映射到钱包/券接口(如slot-foundation\RewardGrantRewardType或 user_coupon),奖池本身不做发放。
- 新建
- 表名冲突风险:现有
docs/requirements/reward_pool/(大转盘超集设计)也用reward_pool/reward_pool_item。实施前需决策本 V1 是否改用独立表名或与之合并(见子需求 README「重要前提」)。 - 抽奖算法复用:把
TrialPrizeDrawService::pickWeightedRandom()的加权累加逻辑下沉为可复用方法(random_int(1,total)+sort ASC,id ASC累加),奖池抽奖与转盘共用,不再写第二份。 - 运营后台(
saas6.x/server)经slot_sdk调 slot-activityinnerapi/admin,参照saas6.x/server/app/controller/operation/ActivityController.php+app/service/activity/ActivityGatewayService.php的proxyActivity()+*GatewayService范式,不直连 activity 库。
一、数据库(reward_pool / reward_pool_item)
按文档 §6 建表,修订:
- 主键改
BIGINT UNSIGNED NOT NULL AUTO_INCREMENT(与现有 Model "自增主键" 一致)。 status统一为1启用 2停用(文档已是;与 prize_pool 的 enabled 1/0 不强行统一,但 Model 注释写清)。reward_pool_item.pool_code为快照;约定pool_code创建后不可改(编辑接口禁止改 code),保证(pool_id,item_code)快照一致。- 可选增
created_by/updated_by(后台操作审计)。
二、slot-activity 核心(数据 + 抽奖)
- Model:
app/model/RewardPoolModel.php、app/model/RewardPoolItemModel.php- 完整类 PHPDoc +
@property(对齐 DDL COMMENT),状态常量带中文注释。 - 查询方法:
findEnabledByPoolCode()、listEnabledItemsByPoolId()、sumEnabledWeight()、existsItemCode()等(命名表达意图,禁止 getData/getList)。
- 完整类 PHPDoc +
- 常量:
app/constants/RewardPoolConstants.php(status、reward_type 复用 foundation + COUPON)。 - 抽奖业务逻辑(供本服务/业务内部调用,第一期不强制开 HTTP):
app/innerapi/logic/RewardPoolDrawLogic.php::drawByPoolCode(string $poolCode): RewardPoolDrawResultEntity,编排文档 §8.1 十步:查池→校验启用→取启用且weight>0奖项→total_weight→加权随机→返回快照。只读、无副作用、无幂等(幂等由业务方负责,PHPDoc 写明)。 - Entity:
app/entity/rewardpool/RewardPoolDrawResultEntity.php(抽中快照,extendsBaseEntity),列表用RewardPoolListEntity/RewardPoolItemListEntity包装(禁止 Logic 返回 array /Xxx[])。
三、slot-activity 后台(app/admin,非 innerapi)
沿用 app/admin saithink 范式(参照 app/admin/controller/ActivityController.php + app/admin/logic/ActivityLogic.php + app/admin/validate/ActivityValidate.php,基类 app/admin/base/AdminController,$this->success() 返回):
- Controller:
app/admin/controller/RewardPoolController.php(奖池 index/read/save/changeStatus)、app/admin/controller/RewardPoolItemController.php(奖项 index/save/changeStatus/destroy/sort)。 - Logic:
app/admin/logic/RewardPoolLogic.php、app/admin/logic/RewardPoolItemLogic.php(search/getList + 保存/启停/排序;多表写入走 activity 库事务)。 - Validate:
app/admin/validate/RewardPoolValidate.php、RewardPoolItemValidate.php,覆盖文档 §11.1~§11.4(reward_type∈{1,2,3};非 COUPON 时reward_amount>0 && coupon_template_id=0;COUPON 时reward_amount=0 && coupon_template_id>0且校验模板存在;启用奖池需至少 1 个启用奖项且weight合计 > 0;pool_code创建后不可改)。 - 路由:按现有 admin 路由约定接入
admin/reward-pool/*、admin/reward-pool-item/*(与admin/activity/*同套路)。
四、slot-sdk
- slot-sdk/src/service/activity/ActivityService.php 增方法,POST/GET 到
admin/reward-pool/*、admin/reward-pool-item/*(与现有adminActivityIndex/adminSave/adminUpdate/adminChangeStatus/adminDestroy命名同套路):rewardPoolIndex/Read/Save/ChangeStatus、rewardPoolItemIndex/Save/ChangeStatus/Destroy/Sort。
五、saas6.x 运营后台
后端 saas6.x/server:
app/controller/operation/RewardPoolController.php(extendsOperationController,方法加#[Permission('奖池...','saimulti:operation:rewardPool:xxx')],proxyActivity()统一封装)。app/service/activity/RewardPoolGatewayService.php(封装 slotsdkActivityClient,host 取ShareConfigService::get('activityApiHost'),与ActivityGatewayService同构)。- 入参轻校验可放控制器或
app/validate/,复杂判断仍在 slot-activity 侧。
前端 saas6.x/admin-vue:
- 运营管理 → 奖池管理页(列表/新增/编辑/启停/进入奖项配置)+ 奖项配置页(新增/编辑/启停/排序)。
- 新增对应
api/请求模块与菜单/权限项(与活动页同套路)。
六、收尾自检(强制)
改完 app/**/*.php 后按 agent-completion-gate 执行 ~/.cursor/skills/slot-backend-completion-report/scripts/report.sh(含 verify 门禁 + docker php -l),最终回复粘贴"检测结果"章节。
调用关系
flowchart LR
Vue[saas6.x admin-vue] --> Server[saas6.x server operation]
Server -->|slot_sdk ActivityClient| AdminApi[slot-activity app/admin reward-pool]
AdminApi --> AdminLogic[admin RewardPoolLogic / ItemLogic]
AdminLogic --> Model[(reward_pool / reward_pool_item)]
Biz[业务活动 Logic] -->|drawByPoolCode| Draw[RewardPoolDrawLogic]
Draw --> Model
Biz -->|按 reward_type 发放| Wallet[slot-wallet / user_coupon]