文档: 无人值守专项设计档+todo 销账(#10/#11/#12), Web 规范合规批(App/视图/组件样式)
This commit is contained in:
@@ -597,7 +597,12 @@ async function backfillQueued(idx: number) {
|
||||
function scrollToBottom(smooth = false) {
|
||||
messageListRef.value?.scrollToBottom(smooth)
|
||||
}
|
||||
// listener 租约句柄(mount 借/unmount 还,所有权模型;startListener 失败时为 null,归还侧判空)
|
||||
let _listenerRelease: (() => void) | null = null
|
||||
onBeforeUnmount(() => {
|
||||
// 归还 listener 租约(最后一份归还才真拆单例 listener;双重归还/下溢由 useAiEvents dev 断言暴露)
|
||||
_listenerRelease?.()
|
||||
_listenerRelease = null
|
||||
// V7 排队时钟 interval 随组件卸载清理(watch 随卸载停但 interval 本体不自停,须显式清)
|
||||
if (queueTickTimer !== null) { clearInterval(queueTickTimer); queueTickTimer = null }
|
||||
// 全局快捷键卸载时移除 window listener,防分离窗口/切组件后泄漏
|
||||
@@ -609,9 +614,8 @@ onBeforeUnmount(() => {
|
||||
// 流式 rAF 清理(streaming watch 内 cancelAnimationFrame)随 MessageList 迁移,子组件
|
||||
// onBeforeUnmount 自管(子 watch streaming 已注册,卸载自动停)。
|
||||
// 释放后端 listener(ai-chat-event/ai-conversation-changed)+清流式看门狗。
|
||||
// 之前 stopListener 定义但全仓零调用 → listener+watchdog 永久泄漏;分离窗口主窗口 AiChat
|
||||
// 卸载(走 App.vue v-if detach)时 listener 仍挂后端,watchdog 130s 后写已卸载 state。
|
||||
store.stopListener()
|
||||
// 旧 stopListener 已删除(所有权模型:租约在 onBeforeUnmount 顶部归还,store 侧 releaseLease
|
||||
// 在最后一份归还时拆 listener + 清看门狗/计时器,此处不再重复清)。
|
||||
// F-15 阶段2: 释放上下文管理事件监听器
|
||||
store.stopContextListener()
|
||||
if (_unlistenToolSlow) { _unlistenToolSlow(); _unlistenToolSlow = null } //
|
||||
@@ -635,9 +639,27 @@ onMounted(async () => {
|
||||
console.debug(`[启动] AiChat mounted: ${(performance.now() - t0).toFixed(0)}ms`)
|
||||
// Markdown 渲染器预热随 MessageList 子组件迁移(子 onMounted 内 loadMarkdown);
|
||||
// useMarkdown 模块级单例,父不再直接调用。
|
||||
await store.startListener()
|
||||
await store.loadProviders()
|
||||
await store.loadConversations()
|
||||
// ── 分级初始化(根本修 #5)──
|
||||
// 第一级(致命):listener 租约。失败 = 无事件通道,面板功能尽失,toast + 止损
|
||||
// (重开面板 re-mount 即重试);租约句柄 null,卸载侧判空归还。
|
||||
try {
|
||||
_listenerRelease = await store.startListener()
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e)
|
||||
console.error('[AiChat] listener 注册失败(致命,面板初始化中止):', e)
|
||||
showToast(t('aiChat.initError', { msg }), 'error')
|
||||
return
|
||||
}
|
||||
// 第二级(可降级):providers/conversations 列表。失败仅列表空,面板/发送/流式仍可用,
|
||||
// toast 提示但继续初始化(skills/上下文监听/生成态恢复不依赖列表数据)。
|
||||
try {
|
||||
await store.loadProviders()
|
||||
await store.loadConversations()
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e)
|
||||
console.error('[AiChat] 列表加载失败(降级继续):', e)
|
||||
showToast(t('aiChat.initDegraded', { msg }), 'warning')
|
||||
}
|
||||
store.loadSkills()
|
||||
store.loadToolRisks()
|
||||
// @ 提及预加载: AiChat 的 @ 联想读取 projectsStore.projects/tasks,
|
||||
|
||||
Reference in New Issue
Block a user