8.1 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 转盘分享周期绑定 | 推荐在 `share_url` 增加通用 `biz_type` + `biz_id`(转盘绑定 `lucky_reward_cycle.id`),按当前轮次复用/新建短码;过期校验以 `lucky_reward_cycle.end_at` 为真源,invite_bind 侧对过期轮次返回 skipped 而不影响注册。 |
|
false |
转盘分享链接与活动轮次绑定方案
结论(直接回答你的二选一)
推荐:biz_type + biz_id(转盘 biz_id = cycle_id),不推荐单独加 expire_at 作为唯一方案。
| 方案 | 优点 | 缺点 |
|---|---|---|
仅 expire_at |
查询简单(expire_at > now) |
与 lucky_reward_cycle.end_at 双份真源,易漂移;user_agent/red_packet 等 origin 语义不同,全局 expire_at 难统一 |
biz_type + biz_id(推荐) |
与业务轮次一一对应;有效期以 lucky_reward_cycle.end_at 为准;同轮次内复用、新轮次新建;可扩展其它活动 |
需改 ShareService 查询与唯一键;invite_bind 需多一步校验 |
可选:可冗余 expire_at = cycle.end_at 仅作索引加速,但判定仍应 join/查 lucky_reward_cycle,不以 share_url.expire_at 为 SSOT。
现状问题
ShareService::createUrl 通过 ShareUrlModel::isPlayerCreated($uid, $from) 按 (creator_id, origin) 永久复用一条记录:
$model = ShareUrlModel::isPlayerCreated($this->userEntity->uid, $from);
if ($model === false) { /* 新建 */ }
LuckyRewardInviteLogic::buildInviteLink 每次调 createUrl(SHARE_FROM_WHEEL),新 cycle 开始后仍返回旧短码。
注册侧 slot_user AbstractRegisterService 只校验 short_code 存在,不校验轮次;console handleInviteBind 直接用当前 active cycle 发奖,导致旧链接可能计入新轮次(与「每轮转盘有有效期」不符)。
你已确认过期策略:注册/agent 关系照常;Lucky Rewards 不计助力。
推荐数据模型
在 s_common.share_url 增加:
ALTER TABLE share_url
ADD COLUMN biz_type varchar(32) NOT NULL DEFAULT '' COMMENT '业务类型,wheel填lucky_reward_cycle',
ADD COLUMN biz_id bigint NOT NULL DEFAULT 0 COMMENT '业务ID,wheel填lucky_reward_cycle.id';
-- wheel:同一用户同一轮次唯一;其它 origin 保持 biz 为空
ADD UNIQUE KEY uk_creator_origin_biz (creator_id, creator_type, origin, biz_type, biz_id);
语义约定:
| origin | biz_type | biz_id | 行为 |
|---|---|---|---|
user_agent / red_packet / user_self |
'' |
0 |
现网永久短码,不变 |
wheel |
lucky_reward_cycle |
cycle.id |
每轮一条,同轮复用 |
code 加密 JSON 可冗余写入 cycle_id 便于排查,但复用查询走 DB 列,不走解密。
核心流程
sequenceDiagram
participant Client as ActivityPage
participant Console as ShareService
participant Cycle as lucky_reward_cycle
participant Share as share_url
participant User as slot_user_register
participant Logic as LuckyRewardInviteLogic
Client->>Console: invite-link / createShareUrl from=wheel
Console->>Cycle: resolveActiveCycle
Console->>Share: find uid+wheel+biz(cycle_id)
alt 当前轮次已有短码
Share-->>Console: 复用 short_code
else 新轮次或无记录
Console->>Share: insert 新 short_code + biz_id
end
Console-->>Client: code + land_url
User->>Share: invite_code 查 short_code
User->>Logic: invite_bind share_origin=wheel
Logic->>Share: invite_code -> biz_id(cycle_id)
Logic->>Cycle: 校验 cycle 仍进行中且 end_at>now
alt cycle 已结束或不匹配 active
Logic-->>User: skipped_expired_cycle
else
Logic-->>User: 正常助力流程
end
实现要点(按服务)
1. slot_console — 分享创建
from !== wheel:保持isPlayerCreated(uid, from)(biz 为空)。from === wheel:LuckyRewardConfigService::requireEnabledConfig+resolveActiveCycleShareUrlModel::findByPlayerBiz($uid, 'wheel', 'lucky_reward_cycle', $cycleId)- 命中则复用;否则新建并写入
biz_type/biz_id - (可选)冗余
expire_at = cycle.end_at仅索引
同步改 GiftController::createShareUrl 与 LuckyRewardInviteLogic::buildInviteLink 路径(均走 ShareService,一处改即可)。
ShareUrlModel + slot_user/ShareUrlModel 补 @property 与新查询方法。
2. slot_console — invite_bind 过期校验
在 LuckyRewardInviteLogic::handleInviteBind 有效助力判定链中(skipped_not_wheel 之后)增加:
- 用
invite_code查share_url(console 可读share_url或经 slot_user innerapi;优先 console 直读同库s_common.share_url) - 若
origin=wheel且biz_type=lucky_reward_cycle:- 查
lucky_reward_cyclebybiz_id - 若
status=已结束或end_at <= now()→ 返回新 statusskipped_expired_cycle(注册/agent 不受影响,仅不发 Spin) - 若
biz_id != 当前 active cycle.id→ 同上(旧轮短码不计新轮助力)
- 查
在 InviteBindResultEntity 增加常量 + 文档表更新(05 文档 §3 判定表)。
3. slot_user — 无需阻断注册
按你的选择:不在注册阶段 reject invite_code。AbstractRegisterService 可不改,或仅补日志(share_url.biz_id + cycle 状态)便于排障。
4. 文档
更新 05_slot_console_邀请助力与弹窗方案.md §2.1:
- wheel 短码 按 cycle 复用/新建,非永久一条
- 过期短码:注册 OK,Lucky Rewards
skipped_expired_cycle
测试
- Unit:
ShareServicewheel 分支 — mock cycle,findByPlayerBiz命中复用 / 新 cycle 新建 - Integration:同一 uid 同 cycle 两次
invite-link返回相同code;模拟新 cycle 返回不同code - Integration:旧 cycle 短码 + invite_bind →
skipped_expired_cycle,无 helper/grant
为何不选「只加 expire_at」
- 真源重复:cycle 结束时间已在
lucky_reward_cycle.end_at;单独expire_at需与轮转任务同步,易不一致。 - 无法表达「属于哪一轮」:仅有
expire_at难以区分「同用户第 N 轮 vs 第 N+1 轮」历史短码;biz_id=cycle_id可精确归因与审计。 - 影响面:
expire_at若加在全局share_url,需约定user_agent等为 0/NULL;而biz_id对非 wheel 恒为 0,更清晰。
不在本次范围
- 修改
user_agent分享逻辑 - 前端 Copy Link 缓存策略(后端保证同 cycle 幂等即可)
- 删除历史 cycle 的
share_url行(可保留作审计;过期靠 invite_bind 拦截)