Files
Genarrative/apps/ai-game-creator-shell/src/view/project-development/resourceCanvasController.ts
T
suzmii 09ed7b099b 视图切换取消排队预取在生产路径上真正生效:视图标识改为必填
- 原缺陷:预览 Hook 的预取作用域 key 缺省退化为"被喂进来的资源集合签名",而宿主按设计要求恒传**全量投影**(传全量才不会让总览里其它栏目只剩栏目标题栏),换栏目/换视图一字不改 ⇒ key 不变 ⇒ 取消上一视图排队预取的 effect 永不执行,"同级裁决"一并退化为 no-op。已有用例用"改 resources"模拟切视图,测的是生产不存在的调用方形状。
- resourceCanvasController.ts 新增 createResourceCanvasPrefetchScopeKey({ view, target, mode }):由视图身份(main / child:<栏目>)加排序模式算出标识。
- index.tsx 在资源画布处显式算出该标识并传给预览 Hook(栏目取 resourceBookState.view / resourceBookState.category,排序取 sortMode)。
- useProjectResourceCardPreviews.ts 把 prefetchScopeKey 由可选改为**必填**并删掉那段兜底:它能"看起来还在工作",正是它掩盖了漏接线;现在漏传是类型错误而不是静默少取消一次。
- 断言:resourceCanvasController.test.ts 新增标识派生两组用例(换栏目/换视图/换排序模式必须变,同一视图必须稳定);useProjectResourceCardPreviews.test.ts 改写两条既有切视图用例为生产形状(resources 恒为全量、只改视图标识与 eagerResources),并在用例内前置断言"换栏目必须换标识";其余既有用例经用例侧包装补齐标识,形状与生产一致,断言一条未放宽。
- 变异验证(提交前已跑):把 createResourceCanvasPrefetchScopeKey 的栏目分量去掉(只留 view + mode)→ 3 条用例变红(标识派生 / 取消上一视图排队预取 / 取消后重新可见再入队),还原后复跑 34 passed。
- 门禁:`npx vitest run` 上述两文件 34 passed;typecheck 见随后整轮。
2026-09-11 21:31:30 +08:00

28 lines
1.2 KiB
TypeScript
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.
export function createResourceCanvasPageCategorySignature<
TCategory extends string,
>(resources: readonly { category: TCategory }[]) {
return resources
.map((resource) => resource.category)
.sort()
.join('|');
}
/**
* 「当前为谁预取」的视图标识(`useProjectResourceCardPreviews` 的 `prefetchScopeKey`)。
*
* 它必须由**视图身份**算出,不能拿喂给预览 Hook 的资源集合签名代替:那个集合是
* **全量投影**(`index.tsx` 的注释写明收窄它会让总览里其它栏目只剩栏目标题栏),
* 换栏目/换视图**一字不改**,于是"资源 id 签名"恒不变 —— 视图切换时取消上一视图
* 排队预取的逻辑就成了一条永不执行的死代码,"同级裁决"也一并退化为 no-op。
*
* 组成:视图(`main` 总览 / `child:<栏目>`)+ 排序模式。同一栏目换排序会整体重排卡片,
* 对用户就是换了一次视图,因此也纳入标识。
*/
export function createResourceCanvasPrefetchScopeKey(input: {
view: 'main' | 'child';
target: string | null;
mode: string;
}) {
return `${input.view}:${input.target ?? ''}|${input.mode}`;
}