fix(web): 修复话题重命名预填字段与写入字段不一致
Bug: 点击铅笔编辑时,输入框显示的是 topic.title(系统生成的 id+时间), 而不是用户看到的 topic.description(AI 生成的摘要)。且后端 rename 写入 title, 但列表显示优先 description,导致改名后视觉上无变化。 根因:显示用 'description || title',编辑预填用 'title',写入也改 'title', 三者不一致。 修复: - 前端 startEdit: 预填 'description || title'(与显示逻辑一致) - 后端 rename_topic: 改用 update_topic_description 写入显示字段, 保留 title 作为内部标识;'未变化'比较也基于当前显示值 - 新增测试: 验证有 description 时比较逻辑基于 description 而非 title
This commit is contained in:
parent
c2cc072b2e
commit
adada2652c
@ -75,10 +75,15 @@ async fn handle_rename_topic(
|
||||
CommandError::new("TOPIC_NOT_FOUND", format!("Topic not found: {}", topic_id))
|
||||
})?;
|
||||
|
||||
let old_title = topic.title.clone();
|
||||
let old_display = topic
|
||||
.description
|
||||
.as_deref()
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or(&topic.title)
|
||||
.to_string();
|
||||
|
||||
// 标题未变化时直接返回当前列表,避免无意义写入
|
||||
if old_title == trimmed_title {
|
||||
if old_display == trimmed_title {
|
||||
let topics = handler
|
||||
.store
|
||||
.list_topics(session_id)
|
||||
@ -98,10 +103,10 @@ async fn handle_rename_topic(
|
||||
.with_metadata("session_id", session_id));
|
||||
}
|
||||
|
||||
// 执行重命名(存储层方法已存在)
|
||||
// 执行重命名:更新 description(显示字段),保留 title 作为内部标识
|
||||
handler
|
||||
.store
|
||||
.update_topic_title(&topic_id, trimmed_title)
|
||||
.update_topic_description(&topic_id, trimmed_title)
|
||||
.map_err(|e| CommandError::new("RENAME_TOPIC_ERROR", e.to_string()))?;
|
||||
|
||||
// 查询更新后的话题列表,返回给前端刷新侧边栏
|
||||
@ -114,7 +119,7 @@ async fn handle_rename_topic(
|
||||
let topic_summaries_json = serde_json::to_string(&topic_summaries)
|
||||
.map_err(|e| CommandError::new("SERIALIZE_ERROR", e.to_string()))?;
|
||||
|
||||
let message = format!("✓ 已重命名话题: {} → {}", old_title, trimmed_title);
|
||||
let message = format!("✓ 已重命名话题: {} → {}", old_display, trimmed_title);
|
||||
|
||||
Ok(CommandResponse::success(ctx.request_id)
|
||||
.with_message(MessageKind::Notification, &message)
|
||||
@ -165,9 +170,10 @@ mod tests {
|
||||
);
|
||||
assert!(resp.metadata.contains_key("topics"));
|
||||
|
||||
// 验证存储层已更新
|
||||
// 验证存储层已更新 description(显示字段),title 保持原内部标识
|
||||
let updated = store.get_topic(&topic.id).unwrap().unwrap();
|
||||
assert_eq!(updated.title, "new title");
|
||||
assert_eq!(updated.title, "old title");
|
||||
assert_eq!(updated.description.as_deref(), Some("new title"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@ -222,6 +228,7 @@ mod tests {
|
||||
let store = handler.store.clone();
|
||||
|
||||
let session = store.create_session("test_channel", Some("test")).unwrap();
|
||||
// description=None,当前显示值 fallback 到 title
|
||||
let topic = store.create_topic(&session.id, "same title", None).unwrap();
|
||||
let original_updated_at = store.get_topic(&topic.id).unwrap().unwrap().updated_at;
|
||||
|
||||
@ -244,6 +251,38 @@ mod tests {
|
||||
assert_eq!(after.updated_at, original_updated_at);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_rename_topic_compares_against_description_when_present() {
|
||||
// 有 description 时,"未变化"比较应基于 description 而非 title
|
||||
let handler = create_test_handler();
|
||||
let store = handler.store.clone();
|
||||
|
||||
let session = store.create_session("test_channel", Some("test")).unwrap();
|
||||
// title 是内部标识,description 是显示值
|
||||
let topic = store
|
||||
.create_topic(&session.id, "topic_internal_id", Some("AI 生成的摘要"))
|
||||
.unwrap();
|
||||
let original_updated_at = store.get_topic(&topic.id).unwrap().unwrap().updated_at;
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
|
||||
let ctx = CommandContext::new("test", "test_channel")
|
||||
.with_session_id(&session.id)
|
||||
.with_chat_id(&session.id);
|
||||
// 提交与 description 相同的值(不是 title),应跳过写入
|
||||
let cmd = Command::RenameTopic {
|
||||
topic_id: topic.id.clone(),
|
||||
title: "AI 生成的摘要".to_string(),
|
||||
};
|
||||
|
||||
let result = handler.handle(cmd, ctx).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let after = store.get_topic(&topic.id).unwrap().unwrap();
|
||||
assert_eq!(after.updated_at, original_updated_at);
|
||||
assert_eq!(after.title, "topic_internal_id");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_can_handle() {
|
||||
let handler = create_test_handler();
|
||||
|
||||
@ -93,7 +93,8 @@ export function TopicList({
|
||||
const startEdit = useCallback((topic: Topic) => {
|
||||
setConfirmDeleteId(null);
|
||||
setEditingTopicId(topic.id);
|
||||
setEditingTitle(topic.title);
|
||||
// 预填当前显示值(description 优先,与列表显示逻辑一致)
|
||||
setEditingTitle(topic.description || topic.title);
|
||||
}, []);
|
||||
|
||||
const cancelEdit = useCallback(() => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user