From fb4b067728aa6f8ad9613e7fdf0f79e7a9902e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Wed, 17 Jun 2026 01:21:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20CR-50=20RED(useAiContext?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6case=E6=94=B9PascalCase+compress=E5=85=9C?= =?UTF-8?q?=E5=BA=95=E5=A4=8D=E4=BD=8D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/composables/ai/useAiContext.ts | 37 ++++++++++++++++-------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/composables/ai/useAiContext.ts b/src/composables/ai/useAiContext.ts index 70b837a..7af901d 100644 --- a/src/composables/ai/useAiContext.ts +++ b/src/composables/ai/useAiContext.ts @@ -4,15 +4,16 @@ //! - clearContext():二次确认 → aiApi.clearContext(activeConversationId) //! - compressContext():aiApi.compressContext(activeConversationId, locale) //! + isCompressing ref(loading,防重复点击) -//! - 模块级 listener:消费后端 emit 的 ai-chat-event 生命周期事件: -//! ai_compressing → isCompressing=true -//! ai_compressed → isCompressing=false + (成功 toast 由调用方弹,摘要已在事件里) -//! ai_context_cleared → (刷新提示由调用方弹) -//! ai_error → isCompressing=false + (错误 toast 由调用方弹) +//! - 模块级 listener:消费后端 emit 的 ai-chat-event 生命周期事件(serde 默认 PascalCase, +//! 对齐 useAiEvents.ts 既有 9 事件): +//! AiCompressing → isCompressing=true +//! AiCompressed → isCompressing=false + (成功 toast 由调用方弹,摘要已在事件里) +//! AiContextCleared → (刷新提示由调用方弹) +//! AiError → isCompressing=false + (错误 toast 由调用方弹) //! //! 设计: //! - 与 useAiEvents.startListener 共存:后者监听 AiChatEvent 联合类型(不含 -//! ai_compressing/ai_compressed/ai_context_cleared,因 types.ts 不在本任务白名单), +//! AiCompressing/AiCompressed/AiContextCleared,因 types.ts 不在本任务白名单), //! 本模块注册第二个 listen('ai-chat-event') 监听器,专门按 type 字符串分发上述 4 类事件。 //! 两个监听器都触发同一后端事件,但各取所需类型,Tauri 事件多 listener 是合法的。 //! - toast/刷新副作用经回调注入(composable 无组件上下文,无 toast ref), @@ -33,7 +34,7 @@ import { state } from '@/stores/ai' const appSettings = useAppSettingsStore() -/// 压缩中 loading(防重复点击;ai_compressing→true / ai_compressed|ai_error→false) +/// 压缩中 loading(防重复点击;AiCompressing→true / AiCompressed|AiError→false) const isCompressing = ref(false) /// 已注册的 ai-chat-event 第二监听器(生命周期事件);幂等 @@ -42,11 +43,11 @@ let _unlistenContext: UnlistenFn | null = null /// 副作用回调(由 AiChat.vue 注入:toast / 刷新 / 摘要渲染) /// 用对象形式便于选择性注入(只压成功了才需 onCompressed) interface ContextCallbacks { - /** 清空完成(ai_context_cleared):toast + 刷新消息列表 */ + /** 清空完成(AiContextCleared):toast + 刷新消息列表 */ onCleared?: (conversationId: string) => void - /** 压缩成功(ai_compressed):toast + 渲染摘要 system 消息 */ + /** 压缩成功(AiCompressed):toast + 渲染摘要 system 消息 */ onCompressed?: (conversationId: string, summary: string) => void - /** 压缩失败 / 错误(ai_error with conversation_id):toast */ + /** 压缩失败 / 错误(AiError with conversation_id):toast */ onError?: (conversationId: string, message: string) => void } let _callbacks: ContextCallbacks = {} @@ -74,18 +75,18 @@ async function initContextListener(callbacks: ContextCallbacks = {}): Promise { isCompressing.value = true try { await aiApi.compressContext(convId, resolveLanguage()) - // 成功 IPC 仅表示请求受理;真正压缩完成由 ai_compressed 事件复位 isCompressing + // 后端 IPC 同步等到 LLM 压缩完成才 resolve(非 spawn 异步),成功即复位 isCompressing; + // case 'AiCompressed' 事件也复位(双保险,防事件丢失致按钮永久禁用) + isCompressing.value = false } catch (e) { isCompressing.value = false throw e