优化: 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

@@ -89,6 +89,8 @@ export const state = reactive({
agentRound: 0,
// 归档分组折叠态(默认折叠)
archivedCollapsed: true,
// 时间分组折叠态(默认:更早折叠,今天/昨天展开;持久化进 df-ai-ui)
foldedGroups: { today: false, yesterday: false, earlier: true } as Record<string, boolean>,
// 对话搜索关键字(UX-06 §3.1):非空时侧栏取消时间分组,平铺展示标题匹配的会话(updated_at DESC)。
// 清空恢复原分组。消费方:Sidebar 渲染(读 searchQuery 决定走 filteredConversations 还是 groupedActive)。
searchQuery: '',

View File

@@ -26,9 +26,13 @@ const state = reactive({
// ── 异步竞态保护(请求序号,类似 ai.ts messages 的 switch token 模式) ──
// 快速连点(切换筛选/连续检索/重连)时,旧响应晚到会覆盖新响应。序号自增,
// 请求发起时捕获序号,响应回时比对:非最新请求的响应直接丢弃,只取最新。
// items 序号覆盖 loadList/loadCandidates/search;candidates 与 items 共用同一队列
// (loadList/search 写 items,loadCandidates 写 candidates),故 items 序号也兜底 candidates
let _itemsReqSeq = 0
// 拆两套序号:loadList/search 都写 state.items 共用 _itemsSeq;loadCandidates 写
// state.candidates 用独立 _candidatesSeq。各自防竞态,互不丢弃
// (P1 修复:原先三者共用 _itemsReqSeq,onMounted 并发 loadList+loadCandidates 会
// 让后发起的 loadCandidates ++ 覆盖 loadList 的 seq,导致 loadList 响应被误判为
// 旧响应丢弃,首次进入列表必空。)
let _itemsSeq = 0
let _candidatesSeq = 0
let _configReqSeq = 0
// 7 种知识类型(snake_case,与后端 KnowledgeKind 对齐)
@@ -59,48 +63,48 @@ export function useKnowledgeStore() {
// 后端 knowledge_list 默认收窄为 published,无需前端传 status。
// 显式 status 仍透传(如 status='archived' 查归档)。
async function loadList(status?: string) {
const seq = ++_itemsReqSeq
const seq = ++_itemsSeq
state.loading = true
state.error = null
try {
const result = await knowledgeApi.list(status ?? null)
if (seq !== _itemsReqSeq) return // 旧响应丢弃,只取最新
if (seq !== _itemsSeq) return // 旧响应丢弃,只取最新
state.items = result
} catch (e: any) {
if (seq !== _itemsReqSeq) return // 旧请求的失败不污染当前视图
if (seq !== _itemsSeq) return // 旧请求的失败不污染当前视图
state.error = e?.toString() ?? t('knowledge.err.loadFailed')
} finally {
if (seq === _itemsReqSeq) state.loading = false
if (seq === _itemsSeq) state.loading = false
}
}
// ── 加载待处理收件箱(candidate + pending_review,F-260616-02 决策 a) ──
// 后端 knowledge_list_candidates 已收两种待处理状态,前端调用不变。
async function loadCandidates() {
const seq = ++_itemsReqSeq
const seq = ++_candidatesSeq
try {
const result = await knowledgeApi.listCandidates()
if (seq !== _itemsReqSeq) return // 旧响应丢弃,只取最新
if (seq !== _candidatesSeq) return // 旧响应丢弃,只取最新
state.candidates = result
} catch (e: any) {
if (seq !== _itemsReqSeq) return
if (seq !== _candidatesSeq) return
state.error = e?.toString() ?? t('knowledge.err.loadInboxFailed')
}
}
async function search(query: string, kind?: string) {
const seq = ++_itemsReqSeq
const seq = ++_itemsSeq
state.loading = true
state.error = null
try {
const result = await knowledgeApi.search({ query, kind })
if (seq !== _itemsReqSeq) return // 旧响应丢弃,只取最新
if (seq !== _itemsSeq) return // 旧响应丢弃,只取最新
state.items = result
} catch (e: any) {
if (seq !== _itemsReqSeq) return
if (seq !== _itemsSeq) return
state.error = e?.toString() ?? t('knowledge.err.searchFailed')
} finally {
if (seq === _itemsReqSeq) state.loading = false
if (seq === _itemsSeq) state.loading = false
}
}