feat(r2): 阶段4 store 降级为离线兜底缓存层

- designList/address 两页缓存优先渲染(冷启动不空屏),联网后以服务端为准覆盖
- store/design.ts、store/address.ts 文件头注明缓存层语义(回写/兜底/旧数据不合并)
- 流程文档勾选阶段 1-4 进度

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-12 03:58:55 +08:00
co-authored by Claude
parent e557dbcb89
commit 954cddfc22
5 changed files with 30 additions and 10 deletions
+10 -8
View File
@@ -89,7 +89,7 @@
`ordered` **不落库**,由 `orderId != null` 派生;前端不提交这个状态。
3. 确认 Prisma `Address` / `DesignList` 模型字段与契约一致,缺字段先出迁移。
### 阶段 1:后端补齐 CRUD(先做,前端等它)
### 阶段 1:后端补齐 CRUD(先做,前端等它)✅(2026-09-12,后端提交 0a3c8e8
改动范围:`src/addresses/``src/design-list/`,两个模块均已注册,骨架已存在。
@@ -114,7 +114,7 @@
4. `findOne` 补归属校验(当前 TODO)。
5. Swagger 补全以上全部接口。
### 阶段 2:前端 API 层(页面不动)
### 阶段 2:前端 API 层(页面不动)✅(2026-09-12,前端提交 8438fea
1. `src/utils/api/address.ts`(现为空占位):实现
`fetchAddresses / createAddress / updateAddress / deleteAddress / setDefaultAddress`
@@ -126,7 +126,7 @@
3. `src/types/index.ts``AddressItem` 增加服务端字段(服务端 id、`createdAt` 等);
`DesignItem.status``'processing'``DesignItem.orderId` 派生 `ordered` 展示。
### 阶段 3:切换页面(两个页面 + 三个写入点)
### 阶段 3:切换页面(两个页面 + 三个写入点)✅(2026-09-12,前端提交 e557dbcWCD 红线已按上文落实)
| 文件 | 改动 |
|---|---|
@@ -136,16 +136,18 @@
| `pages/diy/index.tsx`(保存 designData | `updateDesign` 走 API`designData.category` 裁剪为 `{id, mask, tone}`(决策#2);贴纸本地图路径允许暂存(R4 派单前才持久化,契约约束 #1)。**WCD 红线**`category.mask` 必须保留;`stickers[].rotation/zIndex` 随保存持久化;items 是全量替换——提交前必须基于服务端最新 designData(含 R4 写入的 `wordcloud` 分组)合并改动后整包提交,不得只传改动片段(见「WCD 格式硬性规定」) |
| `pages/diy/stickerEdit/index.tsx` | 同上,保存贴纸改动走 API;同样受 WCD 红线约束(合并后整包提交,rotation/zIndex 带全) |
### 阶段 4:本地 store 降级改造
### 阶段 4:本地 store 降级改造 ✅(2026-09-12
`utils/store/address.ts``design.ts` 保留,但语义变为"离线兜底缓存":
`utils/store/address.ts``design.ts` 保留,但语义变为"离线兜底缓存"(文件头已注明)
- API 成功 → 把服务端数据写回本地缓存(下次冷启动先展示缓存再刷新);
- API 成功 → 把服务端数据写回本地缓存(下次冷启动先展示缓存再刷新designList/address
两页已实现缓存优先渲染);
**designData 原样存储**:不得清洗 `wxfile://` 等本地贴纸路径、不得裁剪任何字段
WCD 硬性规定 #4/#5);
- API 失败/断网 → 页面读缓存并可正常浏览,写操作提示失败;
- 登录后首次进入:只读服务端,**不自动合并**本地旧数据(`smart_design_list_<openid>`
与服务端并存的问题按路线文档风险节处理:忽略或提供一次性导入,默认忽略)。
- 登录后首次进入:只读服务端,**不自动合并**本地旧数据(联网刷新以服务端为准覆盖缓存,
`smart_design_list_<openid>` 与服务端并存的问题按路线文档风险节处理:忽略或提供
一次性导入,默认忽略)。
### 阶段 5:联调与验收
+3 -1
View File
@@ -28,7 +28,9 @@ export default function AddressPage() {
const [isDefault, setIsDefault] = useState(false)
const load = () => {
// API 优先,成功后回写本地缓存;失败降级读缓存
// 缓存优先展示(冷启动不空屏),再拉服务端刷新;
// 刷新成功回写缓存并以服务端为准覆盖(旧本地数据不自动合并,route-r2 风险节)
setList(getAddressList())
fetchAddresses()
.then(data => {
setList(data)
+3 -1
View File
@@ -41,7 +41,9 @@ export default function DesignListPage() {
const [selected, setSelected] = useState<Set<string>>(new Set())
const load = useCallback(() => {
// API 优先,成功后回写本地缓存(checkout 等页面仍读缓存);失败降级读缓存
// 缓存优先展示(冷启动不空屏),再拉服务端刷新;
// 刷新成功回写缓存并以服务端为准覆盖(旧本地数据不自动合并,route-r2 风险节)
setList(getDesignList())
fetchDesignList()
.then(data => {
setList(data)
+7
View File
@@ -1,3 +1,10 @@
/**
* 收货地址本地存储 —— R2 后降级为「离线兜底缓存」层(按 openid 隔离,见 keys.ts)。
* 真实 CRUD 已走 utils/api/address.ts;本层职责:
* - 页面 API 成功 → 回写缓存,供冷启动先展示与未迁移页面(checkout 等)读取;
* - API 失败/断网 → 页面读缓存正常浏览;
* - 联网刷新以服务端为准覆盖缓存,旧本地数据不做自动合并(route-r2 风险节:默认忽略)。
*/
import Taro from '@tarojs/taro'
import type { AddressItem } from '../../types'
import { key } from './keys'
+7
View File
@@ -1,3 +1,10 @@
/**
* 设计清单本地存储 —— R2 后降级为「离线兜底缓存」层(按 openid 隔离,见 keys.ts)。
* 真实 CRUD 已走 utils/api/design.ts;本层职责:
* - 页面 API 成功 → 回写缓存,供冷启动先展示与未迁移页面(checkout 等)读取;
* - API 失败/断网 → 页面读缓存正常浏览;
* - 联网刷新以服务端为准覆盖缓存,旧本地数据不做自动合并(route-r2 风险节:默认忽略)。
*/
import Taro from '@tarojs/taro'
import type { DesignItem } from '../../types'
import { assetUrl } from '../asset'