From a1e05032a214ac14cbb50e1a4c4aab5565209902 Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Tue, 28 Jul 2026 23:24:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(quickdock):=20=E8=BF=9B=E9=A1=B5=E4=B8=8E?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E5=AF=B9=E8=AF=9D=E6=97=B6=E5=BF=AB=E6=8D=B7?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E9=9D=99=E6=80=81=E5=91=88=E7=8E=B0=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B7=A8=E5=B7=A5=E4=BD=9C=E5=8C=BA=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E6=A0=8F=E8=B7=B3=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 设置与内容状态改为 localStorage 同步缓存(主题缓存同模式): 自动展开设置、全局内容状态、按对话 ID 内容状态(LRU 上限 50) - 三态乐观掩码:assumedActive 生效时 hasContent 完全由缓存假定值 决定(含假定无内容),dock 与对话区同刻切换收起/展开 - 无过渡窗口重写为可重入机制:初始加载与切换对话(flush:sync) 两个时机开启,按 filesSyncSeq/todoSyncSeq 序号推进精确关窗 - 跨工作区点选对话时保持当前对话视图冻结,不再经过空对话 中间态,消除输入栏先上后下 --- static/src/app/methods/ui/hostWorkspace.ts | 58 +++--- .../components/chat/quickdock/QuickDock.vue | 165 +++++++++++++++++- .../components/chat/quickdock/quickdock.css | 7 + static/src/stores/file.ts | 6 + static/src/stores/personalization.ts | 36 +++- static/src/stores/quickDock.ts | 113 +++++++++++- 6 files changed, 352 insertions(+), 33 deletions(-) diff --git a/static/src/app/methods/ui/hostWorkspace.ts b/static/src/app/methods/ui/hostWorkspace.ts index 01e1aeca..eef0c4ce 100644 --- a/static/src/app/methods/ui/hostWorkspace.ts +++ b/static/src/app/methods/ui/hostWorkspace.ts @@ -57,7 +57,11 @@ export const hostWorkspaceMethods = { this.runningWorkspaceTasks = []; } }, - async handleHostWorkspaceSwitch(workspaceId) { + async handleHostWorkspaceSwitch(workspaceId, options = {}) { + // preserveConversationView:跨工作区点选具体对话时使用——保持当前对话视图冻结, + // 不做 /new 跳转与状态清空(否则空对话态会让居中输入栏「先往上再往下」), + // 目标对话由调用方随后立即加载 + const preserveConversationView = Boolean(options && options.preserveConversationView); const targetId = String(workspaceId || '').trim(); if (!targetId || this.hostWorkspaceSwitching) { return; @@ -102,31 +106,39 @@ export const hostWorkspaceMethods = { if (data.default_workspace_id) { this.defaultHostWorkspaceId = String(data.default_workspace_id); } - this.messages = []; - this.currentConversationId = null; - this.resetTokenStatistics?.(); - this.currentConversationTitle = '新对话'; - this.titleReady = true; - this.suppressTitleTyping = false; - try { - const { useTaskStore } = await import('../../../stores/task'); - const taskStore = useTaskStore(); - taskStore.clearTask(); - } catch (_) {} - this.clearLocalTaskUiState?.('switch-host-workspace'); + if (!preserveConversationView) { + this.messages = []; + this.currentConversationId = null; + this.resetTokenStatistics?.(); + this.currentConversationTitle = '新对话'; + this.titleReady = true; + this.suppressTitleTyping = false; + try { + const { useTaskStore } = await import('../../../stores/task'); + const taskStore = useTaskStore(); + taskStore.clearTask(); + } catch (_) {} + this.clearLocalTaskUiState?.('switch-host-workspace'); + } await this.fetchHostWorkspaces(); - const activeStatuses = new Set(['pending', 'running', 'cancel_requested']); - const activeTask = (Array.isArray(this.runningWorkspaceTasks) ? this.runningWorkspaceTasks : []) - .filter((task: any) => String(task?.workspace_id || '') === this.currentHostWorkspaceId) - .find((task: any) => activeStatuses.has(String(task?.status || '')) && task?.conversation_id); - if (activeTask?.conversation_id) { - await this.loadConversation(String(activeTask.conversation_id), { force: true }); + if (preserveConversationView) { + // 不做视图跳转(/new 或自动进入运行中任务对话),仅刷新侧边栏列表 this.conversationsOffset = 0; await this.loadConversationsList(); } else { - this.startTitleTyping('新对话', { animate: false }); - history.replaceState({}, '', '/new'); - await this.loadConversationsList(); + const activeStatuses = new Set(['pending', 'running', 'cancel_requested']); + const activeTask = (Array.isArray(this.runningWorkspaceTasks) ? this.runningWorkspaceTasks : []) + .filter((task: any) => String(task?.workspace_id || '') === this.currentHostWorkspaceId) + .find((task: any) => activeStatuses.has(String(task?.status || '')) && task?.conversation_id); + if (activeTask?.conversation_id) { + await this.loadConversation(String(activeTask.conversation_id), { force: true }); + this.conversationsOffset = 0; + await this.loadConversationsList(); + } else { + this.startTitleTyping('新对话', { animate: false }); + history.replaceState({}, '', '/new'); + await this.loadConversationsList(); + } } const switchedWorkspace = (Array.isArray(this.hostWorkspaces) ? this.hostWorkspaces : []) .find((item: any) => String(item?.workspace_id || '') === this.currentHostWorkspaceId); @@ -338,7 +350,7 @@ export const hostWorkspaceMethods = { const { conversationId, workspaceId } = payload || {}; if (!conversationId || !workspaceId) return; if ((this.versioningHostMode || this.dockerProjectMode) && workspaceId !== this.currentHostWorkspaceId) { - await this.handleHostWorkspaceSwitch(workspaceId); + await this.handleHostWorkspaceSwitch(workspaceId, { preserveConversationView: true }); } await this.loadConversation(conversationId, { force: true, workspaceId }); }, diff --git a/static/src/components/chat/quickdock/QuickDock.vue b/static/src/components/chat/quickdock/QuickDock.vue index e0ef2f4c..5296e171 100644 --- a/static/src/components/chat/quickdock/QuickDock.vue +++ b/static/src/components/chat/quickdock/QuickDock.vue @@ -1,7 +1,10 @@