优化: AI Chat全栈多批审查修复与架构清理(risk_level清理/路由解耦/工具渲染/测试补测/死代码)

This commit is contained in:
2026-06-18 22:57:19 +08:00
parent 0ca5d9805f
commit a2871a66e0
87 changed files with 5720 additions and 3012 deletions

View File

@@ -1,9 +1,9 @@
<template>
<div class="ai-tool-calls" ref="rootEl">
<!-- 顶部操作栏批量审批 + 全局收起合并同(UX-260616-02,减少垂直空间占用) -->
<div v-if="pendingCount > 0 || collapsibleGroupCount > 0" class="ai-tool-topbar">
<!-- 顶部操作栏批量审批(全局收起已下沉到首个可折叠分组标题,U-260618) -->
<div v-if="pendingCount > 0" class="ai-tool-topbar">
<!-- 批量操作栏存在待审批项时显示 -->
<div v-if="pendingCount > 0" class="ai-batch-approve">
<div class="ai-batch-approve">
<button class="ai-btn ai-btn--sm" @click="$emit('batch-approve', 'approve')">
{{ $t('aiTool.approveAll', { n: pendingCount }) }}
</button>
@@ -11,12 +11,6 @@
{{ $t('aiTool.rejectAll') }}
</button>
</div>
<!-- 全部展开 / 全部收起仅当存在可折叠分组时显示推到行尾右对齐 -->
<div v-if="collapsibleGroupCount > 0" class="ai-tool-global-toggle" @click="toggleAllGroups">
<span class="ai-tool-global-toggle-icon">{{ allGroupsExpanded ? '▾' : '▸' }}</span>
<span>{{ allGroupsExpanded ? $t('aiTool.collapseAll') : $t('aiTool.expandAll') }}</span>
</div>
</div>
<template v-for="(group, gi) in groupedToolCalls" :key="group.name">
@@ -26,6 +20,15 @@
<span class="ai-tool-group-name">{{ groupDisplayName(group) }}</span>
<span class="ai-tool-group-count">{{ group.calls.length }}</span>
<span class="ai-tool-group-chevron" :class="{ 'is-open': !isGroupCollapsed(gi) }"></span>
<!-- 全部展开/收起(U-260618: topbar 下沉到首个可折叠分组标题行尾巴, run command 同行) -->
<div
v-if="gi === firstCollapsibleGi"
class="ai-tool-global-toggle"
@click.stop="toggleAllGroups"
>
<span class="ai-tool-global-toggle-icon">{{ allGroupsExpanded ? '▾' : '▸' }}</span>
<span>{{ allGroupsExpanded ? $t('aiTool.collapseAll') : $t('aiTool.expandAll') }}</span>
</div>
</div>
<ToolCard
v-for="(tc, ci) in group.calls"
@@ -33,7 +36,7 @@
:tc="tc"
:isExpanded="isCardExpanded(tc, gi, ci)"
:isContentExpanded="expandedTools.has(tc.id)"
@toggle="toggleCardExpand"
@toggle="() => toggleCardExpand(tc, gi, ci)"
@expand-content="toggleExpand"
@approve="(e) => emit('approve', e)"
:class="{ 'ai-tool-card--group-hidden': group.calls.length >= 2 && isGroupCollapsed(gi) }"
@@ -72,6 +75,9 @@ const expandedCards = ref(new Set<string>())
// userExpandedCards 是"用户明确点开"的持久标记,collapseInactive 跳过这些卡。
// 语义:用户读过的卡不强制折叠,符合"跟随阅读位置"的增强目标。
const userExpandedCards = ref(new Set<string>())
// UX-260617-23:用户主动折叠记忆(修复首卡 ci===0 兜底 return true 导致无法折叠)。
// isCardExpanded 最优先判断,覆盖默认首卡展开 + userExpandedCards 记忆。
const userCollapsedCards = ref(new Set<string>())
// 内容级展开read_file "展开全部"
const expandedTools = ref(new Set<string>())
// 分组折叠状态(按分组索引);多卡片分组默认收起
@@ -108,6 +114,14 @@ const collapsibleGroupCount = computed(() =>
groupedToolCalls.value.filter(g => g.calls.length >= 2).length
)
/** 首个可折叠分组索引(U-260618:全部展开/收起按钮下沉到此分组标题行尾巴) */
const firstCollapsibleGi = computed(() => {
for (let i = 0; i < groupedToolCalls.value.length; i++) {
if (groupedToolCalls.value[i].calls.length >= 2) return i
}
return -1
})
/** 待审批工具数status === 'pending_approval'),控制批量操作栏显隐 */
const pendingCount = computed(() =>
props.toolCalls.filter(tc => tc.status === 'pending_approval').length
@@ -207,6 +221,8 @@ function groupDisplayName(group: ToolCallGroup): string {
*/
function isCardExpanded(tc: AiToolCallInfo, gi: number, ci: number): boolean {
if (isGroupCollapsed(gi)) return false
// UX-260617-23:用户主动折叠最优先(覆盖默认首卡 ci===0 兜底展开 + 用户展开记忆)
if (userCollapsedCards.value.has(tc.id)) return false
// UX-260616-03:用户主动展开的卡片记忆态优先(不被自动收起影响)
if (userExpandedCards.value.has(tc.id)) return true
// 用户手动切换过该卡(当前态)
@@ -217,15 +233,21 @@ function isCardExpanded(tc: AiToolCallInfo, gi: number, ci: number): boolean {
return true
}
function toggleCardExpand(id: string) {
if (expandedCards.value.has(id)) {
function toggleCardExpand(tc: AiToolCallInfo, gi: number, ci: number) {
const id = tc.id
// 用 isCardExpanded 判当前真实态(含默认首卡展开),而非 expandedCards(默认首卡不在其中,
// 否则首卡点 toggle 会误判"当前折叠"反向展开)
const currentlyExpanded = isCardExpanded(tc, gi, ci)
if (currentlyExpanded) {
// 展开 → 折叠
expandedCards.value.delete(id)
// 收起时同步清记忆(下次自动收起可作用于它)
userExpandedCards.value.delete(id)
userCollapsedCards.value.add(id)
} else {
// 折叠 → 展开
expandedCards.value.add(id)
// UX-260616-03:展开即记忆(用户主动展开,后续不被自动收起)
userExpandedCards.value.add(id)
userCollapsedCards.value.delete(id)
}
}
@@ -313,24 +335,21 @@ function groupIcon(name: string): string {
font-size: 11px;
}
/* -- 全部展开/收起按钮 -- */
/* -- 全部展开/收起(U-260618:从 topbar 下沉到分组标题行,移除独立按钮 padding/背景,
高度=文字行高,不撑高分组标题行;融入标题视觉,仅 hover 变色) -- */
.ai-tool-global-toggle {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
cursor: pointer;
user-select: none;
font-size: 11px;
color: var(--df-text-dim);
border-radius: var(--df-radius-sm);
transition: background 0.15s var(--df-ease);
width: fit-content;
/* UX-260616-02: 合并同行时推到行尾右对齐(batch-approve 在左,收起在右) */
transition: color 0.15s var(--df-ease);
/* 推到分组标题行尾巴右对齐 */
margin-left: auto;
}
.ai-tool-global-toggle:hover {
background: rgba(255,255,255,0.03);
color: var(--df-text-secondary);
}
.ai-tool-global-toggle-icon {
@@ -344,6 +363,8 @@ function groupIcon(name: string): string {
align-items: center;
gap: 6px;
padding: 6px 10px;
/* U-260618: max-width 对齐气泡/卡片(90%),不拉满 ai-msg-content 右侧 */
max-width: var(--df-msg-max-width);
cursor: pointer;
user-select: none;
border-radius: var(--df-radius-sm);
@@ -378,7 +399,7 @@ function groupIcon(name: string): string {
color: var(--df-accent);
}
.ai-tool-group-chevron {
margin-left: auto;
/* U-260618: 移除 margin-left:auto,让全部展开/收起按钮(global-toggle)占据行尾右对齐 */
font-size: 10px;
color: var(--df-text-dim);
transition: transform 0.15s var(--df-ease);