新增: 父子任务支持(数据→后端→前端全链路,会话前基线收尾)
- df-nodes task_advance_node(父聚合推进)+ task.rs 命令(create parent_id 支持/delete 级联软删子任务)+ task_graph 工具 - 前端 Tasks 树形列表(折叠箭头/子进度徽章/缩进)+ 新建弹窗父任务下拉 + TaskDetail 父面包屑/子任务面板 - 设计文档: 父子任务支持设计-2026-08-04
This commit is contained in:
@@ -89,6 +89,106 @@ pub async fn advance_task_atomic(
|
||||
})
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 父任务聚合 — 父任务 status 重算 + 推进联动(知识图谱 Phase 1 V29,设计 §2.1)
|
||||
// ============================================================
|
||||
|
||||
/// 父任务 status 重算(容器模型,不走状态机)。
|
||||
///
|
||||
/// 聚合规则(设计 §2.1 父聚合规则,优先级从高到低):
|
||||
/// 1. 任一子 blocked → 父 blocked(阻塞优先,避免掩盖卡点)
|
||||
/// 2. 任一子 in_progress → 父 in_progress(执行中)
|
||||
/// 3. 全子 done/cancelled → 父 done(全部完成/取消)
|
||||
/// 4. 全子 todo → 父 todo(尚未开始)
|
||||
/// 5. 其他混合态(如 todo+done)→ 父 in_progress(进行中,有进展未全完)
|
||||
///
|
||||
/// 无子任务(悬空)→ 不重算,返回当前 status。
|
||||
/// 数据源 `repo.count_children_by_status`(一次 GROUP BY 查询,数据量小无压力);
|
||||
/// 写入 `repo.set_status_for_aggregation`(父任务 status 唯一非状态机写入路径)。
|
||||
/// 状态相同则不写(避免无谓 updated_at 抖动)。
|
||||
///
|
||||
/// 返回:重算后的父任务最新 status。
|
||||
pub async fn recompute_parent_status(
|
||||
repo: &TaskRepo,
|
||||
parent_id: &str,
|
||||
) -> df_types::error::Result<String> {
|
||||
let counts = repo
|
||||
.count_children_by_status(parent_id)
|
||||
.await?;
|
||||
// 无子任务(parent_id 悬空,理论上不该发生):不重算,返当前 status
|
||||
if counts.is_empty() {
|
||||
return repo
|
||||
.get_by_id(parent_id)
|
||||
.await?
|
||||
.map(|t| t.status.as_str().to_string())
|
||||
.ok_or_else(|| df_types::error::Error::NotFound(format!("父任务 {parent_id} 不存在")));
|
||||
}
|
||||
|
||||
// 转 HashMap<status, count> 便于按规则判定
|
||||
let map: std::collections::HashMap<String, i64> = counts.into_iter().collect();
|
||||
let total: i64 = map.values().sum();
|
||||
let blocked = map.get("blocked").copied().unwrap_or(0);
|
||||
let in_progress = map.get("in_progress").copied().unwrap_or(0);
|
||||
let todo = map.get("todo").copied().unwrap_or(0);
|
||||
let done = map.get("done").copied().unwrap_or(0);
|
||||
let cancelled = map.get("cancelled").copied().unwrap_or(0);
|
||||
|
||||
// 聚合规则判定(优先级从高到低,首个命中即定)
|
||||
let new_status = if blocked > 0 {
|
||||
"blocked".to_string()
|
||||
} else if in_progress > 0 {
|
||||
"in_progress".to_string()
|
||||
} else if (done + cancelled) == total {
|
||||
// 全 done/cancelled → done(终端态聚合为 done)
|
||||
"done".to_string()
|
||||
} else if todo == total {
|
||||
// 全 todo → todo(尚未开始)
|
||||
"todo".to_string()
|
||||
} else {
|
||||
// 其他混合态(如 todo+done, in_review+done 等)→ in_progress(进行中)
|
||||
"in_progress".to_string()
|
||||
};
|
||||
|
||||
// 读当前父 status,相同则不写(避免无谓 updated_at 抖动)
|
||||
let current = repo
|
||||
.get_by_id(parent_id)
|
||||
.await?
|
||||
.ok_or_else(|| df_types::error::Error::NotFound(format!("父任务 {parent_id} 不存在")))?;
|
||||
if current.status.as_str() == new_status {
|
||||
return Ok(new_status);
|
||||
}
|
||||
repo.set_status_for_aggregation(parent_id, &new_status).await?;
|
||||
Ok(new_status)
|
||||
}
|
||||
|
||||
/// 推进任务 + 若为子任务则触发父聚合(父聚合失败仅 warn 不阻断,宽容语义)。
|
||||
///
|
||||
/// 推进链唯一 status 写入路径的两段式(设计 D3 统一,IPC/AI 工具/MCP 同源):
|
||||
/// 1. 推进自身:调 `advance_task_atomic`(状态机校验 + 原子 CAS + review_rounds 累加)。
|
||||
/// 2. 父聚合:推进成功后若 `updated.parent_id` 有值,触发 `recompute_parent_status` 重算
|
||||
/// 父 status(父任务=容器模型,聚合规则见 recompute_parent_status)。父聚合失败仅
|
||||
/// tracing::warn 不阻断——子任务推进成功是主结果,父 status 漂移可后续修正。
|
||||
///
|
||||
/// 返回:推进成功后的最新 TaskRecord(含新 status / 累加后的 review_rounds)。
|
||||
pub async fn advance_task_with_parent(
|
||||
repo: &TaskRepo,
|
||||
id: &str,
|
||||
target_status: &str,
|
||||
) -> df_types::error::Result<TaskRecord> {
|
||||
let updated = advance_task_atomic(repo, id, target_status).await?;
|
||||
if let Some(pid) = &updated.parent_id {
|
||||
if let Err(e) = recompute_parent_status(repo, pid).await {
|
||||
tracing::warn!(
|
||||
task_id = %id,
|
||||
parent_id = %pid,
|
||||
error = %e,
|
||||
"[父聚合] 重算父任务 status 失败(不阻断子任务推进)"
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(updated)
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// DAG 工作流节点 — TaskAdvanceNode(推进链在 DAG 内的形态)
|
||||
// ============================================================
|
||||
|
||||
Reference in New Issue
Block a user