diff --git a/pipeline_service/human_task_capability.py b/pipeline_service/human_task_capability.py index 22d957f..8e66f44 100644 --- a/pipeline_service/human_task_capability.py +++ b/pipeline_service/human_task_capability.py @@ -32,6 +32,20 @@ T_BUG_ACCEPT = "bug_acceptance" T_REQ_CONFIRM = "requirement_confirmation" T_DESIGN_CONFIRM = "design_confirmation" +# ══════════════ 待办提供者注册表(2026-09-10 工单模块接入) ══════════════ +# 平台待办是平台级机制:各部分(产线任务/冒泡问题/工单/…)产生待办, +# 本模块聚合。外部模块通过 register_todo_provider 注入,不跨模块读表。 +# provider 签名: async fn(user_id, roles, limit) -> [todo dict] +# todo dict 须含 source(弹窗按它分流详情端点)+ title/description/created_at。 +_TODO_PROVIDERS = [] + + +def register_todo_provider(fn): + """注册待办提供者(幂等:同函数不重复注册)。""" + if callable(fn) and fn not in _TODO_PROVIDERS: + _TODO_PROVIDERS.append(fn) + logger.info("todo provider registered: %s", getattr(fn, '__module__', '?')) + def _get_db(): db = DBPools() @@ -401,7 +415,20 @@ async def count_my_human_tasks(user_id, project_id=None): n_q = getattr(q[0], 'c', 0) if q else 0 n_ht = getattr(ht[0], 'c', 0) if ht else 0 - return int(n_q) + int(n_ht) + _roles_cache = roles + total = int(n_q) + int(n_ht) + + # 外部待办提供者(工单等,2026-09-10):仅全局角标(project_id 空)计入—— + # 工单不属于任何产线项目,项目内角标不混入。坏 provider 不拖垮计数。 + if not project_id: + for fn in list(_TODO_PROVIDERS): + try: + extra = await fn(user_id, _roles_cache, 100) + total += len(extra or []) + except Exception as e: + logger.warning("todo provider count %s failed: %s", + getattr(fn, '__module__', '?'), str(e)[:160]) + return total async def list_my_human_todos(user_id, limit=100): @@ -442,8 +469,21 @@ async def list_my_human_todos(user_id, limit=100): d = _rec_to_dict(r) d['source'] = 'question' todos.append(d) - todos.sort(key=lambda x: str(x.get('created_at') or ''), reverse=True) - return todos[:limit] + _roles_cache = roles + + # 外部待办提供者(工单等,2026-09-10):在 db context 外调用,provider 自开连接。 + # 逐个 try/except——坏 provider 不拖垮整个待办列表(平台级机制必须健壮)。 + for fn in list(_TODO_PROVIDERS): + try: + extra = await fn(user_id, _roles_cache, limit) + for d in (extra or []): + todos.append(d) + except Exception as e: + logger.warning("todo provider %s failed: %s", + getattr(fn, '__module__', '?'), str(e)[:160]) + + todos.sort(key=lambda x: str(x.get('created_at') or ''), reverse=True) + return todos[:limit] async def bug_accept(bug_id, accept, user_id, comment=None):