修复资源总览只画当前栏目卡片的问题:拆开身份口径与热预取口径
前一次改动(60d8b8fbb)把 `useProjectResourceCardPreviews` 的 `resources` 从全量投影收窄成当前分页栏目,造成产品回归:该入参不只喂热预取,它同时决定返回的 `identityByResourceId`,而 `renderResourceBookCard` 在身份缺失时 `return null`,于是资源总览(main 态)只有当前分页栏目画出真实卡片,其余栏目只剩栏目标题栏加空的层叠占位。 - 拆成两个入参:`resources` 恢复全量资源投影语义(决定 `identityByResourceId`、缓存与卡片挂载),新增 `eagerResources` 只用于 `eagerPreviewLimit` 计数的热预取,缺省回退 `resources`。两个入参的语义写进 Hook 参数注释,调用方 `index.tsx` 在传参处注明「收窄 `resources` 会让其它栏目只剩标题栏」。 - 纠正前一次提交的说法:**identity map 必须保持全量**,不能跟着热预取一起收窄。热预取可以只喂当前栏目(上一个提交的意图保留、`A → B → 回 A` 会重读 A 可见卡的已知代价也保留),但身份 / 渲染口径收窄会让总览其它栏目不再挂载卡片——技术方案要求「主画布展示各子画布的缩略入口,内部按资源类型显示有限层叠卡片……主画布预览和子画布展开态复用同一套卡片视觉」,这是产品回归而非可接受的行为变更。 - 不使用「身份未知时用 idle 占位兜底渲染」这条备选:它会让总览卡片失去真实预览,观感更差。 - `pitfalls.md` 追加同题排障口径,含通用规则:凡 Hook 入参同时参与「身份 / 缓存 key」与「调度 / 预热」,就不能为优化调度去收窄它,应先确认它还有没有别的消费者。 - 回归用例 `appSurface > uses one full-page canvas per resource section with dependency-only guide lines` 已自行变绿(未改该断言)。验证:`npm run test -- apps/ai-game-creator-shell/tests` 1171 passed / 4 skipped / 0 failed;`appSurface.test.ts` + `useProjectResourceCardPreviews.test.ts` 415 passed;`src/components/image-editor` 1385 passed;typecheck exit 0;check:encoding 4374 文件;`git diff --check` 干净。
This commit is contained in:
@@ -1860,7 +1860,13 @@ export default function ProjectDevelopmentView({
|
||||
projectPath,
|
||||
projectId: manifest.projectId,
|
||||
mode: sortMode,
|
||||
resources: activePageResources,
|
||||
// `resources` 决定 `identityByResourceId`,而 `renderResourceBookCard` 在身份缺失时
|
||||
// 直接不挂载卡片。总览(main 态)要同时画出每个栏目的层叠卡片,所以这里必须保持
|
||||
// 全量投影;收窄它会让除当前分页栏目以外的栏目只剩栏目标题栏。
|
||||
resources: canvasResources,
|
||||
// 真正要收窄的是热预取:只让当前分页栏目先占读取槽。传全量时前 12 张可能落在
|
||||
// 用户看不到的栏目,看得见的卡片反而要排队。
|
||||
eagerResources: activePageResources,
|
||||
canvasRef: resourceCanvasRef,
|
||||
// 资源卡片渲染在资源画本场景里,可见性判定要用真正包含它们的容器。
|
||||
intersectionRootRef: resourceBookManagerRef,
|
||||
|
||||
+20
-1
@@ -201,7 +201,22 @@ export function useProjectResourceCardPreviews(input: {
|
||||
projectPath: string;
|
||||
projectId: string;
|
||||
mode: ProjectResourceCanvasLayoutMode;
|
||||
/**
|
||||
* 身份与渲染口径,**必须传全量资源投影**。
|
||||
*
|
||||
* 这里同时决定 `identityByResourceId`,而调用方在身份缺失时会直接不挂载卡片
|
||||
* (`ProjectDevelopmentView` 的 `renderResourceBookCard` 对未知身份 `return null`)。
|
||||
* 因此把本参数收窄成「当前分页栏目」会让总览里其它栏目只剩栏目标题栏和空的缩略卡片。
|
||||
* 需要缩小预热范围请用 [`eagerResources`],不要改这里。
|
||||
*/
|
||||
resources: ProjectResource[];
|
||||
/**
|
||||
* 只用于热预取(`eagerPreviewLimit` 计数的那个集合),不影响身份 / 缓存 / 渲染。
|
||||
*
|
||||
* 缺省回退到 `resources`。资源画布传「当前分页栏目」,避免用户看不到的栏目先占满
|
||||
* 全局物理读取槽;传全量时前若干张可能落在别的栏目,看得见的卡片反而要排队。
|
||||
*/
|
||||
eagerResources?: ProjectResource[];
|
||||
canvasRef: React.RefObject<HTMLDivElement | null>;
|
||||
// 可见性判定容器。卡片渲染在资源画本场景里时,传真正包含卡片的容器;
|
||||
// 缺省回退到 canvasRef。
|
||||
@@ -670,8 +685,11 @@ export function useProjectResourceCardPreviews(input: {
|
||||
Math.floor(input.eagerPreviewLimit ?? 0),
|
||||
),
|
||||
);
|
||||
// 只预热 `eagerResources`(缺省回退 `resources`):身份与缓存仍然覆盖全量投影,
|
||||
// 这里收窄的仅仅是「谁先占读取槽」。
|
||||
const eagerResources = input.eagerResources ?? input.resources;
|
||||
let requested = 0;
|
||||
for (const resource of input.resources) {
|
||||
for (const resource of eagerResources) {
|
||||
if (requested >= eagerPreviewLimit) {
|
||||
break;
|
||||
}
|
||||
@@ -690,6 +708,7 @@ export function useProjectResourceCardPreviews(input: {
|
||||
}, [
|
||||
identityByResourceId,
|
||||
input.eagerPreviewLimit,
|
||||
input.eagerResources,
|
||||
input.resources,
|
||||
requestPreview,
|
||||
]);
|
||||
|
||||
@@ -197,6 +197,15 @@
|
||||
- 验证:先让旧 scope 占满 3 个 permit,再连续执行 A → B → A、mode、Hook 和多窗口切换;断言原生活动峰值始终 `<= 3`,旧等待任务不打开文件,旧在途任务在最近检查点释放,新 scope 随后启动,取消任务不编码 data URL / 不创建 Blob URL,最终活动 request / scope registry 为零。阻塞读取进入后主动 abort 外层 future,必须证明旧 blocking 任务仍占 permit、仍可按 scope 取消且新请求不能提前启动。另分别证明 seen request `8192` 项的硬上限、cancelled scope 超预算时不淘汰活动记录,以及任一活动 scope 结束后非活动 tombstone 立即收敛到 `1024` 项预算。前端再断言旧 `then / catch / finally` 和取消 ACK 均不写新 scope;内部取消类别只允许精确匹配,不能因真实错误正文恰好包含该标识而静默吞错。
|
||||
- 关联:`apps/ai-game-creator-shell/src/view/project-development/useProjectResourceCardPreviews.ts`、`apps/ai-game-creator-shell/src-tauri/src/resource_preview_scheduler.rs`、`apps/ai-game-creator-shell/src-tauri/src/resource_inspect.rs`、`apps/ai-game-creator-shell/src-tauri/src/image_inspect.rs`。
|
||||
|
||||
## 预览 Hook 的资源入参收窄会连带收窄 identity map,进而让总览其它栏目不画卡片(2026-09-11)
|
||||
|
||||
- 现象:资源总览(`main` 态)里只有「当前分页栏目」那一个栏目画出真实卡片,其余栏目只剩栏目标题栏加空的层叠占位。插桩实测:`main` 态下 5 个 `.game-resource-book-scene-card`,只有当前分页栏目的那个带 `.game-resource-card` 子节点,其余全部 0 子节点;把入参换回全量投影即整体恢复。
|
||||
- 原因:`useProjectResourceCardPreviews` 的 `resources` 入参**不只喂热预取**,它同时决定返回的 `identityByResourceId`;而 `ProjectDevelopmentView` 的 `renderResourceBookCard` 在身份缺失时直接 `return null`。所以「把 `resources` 换成当前栏目」看起来只是缩小预热范围,实际把身份 map 一起收窄了,总览里不在当前栏目的卡片就此不再挂载。技术方案明确要求「主画布展示各子画布的缩略入口,内部按资源类型显示有限层叠卡片……主画布预览和子画布展开态复用同一套卡片视觉」,因此这是产品回归,不是可接受的行为变更。
|
||||
- 处理:**把「身份 / 渲染口径」与「热预取口径」拆成两个入参**——`resources` 保持全量资源投影不变(决定 `identityByResourceId`、缓存与卡片挂载),新增 `eagerResources` 只用于 `eagerPreviewLimit` 计数的热预取,缺省回退 `resources`。两个入参的语义写进 `useProjectResourceCardPreviews` 的参数注释,调用方 `index.tsx` 也在传参处注明「收窄 `resources` 会让其它栏目只剩标题栏」。**不要**改用「身份未知时用 idle 占位兜底渲染」:那会让总览卡片失去真实预览,观感更差。
|
||||
- 通用规则:凡 Hook 的某个入参同时参与「身份 / 缓存 key」与「调度 / 预热」,就不能为了优化调度去收窄它。先确认这个入参还有没有别的消费者,再决定是拆参数还是加参数;同理适用于今后任何「只预热一部分」的优化。
|
||||
- 验证:`apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts` 的 `uses one full-page canvas per resource section with dependency-only guide lines` 会断言非当前栏目的 `.game-resource-book-scene-card` 内存在 `.game-resource-card`;`tests/useProjectResourceCardPreviews.test.ts` 覆盖 `eagerResources` 缺省回退到 `resources` 的语义。
|
||||
- 关联:`apps/ai-game-creator-shell/src/view/project-development/useProjectResourceCardPreviews.ts`、`apps/ai-game-creator-shell/src/view/project-development/index.tsx`、`apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts`、`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`。
|
||||
|
||||
## 依赖线与资源卡不在同一 transform 层时会在滚动和缩放中分离
|
||||
|
||||
- 现象:静止时依赖线似乎对齐,触摸板缩放或连续滚动后线段会追赶、漂移或忽隐忽现;某一资源分区的长线还可能出现在相邻分区。
|
||||
|
||||
Reference in New Issue
Block a user