diff --git a/docs/adr/【ADR】DirectProject对话滚动与历史自动加载-2026-10-02.md b/docs/adr/【ADR】DirectProject对话滚动与历史自动加载-2026-10-02.md index f47019f52..2727e9a24 100644 --- a/docs/adr/【ADR】DirectProject对话滚动与历史自动加载-2026-10-02.md +++ b/docs/adr/【ADR】DirectProject对话滚动与历史自动加载-2026-10-02.md @@ -35,14 +35,15 @@ DirectProject 聊天区(`apps/ai-game-creator-shell/src/view/project-developme - 列表底部居中的悬浮胶囊(`sticky`),跟着滚动容器走、不随内容滚走。 - 距底部超过 48px 时出现,文案「回到底部」;用户不跟随时来了新的终态内容就改成「有新回复 · 回到底部」。 - 点击:平滑滚到底部 + 恢复跟随最新 + 清除「有新回复」,随后按钮自行消失。 +- 平滑滚动期间滚动位置归这次程序化滚动所有:滚动事件不再翻转「跟随最新」,布局补偿也不写 `scrollTop`(写一次就会取消动画并把画面拉回原处,表现为「点了只下去一屏、到不了底」)。滚到贴底阈值即交还控制权;用户中途用滚轮 / 触摸 / 键盘打断则立刻交还,不会卡住后续跟随。 ### 4. 跟随最新与折叠展开 - 距底部 ≤ 48px 视为「在底部」,即跟随最新;用户手动滚回去(进入阈值)就自动恢复跟随,不需要额外开关。 - 用 `ResizeObserver` 观察列表的直接子元素(`MutationObserver` 负责在子元素变化时重订阅)——任何高度变化: - 跟随时 → 贴底; - - 不跟随时 → 还原顶部可见回合锚点(用户正在读的那条折叠头留在原位);若刚刚展开的那个块头部仍然可见,则按展开前记录的屏幕位置把它冻结; - - 展开正文比视口还高、头部锚不住时 → 对齐正文顶部。 + - 不跟随时 → 还原顶部可见回合锚点(用户正在读的那条折叠头留在原位);若刚刚展开的那个块头部仍然可见,则按展开前记录的屏幕位置把它冻结,并把新展开的正文露出来:正文底边超出视口就只滚到刚好露出底边,正文比视口还高则对齐正文顶部; + - 收起(正文高度归零)不额外滚动,只冻结头部。 - 新一回合开始(`turnInFlight` 由假转真)时强制恢复跟随并贴底,替代原先由视图直接写 `shouldFollowLatestRef` 的做法。 ### 5. 结构与样式 @@ -56,8 +57,9 @@ DirectProject 聊天区(`apps/ai-game-creator-shell/src/view/project-developme 1. **保留按钮 + 只加自动加载**:加载中仍靠按钮做唯一反馈,且删掉按钮后失败路径没有补救入口;按钮本身与滚动自动加载重复。 2. **在列表外面套一层 viewport 做浮层定位**:`PlanningChatView` 共用同一套容器规则,且工作台里 `.project-chat-conversation` 是 `display: block` + `height: 100%` 几何,套一层就会让 `height: 100%` 的列表塌成内容高度;改公共类会连带策划对话。改用列表内的 `sticky` 胶囊,零结构改动。 3. **只依赖原生 CSS scroll anchoring**:前插能免费对齐,但做不到「跟随时展开要贴底」,也无法在加载期间冻结同一套锚点;因此显式补偿 + 关闭原生锚定。 -4. **展开后总是把正文滚进视口**:会打断正在读历史的用户;采用「跟随时贴底 / 否则保锚点、头部锚不住才对齐正文顶部」。 -5. **自动重试失败的历史加载**:弱网下会反复打接口,且用户看不出到底在重试还是在挂起;改为挂起 + 内联重试行。 +4. **展开后总是把正文滚进视口**:对正文比视口矮的折叠块会把画面大幅上移,打断正在读历史的用户;采用「跟随时贴底 / 否则冻结折叠头 + 只滚到刚好露出新展开正文的最小位移」。 +5. **平滑滚动期间照常处理滚动事件与布局补偿**:程序化滚动会被应用自己的补偿打断(第一次写 `scrollTop` 即取消动画),用户点了「回到底部」也停在半路;因此改为滚动期间冻结这两条路径。 +6. **自动重试失败的历史加载**:弱网下会反复打接口,且用户看不出到底在重试还是在挂起;改为挂起 + 内联重试行。 ## 影响 diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index bc2fa653a..fddbd7a79 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -6,6 +6,8 @@ - 决策:删按钮改自动加载——触顶 24px 与「首帧后内容填不满视口」共用一道门(有更早历史 ∧ 不在加载中 ∧ 无失败记录),失败挂起、只留内联「加载更早对话失败 · 重试」且不自动重试;加载行挂载在列表最上方、延迟 150ms 才显示。前插按「回合 key(`data-turn-key`)+ 块内序号 + 相对列表顶边偏移」冻结锚点,列表显式 `overflow-anchor: none`;加载期间所有补偿还原同一个冻结锚点,加载结束后的下一次补偿再刷新。底部居中 `sticky` 胶囊「回到底部」(不跟随时来了新终态内容改「有新回复 · 回到底部」):距底 48px 阈值、点击平滑滚动并恢复跟随。`ResizeObserver` 观察列表直接子元素(`MutationObserver` 负责子元素变化时重订阅):跟随时任何高度变化贴底,否则冻结刚展开的折叠头,头部锚不住再对齐展开正文顶边;新一回合开始(`turnInFlight` 假转真)强制恢复跟随。滚动所有权(列表 ref、跟随最新、补偿、胶囊显隐)从 `DirectProjectChatView` 搬进 `DirectProjectConversation` 及其同目录 hook,控制器新增可渲染的 `historyLoading` / `historyError` 与 `retryEarlierHistory`。 - 边界:只做 DirectProject;`PlanningChatView` 与 `App.tsx` 里的 `message-history-more` 遗留路径不动,因此该样式保留(后续项已写进 ADR)。新增元素全部用内联 Tailwind,`styles.css` 未改;阈值、文案与判据集中在同目录 `conversationScrollPolicy.ts`,契约见 [`【ADR】DirectProject对话滚动与历史自动加载-2026-10-02`](../../adr/【ADR】DirectProject对话滚动与历史自动加载-2026-10-02.md),旧「单一事实源」ADR 的分页条目已改为引用它。 - 验证:新增 37 条与实现同目录的用例(阈值与加载门、锚点读取/还原、折叠头冻结与正文对齐、hook 的触顶/填充/胶囊/未读/延迟加载行、组件层的按钮移除与内联重试行)由根 `vitest.config.ts` 的 include 收进门禁;`npm run ai-game-creator-shell:typecheck`、`eslint`(含新文件)、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过;滚动观感(顶部加载圈、胶囊显隐、底部展开回贴、历史前插不跳)留真机手动验收。 +- 追加(2026-10-02,两个真机缺陷的根因与修正):①「点回到底部只下去一屏、到不了底」——平滑动画期间滚动事件把「跟随最新」翻成假,布局补偿与锚点还原接着写 `scrollTop`,而真实浏览器里任何一次写都会取消正在跑的平滑动画;现在滚动位置由这次程序化滚动独占(滚动事件只在贴底时才结算并交还,补偿整段跳过),滚轮 / 触摸 / 键盘接手立刻交还,避免标记永远挂着。②「展开折叠块没有自动滚动到位」——旧规则只在展开正文比视口还高时才动,正文矮的折叠块(工具组、思考块)展开后正文仍在视口外;现在冻结折叠头之后统一补「刚好露出新展开正文」的最小位移(底边超出就补超出量,比视口还高则对齐正文顶边),两段位移合成一次写。落在 `conversationToggleReveal.ts`(新增纯函数 `toggleRevealDelta`)与 `useConversationScroll.ts`(新增 `programmaticScrollRef`)。 +- 验证(2026-10-02 追加):同目录用例补齐到 48 条(新增 `toggleRevealDelta` 六例、hook 的四例程序化滚动用例,其中两例在修正前确实红)全部通过;Chromium 真机脚本复验三处——点回到底部收敛到 `scrollHeight - clientHeight`、底部展开贴到新底、视口外展开补 269px 后正文底边正好贴视口下缘。 ## 2026-10-01 Web、后台与 AGC 一键联调