修复: 审批浮窗 3 bug(打开面板权限/审批后空转自关/关闭顺序)

This commit is contained in:
lxy
2026-08-01 16:05:44 +08:00
parent 7193901bc4
commit 2b08e32c26
5 changed files with 39 additions and 19 deletions
+28 -13
View File
@@ -30,7 +30,8 @@
<!-- 待审批列表 -->
<div class="popup-body">
<div v-if="approvals.length === 0" class="popup-empty">
<span class="popup-empty-spinner"></span>
<!-- BUG2 修复:空态不再永久转圈( popup-empty-spinner 处理完仍转圈误判卡死)
空态正常会被 maybeAutoClose 即时关窗; hint 仅作防御性兜底(close 失败时给可见反馈) -->
<span class="popup-empty-hint">{{ $t('aiChat.popupEmptyHint') }}</span>
</div>
<div
@@ -144,6 +145,8 @@ onMounted(async () => {
ApprovalPopupEvents.EVT_UPDATE,
(e) => {
approvals.value = e.payload?.approvals || []
// BUG2 修复:主窗口推空快照(所有 pending 已清)→ 立即关浮窗,避免停留在空态转圈
void maybeAutoClose()
},
)
} catch (e) {
@@ -175,6 +178,8 @@ async function onApprove(tc: AiToolCallInfo) {
}
// 乐观移除(主窗口 listener 收后端 emit 后会推新快照覆盖,此乐观仅缩短视觉延迟)
approvals.value = approvals.value.filter(a => a.id !== tc.id)
// BUG2 修复:乐观移除后若列表空,立即关浮窗(避免空列表停留在 popup-empty 永久转圈态)
await maybeAutoClose()
} catch (e) {
console.error('[ApprovalPopup] 批准失败:', e)
} finally {
@@ -193,6 +198,7 @@ async function onReject(tc: AiToolCallInfo) {
await aiApi.approve(tc.id, false)
}
approvals.value = approvals.value.filter(a => a.id !== tc.id)
await maybeAutoClose()
} catch (e) {
console.error('[ApprovalPopup] 拒绝失败:', e)
} finally {
@@ -200,6 +206,20 @@ async function onReject(tc: AiToolCallInfo) {
}
}
/** 列表清空时自动关浮窗。
* 场景:用户处理完最后一条审批 / 主窗口推空快照(EVT_UPDATE approvals:[])。
* 修复 BUG2:原实现空列表渲染 popup-empty + 永久 popup-empty-spinner,用户看到「列表空 + 一直转」
* 误以为卡死。空 = 完成,应即时关浮窗(不等待主窗口 watch closePopup 的跨窗口往返)。 */
async function maybeAutoClose() {
if (approvals.value.length > 0) return
try {
const { emit } = await import('@tauri-apps/api/event')
// 先关窗(确保用户立刻看到反馈),再 emit 清主窗口引用(顺序与 onClose 一致)
await getCurrentWebviewWindow().close()
await emit(ApprovalPopupEvents.EVT_CLOSED, {})
} catch { /* ignore */ }
}
/** 点击「打开审批面板」:emit 主窗口聚焦 + togglePanel */
async function onActivate() {
try {
@@ -208,12 +228,17 @@ async function onActivate() {
} catch { /* ignore */ }
}
/** 关闭浮窗(用户主动关 → emit closed 让主窗口清引用,允许下次有新审批再弹) */
/** 关闭浮窗(用户主动关 → emit closed 让主窗口清引用,允许下次有新审批再弹)
* 修复 BUG3:原顺序 emit→close,若 emit 跨窗口分发阻塞/异常(close 永不执行)→ 关闭按钮「无效」。
* 改为先 close(即时反馈,core:window:allow-close 已授权),再 emit 清主窗口引用;
* 即便 emit 失败,主窗口 win.once('tauri://destroyed') 也会清 _popupWin(双保险)。 */
async function onClose() {
try {
await getCurrentWebviewWindow().close()
} catch { /* ignore */ }
try {
const { emit } = await import('@tauri-apps/api/event')
await emit(ApprovalPopupEvents.EVT_CLOSED, {})
await getCurrentWebviewWindow().close()
} catch { /* ignore */ }
}
@@ -323,16 +348,6 @@ function onDragEnd() { isDragging.value = false }
min-height: 80px;
padding: 16px;
}
.popup-empty-spinner {
width: 14px;
height: 14px;
border: 2px solid var(--df-border, #444);
border-top-color: var(--df-accent);
border-radius: 50%;
animation: df-spin 0.8s linear infinite;
display: inline-block;
flex-shrink: 0;
}
.popup-empty-hint {
font-size: 11px;
color: var(--df-text-dim);