修复: 审批不超时+重启恢复 + 其他小改

- APPROVAL_TIMEOUT_MS=Infinity(已决策:审批不做超时)
- V33 迁移: ai_conversations 加 pending_approvals 列
- save_conversation 持久化 pending_approvals
- ai_conversation_switch 从 DB 恢复 pending_approvals
- switchConversation 加 try/catch(对话不存在→建新)
- @项目 关联添加取消按钮(×)
- TopBar 底部无标题时图标右对齐
- TaskDetail.vue 删除重复 case
This commit is contained in:
2026-06-28 13:09:55 +08:00
parent c4b02b5370
commit ad1821bc14
11 changed files with 140 additions and 19 deletions

View File

@@ -71,7 +71,7 @@ export function findToolCall(id: string): AiToolCallInfo | undefined {
// ── 审批超时计时器(原 useAiSend,下沉打破 events↔send 循环依赖) ──
/// 审批等待超时阈值(ms) — 用户 5 分钟内不处理则自动拒绝
const APPROVAL_TIMEOUT_MS = 5 * 60 * 1000
const APPROVAL_TIMEOUT_MS = Infinity // 已决策:不做超时,用户不审批就一直等
/** toolCallId → 审批超时计时器 */
const _approvalTimers = new Map<string, ReturnType<typeof setTimeout>>()

View File

@@ -10,9 +10,9 @@ import { state } from '@/stores/ai'
import { notifyConversationChanged } from './useAiEvents'
import { persistUiState } from './useAiPanel'
import { setStreaming } from './streamingGuard'
import { nextMsgId, getConvState, clearConvStreamState } from './aiShared'
import { nextMsgId, getConvState, clearConvStreamState, startApprovalTimer } from './aiShared'
import { t } from '@/i18n/i18n-helpers'
import type { AiMessage, AiToolCallInfo } from '@/api/types'
import type { AiConversationDetail, AiMessage, AiToolCallInfo } from '@/api/types'
const appSettings = useAppSettingsStore()
@@ -92,7 +92,22 @@ let _latestSwitchId = 0
export async function switchConversation(id: string) {
const mySwitchId = ++_latestSwitchId
// 允许生成中切换:后台继续生成,事件按 conversation_id 路由不污染当前视图
const detail = await aiApi.switchConversation(id)
let detail: AiConversationDetail
try {
detail = await aiApi.switchConversation(id)
} catch {
// 对话不存在(已删除/未落库的虚 ID)→ 创建新对话替代
console.warn('[AI] switchConversation 失败,创建新对话:', id)
const created = await aiApi.createConversation()
if (mySwitchId !== _latestSwitchId) return
void appSettings.set('df-ai-active-conv', created.id)
// 用新对话 id 重走后续逻辑
detail = { id: created.id, title: null, messages: '[]' }
state.messages = []
notifyConversationChanged()
void loadConversations()
return
}
// 过期响应丢弃(用户已切到别的对话,防 A 后返回覆盖 B)
if (mySwitchId !== _latestSwitchId) return
state.activeConversationId = id
@@ -226,6 +241,9 @@ export async function switchConversation(id: string) {
dir: tc.dir,
reason: tc.reason,
})
// 重新启动审批计时器(APPROVAL_TIMEOUT_MS=Infinity 已决策,不会超时自动拒绝,
// 启动仅用于计时器注册一致性,保持与 AiApprovalRequired 事件处理对称)
startApprovalTimer(tc.id, tc.name, kind)
}
}
}