feat(ui): 计划批准弹窗支持最小化关闭,状态栏可恢复处理
- PlanApprovalDialog windowbar 新增关闭(X)按钮,点击后弹窗收起不打扰 - InputComposer 底部状态栏新增「有待批准的计划」按钮(对齐等待回答问题交互),点击恢复弹窗 - floatingStatusVisible 可见性判断纳入计划批准最小化状态,修复弹窗收起后浮栏不渲染的问题 - 批准解决后自动复位最小化状态,避免按钮残留
This commit is contained in:
parent
89bcca744d
commit
4c3d8cedc7
@ -302,6 +302,8 @@
|
|||||||
:project-git-summary="projectGitSummary"
|
:project-git-summary="projectGitSummary"
|
||||||
:user-question-minimized="userQuestionMinimized"
|
:user-question-minimized="userQuestionMinimized"
|
||||||
:pending-user-question-count="pendingUserQuestions.length"
|
:pending-user-question-count="pendingUserQuestions.length"
|
||||||
|
:plan-approval-minimized="planApprovalMinimized"
|
||||||
|
:pending-plan-approval-count="pendingPlanApprovals.length"
|
||||||
:goal-mode-armed="goalModeArmed"
|
:goal-mode-armed="goalModeArmed"
|
||||||
:goal-running="goalRunning"
|
:goal-running="goalRunning"
|
||||||
:goal-progress="goalProgress"
|
:goal-progress="goalProgress"
|
||||||
@ -319,6 +321,7 @@
|
|||||||
:active-sub-agent-count="activeSubAgentCount"
|
:active-sub-agent-count="activeSubAgentCount"
|
||||||
:avatar-status="showStatusAvatar && messages.length > 0 ? avatarStatus : null"
|
:avatar-status="showStatusAvatar && messages.length > 0 ? avatarStatus : null"
|
||||||
@restore-user-question="restoreUserQuestionDialog"
|
@restore-user-question="restoreUserQuestionDialog"
|
||||||
|
@restore-plan-approval="restorePlanApprovalDialog"
|
||||||
@stop-all-sub-agents="handleStopAllSubAgents"
|
@stop-all-sub-agents="handleStopAllSubAgents"
|
||||||
@update:input-message="inputSetMessage"
|
@update:input-message="inputSetMessage"
|
||||||
@input-change="handleInputChange"
|
@input-change="handleInputChange"
|
||||||
@ -544,10 +547,11 @@
|
|||||||
@dismiss="dismissUserQuestions"
|
@dismiss="dismissUserQuestions"
|
||||||
/>
|
/>
|
||||||
<PlanApprovalDialog
|
<PlanApprovalDialog
|
||||||
:visible="pendingPlanApprovals.length > 0"
|
:visible="pendingPlanApprovals.length > 0 && !planApprovalMinimized"
|
||||||
:approvals="pendingPlanApprovals"
|
:approvals="pendingPlanApprovals"
|
||||||
:submitting-ids="answeringPlanApprovalIds"
|
:submitting-ids="answeringPlanApprovalIds"
|
||||||
@submit="submitPlanApproval"
|
@submit="submitPlanApproval"
|
||||||
|
@minimize="minimizePlanApprovalDialog"
|
||||||
/>
|
/>
|
||||||
<transition name="overlay-fade">
|
<transition name="overlay-fade">
|
||||||
<VersioningDialog
|
<VersioningDialog
|
||||||
|
|||||||
@ -446,6 +446,10 @@ export const toolMethods = {
|
|||||||
this.pendingPlanApprovals = this.pendingPlanApprovals.filter(
|
this.pendingPlanApprovals = this.pendingPlanApprovals.filter(
|
||||||
(item: any) => item && String(item.approval_id || '') !== id
|
(item: any) => item && String(item.approval_id || '') !== id
|
||||||
);
|
);
|
||||||
|
// 弹窗被关闭(最小化)期间批准已解决:无待批事项时复位,避免状态栏按钮残留
|
||||||
|
if (!this.pendingPlanApprovals.length) {
|
||||||
|
this.planApprovalMinimized = false;
|
||||||
|
}
|
||||||
// 批准后后端已切换运行模式/恢复权限与执行环境,刷新显示(多标签页同步场景)
|
// 批准后后端已切换运行模式/恢复权限与执行环境,刷新显示(多标签页同步场景)
|
||||||
if (String(data?.decision || '') === 'approved') {
|
if (String(data?.decision || '') === 'approved') {
|
||||||
this.fetchWorkMode();
|
this.fetchWorkMode();
|
||||||
|
|||||||
@ -95,6 +95,18 @@ export const dialogMethods = {
|
|||||||
// ignore
|
// 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) {
|
async submitPlanApproval(payload) {
|
||||||
const approvalId = String(payload?.approval_id || '').trim();
|
const approvalId = String(payload?.approval_id || '').trim();
|
||||||
if (!approvalId) {
|
if (!approvalId) {
|
||||||
|
|||||||
@ -292,6 +292,7 @@ export function dataState() {
|
|||||||
pendingUserQuestions: [],
|
pendingUserQuestions: [],
|
||||||
pendingPlanApprovals: [],
|
pendingPlanApprovals: [],
|
||||||
answeringPlanApprovalIds: [],
|
answeringPlanApprovalIds: [],
|
||||||
|
planApprovalMinimized: false,
|
||||||
userQuestionDialogVisible: false,
|
userQuestionDialogVisible: false,
|
||||||
userQuestionMinimized: false,
|
userQuestionMinimized: false,
|
||||||
userQuestionActiveIndex: 0,
|
userQuestionActiveIndex: 0,
|
||||||
|
|||||||
@ -179,6 +179,14 @@
|
|||||||
>
|
>
|
||||||
{{ $t('input.waitingForQuestion') }}
|
{{ $t('input.waitingForQuestion') }}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="planApprovalMinimized && (pendingPlanApprovalCount || 0) > 0"
|
||||||
|
type="button"
|
||||||
|
class="floating-project-status__notice floating-project-status__notice--button"
|
||||||
|
@click.stop="$emit('restore-plan-approval')"
|
||||||
|
>
|
||||||
|
{{ $t('input.planApprovalPending') }}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="(activeSubAgentCount || 0) > 0"
|
v-if="(activeSubAgentCount || 0) > 0"
|
||||||
type="button"
|
type="button"
|
||||||
@ -698,6 +706,7 @@ const emit = defineEmits([
|
|||||||
'delete-runtime-message',
|
'delete-runtime-message',
|
||||||
'composer-height-change',
|
'composer-height-change',
|
||||||
'restore-user-question',
|
'restore-user-question',
|
||||||
|
'restore-plan-approval',
|
||||||
'toggle-goal-mode',
|
'toggle-goal-mode',
|
||||||
'open-goal-dialog',
|
'open-goal-dialog',
|
||||||
'workflow-activated',
|
'workflow-activated',
|
||||||
@ -776,6 +785,8 @@ const props = defineProps<{
|
|||||||
} | null;
|
} | null;
|
||||||
userQuestionMinimized?: boolean;
|
userQuestionMinimized?: boolean;
|
||||||
pendingUserQuestionCount?: number;
|
pendingUserQuestionCount?: number;
|
||||||
|
planApprovalMinimized?: boolean;
|
||||||
|
pendingPlanApprovalCount?: number;
|
||||||
goalModeArmed?: boolean;
|
goalModeArmed?: boolean;
|
||||||
goalRunning?: boolean;
|
goalRunning?: boolean;
|
||||||
goalProgress?: Record<string, any> | null;
|
goalProgress?: Record<string, any> | null;
|
||||||
@ -1066,6 +1077,7 @@ const floatingStatusVisible = computed(() => {
|
|||||||
!!props.goalRunning ||
|
!!props.goalRunning ||
|
||||||
!!props.goalModeArmed ||
|
!!props.goalModeArmed ||
|
||||||
(Number(props.pendingUserQuestionCount || 0) > 0) ||
|
(Number(props.pendingUserQuestionCount || 0) > 0) ||
|
||||||
|
(!!props.planApprovalMinimized && Number(props.pendingPlanApprovalCount || 0) > 0) ||
|
||||||
(Number(props.activeSubAgentCount || 0) > 0);
|
(Number(props.activeSubAgentCount || 0) > 0);
|
||||||
return visible;
|
return visible;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,6 +4,17 @@
|
|||||||
<section class="plan-approval-card" role="dialog" aria-modal="true" :aria-label="$t('overlay.planApprovalAriaLabel')">
|
<section class="plan-approval-card" role="dialog" aria-modal="true" :aria-label="$t('overlay.planApprovalAriaLabel')">
|
||||||
<header class="plan-approval-windowbar">
|
<header class="plan-approval-windowbar">
|
||||||
<div class="plan-approval-window-title">{{ $t('overlay.planApprovalTitle') }}</div>
|
<div class="plan-approval-window-title">{{ $t('overlay.planApprovalTitle') }}</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="plan-approval-close"
|
||||||
|
:title="$t('overlay.planApprovalMinimize')"
|
||||||
|
:aria-label="$t('overlay.planApprovalMinimize')"
|
||||||
|
@click="emit('minimize')"
|
||||||
|
>
|
||||||
|
<svg viewBox="0 0 20 20" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||||
|
<path d="M5 5l10 10M15 5L5 15" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<header class="plan-approval-header">
|
<header class="plan-approval-header">
|
||||||
@ -75,6 +86,7 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: 'submit', payload: { approval_id: string; approved: boolean; comment: string }): void;
|
(event: 'submit', payload: { approval_id: string; approved: boolean; comment: string }): void;
|
||||||
|
(event: 'minimize'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// 计划批准一次只处理一份(plan 模式下模型阻塞等待,天然串行);
|
// 计划批准一次只处理一份(plan 模式下模型阻塞等待,天然串行);
|
||||||
@ -139,6 +151,7 @@ function reject() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.plan-approval-windowbar {
|
.plan-approval-windowbar {
|
||||||
|
position: relative;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
flex: 0 0 40px;
|
flex: 0 0 40px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -147,6 +160,29 @@ function reject() {
|
|||||||
border-bottom: 1px solid var(--border-default);
|
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 {
|
.plan-approval-window-title {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export default {
|
|||||||
goalModeRunning: 'Goal mode running',
|
goalModeRunning: 'Goal mode running',
|
||||||
goalModeReady: 'Goal mode ready',
|
goalModeReady: 'Goal mode ready',
|
||||||
waitingForQuestion: 'Waiting for your answer',
|
waitingForQuestion: 'Waiting for your answer',
|
||||||
|
planApprovalPending: 'Plan awaiting approval',
|
||||||
subAgentsRunning: '{n} sub-agents running',
|
subAgentsRunning: '{n} sub-agents running',
|
||||||
terminalsRunning: '{n} terminals',
|
terminalsRunning: '{n} terminals',
|
||||||
quickMenuAriaLabel: 'Quick menu',
|
quickMenuAriaLabel: 'Quick menu',
|
||||||
|
|||||||
@ -88,6 +88,7 @@ export default {
|
|||||||
// ── PlanApprovalDialog ──
|
// ── PlanApprovalDialog ──
|
||||||
planApprovalAriaLabel: 'Plan awaiting approval',
|
planApprovalAriaLabel: 'Plan awaiting approval',
|
||||||
planApprovalTitle: '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)',
|
planTruncatedNote: '(Content too long; preview truncated. See the file for the full content)',
|
||||||
planCommentPlaceholder:
|
planCommentPlaceholder:
|
||||||
'Feedback (optional): added as extra requirements when approving, or describe what to adjust when rejecting...',
|
'Feedback (optional): added as extra requirements when approving, or describe what to adjust when rejecting...',
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export default {
|
|||||||
goalModeRunning: '目标模式运行中',
|
goalModeRunning: '目标模式运行中',
|
||||||
goalModeReady: '目标模式就绪',
|
goalModeReady: '目标模式就绪',
|
||||||
waitingForQuestion: '等待回答问题',
|
waitingForQuestion: '等待回答问题',
|
||||||
|
planApprovalPending: '有待批准的计划',
|
||||||
subAgentsRunning: '{n} 个子智能体运行中',
|
subAgentsRunning: '{n} 个子智能体运行中',
|
||||||
terminalsRunning: '{n} 个终端',
|
terminalsRunning: '{n} 个终端',
|
||||||
quickMenuAriaLabel: '快捷菜单',
|
quickMenuAriaLabel: '快捷菜单',
|
||||||
|
|||||||
@ -87,6 +87,7 @@ export default {
|
|||||||
// ── PlanApprovalDialog:计划待批准 ──
|
// ── PlanApprovalDialog:计划待批准 ──
|
||||||
planApprovalAriaLabel: '计划待批准',
|
planApprovalAriaLabel: '计划待批准',
|
||||||
planApprovalTitle: '计划待批准',
|
planApprovalTitle: '计划待批准',
|
||||||
|
planApprovalMinimize: '关闭弹窗,稍后从状态栏恢复',
|
||||||
planTruncatedNote: '(内容过长,已截断预览,完整内容见文件)',
|
planTruncatedNote: '(内容过长,已截断预览,完整内容见文件)',
|
||||||
planCommentPlaceholder: '意见(可选):批准时作为补充要求,拒绝时说明需要调整的方向…',
|
planCommentPlaceholder: '意见(可选):批准时作为补充要求,拒绝时说明需要调整的方向…',
|
||||||
planRejectTitle: '拒绝这份计划,AI 将根据你的意见修订后重新提交',
|
planRejectTitle: '拒绝这份计划,AI 将根据你的意见修订后重新提交',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user