新增: 多会话并发前端 UI 阶段3/4(F-09 收尾)

后端 per-conv 并发已就绪(d899c58 + CR-03~07),前端呈现层收尾:

阶段3 多会话生成态:
- stores/ai.ts generatingConvId 单值 → generatingConvs:Set + add/remove/isGenerating helper
- useAiEvents 5 处迁移(Completed/Error/路由标记改 per-conv Set 操作,
  AiError 精确清出错会话非全局清空,修原 = null 误清其他会话)
- ConversationSidebar 多会话并行生成脉冲指示(isGenerating 各会话独立)

阶段4 独立窗口多会话:
- useAiWindow label ai-detached → ai-detached-{convId}(per-conv 独立窗口)
- localStorage 单 key → per-conv key(防多会话串扰,读路径兼容旧 key 回退)

vue-tsc EXIT 0 + generatingConvId 零代码残留(仅注释)
This commit is contained in:
lxy
2026-06-19 20:15:37 +08:00
parent 19eb14ffc8
commit 7d5402951b
12 changed files with 181 additions and 53 deletions
+10 -2
View File
@@ -45,7 +45,10 @@
@click="onSelectSearchResult(conv.id)"
>
<div class="ai-conv-item-main">
<span class="ai-conv-item-title" :title="conv.title || ''">{{ conv.title || t('aiChat.newConversation') }}</span>
<span class="ai-conv-item-title" :title="conv.title || ''">
{{ conv.title || t('aiChat.newConversation') }}
<span v-if="store.isGenerating(conv.id)" class="ai-conv-gen-dot" :title="t('aiChat.generating')"></span>
</span>
<span class="ai-conv-item-time">{{ formatTime(conv.updated_at) }}</span>
</div>
<div class="ai-conv-item-actions">
@@ -125,6 +128,8 @@
class="ai-conv-item-title-badge"
width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"
><polyline points="20 6 9 17 4 12"/></svg>
<!-- F-09: 多会话并发生成指示器(后台/当前会话生成中均显脉冲点,多会话可同时显示) -->
<span v-if="store.isGenerating(conv.id)" class="ai-conv-gen-dot" :title="t('aiChat.generating')"></span>
</span>
<span class="ai-conv-item-time">{{ formatTime(conv.updated_at) }}</span>
</div>
@@ -167,7 +172,10 @@
@click="store.switchConversation(conv.id)"
>
<div class="ai-conv-item-main">
<span class="ai-conv-item-title" :title="conv.title || ''">{{ conv.title || t('aiChat.newConversation') }}</span>
<span class="ai-conv-item-title" :title="conv.title || ''">
{{ conv.title || t('aiChat.newConversation') }}
<span v-if="store.isGenerating(conv.id)" class="ai-conv-gen-dot" :title="t('aiChat.generating')"></span>
</span>
<span class="ai-conv-item-time">{{ formatTime(conv.updated_at) }}</span>
</div>
<div class="ai-conv-item-actions">