From 36537b3297483dd2470ef627a3de2b0495641b5e Mon Sep 17 00:00:00 2001 From: ymq Date: Tue, 1 Sep 2026 18:01:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=A0=E9=99=A4/=E5=81=9C=E6=AD=A2/?= =?UTF-8?q?=E5=BD=92=E6=A1=A3=E9=A1=B9=E7=9B=AE=E5=90=8E=E6=B8=85=E7=A9=BA?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=85=A8=E9=83=A8=E5=BE=85=E5=8A=9E=E2=80=94?= =?UTF-8?q?=E2=80=94=E6=96=B0=E5=A2=9E=5Fclear=5Fproject=5Ftodos(human=5Ft?= =?UTF-8?q?asks=E4=B8=89=E6=9D=A1=E5=85=B3=E8=81=94=E9=93=BE+agent=5Fquest?= =?UTF-8?q?ions),=E6=8E=A5=E5=85=A5pause/archive/delete=E4=B8=89=E6=93=8D?= =?UTF-8?q?=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pipeline_service/project_capability.py | 41 +++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/pipeline_service/project_capability.py b/pipeline_service/project_capability.py index ff7fde7..dd2d2b3 100644 --- a/pipeline_service/project_capability.py +++ b/pipeline_service/project_capability.py @@ -216,6 +216,28 @@ async def start_project(project_id, who=None, agent_id=None): who=who, agent_id=agent_id) +async def _clear_project_todos(sor, project_id): + """删除项目全部待办:人类任务 + 冒泡问题(待办角标/列表的两个来源)。 + 关联链:project_id 直挂 / iteration_id 经迭代 / task_id 经任务 / tenant_id(questions)。 + 调用方保证在 sd_iterations / pipeline_tasks 删除之前执行(子查询依赖)。 + """ + if not project_id: + return + for sql in [ + "DELETE FROM pipeline_human_tasks WHERE project_id=${pid}$", + "DELETE FROM pipeline_human_tasks WHERE iteration_id IN (SELECT id FROM sd_iterations WHERE project_id=${pid}$)", + "DELETE FROM pipeline_human_tasks WHERE task_id IN (SELECT id FROM pipeline_tasks WHERE tenant_id=${pid}$)", + "DELETE FROM pipeline_agent_questions WHERE tenant_id=${pid}$", + "DELETE FROM pipeline_agent_questions WHERE task_id IN (SELECT id FROM pipeline_tasks WHERE tenant_id=${pid}$)", + ]: + try: + await sor.sqlExe(sql, {"pid": project_id}) + except Exception as e: + logger.warning("clear_project_todos failed: %s err=%s", sql, e) + await sor.sqlExe("COMMIT", {}) + logger.info("clear_project_todos: project=%s done", project_id) + + async def complete_project(project_id, who=None, agent_id=None): """完成项目:active → completed。""" return await _transition(project_id, S_ACTIVE, S_COMPLETED, 'complete', @@ -223,13 +245,18 @@ async def complete_project(project_id, who=None, agent_id=None): async def archive_project(project_id, who=None, agent_id=None): - """归档项目:completed → archived(也兼容 active → archived 强制归档)。""" + """归档项目:completed → archived(也兼容 active → archived 强制归档)。 + 归档成功后清空项目全部待办(2026-09-01)。""" ok, msg = await _transition(project_id, S_COMPLETED, S_ARCHIVED, 'archive', who=who, agent_id=agent_id) + if not ok: + ok, msg = await _transition(project_id, S_ACTIVE, S_ARCHIVED, 'archive', + who=who, agent_id=agent_id) if ok: - return ok, msg - return await _transition(project_id, S_ACTIVE, S_ARCHIVED, 'archive', - who=who, agent_id=agent_id) + db, dbname = _get_db() + async with db.sqlorContext(dbname) as sor: + await _clear_project_todos(sor, project_id) + return ok, msg async def reopen_project(project_id, who=None, agent_id=None): @@ -271,6 +298,8 @@ async def pause_project(project_id, who=None, agent_id=None): from_state=cur, to_state=S_PAUSED, who=_normalize_role(who), agent_id=agent_id, detail=f"prev_state={cur}", sor=sor) + # 停止推进后清空项目全部待办(2026-09-01):项目不再推进,遗留待办无意义且占角标 + await _clear_project_todos(sor, project_id) return True, S_PAUSED @@ -513,6 +542,10 @@ async def delete_project(project_id, who=None, agent_id=None, confirm=False): for sql in indirect: await sor.sqlExe(sql, {"pid": project_id}) + # 2a. 清空项目全部待办(2026-09-01):project_id 直挂 + iteration/task 关联。 + # 必须在 sd_iterations / pipeline_tasks 删除之前(子查询依赖)。 + await _clear_project_todos(sor, project_id) + # 2b. 任务关联表:先取本项目的任务 id,再删 task_id 指向它们的行 # (pipeline_deliverables 等同时有 project_id 和 task_id 两列,仅按 project_id # 删会漏掉「项目删除时 task 已先被删、project_id 已失效」的残留)