修复: 主菜单点不开 + 对话列表样式/菜单 + 标题卡死/弹回/updated_at(God 拆分遗漏 + 多 bug 合并)
主菜单点不开(7f1242c):c38cefe ErrorBoundary 嵌 transition 内部,slot 透传非元素根 → mode="out-in" 过渡卡死 → 点主菜单 URL 变页面不切换。修:ErrorBoundary 移 transition 外 + 根固定 div.error-boundary-root + display:contents 对话列表样式/菜单(God 拆分遗漏4f8f1cf+ 脉冲点5c395f4+ 审查 agent 菜单): - God 拆分样式没移子组件,AiChat scoped 不匹配子元素 → 列表/输入框样式丢。修:样式移 ConversationSidebar/ChatInput scoped + 复用抽 components.css - 脉冲点 vertical-align/margin-left 冲突。修:移除用 flex gap 统一 - 4 操作按钮窄宽撑高 → 收进"..."下拉菜单(置顶/归档/删除)+ 移除导出(后端 IPC 保留) 标题 3 重根因(8192cd2 合并): - 卡死:ensure :40 title.is_some() return,"新对话"占位永远跳过;switch need_title_regen 仅 None 不触发。修:排除"新对话"占位 + need_title_regen 含"新对话" - 弹回::121 无条件落 LLM 结果,clean_title 空兜底"新对话"覆盖 extract。修:非空非"新对话"才落 - updated_at 跳变:update_field 强制 SET updated_at=now,标题生成致时间分组跳。修:set_title 不动 updated_at CR-20/21 审查登记(待审查.md) cargo check + vue-tsc + vite build EXIT 0
This commit is contained in:
@@ -135,8 +135,10 @@ pub async fn ai_conversation_switch(
|
||||
|
||||
let messages_json = record.messages.clone();
|
||||
let title = record.title.clone();
|
||||
// B-260617-17 续:历史会话 title 空(显"新对话")→ 切入后触发重新生成(用户诉求)
|
||||
let need_title_regen = record.title.is_none();
|
||||
// B-260617-17 续:历史会话 title 空(显"新对话")→ 切入后触发重新生成(用户诉求)。
|
||||
// 含 "新对话" 占位(Some 但未生成):title.rs ensure :40 同步排除"新对话"占位不跳过,
|
||||
// 否则 title 落"新对话"(LLM 返空兜底/默认)后 is_some()=true 永远跳过 → 标题卡死。
|
||||
let need_title_regen = record.title.is_none() || record.title.as_deref() == Some("新对话");
|
||||
|
||||
let mut session = state.ai_session.lock().await;
|
||||
// F-260616-09 B 批4(决策 e 真并发上线):删除 readonly 分支。
|
||||
|
||||
@@ -35,10 +35,14 @@ pub(crate) async fn ensure_conversation_title(
|
||||
) {
|
||||
let conv_repo = AiConversationRepo::new(db);
|
||||
|
||||
// 已有标题(用户改名或已生成)→ 不覆盖
|
||||
// 已有标题(用户改名或已生成)→ 不覆盖。
|
||||
// 但 "新对话" 是未生成占位(默认/LLM 返空兜底/清理后空回退),视为未生成可重新生成,
|
||||
// 否则一旦 title 落"新对话"便 is_some()=true 永远跳过 → 标题卡死"新对话"。
|
||||
if let Ok(Some(rec)) = conv_repo.get_by_id(conv_id).await {
|
||||
if rec.title.is_some() {
|
||||
return;
|
||||
if let Some(t) = &rec.title {
|
||||
if !t.is_empty() && t != "新对话" {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +82,7 @@ pub(crate) async fn ensure_conversation_title(
|
||||
// spawn 未跑完即刷新)时,既不返回 None 也不落库 → 标题长期停留"新对话"。现先落 extract
|
||||
// 兜底,下方 LLM 生成成功后覆盖;LLM 卡住/失败/超时则保留兜底,无论如何不再"新对话"。
|
||||
let fallback_title = extract_title(&all_msgs).unwrap_or_else(|| "新对话".to_string());
|
||||
if let Err(e) = conv_repo.update_field(conv_id, "title", &fallback_title).await {
|
||||
if let Err(e) = conv_repo.set_title(conv_id, &fallback_title).await {
|
||||
tracing::error!("对话标题兜底落库失败(conv_id={}, title={}): {}", conv_id, fallback_title, e);
|
||||
}
|
||||
let _ = app_handle.emit("ai-conversation-changed", ());
|
||||
@@ -117,11 +121,14 @@ pub(crate) async fn ensure_conversation_title(
|
||||
}
|
||||
};
|
||||
|
||||
// LLM 生成成功 → 覆盖 extract 兜底
|
||||
if let Err(e) = conv_repo.update_field(conv_id, "title", &title).await {
|
||||
tracing::error!("对话标题 LLM 落库失败(conv_id={}, title={}): {}", conv_id, title, e);
|
||||
// LLM 生成成功且有效(非空非"新对话")→ 覆盖 extract 兜底。
|
||||
// LLM 返空/无效(clean_title 兜底"新对话")→ 保留上方已落的 extract 兜底,不覆盖(防弹回"新对话")。
|
||||
if !title.is_empty() && title != "新对话" {
|
||||
if let Err(e) = conv_repo.set_title(conv_id, &title).await {
|
||||
tracing::error!("对话标题 LLM 落库失败(conv_id={}, title={}): {}", conv_id, title, e);
|
||||
}
|
||||
let _ = app_handle.emit("ai-conversation-changed", ());
|
||||
}
|
||||
let _ = app_handle.emit("ai-conversation-changed", ());
|
||||
}
|
||||
|
||||
/// 后台生成对话标题(不阻塞主流程;失败有 extract_title 兜底)
|
||||
|
||||
Reference in New Issue
Block a user