新增: 后台会话系统通知与托盘运行态
- 完成/失败/需介入三类系统通知,主窗聚焦静默 - 同类通知五秒合并,用户主动停止不通知 - 托盘菜单与悬浮提示实时显运行中会话数 - 关窗遇运行会话提示后台续跑,每进程一次 - 侧栏常驻徽章显后台运行会话数
This commit is contained in:
@@ -51,12 +51,14 @@
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="sidebar-footer">
|
||||
<!-- AI 面板切换按钮 -->
|
||||
<button class="nav-link ai-toggle-btn" :class="{ 'ai-toggle-btn--active': aiStore.state.panelOpen }" @click="aiStore.togglePanel()" :title="collapsed ? $t('nav.aiPanel') : undefined">
|
||||
<!-- AI 面板切换按钮(footer 常驻跨路由渲染,承担后台运行中会话的全局可见标识) -->
|
||||
<button class="nav-link ai-toggle-btn" :class="{ 'ai-toggle-btn--active': aiStore.state.panelOpen }" @click="aiStore.togglePanel()" :title="runningConvCount > 0 ? `${runningConvCount} 个会话运行中` : (collapsed ? $t('nav.aiPanel') : undefined)">
|
||||
<span class="nav-link-icon ai-spark-icon">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9z"/><path d="M19 3v3M21 4.5h-3M5 17v3M6.5 18.5h-3"/></svg>
|
||||
</span>
|
||||
<span v-if="!collapsed" class="nav-link-text">{{ $t('nav.aiPanel') }}</span>
|
||||
<span v-if="!collapsed && runningConvCount > 0" class="nav-link-badge">{{ runningConvCount }}</span>
|
||||
<span v-if="collapsed && runningConvCount > 0" class="ai-running-dot"></span>
|
||||
<span v-if="!collapsed" class="ai-toggle-shortcut">⌘I</span>
|
||||
</button>
|
||||
<router-link to="/settings" class="nav-link" active-class="nav-link--active" :title="collapsed ? $t('nav.settings') : undefined">
|
||||
@@ -83,6 +85,7 @@ import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useAiStore } from '@/stores/ai'
|
||||
import { useKnowledgeStore } from '@/stores/knowledge'
|
||||
import { useAppSettingsStore } from '@/stores/appSettings'
|
||||
import { convStates } from '@/composables/ai/aiShared'
|
||||
|
||||
const aiStore = useAiStore()
|
||||
const knowledgeStore = useKnowledgeStore()
|
||||
@@ -135,6 +138,17 @@ onBeforeUnmount(() => {
|
||||
// 知识库候选数量(侧栏 badge)— 解包 computed 取值保持响应式
|
||||
const candidateCount = computed(() => knowledgeStore.candidateCount)
|
||||
|
||||
// 全局运行中会话数(AI 面板关闭或切到 Tasks/Ideas 等页面时,后台生成在 footer 常驻按钮上仍可见)。
|
||||
// 真相源 convStates(reactive Map,消费后端 AiConvStateChanged,写入在 isCurrent 守卫之前故后台会话也更新),
|
||||
// 非终止三态计入,与 stores/ai.ts isGenerating 桥接语义一致;computed 内遍历 Map 即建立响应式依赖
|
||||
const runningConvCount = computed(() => {
|
||||
let n = 0
|
||||
for (const s of convStates.values()) {
|
||||
if (s === 'generating' || s === 'stopping' || s === 'compressed') n++
|
||||
}
|
||||
return n
|
||||
})
|
||||
|
||||
const primaryNav = [
|
||||
{ path: '/dashboard', label: 'nav.overview', badge: null,
|
||||
svg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>' },
|
||||
@@ -349,6 +363,23 @@ const secondaryNav = [
|
||||
border-radius: var(--df-radius-sm);
|
||||
}
|
||||
|
||||
/* 收缩态运行中标识:绿点钉在按钮右上角(展开态走 nav-link-badge 数字徽章,无空间放数字)。
|
||||
脉冲范式与 ConversationSidebar 的 ai-conv-gen-dot 同源 */
|
||||
.ai-running-dot {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 6px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--df-accent);
|
||||
animation: ai-sidebar-gen-pulse 1.4s ease-in-out infinite;
|
||||
}
|
||||
@keyframes ai-sidebar-gen-pulse {
|
||||
0%, 100% { opacity: 0.35; transform: scale(0.85); }
|
||||
50% { opacity: 1; transform: scale(1.15); }
|
||||
}
|
||||
|
||||
/* — Footer — */
|
||||
.sidebar-footer {
|
||||
padding: 6px 8px;
|
||||
|
||||
Reference in New Issue
Block a user