优化: 所有剩余UI/UX待办一批完成(持久化+AuditLog+解耦+total+原12大改+P2)

持久化(P1-c):新建 usePersistedRef composable,Tasks/AuditLog/ProjectDetail 等接入 localStorage

AuditLog(P1-d):后端 list_tool_executions 加 WHERE 筛选+返 {items,total,has_more},前端对接+长列折叠+筛选持久化

数据源解耦(P1-g):ProjectDetail projectTasks 按 project_id 独立加载 + ChatInput @项目联想独立加载(不读 store.tasks 当前页)

GitChanges(12a):后端 get_module_commits 加 git rev-list --count 返 total,前端显真实总数

原12大改:Dashboard 统计卡压底行(1)/Projects 列表卡片视图(2)/project_event 埋点排序(3)/TaskDetail 重设计(4)/IdeaDetail 重设计(5)/KnowledgeDetail 重设计(6)/界面持久化+侧栏Ctrl+B+审批数字键(7)/ProjectDetail 三栏改两栏(10)

P2打磨:文件浏览器(FileTree去重/FilePreview行号.md Diff/selectedFilePath归位)/settings反馈(假保存/端口校验)/AI会话(try-catch/scrollIntoView)/后端计数(move_queue事件/timeline total/workflow分页/import_batch分块)/杂项(TopBar/ConfirmDialog键盘/CIStatus i18n/ToolResultBody/ModuleNode/ApprovalDialog全选)
This commit is contained in:
lxy
2026-08-02 13:11:06 +08:00
parent caaabf0c15
commit f736f435bc
70 changed files with 2645 additions and 576 deletions
+70 -4
View File
@@ -408,6 +408,15 @@ pub async fn update_task(
}
// B-260801-01(P0-1):update_field 返 affected>0;false = id 不存在或已软删(0 行)。
// 不可静默返 false——前端 store.runWithCatch 把 Err 转 toast,而 false 会被忽略致假成功。
//
// 任务字段更新是高频「项目活跃」信号(改 title/priority/assignee 等),埋点 task_updated
// 推动项目最近活跃排序反映真实业务(问题3)。best-effort 不阻断。
// 读当前 project_id(一次轻量读):update_field 返 bool 不带 project_id,无法直接埋点。
let current = state
.tasks
.get_by_id(&id)
.await
.map_err(err_str)?;
let updated = state
.tasks
.update_field(&id, &field, &value)
@@ -416,19 +425,68 @@ pub async fn update_task(
if !updated {
return Err(format!("任务 ID {id} 不存在或已删除"));
}
if let Some(rec) = current {
emit_event(
&state,
&rec.project_id,
"task_updated",
Some("task"),
Some(&rec.id),
None,
None,
)
.await;
}
Ok(true)
}
/// 删除任务(软删 → 回收站,可恢复)。对标 delete_project(SET deleted_at=now)。
///
/// 埋点 task_deleted(问题3 项目最近活跃排序):删除是业务事件,推动项目活跃时间。
/// best-effort 不阻断。读 project_id 一次轻量读(soft_delete 返 bool 不带 project_id)。
#[tauri::command]
pub async fn delete_task(state: State<'_, AppState>, id: String) -> Result<bool, String> {
state.tasks.soft_delete(&id).await.map_err(err_str)
let rec = state.tasks.get_by_id(&id).await.map_err(err_str)?;
let ok = state.tasks.soft_delete(&id).await.map_err(err_str)?;
if ok {
if let Some(r) = rec {
emit_event(
&state,
&r.project_id,
"task_deleted",
Some("task"),
Some(&r.id),
None,
None,
)
.await;
}
}
Ok(ok)
}
/// 恢复任务(从回收站还原,清 deleted_at)。对标 restore_project。
///
/// 埋点 task_restored(问题3 项目最近活跃排序):恢复是业务事件。best-effort 不阻断。
#[tauri::command]
pub async fn restore_task(state: State<'_, AppState>, id: String) -> Result<bool, String> {
state.tasks.restore(&id).await.map_err(err_str)
let rec = state.tasks.get_by_id(&id).await.map_err(err_str)?;
let ok = state.tasks.restore(&id).await.map_err(err_str)?;
if ok {
if let Some(r) = rec {
emit_event(
&state,
&r.project_id,
"task_restored",
Some("task"),
Some(&r.id),
None,
None,
)
.await;
}
}
Ok(ok)
}
/// 推进任务状态(任务推进链 F-260616-02,推进链唯一 status 写入路径)。
@@ -741,12 +799,20 @@ pub async fn move_task_queue(
}
// 知识图谱 Phase 2(对标设计 §2.4 hook/after):queue 变化事件。best-effort 不阻断。
// 仅在 queue 实际变化时埋点(避免 no-op 移动产噪音事件)。from/to 用 queue 值。
// 仅在 queue 实际变化时埋点(避免 no-op 移动产噪音事件)。
//
// M17:用独立 event_type "task_queue_moved"(非复用 "task_advanced"),与 status 推进事件
// 语义解耦——advance_task 触发的 task_advanced 用 from_state/to_state 装**执行态**值
// (todo→in_progress 等),而 move_task_queue 改的是**管理维度池**(backlog/todo/decision/
// active/done),两者正交。混用同一 event_type + 同样的 from/to 字段会让消费者无法区分
// 「任务执行推进」与「跨池移动」,过滤 task_advanced 的事件流会混入 queue 漂移噪音。
// 独立 type 后:status 推进走 task_advanced,queue 移动走 task_queue_moved,语义自洽,
// from/to 字段各自装对应维度的值(queue_moved 装 queue 值),不冲突。
if current.queue != new_queue {
emit_event(
&state,
&current.project_id,
"task_advanced",
"task_queue_moved",
Some("task"),
Some(&current.id),
Some(&current.queue),