From c0cb3148a14fd1ff3da9247135087997b320baa8 Mon Sep 17 00:00:00 2001 From: ymq Date: Wed, 19 Aug 2026 05:53:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20PM=E4=BB=BB=E5=8A=A1=E5=88=86=E8=A7=A3?= =?UTF-8?q?=E4=B8=8E=E7=BC=96=E6=8E=92=E2=80=94=E2=80=94=E7=88=B6=E5=AD=90?= =?UTF-8?q?=E5=85=B3=E7=B3=BB(parent=5Fid)+=E4=BE=9D=E8=B5=96=E4=B8=B2?= =?UTF-8?q?=E8=A1=8C(depends=5Fon)+=E4=BB=BB=E5=8A=A1=E6=A0=91=E5=88=86?= =?UTF-8?q?=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wwwroot/api/task_tree.dspy | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/wwwroot/api/task_tree.dspy b/wwwroot/api/task_tree.dspy index 77a2dd8..c5c421e 100644 --- a/wwwroot/api/task_tree.dspy +++ b/wwwroot/api/task_tree.dspy @@ -83,7 +83,7 @@ async with DBPools().sqlorContext(dbname) as sor: # 一次查所有任务 + 所有迭代(任务数不大,Python 分组避免 SQL JSON 函数坑) all_tasks = await sor.sqlExe( - "SELECT id, title, role, state, params FROM pipeline_tasks WHERE tenant_id=${p}$ ORDER BY created_at ASC", + "SELECT id, title, role, state, params, parent_id FROM pipeline_tasks WHERE tenant_id=${p}$ ORDER BY created_at ASC", {"p": pid}) or [] iters = await sor.sqlExe( "SELECT id, iteration_name, status FROM sd_iterations WHERE project_id=${p}$ ORDER BY created_at ASC", @@ -162,7 +162,7 @@ async with DBPools().sqlorContext(dbname) as sor: }) return json.dumps(nodes, ensure_ascii=False) - # 任务列表 + # 任务列表(只列顶层任务:parent_id 为空的;子任务挂在父任务下展开,避免平铺重复) nodes = [] for t in iter_tasks: r = (getattr(t, 'role', '') or '').strip() @@ -174,15 +174,37 @@ async with DBPools().sqlorContext(dbname) as sor: tid = getattr(t, 'id', '') title = getattr(t, 'title', '') or '' state = getattr(t, 'state', '') or '' + parent = (getattr(t, 'parent_id', '') or '').strip() + if parent: + continue # 子任务不在阶段平铺,挂在父任务下展示 if not tid or not title: continue icon = _state_icons.get(state, '⬜') zh = _state_zh.get(state, state) + has_child = any((getattr(c, 'parent_id', '') or '').strip() == tid for c in all_tasks) nodes.append({ "id": tid, "label": "{} [{}] {}".format(icon, zh, title), - "is_leaf": True, + "is_leaf": not has_child, }) return json.dumps(nodes, ensure_ascii=False) - return json.dumps([], ensure_ascii=False) + # 子任务层:裸任务ID → 返回该任务的子任务(parent_id == 该ID),递归支持多级分解 + nodes = [] + for t in all_tasks: + if (getattr(t, 'parent_id', '') or '').strip() != node_id: + continue + tid = getattr(t, 'id', '') + title = getattr(t, 'title', '') or '' + state = getattr(t, 'state', '') or '' + if not tid or not title: + continue + icon = _state_icons.get(state, '⬜') + zh = _state_zh.get(state, state) + has_child = any((getattr(c, 'parent_id', '') or '').strip() == tid for c in all_tasks) + nodes.append({ + "id": tid, + "label": "{} [{}] {}".format(icon, zh, title), + "is_leaf": not has_child, + }) + return json.dumps(nodes, ensure_ascii=False)