# 七日活动实现与维护说明 核对日期:2026-09-16。本文以当前工作区代码和资源为准,不代表已发布版本或后端实时配置。测试步骤见 [预览与测试说明](testSeven-local-preview.md)。 ## 当前流程 1. `HomeScene` 的 `SevenDayGiftHost` 等待 UID,调用 `signInActivityInfo` 查询活动;UID 未就绪最多按一秒间隔重试十次。 2. 满足自动展示条件后,以键 `sevenDayGift`、优先级 `10` 加入 `HomePopupQueue`。 3. 通过主页的 `loadHomeBundleWithDependencies("seven_day_gift", 5, ...)` 加载分包及依赖,再加载并实例化 `prefab/sevenDayGift`。 4. 将查询快照交给活动视图,成功显示后才记录当天已弹。加载或初始化失败不会写已弹记录。 5. 打开后等待点击,不自动领取。点击当天卡片或弹窗外部,使用快照中当天的奖励执行发奖;成功后更新本地领取状态并播放上浮效果。 6. 领取后再次点击外部关闭。销毁活动节点,通常下一帧释放活动 Bundle;宿主销毁时立即释放。独立测试服的测试入口存在时保留 Bundle,退出主页时一并释放。 没有手动入口或关闭按钮。代码中的 `autoClaim` 是保留的旧参数名,目前表示自动展示来源,不代表自动领取。 ### 自动展示条件 - 存在 `activityId`,且 `triggerReached` 为真。 - `status` 不是 `expired` 或 `completed`。 - 时间可解析时要求 `serverNow < endAt`;当前代码遇到不可解析时间不会因此阻止展示。 - `canClaim` 为真,`todayClaimed` 为假,当前账号、活动、服务器日期尚未成功显示过。 触发等级、开始时间和期限由后端决定;前端不硬编码 23 关或 14 天,也不单独检查 `startAt` 是否已经到达。 自动弹窗记录键为 `seven_day_gift_auto_open_v1::`,值为 UTC+8 自然日编号字符串;缺少有效服务器时间时使用设备时间。已弹记录不代表已领取,领取失败不会清除该记录。 主页进入和回到前台会查询。弹窗加载中或显示中不重复查询;Cocos `CC_PREVIEW` 环境不会自动查询或自动打开活动。 ## 文件职责 以下路径均相对于项目根目录。 | 文件 | 职责 | | --- | --- | | `assets/Script/seven_day_gift/SevenDayGiftHost.ts` | 展示条件、主页队列、分包加载与释放 | | `assets/Script/seven_day_gift/SevenDayGiftBootstrapApi.ts` | 主包活动查询 | | `assets/seven_day_gift/SevenDayGift.ts` | 预制体节点绑定、数据刷新、点击和动画调用 | | `assets/seven_day_gift/SevenDayGiftRuntime.ts` | 领取流程、Loading、状态更新 | | `assets/seven_day_gift/SevenDayGiftApi.ts` | 数据类型、猫皮肤与道具保存接口 | | `assets/seven_day_gift/SevenDayGiftReward.ts` | 本地资产增加、同步及成功记录防重 | | `assets/seven_day_gift/prefab/sevenDayGift.prefab` | 面板最终布局 | | `assets/seven_day_gift/texture/reward_numbers_medium/` | 数字、乘号、加号、分钟图片 | | `assets/seven_day_gift/SevenDayHitTest.ts`、`SevenDayHitMasks.ts` | 透明区域点击判定及离线命中数据 | | `assets/reward_claim_effect/RewardClaimEffect.ts` | 独立领取上浮特效 | | `assets/Script/ActivityPopupAnimator.ts` | 面板开关动画 | | `assets/home_popup_queue/HomePopupQueue.ts` | 主页活动弹窗协调 | | `assets/seven_day_gift/test/SevenDayTest.ts`、`SevenDayTest.prefab` | 独立测试服白字入口、接口字段查看、当前账号活动缓存清理 | 主包宿主通过接口调用活动组件,不静态导入活动实现。维护时保留资源 `.meta` 和 UUID,避免场景直接引用活动资源而破坏按需加载。 ## 预制体与美术维护 面板共 85 个节点,奖励节点全部存放在预制体中。运行时不创建或销毁面板奖励节点,只更新图片、数量字位和状态,播放动画。 ```text sevenDayGift ├─ mask └─ panel ├─ header └─ cards └─ giftDay1 … giftDay7 ├─ dayLabel ├─ rewardItems │ └─ rewardItem0 / rewardItem1 │ └─ amount │ └─ digit0 … 实际需要的字位 ├─ claimedOverlay └─ claimedBadge ``` 默认展示第 1 天可领取。仅 `claimedOverlay` 和 `claimedBadge` 默认未激活,领取后显示。备用布局、额外字位、文字兜底、旧关闭按钮、提示和重复标题文字均已删除。 ### 当前编辑器展示值与容量 下表是预制体默认展示和测试基线,不是服务端奖励配置的证明。实际发奖仍以接口 `rewards` 为准。 | 天数 | 默认展示 | 奖励槽位数 | 各奖励数量字位数 | | --- | --- | ---: | --- | | 1 | 无限体力 15 分钟 | 1 | 3 | | 2 | 锤子 ×1 | 1 | 2 | | 3 | 无限体力 30 分钟 | 1 | 3 | | 4 | 冻结 ×1、魔法棒 ×1 | 2 | 2、2 | | 5 | 金币 600 | 1 | 3 | | 6 | 锤子 ×1、冻结 ×1 | 2 | 2、2 | | 7 | 无限体力 60 分钟、猫皮肤 ×1 | 2 | 3、2 | “分钟”整张图片占一个字位,乘号也占一个字位。猫的发奖编号由接口 `itemId` 指定;面板当前使用绑定的固定猫图片。 ### 当前视觉规格 - “分钟”按数字的可见高度等比放大,不按较小的原始贴图尺寸显示。 - 同一卡片内各奖励的数量排在同一水平线上;此前按各图标底边定位导致高低不齐。 - 所有面板数量相对调整前放大 15%,数量容器高度为 29.9。 - 第七天爱心相对调整前放大 10%、左移 6px。 - 当前可领取卡片为黄色并播放 1~1.04 倍呼吸缩放;第七天使用专用底图。猫在可领取或已领取时显示正常图,否则显示锁定图。 直接在预制体调整 `rewardItem*` 的位置、尺寸及 `amount` 的整体位置;这些值不会被数据刷新重设。数量字位内部尺寸和间距仍由 `refreshAmount()` 按容器宽高更新,日期描边颜色、卡片底图和状态仍受脚本控制。 增加奖励项、调整奖励顺序或改变类型时,必须同步检查固定槽位、图片比例及位置。增加数量位数时,需添加连续命名的 `digitN` Sprite 节点。超出槽位的奖励不会显示,但发奖逻辑仍消费完整接口数组;字位不足、缺图或小数数量会隐藏该数量并警告,不显示文字兜底,不可把显示限制当作发奖限制。 面板预制体与领取特效是两套展示:`RewardClaimEffect` 仍动态创建临时特效节点,并保留它自身的数量绘制逻辑。此次分钟等高、15% 数量放大及无文字兜底针对面板,不代表特效已同步采用这些规格。 ## 接口与发奖 主包向 `signInActivityInfo` 提交 UID,公共 `Utils.POST` 补充 token 等公共参数。仅 `code === 1` 且 `data` 为有效对象时消费结果;`data: false` 不展示活动。活动查询和分包资产保存接口均有 5.5 秒超时保护。 | 快照字段 | 用途 | | --- | --- | | `activityId`、`startAt` | 活动识别、本次领取记录 | | `serverNow`、`endAt`、`status` | 日期及展示条件 | | `triggerLevel`、`triggerReached` | 后端触发信息;实际展示判断使用后者 | | `canClaim`、`todayClaimed`、`nextRewardDay` | 当天领取资格和目标天数 | | `claimedCount`、`rewards[].claimed` | 已领进度 | | `rewards[].day`、`rewards[].items` | 按天查找奖励,不能假定天数组顺序 | 奖励项包括 `type`、`count`(兼容旧字段 `amount`)和猫皮肤 `itemId`。无限体力原值为秒,仅显示时除以 60。 没有独立活动领取请求:从查询快照取出 `nextRewardDay` 对应的 `items`,执行以下资产更新。 | 奖励 | 当前实现 | | --- | --- | | 金币 | `GameTool.changeCoin()` | | 锤子、冻结、魔法棒 | 增加本地总量,再经 `userProp` 保存总量 | | 无限体力 | `GameTool.setUserPowerTime(seconds, "seven_day_gift")`,刷新主页体力显示 | | 猫皮肤 | `setCatArr` 保存 `itemId`,更新猫列表 | 成功后本地标记当天已领取,设置 `canClaim=false`、`todayClaimed=true`;第七天标记活动完成,再播放特效。领取 Loading 有 7 秒兜底;失败允许在当前弹窗重试。 ### 防重与当前边界 成功记录存放在 `seven_day_gift_processed_claims_v1`,按 UID 和 `JSON.stringify([activityId, startAt, nextRewardDay])` 生成的领取标识区分。只有整体同步成功后才写记录;同一设备的成功记录可阻止重复发奖,不能代替后端跨设备幂等。 当前先增加本地资产,再等待部分保存接口。若道具或猫保存失败,前面已经增加的资产没有事务回滚,重试可能再次累加。金币、体力路径也不等同于逐项确认服务端最终到账。测试需覆盖部分失败,不应把“可重试”描述为“不会重复增加”。 如果后端查询本身已直接增加资产,当前客户端累加方式需与后端重新确认,避免重复发奖。视图和 Runtime 不独立定时检查过期;展示后的过期边界仍需要接口约定和真实环境验证。 ## 当前环境配置 `assets/Script/module/Pay/Utils.ts` 当前配置: - `httpip`:`https://q6rvwvtnga.sealoshzh.site/` - `testHttpip`:`https://q6rvwvtnga.sealoshzh.site/`,与正式地址相同。 - 旧测试地址 `https://sor779u2w8.sealoshzh.site/` 仅为注释。 开发版、体验版选择 `testHttpip`,正式版及其他情况选择 `httpip`。因此当前不能把开发版/体验版称为独立测试服;真实领取前应确认目标地址和测试账号。本次文档整理不修改服务器配置,也未请求线上接口。 测试入口由 `SevenDayGiftBootstrapApi.getTestEnvironment()` 统一门禁:仅开发版/体验版且测试、正式地址不同源时显示,每次按钮操作再次校验。测试脚本和预制体位于本包 `test/` 目录,主包仅按路径加载。当前配置下入口隐藏,未擅自恢复旧测试地址。具体操作见测试文档。 ## 排查与修改入口 | 现象 | 检查位置 | | --- | --- | | 主页不弹 | 是否 `CC_PREVIEW`、UID、接口响应、展示条件、当天已弹记录、主页队列是否有其他窗口 | | 分包或预制体加载失败 | 主页依赖加载器、Bundle 名、Prefab 路径和 `SevenDayGift` 组件 | | 编辑器与运行图标位置不同 | 是否重新导入/构建、是否修改了当前实际使用的奖励槽位、是否处于动画中 | | 数量消失或奖励少显示 | 控制台容量警告、字位数、图片绑定、后端项数及顺序 | | 点透明区域行为异常 | `SevenDayHitTest` 与贴图对应的命中数据 | | 发奖失败或资产重复 | 保存接口响应、成功记录、部分失败重试路径 | 当前宿主仍有展示判断和打开日志,不能描述为“仅有异常日志”。重新打包需先经 Cocos 构建,再到微信开发者工具验证,单点微信编译不会更新 Cocos 资源。 ## 第七天小猫光效 小猫背后的 catGlow 已固化在预制体中,使用本包独立复制的 exture/catAnimation3.png,不引用扭蛋包资源。CatRewardGlow.anim 循环播放(视图刷新时显式确保启动,重复刷新不重播):6 秒旋转一圈、2 秒明暗呼吸,金色,480×480,透明度 170~255。第七天包含猫奖励且尚未领取时显示,领取后隐藏;装饰节点不参与点击命中。编辑器可直接调整位置、尺寸、颜色和动画。此效果与领取后的上浮动画相互独立。