feat(chat): improve resilience and collapsible sidebar
问题描述:\n- 刷新页面、切后台或手机锁屏后,进行中的对话容易丢失,SSE 断开时前端还会插入假的错误气泡\n- 移动端首屏会话列表会短暂遮住聊天区\n- 桌面端侧栏无法折叠,在窄窗口和缩放场景占用过多横向空间\n\n复现路径:\n- 发起一轮对话,在模型仍在输出时刷新页面或锁屏后再回到页面\n- 在窄屏设备首次打开聊天页,观察会话列表首帧覆盖聊天内容\n- 在桌面端缩窄浏览器窗口,观察侧栏始终保持完整宽度\n\n修复思路:\n- 为 chat store 增加本地缓存、水合、in-flight 标记和轮询恢复,SSE 断开后静默从服务端回补真实结果\n- 将运行中指示统一到 isRunActive,让实时流式与恢复轮询共享同一状态\n- 在 ChatPanel 首帧同步读取媒体查询,避免移动端会话列表闪烁覆盖\n- 为侧栏增加可持久化的桌面折叠状态,并补充对应文案与回归测试
This commit is contained in:
@@ -11,7 +11,15 @@ const chatStore = useChatStore()
|
||||
const message = useMessage()
|
||||
const { t } = useI18n()
|
||||
|
||||
const showSessions = ref(true)
|
||||
// Initialize synchronously from the media query so first paint is correct.
|
||||
// On narrow viewports the session list is an absolute-positioned overlay
|
||||
// (z-index 10) on top of the chat area; if we default to `true`, onMounted
|
||||
// only flips it to `false` AFTER the first render, causing a visible flash
|
||||
// where the session list covers the chat content ("auto-fixes after a
|
||||
// moment" — that was the race).
|
||||
const showSessions = ref(
|
||||
typeof window === 'undefined' || !window.matchMedia('(max-width: 768px)').matches,
|
||||
)
|
||||
let mobileQuery: MediaQueryList | null = null
|
||||
|
||||
function handleSessionClick(sessionId: string) {
|
||||
|
||||
@@ -45,7 +45,7 @@ watch(
|
||||
scrollToBottom,
|
||||
);
|
||||
watch(
|
||||
() => chatStore.isStreaming,
|
||||
() => chatStore.isRunActive,
|
||||
(v) => {
|
||||
if (v) scrollToBottom();
|
||||
},
|
||||
@@ -61,7 +61,7 @@ watch(currentToolCalls, scrollToBottom);
|
||||
</div>
|
||||
<MessageItem v-for="msg in displayMessages" :key="msg.id" :message="msg" />
|
||||
<Transition name="fade">
|
||||
<div v-if="chatStore.isStreaming" class="streaming-indicator">
|
||||
<div v-if="chatStore.isRunActive" class="streaming-indicator">
|
||||
<video
|
||||
:src="isDark ? thinkingVideoDark : thinkingVideoLight"
|
||||
autoplay
|
||||
|
||||
Reference in New Issue
Block a user