From 4c3d8cedc74dc01bda2eddc769548e34a42a5f90 Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Sun, 30 Aug 2026 00:33:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E8=AE=A1=E5=88=92=E6=89=B9?= =?UTF-8?q?=E5=87=86=E5=BC=B9=E7=AA=97=E6=94=AF=E6=8C=81=E6=9C=80=E5=B0=8F?= =?UTF-8?q?=E5=8C=96=E5=85=B3=E9=97=AD=EF=BC=8C=E7=8A=B6=E6=80=81=E6=A0=8F?= =?UTF-8?q?=E5=8F=AF=E6=81=A2=E5=A4=8D=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PlanApprovalDialog windowbar 新增关闭(X)按钮,点击后弹窗收起不打扰 - InputComposer 底部状态栏新增「有待批准的计划」按钮(对齐等待回答问题交互),点击恢复弹窗 - floatingStatusVisible 可见性判断纳入计划批准最小化状态,修复弹窗收起后浮栏不渲染的问题 - 批准解决后自动复位最小化状态,避免按钮残留 --- static/src/App.vue | 6 +++- static/src/app/methods/taskPolling/tool.ts | 4 +++ static/src/app/methods/ui/dialog.ts | 12 +++++++ static/src/app/state.ts | 1 + static/src/components/input/InputComposer.vue | 12 +++++++ .../components/overlay/PlanApprovalDialog.vue | 36 +++++++++++++++++++ static/src/locales/en-US/input.ts | 1 + static/src/locales/en-US/overlay.ts | 1 + static/src/locales/zh-CN/input.ts | 1 + static/src/locales/zh-CN/overlay.ts | 1 + 10 files changed, 74 insertions(+), 1 deletion(-) diff --git a/static/src/App.vue b/static/src/App.vue index 1bbbb6b5..40c2e0f3 100644 --- a/static/src/App.vue +++ b/static/src/App.vue @@ -302,6 +302,8 @@ :project-git-summary="projectGitSummary" :user-question-minimized="userQuestionMinimized" :pending-user-question-count="pendingUserQuestions.length" + :plan-approval-minimized="planApprovalMinimized" + :pending-plan-approval-count="pendingPlanApprovals.length" :goal-mode-armed="goalModeArmed" :goal-running="goalRunning" :goal-progress="goalProgress" @@ -319,6 +321,7 @@ :active-sub-agent-count="activeSubAgentCount" :avatar-status="showStatusAvatar && messages.length > 0 ? avatarStatus : null" @restore-user-question="restoreUserQuestionDialog" + @restore-plan-approval="restorePlanApprovalDialog" @stop-all-sub-agents="handleStopAllSubAgents" @update:input-message="inputSetMessage" @input-change="handleInputChange" @@ -544,10 +547,11 @@ @dismiss="dismissUserQuestions" /> item && String(item.approval_id || '') !== id ); + // 弹窗被关闭(最小化)期间批准已解决:无待批事项时复位,避免状态栏按钮残留 + if (!this.pendingPlanApprovals.length) { + this.planApprovalMinimized = false; + } // 批准后后端已切换运行模式/恢复权限与执行环境,刷新显示(多标签页同步场景) if (String(data?.decision || '') === 'approved') { this.fetchWorkMode(); diff --git a/static/src/app/methods/ui/dialog.ts b/static/src/app/methods/ui/dialog.ts index c5c4c9b6..2791621a 100644 --- a/static/src/app/methods/ui/dialog.ts +++ b/static/src/app/methods/ui/dialog.ts @@ -95,6 +95,18 @@ export const dialogMethods = { // ignore } }, + minimizePlanApprovalDialog() { + if (!Array.isArray(this.pendingPlanApprovals) || !this.pendingPlanApprovals.length) { + return; + } + this.planApprovalMinimized = true; + }, + restorePlanApprovalDialog() { + if (!Array.isArray(this.pendingPlanApprovals) || !this.pendingPlanApprovals.length) { + return; + } + this.planApprovalMinimized = false; + }, async submitPlanApproval(payload) { const approvalId = String(payload?.approval_id || '').trim(); if (!approvalId) { diff --git a/static/src/app/state.ts b/static/src/app/state.ts index 8e6ec6cd..5659a98f 100644 --- a/static/src/app/state.ts +++ b/static/src/app/state.ts @@ -292,6 +292,7 @@ export function dataState() { pendingUserQuestions: [], pendingPlanApprovals: [], answeringPlanApprovalIds: [], + planApprovalMinimized: false, userQuestionDialogVisible: false, userQuestionMinimized: false, userQuestionActiveIndex: 0, diff --git a/static/src/components/input/InputComposer.vue b/static/src/components/input/InputComposer.vue index e0d15d15..e41fad97 100644 --- a/static/src/components/input/InputComposer.vue +++ b/static/src/components/input/InputComposer.vue @@ -179,6 +179,14 @@ > {{ $t('input.waitingForQuestion') }} + + {{ $t('input.planApprovalPending') }} + | null; @@ -1066,6 +1077,7 @@ const floatingStatusVisible = computed(() => { !!props.goalRunning || !!props.goalModeArmed || (Number(props.pendingUserQuestionCount || 0) > 0) || + (!!props.planApprovalMinimized && Number(props.pendingPlanApprovalCount || 0) > 0) || (Number(props.activeSubAgentCount || 0) > 0); return visible; }); diff --git a/static/src/components/overlay/PlanApprovalDialog.vue b/static/src/components/overlay/PlanApprovalDialog.vue index a964a4ff..101764d1 100644 --- a/static/src/components/overlay/PlanApprovalDialog.vue +++ b/static/src/components/overlay/PlanApprovalDialog.vue @@ -4,6 +4,17 @@ {{ $t('overlay.planApprovalTitle') }} + + + + + @@ -75,6 +86,7 @@ const props = defineProps<{ const emit = defineEmits<{ (event: 'submit', payload: { approval_id: string; approved: boolean; comment: string }): void; + (event: 'minimize'): void; }>(); // 计划批准一次只处理一份(plan 模式下模型阻塞等待,天然串行); @@ -139,6 +151,7 @@ function reject() { } .plan-approval-windowbar { + position: relative; height: 40px; flex: 0 0 40px; display: flex; @@ -147,6 +160,29 @@ function reject() { border-bottom: 1px solid var(--border-default); } +.plan-approval-close { + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + width: 26px; + height: 26px; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + border: none; + border-radius: 7px; + background: transparent; + color: var(--text-secondary); + cursor: pointer; +} + +.plan-approval-close:hover { + background: var(--hover-bg); + color: var(--text-primary); +} + .plan-approval-window-title { font-size: 13px; font-weight: 600; diff --git a/static/src/locales/en-US/input.ts b/static/src/locales/en-US/input.ts index 5816eebe..07d4c564 100644 --- a/static/src/locales/en-US/input.ts +++ b/static/src/locales/en-US/input.ts @@ -9,6 +9,7 @@ export default { goalModeRunning: 'Goal mode running', goalModeReady: 'Goal mode ready', waitingForQuestion: 'Waiting for your answer', + planApprovalPending: 'Plan awaiting approval', subAgentsRunning: '{n} sub-agents running', terminalsRunning: '{n} terminals', quickMenuAriaLabel: 'Quick menu', diff --git a/static/src/locales/en-US/overlay.ts b/static/src/locales/en-US/overlay.ts index a6585e23..9a842385 100644 --- a/static/src/locales/en-US/overlay.ts +++ b/static/src/locales/en-US/overlay.ts @@ -88,6 +88,7 @@ export default { // ── PlanApprovalDialog ── planApprovalAriaLabel: 'Plan awaiting approval', planApprovalTitle: 'Plan awaiting approval', + planApprovalMinimize: 'Close the dialog; restore it later from the status bar', planTruncatedNote: '(Content too long; preview truncated. See the file for the full content)', planCommentPlaceholder: 'Feedback (optional): added as extra requirements when approving, or describe what to adjust when rejecting...', diff --git a/static/src/locales/zh-CN/input.ts b/static/src/locales/zh-CN/input.ts index 2657f5f5..809f5955 100644 --- a/static/src/locales/zh-CN/input.ts +++ b/static/src/locales/zh-CN/input.ts @@ -9,6 +9,7 @@ export default { goalModeRunning: '目标模式运行中', goalModeReady: '目标模式就绪', waitingForQuestion: '等待回答问题', + planApprovalPending: '有待批准的计划', subAgentsRunning: '{n} 个子智能体运行中', terminalsRunning: '{n} 个终端', quickMenuAriaLabel: '快捷菜单', diff --git a/static/src/locales/zh-CN/overlay.ts b/static/src/locales/zh-CN/overlay.ts index 0438e4ad..6fd7db38 100644 --- a/static/src/locales/zh-CN/overlay.ts +++ b/static/src/locales/zh-CN/overlay.ts @@ -87,6 +87,7 @@ export default { // ── PlanApprovalDialog:计划待批准 ── planApprovalAriaLabel: '计划待批准', planApprovalTitle: '计划待批准', + planApprovalMinimize: '关闭弹窗,稍后从状态栏恢复', planTruncatedNote: '(内容过长,已截断预览,完整内容见文件)', planCommentPlaceholder: '意见(可选):批准时作为补充要求,拒绝时说明需要调整的方向…', planRejectTitle: '拒绝这份计划,AI 将根据你的意见修订后重新提交',