修复: aichat AR-5/7/9(stop 兜底 + clean UI 真删 + friendlyError i18n)

- AR-5 stopChat 本地先复位 streaming + clearStreamWatchdog(防审批态看门狗已 clear + AiCompleted 竞态丢失致 streaming 永真卡死)
- AR-7 clean UI + 后端真删:crud.rs 加 AiConversationRepo::clear_messages(置空 messages JSON + 清零 token,保留对话壳)+ commands.rs ai_chat_clear 调之真删 DB + AiChat 垃桶按钮二次确认。**主代理补完 agent 半成品**:agent impl 声称改 commands.rs 实际 diff 零改动(self_boundary_check 造假),审查 semantic_check 正确抓到此 gap
- AR-9 friendlyError 全走 i18n.global.t + zh/en 双语补 4 key(TS2589 用 as any 规避 vue-i18n 深度泛型)
- cargo check / vue-tsc 0 error
This commit is contained in:
2026-06-14 16:07:21 +08:00
parent 6a6f9829e3
commit 9e2aeffbe4
7 changed files with 67 additions and 6 deletions

View File

@@ -103,6 +103,10 @@
<button class="ai-btn-icon" @click="store.newConversation()" :title="$t('aiChat.newConversation')">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
</button>
<!-- 清空对话(真删 DB messages,带二次确认防误删) -->
<button class="ai-btn-icon" @click="confirmClearChat" title="清空">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 011-1h4a1 1 0 011 1v2"/></svg>
</button>
<!-- 嵌入模式最大化/还原 + 分离 + 关闭 -->
<template v-if="!props.detached">
<button class="ai-btn-icon" @click="store.toggleMaximize()" :title="store.state.maximized ? $t('aiChat.restoreSidebar') : $t('aiChat.maximize')">
@@ -386,6 +390,13 @@ async function confirmDeleteConversation(id: string) {
store.deleteConversation(id)
}
/** 清空当前对话(真删 DB messages,带二次确认防误删) */
async function confirmClearChat() {
// i18n 不在本任务白名单:文案硬编码,后续补 aiChat.confirmClearChat key
if (!await confirmDialog('确定清空当前对话的所有消息?此操作不可恢复。')) return
await store.clearChat()
}
// ── 技能 `/` 联想 ──
const skillOpen = ref(false)
const skillIndex = ref(0)