重构: 审批交互重设计
This commit is contained in:
@@ -4,12 +4,19 @@
|
||||
<div v-if="pendingCount > 0" class="ai-tool-topbar">
|
||||
<!-- 批量操作栏(存在待审批项时显示) -->
|
||||
<div class="ai-batch-approve">
|
||||
<button class="ai-btn ai-btn--sm" @click="$emit('batch-approve', 'approve')">
|
||||
<!-- 批量批准含 High 风险工具时前置二次确认(与单卡 onApprove 同门槛;
|
||||
纯低风险批量保持一键直批) -->
|
||||
<button class="ai-btn ai-btn--sm" :disabled="batchProcessing" @click="onBatchApprove">
|
||||
<span v-if="batchProcessing" class="ai-btn-spinner" />
|
||||
{{ $t('aiTool.approveAll', { n: pendingCount }) }}
|
||||
</button>
|
||||
<button class="ai-btn ai-btn--sm ai-btn--danger" @click="$emit('batch-approve', 'reject')">
|
||||
<button class="ai-btn ai-btn--sm ai-btn--danger" :disabled="batchProcessing" @click="$emit('batch-approve', 'reject')">
|
||||
{{ $t('aiTool.rejectAll') }}
|
||||
</button>
|
||||
<!-- High 风险计数徽标:批量批准将二次确认的项数,提示操作后果 -->
|
||||
<span v-if="highRiskPendingCount > 0" class="ai-batch-high-risk-hint">
|
||||
{{ $t('aiTool.batchHighRiskHint', { n: highRiskPendingCount }) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -34,6 +41,14 @@
|
||||
:class="{ 'ai-tool-card--group-hidden': isGroupHidden(tc, group, gi) }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 批量批准 High 风险二次确认(本组件自治 useConfirm,不与父级串台) -->
|
||||
<ConfirmDialog
|
||||
:visible="confirmState.visible"
|
||||
:msg="confirmState.msg"
|
||||
:danger-label="t('common.confirm')"
|
||||
@result="answerConfirm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -41,8 +56,11 @@
|
||||
import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import ToolCard from './ToolCard.vue'
|
||||
import ConfirmDialog from './ConfirmDialog.vue'
|
||||
import { listen, type UnlistenFn } from '@tauri-apps/api/event'
|
||||
import type { AiToolCallInfo } from '@/api/types'
|
||||
import { useConfirm } from '@/composables/useConfirm'
|
||||
import { toolRiskLevel } from '@/composables/ai/useToolApproval'
|
||||
|
||||
// useI18n needed for $t() in template (collapseAll / expandAll) + groupDisplayName(i18n key)
|
||||
const { t } = useI18n()
|
||||
@@ -123,6 +141,37 @@ const pendingCount = computed(() =>
|
||||
props.toolCalls.filter(tc => tc.status === 'pending_approval').length
|
||||
)
|
||||
|
||||
// -- 批量批准 High 风险拦截(治安全缺口:原批量批准绕过单卡二次确认直接放行) --
|
||||
const { confirmState, confirmDialog, answerConfirm } = useConfirm()
|
||||
/** 待审批中的 High 风险项数(徽标提示 + 确认门槛判定) */
|
||||
const highRiskPendingCount = computed(() =>
|
||||
props.toolCalls.filter(tc => tc.status === 'pending_approval' && toolRiskLevel(tc.name) === 'high').length
|
||||
)
|
||||
/** 批量处理中(透传 isBatchProcessing 不便——本组件直接用 pendingCount 收敛到 0 判断,简单可靠) */
|
||||
const batchProcessing = ref(false)
|
||||
|
||||
/**
|
||||
* 批量批准入口:含 High 风险项 → 先二次确认(文案对齐单卡 highRiskConfirmText 语义,
|
||||
* 列出将放行的高危工具数);确认后才向父级派发 batch-approve('approve')。
|
||||
* 拒绝批量无破坏性,不拦。
|
||||
*/
|
||||
async function onBatchApprove() {
|
||||
if (highRiskPendingCount.value > 0) {
|
||||
const ok = await confirmDialog(
|
||||
t('aiTool.batchHighRiskConfirm', { n: highRiskPendingCount.value }),
|
||||
)
|
||||
if (!ok) return
|
||||
}
|
||||
batchProcessing.value = true
|
||||
emit('batch-approve', 'approve')
|
||||
// emit 后父级异步批量处理;本组件无完成回执,以 pendingCount 归零兜底复位
|
||||
const stop = watch(pendingCount, (n, old) => {
|
||||
if (n === 0 || n < old) { batchProcessing.value = false; stop() }
|
||||
}, { flush: 'post' })
|
||||
// 兜底:pendingCount 因新增挂起不清零时 3s 后自动复位
|
||||
setTimeout(() => { batchProcessing.value = false }, 3000)
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认收起补齐:达到多卡阈值(>=2)且用户未手动操作过的组自动收起。
|
||||
* 响应式而非一次性初始化——流式场景第一张卡到达即触发旧一次性逻辑,
|
||||
@@ -398,6 +447,16 @@ function groupIcon(name: string): string {
|
||||
border-radius: var(--df-radius-sm);
|
||||
background: rgba(255,255,255,0.02);
|
||||
}
|
||||
/* 批量批准将二次确认的 High 风险项数徽标(橙红警示,不抢按钮焦点) */
|
||||
.ai-batch-high-risk-hint {
|
||||
font-size: 10px;
|
||||
color: var(--df-danger);
|
||||
background: var(--df-danger-bg);
|
||||
border: 0.5px solid color-mix(in srgb, var(--df-danger) 40%, transparent);
|
||||
border-radius: var(--df-radius-sm);
|
||||
padding: 2px 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* .ai-btn 基类:批量审批按钮(历史重构遗漏定义,补全治本) */
|
||||
.ai-btn {
|
||||
display: inline-flex;
|
||||
|
||||
Reference in New Issue
Block a user