Files
HomeAgent/cmd
root e0514c3692 refactor(ohos): ChatPage 1962→207 行(状态机/SSE/气泡/输入区拆分)
- common/ChatStore.ets(388):消息数组、分页游标、新消息入场标记、
  SSE 连接与重连、防抖刷新(50ms)统一成一个单例状态机
- common/ChatSse.ets(192):SSE 事件 → 状态的翻译层,逐分支照搬
  channel_output/agent_output/reasoning/delta/tool_call/stage/agent_error/
  sync_required;通过 ChatStreamSink 接口写入,避免与 ChatStore 形成循环依赖
- common/ChatSession.ets(176):POST /chat 与 POST /chat/file 的发送、
  超时兜底、POST 响应与 SSE 的合并判定
- common/ChatFormat.ets(223):mime 推断、ForEach 键 structSig、工具卡
  状态/颜色、渠道判定与头像配色
- common/ChatHistory.ets(96):历史载荷与 tool_calls 解析
- components/ChatBubble.ets(247):气泡(头像/渠道名/思考卡/工具卡/附件卡/正文)
- components/ChatToolCard.ets(253):思考卡 + 工具卡
- components/ChatStream.ets(210):消息列表 + 顶栏遮罩 + 底部淡出 + 触顶懒加载
- components/ChatComposer.ets(357):输入行、选图/选文件、沙箱落盘、发送
- components/ChatAttachBar.ets(139):加号菜单 + 待发送附件条

响应式语义刻意保持不变:数组不进 AppStorage,改用自增版本号 K_CHAT_REV
通知订阅组件重取快照(ChatStream 把它镜像进 @State messages,ForEach 每次
拿到的仍是新数组引用,与拆分前 this.messages = this.messages.slice() 等价);
structSig 仍不含 content,正文靠 MarkdownView 的 @Prop 流式更新;
markNew 仍不切片、入场动画交给紧随其后的 refresh();
animateTo 只能存在于组件里,所以折叠翻转的动作留在 ChatStream 内。

验证:hvigorw assembleHap BUILD SUCCESSFUL;SSE 各分支、ensureToolCall、
markNew、sendChat/sendWithAttachment 的守卫顺序均与原实现逐条比对过,
守卫从"页面方法内"移到输入区组件时保持了原有先后(连接判定先于清空输入)。
2026-09-13 22:19:05 +08:00
..