新增: 审批系统级浮窗(WebviewWindow 自定义样式 + 内容/直接操作 + 点击回审批)
This commit is contained in:
+54
-5
@@ -34,8 +34,9 @@
|
||||
<div v-if="errorMsg" class="df-toast">⚠ {{ errorMsg }}</div>
|
||||
</transition>
|
||||
|
||||
<!-- 审批待办浮层(屏幕右上角,窗口置顶时浮于所有桌面窗口上面)。
|
||||
仅在主窗口与 ai-detached 窗口挂载(file-explorer 等其他分离窗口不挂)。 -->
|
||||
<!-- 审批待办浮层(应用内右上角,窗口聚焦/可见时作快速提示)。
|
||||
仅在主窗口与 ai-detached 窗口挂载(file-explorer / approval-popup 自身不挂)。
|
||||
应用失焦/最小化时的系统级提示由 useApprovalPopup 启动的独立浮窗(approval-popup)负责。 -->
|
||||
<ApprovalOverlay v-if="showApprovalOverlay" @activate="activateAiPanel" />
|
||||
</template>
|
||||
|
||||
@@ -51,15 +52,19 @@ import AiChat from './components/AiChat.vue'
|
||||
import ApprovalOverlay from './components/ai/ApprovalOverlay.vue'
|
||||
import ErrorBoundary from './components/ErrorBoundary.vue'
|
||||
import AppLayout from './components/layout/AppLayout.vue'
|
||||
import { startApprovalPopup } from '@/composables/ai/useApprovalPopup'
|
||||
import { aiApi } from '@/api'
|
||||
|
||||
const route = useRoute()
|
||||
const isDetached = computed(() => route.path === '/ai-detached' || route.path === '/file-explorer-detached')
|
||||
const isDetached = computed(() => route.path === '/ai-detached' || route.path === '/file-explorer-detached' || route.path === '/approval-popup')
|
||||
const aiStore = useAiStore()
|
||||
const appSettings = useAppSettingsStore()
|
||||
|
||||
// 审批浮层仅在主窗口与 ai-detached 窗口挂载(不在 file-explorer 等其他分离窗口弹)
|
||||
const showApprovalOverlay = computed(() => route.path !== '/file-explorer-detached')
|
||||
// 审批浮层仅在主窗口与 ai-detached 窗口挂载(不在 file-explorer / approval-popup 等其他分离窗口弹)
|
||||
// approval-popup 是系统级浮窗本身,内部已显式渲染 pending 列表,再挂 ApprovalOverlay 会重复
|
||||
const showApprovalOverlay = computed(() =>
|
||||
route.path !== '/file-explorer-detached' && route.path !== '/approval-popup'
|
||||
)
|
||||
|
||||
/** 用户点击审批浮层 → 激活 AI 面板/分离窗口。
|
||||
* 主窗口:打开 AI 面板;分离窗口:提升焦点(窗口本身 alwaysOnTop 已置顶)。 */
|
||||
@@ -112,6 +117,24 @@ function handleKeydown(e: KeyboardEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
// 系统级审批浮窗(独立窗口):仅主窗口启动(ai-detached/approval-popup 自身不启动,避免重复 watch)
|
||||
let _stopApprovalPopup: (() => void) | null = null
|
||||
let _unlistenPopupReady: (() => void) | null = null
|
||||
async function activateForPopup() {
|
||||
// 浮窗「打开审批面板」按钮 → 聚焦主窗口 + 打开 AI 面板/激活分离窗口
|
||||
try {
|
||||
const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow')
|
||||
const mainWin = await WebviewWindow.getByLabel('main')
|
||||
if (mainWin) {
|
||||
await mainWin.show()
|
||||
await mainWin.setFocus()
|
||||
}
|
||||
} catch { /* 忽略 */ }
|
||||
if (!aiStore.state.detached && !aiStore.state.panelOpen) {
|
||||
aiStore.togglePanel()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 1. 先把 SQLite 全表 KV 填进 appSettings 缓存(后续 get/useSetting 才能读到真实值)
|
||||
await appSettings.loadAll()
|
||||
@@ -153,6 +176,28 @@ onMounted(async () => {
|
||||
} catch (e) {
|
||||
console.error('启动数据变更监听失败:', e)
|
||||
}
|
||||
// 系统级审批浮窗:仅主窗口启动(approval-popup 自身路由不启动,避免重复 watch)。
|
||||
// 设计见 useApprovalPopup.ts:主窗口 watch pendingApprovals → 弹/更新/关浮窗(单一真相源)。
|
||||
if (route.path !== '/approval-popup') {
|
||||
_stopApprovalPopup = startApprovalPopup(
|
||||
() => aiStore.state.pendingApprovals,
|
||||
activateForPopup,
|
||||
)
|
||||
// 浮窗 webview 挂载后会 emit 'approval-popup-ready' 请求初始快照(防主窗口在浮窗 listen 前
|
||||
// emit 丢失)。此处 listen 后立即重推当前 pendingApprovals。
|
||||
try {
|
||||
const { listen } = await import('@tauri-apps/api/event')
|
||||
const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow')
|
||||
_unlistenPopupReady = await listen('approval-popup-ready', async () => {
|
||||
const popup = await WebviewWindow.getByLabel('approval-popup')
|
||||
if (popup) {
|
||||
await popup.emit('approval-popup-update', { approvals: aiStore.state.pendingApprovals })
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('[ApprovalPopup] ready 监听失败:', e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/// 一次性迁移:遍历遗留的 localStorage key,若有值则导入 appSettings(SQLite),
|
||||
@@ -193,6 +238,10 @@ const knowledgeStore = useKnowledgeStore()
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('keydown', handleKeydown)
|
||||
projectStore.stopDataChangedListener?.()
|
||||
_stopApprovalPopup?.()
|
||||
_unlistenPopupReady?.()
|
||||
_stopApprovalPopup = null
|
||||
_unlistenPopupReady = null
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user