feat(human_task): 待办提供者注册表register_todo_provider——平台待办开放给外部模块注入(工单模块首用)

- _TODO_PROVIDERS注册表: provider签名async fn(user_id, roles, limit)->[todo dict], dict须含source
- list_my_human_todos: db context外遍历providers union(逐个try/except,坏provider不拖垮列表)
- count_my_human_tasks: 仅全局角标(project_id空)计入providers——工单不属于产线项目
- 架构: 待办是平台级机制,各部分(产线任务/冒泡问题/工单)产生待办,本模块聚合;
  外部模块注册钩子注入,不跨模块读表(sage-module-scaffolding 7.3)
This commit is contained in:
ymq 2026-09-10 16:14:20 +08:00
parent b8a2aeadb7
commit 736a2dd579

View File

@ -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):