MatchMaster/docs/seven-day-gift-maintenance.md

553 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

> 当前交互更新:七日弹窗无关闭按钮;首次外部点击与卡片领取一致,只领取当前奖励,后一次外部点击再关闭。领取及效果期间禁止重复操作。奖励改用 `assets/reward_claim_effect/RewardClaimEffect.ts` 上浮效果;下文旧版自动领取、关闭按钮和公共奖励动画说明仅作历史记录,测试以 `testSeven-local-preview.md` 为准。
# 七日好礼活动实现与维护说明
本文记录 `feature/seven_day_gift` 分支从 `main` 拉出后完成的七日签到活动相关改动,供后续开发、联调、测试和上线维护使用。
记录日期:2026-09-04
基线提交:`6b56b88284e1bb864241530a23aa3376ce0faf3e`
开发分支:`feature/seven_day_gift`
> 重要:记录时该分支相对 `main` 没有新的已提交 commit,功能改动仍在工作区。本文描述的是“当前工作区相对 `main`”的实际差异,不代表这些文件已经提交或合并。
## 1. 功能目标
本次增加一个由后端控制状态的七日好礼活动,主要规则如下:
- 玩家主线达到活动触发条件后,在主页自动弹出七日活动,不再显示手动入口按钮。
- 当前约定的触发等级为 23,但前端不自行计算触发结果,以后端返回的 `triggerReached` 为准。
- 活动有效期由后端的 `startAt`、`endAt` 和 `status` 控制;当前产品约定是 14 天内领取 7 天奖励。
- 每个服务器自然日最多领取一次,具体是否可领取以后端 `canClaim` 为准。
- 当天有奖励可领且当天没有自动弹过时,进入主页自动打开并自动领取当天奖励。
- 自动领取结束(成功或失败)后才开放关闭按钮;失败时可点击当天卡片重试。
- 当天领取后关闭页面,即销毁活动实例并释放 Bundle;第二天满足条件时重新加载。
- 开发版和体验版使用测试服务器;正式版使用正式服务器。
- 上线代码不包含测试面板、接口反馈、模拟日期或测试资产注入功能。
## 2. 总体结构
七日活动采用“主包轻量宿主 + 活动 Bundle”的结构。主包只负责首次状态查询、自动弹出判断和 Bundle 生命周期;活动 UI、领取和发奖代码均放入 `seven_day_gift` Bundle:
```text
HomeScene
└─ Canvas/sevenDayGift 主包中的轻量宿主节点
├─ SevenDayGiftHost Bundle 加载与释放
└─ SevenDayGiftBootstrapApi 首次状态查询
seven_day_gift Bundle
├─ prefab/sevenDayGift.prefab 活动弹窗
├─ SevenDayGift + SevenDayGiftRuntime UI 与业务流程
├─ SevenDayGiftApi + SevenDayGiftReward 完整接口与发奖
└─ texture/* 活动图片
```
核心调用链:
```text
进入 HomeScene / 小游戏回到前台
↓
SevenDayGiftHost.queryActivity(true)
↓
signInActivityInfo
↓
判断活动是否可见、当天是否可领取
↓
满足 canClaim 且当天未弹过 → 自动打开活动
自动弹窗完成后自动领取当天卡片
↓
使用本次查询的 nextRewardDay 对应 items
↓
SevenDayGiftReward.grant
↓
更新本地资产并同步相关资产接口
↓
打开项目公共奖励动画
↓
在当前快照上更新已领取状态,不重复查询
```
## 3. 新增文件
### 3.1 主包引导层
`assets/Script/seven_day_gift/SevenDayGiftHost.ts` 挂载在 `HomeScene` 的 `sevenDayGift` 节点上,只负责:
- 进入主页时查询活动。
- 监听 `cc.game.EVENT_SHOW`,从后台回到前台时重新查询活动。
- 判断是否需要自动弹出。
- 按需加载 `seven_day_gift` Bundle 和 `prefab/sevenDayGift`。
- 弹窗关闭后销毁实例,并在下一帧执行 `bundle.releaseAll()` 和 `cc.assetManager.removeBundle()`。
`assets/Script/seven_day_gift/SevenDayGiftBootstrapApi.ts` 是主包中的最小查询接口,只包含 `signInActivityInfo`、UID 获取、服务器选择、超时和基础日志。它不能引用 Bundle 内的完整 API、Reward、Prefab 或调试脚本,否则这些代码会被重新打进主包。
#### 活动可见条件
`isActivityVisible()` 当前要求:
- 返回了 `activityId`。
- `triggerReached === true`。
- `status` 不是 `expired`。
- `status` 不是 `completed`。
- `serverNow < endAt`。
前端没有直接检查 `startAt`,正常情况下应由后端通过 `status` 保证活动尚未开始时不返回可见状态。
#### 自动弹出条件
`shouldAutoOpen()` 当前要求:
- 活动处于可见状态。
- 后端返回 `canClaim === true`。
- 本地没有当前用户、当前活动、当天的自动弹出记录。
本地记录键:
```text
seven_day_gift_auto_open_v1:<uid>:<activityId>
```
值为根据 `serverNow` 计算出的东八区自然日编号。自动弹出前先写记录,再执行 `show()`,防止同一运行过程重复触发。
以下操作不会自动清除该记录:
- 修改服务器关卡等级。
- 将等级从 23 改回 22 后再次通关。
- 重新请求活动接口。
- 关闭活动但不领取。
清除微信缓存、更换设备、更换 UID 或更换 `activityId`,会允许再次自动弹出。
#### 查询时机
- `HomeScene` 中宿主组件执行 `onLoad()`。
- 小游戏触发 `cc.game.EVENT_SHOW`,并且宿主仍位于当前主页场景。
七日活动宿主不在关卡场景中,因此玩家在关卡里达到触发等级时不会立即弹窗;返回主页后才查询和判断。
#### 加载与释放
- 点击领取时,加载动画最长兜底 7 秒。
- 七日 API 自身的请求超时是 5.5 秒。
- 自动后台查询不主动显示 Loading,避免进入主页时无条件遮挡界面。
- 各微信环境都只有命中自动弹出条件时才加载 Bundle。
- Cocos 编辑器预览不主动请求活动,也不加载 Bundle;联调应使用微信开发版或体验版。
- 节点先销毁,Bundle 在下一帧释放,避免在组件销毁回调尚未结束时回收其脚本和资源。
### 3.2 `assets/seven_day_gift/SevenDayGift.ts`
活动弹窗视图组件,负责:
- 缓存 7 张奖励卡片。
- 根据接口数据刷新卡片底图、日期、奖励图标和领取状态。
- 仅允许点击 `nextRewardDay` 对应且 `canClaim` 为真的卡片。
- 防止领取过程中重复点击。
- 活动打开和关闭时播放缩放、透明度动画。
- 当前可领取卡片播放轻微循环缩放提示。
- 自动领取期间隐藏关闭按钮并禁止遮罩关闭;领取回调结束后才允许关闭。
UI 约定:
- 图片统一保持 `cc.Color.WHITE`,不对原图进行额外染色。
- 活动卡片底部状态文字节点被隐藏,不显示“点击领取/未解锁”等附加文字。
- 单奖励和多奖励使用相同的大图标尺寸。
- 多奖励从左到右排列并允许部分重叠,但按卡片可用宽度计算间距,避免越界。
- 卡片只显示道具图片,不显示奖励名称或数量文字。
- 第 7 天猫皮肤在未解锁时使用隐藏猫图片,解锁后使用正常猫图片。
### 3.3 `assets/seven_day_gift/SevenDayGiftApi.ts`
七日活动接口封装和 TypeScript 数据契约,负责:
- 活动查询由主包 `SevenDayGiftBootstrapApi` 调用 `signInActivityInfo`,Bundle 内不再请求活动接口。
- 保存猫皮肤:`setCatArr`。
- 保存普通道具:`userProp`。
- 5.5 秒没有回调时返回统一超时结果,迟到回调不再重复执行业务回调。
UID 优先读取:
```text
cc.fx.StorageMessage.getStorage("uid")
```
并同步回 `cc.fx.GameConfig.GM_INFO.uid`。如果发现 UID 改变,应先检查登录流程和本地 `uid` 缓存,而不是只看七日活动脚本。
### 3.4 `assets/seven_day_gift/SevenDayGiftReward.ts`
将后端奖励转换成项目现有资产操作,支持以下类型:
| 后端类型 | 前端处理 |
| --- | --- |
| `coin` | `cc.fx.GameTool.changeCoin()` |
| `hammer` | 增加 `GM_INFO.hammerAmount`,保存 `prop`,通过 `SevenDayGiftApi.saveProps()` 同步 `/userProp` |
| `freeze` | 增加 `GM_INFO.freezeAmount`,保存 `prop`,通过 `SevenDayGiftApi.saveProps()` 同步 `/userProp` |
| `magic_wand` | 增加 `GM_INFO.magicAmount`,保存 `prop`,通过 `SevenDayGiftApi.saveProps()` 同步 `/userProp` |
| `infinite_health` | 调用 `setUserPowerTime(seconds, "seven_day_gift")` |
| `cat_skin` | 使用 `itemId` 调用 `setCatArr?action=save` |
奖励数量兼容:
```ts
const rewardAmount = item.count !== undefined ? item.count : item.amount;
```
即优先读取 `count`,旧接口使用 `amount` 时仍能正常发奖。卡片虽然不显示数量文字,发奖逻辑仍必须保留此兼容,除非后端已确认所有环境和历史数据都统一完成迁移。
领取幂等记录保存在:
```text
seven_day_gift_processed_claims_v1
```
记录键为 `<uid>:<claimId>`;这里的 `claimId` 是前端用 `[activityId, startAt, nextRewardDay]` 序列化生成的本地同步标识,接口不需要返回该字段。同一个 `claimId` 在同一设备上再次处理时直接视为成功,不重复增加资产。
注意:这个记录是客户端本地幂等保护,不能代替服务端活动领取的幂等校验。清缓存或换设备后本地记录会消失,后端仍必须保证同一用户、同一天、同一领取不能重复发放。
### 3.5 `assets/seven_day_gift/SevenDayGiftRuntime.ts`
Bundle 内的活动业务控制器,只有 Bundle 加载后才进入内存,负责:
- 直接消费主页查询结果中的当日奖励,交给 `SevenDayGiftReward` 同步本地资产及对应资产接口。
- 更新当前快照的领取状态、调用项目公共奖励动画;不再发起额外活动请求。
- 管理主页 Loading、错误提示和领取失败后的重试状态。
- 销毁时清理 Loading 和运行状态。
旧的 `SevenDayHomeEntryLayout.ts` 和主页入口 Prefab 已删除;七日活动不再参与主页入口排序,也不会改动商城、排行榜等既有入口的位置或透明度。
### 3.6 Prefab 和图片资源
新增:
- `assets/seven_day_gift/prefab/sevenDayGift.prefab`:七日活动主弹窗。
- `assets/seven_day_gift/texture/*.png`:活动面板、卡片、标题、猫、道具和已领取标记等图片。
所有 Cocos 资源必须连同对应 `.meta` 文件提交,不能只提交 PNG、Prefab 或 TypeScript 文件。`.meta` 中的 UUID 是场景和 Prefab 引用资源的依据。
### 3.7 `assets/Script/ActivityPopupAnimator.ts`
公共活动弹窗动画工具,七日活动通过 `popupAnimation` 选择动画类型。该脚本属于主包是因为 Bundle 内弹窗需要引用它;它不包含活动数据、测试入口或网络逻辑。
## 4. 接口契约
### 4.1 查询活动 `signInActivityInfo`
请求:
```json
{
"uid": "用户UID"
}
```
主要返回字段:
| 字段 | 含义 |
| --- | --- |
| `serverNow` | 服务器当前时间,支持毫秒、秒级数值或可解析日期字符串 |
| `activityId` | 活动标识,同时用于自动弹出本地键 |
| `status` | 当前状态,前端明确识别 `active`、`completed`、`expired` |
| `triggerLevel` | 后端配置的触发等级,仅展示/诊断 |
| `triggerReached` | 后端最终触发判断;是否允许自动弹出依赖此字段 |
| `startAt` | 活动开始时间,当前前端不直接校验 |
| `endAt` | 活动结束时间,活动可见性判断会校验 |
| `claimedCount` | 已领取天数 |
| `todayClaimed` | 当天是否已领取 |
| `canClaim` | 当前是否允许领取,同时控制自动弹窗和卡片领取 |
| `nextRewardDay` | 下一次应该领取第几天 |
| `rewards` | 7 天奖励数组及每项 `claimed` 状态 |
活动自动弹窗要求活动处于可见状态、`canClaim === true` 且当天未弹过。当前版本没有手动入口。
### 4.2 查询结果直接驱动领取
不再使用独立领取接口。`signInActivityInfo` 的请求携带 uid,由公共 POST 层补 token,不传 gameName。未达到 23 关时 `code: 1, data: false`,主页不弹窗。
达到条件后,使用查询响应中的 `nextRewardDay` 在 `rewards` 中找到对应 `day` 的 `items`。自动弹窗动画结束后同步这些奖励,完成后本地更新 claimed、claimedCount、todayClaimed、canClaim 和第七天 completed 状态,再播放公共奖励动画。领取过程不重新请求活动接口。
每天自动弹窗记录按 UID、活动 ID 和服务器 UTC+8 日期隔离。同步失败允许在当前弹窗点击当天卡片重试,但不清除当天已弹记录;关闭后当天不会再次自动弹出。弹窗打开期间切回前台不重复查询。
当前沿用客户端增加资产并调用资产保存接口的方式;查询响应必须是可消费的领取快照。后端若已经直接增加资产,必须改为读取资产最终值,不能再使用客户端累加。服务器需要维护跨日进度和幂等;前端不会把自己计算的 claimedCount 写回活动接口。
### 4.3 当前奖励配置
当前已联调的后端数据为:
| 天数 | 奖励 |
| ---: | --- |
| 1 | 无限体力 900 秒(15 分钟) |
| 2 | 锤子 ×1 |
| 3 | 无限体力 1800 秒(30 分钟) |
| 4 | 冻结 ×1、魔法棒 ×1 |
| 5 | 金币 ×600 |
| 6 | 锤子 ×1、冻结 ×1(策划调整:删除魔法棒,服务端待同步确认) |
| 7 | 无限体力 3600 秒(1 小时)、猫皮肤 `itemId=12` ×1 |
正式奖励完全以服务端 `rewards` 为准,前端不再维护模拟奖励配置。
## 5. 环境和服务器路由
服务器地址定义在 `assets/Script/module/Pay/Utils.ts`:
```text
正式服务器:https://q6rvwvtnga.sealoshzh.site/
测试服务器:https://sor779u2w8.sealoshzh.site/
```
路由规则:
| `envVersion` | 项目识别 | 使用地址 |
| --- | --- | --- |
| `develop` | 开发版 | 测试服务器 |
| `trial` | 体验版 | 测试服务器 |
| `release` | 正式版 | 正式服务器 |
| 其他/未知 | 未知版本 | 正式服务器兜底 |
因此正常发布流程不需要上线前手工把 `testHttpip` 改成正式地址。体验版继续访问测试服,正式发布后自动切换正式服。
正式上线前必须同时确认:
- 微信后台已经配置正式请求域名。
- 开发/体验测试需要的测试域名也已配置。
- 两个服务器部署了兼容的数据结构和对应接口。
- 正式服的活动配置、奖励、触发等级、活动期限已经检查。
## 6. 对主项目原有文件的修改
### 6.1 `assets/Scene/HomeScene.fire`
语义上的新增内容只有 `Canvas/sevenDayGift` 活动宿主节点,并挂载主包中的 `SevenDayGiftHost`。场景不再序列化引用活动 Prefab;宿主通过 Bundle 名和资源路径动态加载,避免 Prefab 依赖把整个活动反向带入主包。
由于 Cocos 场景文件使用数组 `__id__` 交叉引用,插入节点后大量后续编号发生位移,Git 会显示上千行机械差异。评审时应重点确认新增节点、父节点、组件和 UUID 引用,不应把所有 `__id__` 位移误判成业务改动。
### 6.2 `assets/Script/JiaZai.ts`
每日任务数据增加空字段保护:
- `levelPass`、`share`、`useEnergy`、`useProp` 缺失时建立默认对象。
- 后端任务数据不完整时只更新实际存在的字段。
这属于联调期间为避免每日任务接口变化导致主页 `checkTasks()` 崩溃而增加的兼容,不是七日活动核心逻辑,但主页如果在这里抛异常,会连带影响七日活动初始化和测试。七日活动已删除入口,不再修改主页入口渐隐列表。
### 6.3 `assets/Script/GameManager.ts`
登录返回的 `data.data.task` 同时兼容:
- JSON 字符串。
- 已经解析好的对象。
- 缺少部分任务字段。
- 无法解析的异常字符串。
原实现无条件 `JSON.parse()`,后端改为对象或返回异常结构时会抛错;现在使用类型判断和 `try/catch`,只覆盖实际存在的任务字段。
### 6.4 `assets/Script/module/Pay/Utils.ts`
修改内容:
- 恢复独立测试服务器 `testHttpip`。
- `POST()` 根据微信环境选择 `testHttpip` 或 `httpip`。
- 每日任务保存和领取结果增加空字段保护。
这项环境路由是七日活动安全测试和上线的关键。不要为了临时联调再次把 `testHttpip` 指向正式服,否则开发版和体验版会修改正式用户数据。
### 6.5 `assets/Script/Reward.ts`
项目公共奖励弹窗原来只支持 Prefab 中预先存在的固定图标节点。本次增加 `getOrCreateRewardIcon()`:
- 优先查找 `icon/<reward type>` 现有节点。
- 找不到节点但调用方传入 `spriteFrame` 时,运行时创建 Sprite 节点。
- 找不到节点且没有 `spriteFrame` 时打印警告,不让空引用直接崩溃。
- `cat_skin` 使用 1.1 缩放。
七日活动把 `magic_wand` 转为公共奖励弹窗原有名称 `magic`;猫皮肤则额外传入活动中的 `catArt` SpriteFrame。
### 6.6 `build-templates`
记录时 `build-templates` 相对 `main` 没有差异,不属于本次七日活动功能改动。后续排查 `game.json`、`project.config.json` 或分包模板问题时,应单独检查负责人提供的模板版本,不要把模板问题和七日活动脚本混为一谈。
## 7. 日志和排查方式
上线版本只保留超时、领取失败、资产同步失败和缺失资源等异常日志,不再打印完整请求参数及响应。联调时使用微信开发者工具 Network 面板,并结合后端日志确认接口:
```text
signInActivityInfo
userCoin / userProp / userPower / setCatArr
```
常见问题排查:
| 现象 | 优先检查 |
| --- | --- |
| 达到 23 关但没有自动弹 | `signInActivityInfo` 的 `activityId`、`triggerReached`、`status`、`endAt`、`canClaim`;再查服务器 `levelAmount` 和本地当天自动弹记录 |
| 每次回主页都重复弹 | 是否每次清缓存;UID/activityId 是否变化;自动弹出本地记录是否被其他逻辑清除 |
| 卡片不能领取 | `canClaim`、`nextRewardDay`、当前卡片 `claimed`;查看 `signInActivityInfo` 返回及资产同步错误 |
| 奖励数量为 0 | 后端是否返回 `count` 或 `amount`;值是否能转换为数字 |
| 猫皮肤动画不显示 | `Reward.ts` 是否收到 `spriteFrame`;活动猫图片 UUID 是否有效 |
| 猫皮肤没有保存 | 查看 `setCatArr` 的请求、`itemId` 和返回内容 |
| 微信报合法域名错误 | 微信后台 request 合法域名是否包含当前环境服务器域名 |
| 活动测试 UID 变化 | 登录接口、本地 `uid` 缓存、`GM_INFO.uid` 是否被其他流程重写 |
## 8. 正确测试流程
### 8.1 UI 验收
测试代码已从上线分支删除。请由后端准备不同活动进度的测试 UID,在微信开发版或体验版依次验证:
- 第 1~7 天布局。
- 单奖励和多奖励的图片大小与重叠,确认不显示数量文字。
- 今日已领取状态。
- 七天完成状态。
- 活动过期状态。
- 自动弹出、自动领取、领取期间禁止关闭和领取后关闭。
- 公共奖励动画。
前端不再提供模拟日期、清除自动弹出记录或增加资产按钮。
### 8.2 完整测试服流程
准备干净测试 UID:服务器等级 22,并且没有七日活动记录。
1. 22 级进入主页,确认没有自动弹窗。
2. 通关并让服务器等级变成 23。
3. 返回主页,确认自动弹一次并自动发起领取。
4. 自动领取完成前确认关闭按钮不可用,完成后可以关闭。
5. 再进主页或切前后台,确认当天不重复自动弹。
6. 确认领取接口、Loading、奖励动画和资产变化。
7. 重启游戏,确认资产持久化。
8. 当天重复点击领取,确认后端不重复发放。
9. 由后端推进测试日期或重置测试活动,完成第 2~7 天验证。
10. 领满后确认不再弹出。
11. 使用另一条未领满记录推进到 `endAt` 之后,确认不再弹出。
12. 使用一个等级大于 23 且没有活动记录的老玩家 UID,验证补触发逻辑。
修改服务器等级不会删除已经创建的活动记录,也不会清除本地自动弹出记录。要重新测试“22 → 23 首次触发”,必须使用新 UID,或者让后端删除该 UID 的活动记录,并同时清除本地自动弹出记录。
### 8.3 异常测试
- 断网进入主页。
- 查询接口超时后恢复网络。
- 领取时连续快速点击。
- 领取响应返回后立即杀进程。
- 第 7 天保存猫皮肤时断网。
- 切后台后重新进入。
- 清缓存后重新登录。
- 同一设备切换两个 UID。
- 后端缺少部分每日任务字段时主页不崩溃。
其中“后端已经确认领取,但客户端资产同步尚未完成时退出”是需要重点关注的边界。当前流程消费 `signInActivityInfo` 返回的奖励快照,再更新金币、道具、无限体力和猫皮肤;服务端必须提供可查询、可重试且幂等的最终结果,不能只依赖本地领取标记。
## 9. 上线流程
1. 整理工作区,只保留确认需要的业务改动。
2. 把七日活动目录和所有对应 `.meta` 纳入 Git。
3. 提交功能分支。
4. 获取并合并最新 `main`。
5. 冲突解决后重新执行测试服完整流程。
6. 合并到发布分支或 `main`。
7. 从确定的发布 commit 做一次干净微信小游戏构建。
8. 微信开发者工具确认无新增红色业务错误、分包正确、请求域名正常。
9. 上传开发版本并设置体验版。
10. Android、iOS 真机测试,确认体验版仍访问测试服务器。
11. 后端确认正式接口和活动配置已部署。
12. 提交审核;审核通过后发布。
13. 如果后台支持灰度,优先灰度并观察活动查询、领取、重复领取拦截和猫皮肤保存错误率。
正式发布后需用正式环境测试账号做最小冒烟验证:
- 页面上不存在“7日测试”和“接口反馈”按钮。
- `signInActivityInfo` 请求正式服务器。
- 达标且可领取用户当天自动弹出一次并自动领取。
- 一次领取可以完整到账。
- 领取后状态和资产重登仍一致。
## 10. 后续修改指南
### 10.1 修改触发等级或活动期限
触发等级和期限应优先修改后端配置。前端只消费:
- `triggerLevel`
- `triggerReached`
- `startAt`
- `endAt`
- `status`
前端没有触发等级和期限的本地模拟配置。
### 10.2 修改奖励数量
修改后端 `rewards` 配置。保持 `count` 为首选字段,并继续兼容 `amount`。
### 10.3 增加新的奖励类型
至少检查以下位置:
1. `SevenDayRewardItem.type` 类型声明。
2. `SevenDayGift.getRewardIcon()` 的活动卡片图标。
3. `SevenDayGiftReward.grant()` 的真实资产发放。
4. `SevenDayGiftRuntime.showRewardWindow()` 对公共奖励类型的转换。
5. `Reward.ts` 的公共奖励动画图标创建逻辑。
6. 图片资源及 `.meta`。
7. 后端奖励配置与服务端幂等处理。
只增加图片但不增加发奖分支,会出现“界面能看到、资产不增加”;只增加发奖分支但不配置图标,会出现“奖励到账但动画没有图”。
### 10.4 修改 Bundle 加载策略
- 主包只能依赖 `SevenDayGiftHost.ts` 和 `SevenDayGiftBootstrapApi.ts`。
- 不要在主包脚本中静态 `import` Bundle 内的 `SevenDayGift`、`SevenDayGiftRuntime`、完整 API 或 Reward。
- `HomeScene.fire` 不要重新添加活动 Prefab 的序列化引用。
- 正式版保持按需加载;如果修改释放逻辑,必须验证关闭活动后 `cc.assetManager.getBundle("seven_day_gift")` 返回空,并验证第二天仍可重新加载。
### 10.5 修改活动图片或 Prefab
- 优先在 Cocos Creator 2.4.15 中操作 Prefab 和场景。
- 保留已有 `.meta`,不要删除后让 Creator 生成新 UUID。
- 替换图片时检查透明边距、原始尺寸和 Sprite `sizeMode`。
- 保存场景后检查是否只产生预期语义变化。
- 构建后必须在微信开发者工具再次验证,不能只点微信开发者工具“编译”来代替 Cocos 重新构建。
## 11. 当前工作区风险快照
当前工作区仍有数千项状态变化,绝大多数为 `.meta` 修改,并有 3 个与七日活动无关的 `.meta` 删除:
```text
assets/gacha_bundle/img/cat.meta
assets/libs/dn-sdk-minigame.meta
assets/pause/texture.meta
```
不要使用未经检查的 `git add -A`,否则可能把大量 Creator 自动改写或无关资源变化一起提交。
建议提交前逐项确认以下范围:
```text
assets/seven_day_gift.meta
assets/seven_day_gift/
assets/Script/seven_day_gift.meta
assets/Script/seven_day_gift/
assets/Script/ActivityPopupAnimator.ts
assets/Script/ActivityPopupAnimator.ts.meta
assets/Scene/HomeScene.fire
assets/Script/GameManager.ts
assets/Script/JiaZai.ts
assets/Script/Reward.ts
assets/Script/module/Pay/Utils.ts
docs/seven-day-gift-maintenance.md
```
项目配置文件和 `build-templates` 不属于当前七日活动相对 `main` 的有效内容差异,除非负责人明确要求更新,否则不要顺手提交。
## 12. 已知边界与维护原则
- 活动创建、触发等级、自然日、可领取状态和过期判断的最终权威是后端。
- 上线分支没有内置测试面板,活动状态测试依赖后端测试账号和微信开发者工具 Network 面板。
- 自动弹出记录是设备本地状态,清缓存和换设备后可能再次弹出;但后端 `canClaim` 仍决定是否有奖励可领。
- 客户端 `claimId` 防重不能代替服务端幂等。
- 正式版不打印七日 API 的详细前端日志,因此正式环境需要后端监控。
- 体验版走测试服,无法仅靠体验版证明正式服务器配置正确;正式发布前必须单独验证正式接口部署和配置。
- 场景和 Prefab 的 UUID 依赖 `.meta`,资源提交必须完整。
- 修改主项目公共奖励窗口或网络基类时,要回归其他活动,避免只验证七日活动。
- Bundle 卸载只能保证七日活动自身持有的资源引用被释放;若其他主包节点重新持有 Bundle 内 SpriteFrame、Prefab 或脚本对象,资源仍可能无法及时回收。