pipeline-sdlc/wwwroot/api/cockpit_cards.dspy
ymq 0a339a2b19 refactor(ownership): 三张跨产线表定义删除不留副本(第2轮迁归属,已迁入pipeline-core@4b2fd4c)
- models: sd_projects/sd_project_role_models/pipeline_deliverables 3个JSON删除——归属core,双源必乱
- json: sd_project_list/pipeline_deliverables_list CRUD定义删除(迁core)
- wwwroot/api: 15个CRUD页面依赖的dspy删除(随页面迁core,entire_url相对解析跟页面走)
- wwwroot/sd_project_role_models: 手写角色模型页整目录删除(迁core)
- scripts/load_path.py: 已迁页面的RBAC注册条目删除(sd_projects 5条/sd_project_list 1条/role_models 5条/api 4条)
- json/sd_iteration_list+sd_deploy_env_list+sd_features_list: get_project_options.dspy引用改绝对路径/pipeline_core/api/**(留在sdlc的页面消费迁走的api)
- wwwroot/api/cockpit_cards.dspy: 项目管理弹窗URL改/pipeline_core/sd_projects/index.ui
- init/data.json: 4组字典随表迁core(sd_project_status/sd_project_type/deliverable_type/review_status)
- .gitignore: 已迁生成目录条目清理(sd_projects//pipeline_deliverables/)
- 顺带清死双源: wwwroot/json/整目录(build.sh只读模块根json/,wwwroot/json零消费方+内容漂移:subtables还指着改名前的目录)+wwwroot/sd_project_list/index.ui死占位页(零菜单引用)
2026-09-10 12:33:42 +08:00

61 lines
2.9 KiB
Plaintext

# cockpit_cards.dspy — Returns 4 dynamic dashboard cards with popups
uid = await get_user()
org_id = await get_userorgid() or '0'
async with DBPools().sqlorContext(get_module_dbname('pipeline-sdlc')) as sor:
# Counts
projs = await sor.sqlExe("SELECT COUNT(*) as cnt FROM sd_projects WHERE status='active' AND org_id=${oid}$", {"oid": org_id})
iters = await sor.sqlExe("SELECT COUNT(*) as cnt FROM sd_iterations WHERE status='active'", {})
bugs = await sor.sqlExe("SELECT COUNT(*) as cnt FROM sd_bugs WHERE status IN ('open','confirmed')", {})
approvs = await sor.sqlExe("SELECT COUNT(*) as cnt FROM pipeline_task_steps WHERE state='waiting' AND step_type IN ('human_task','approval_gate')", {})
pc = projs[0].cnt if projs else 0
ic = iters[0].cnt if iters else 0
bc = bugs[0].cnt if bugs else 0
ac = approvs[0].cnt if approvs else 0
cards = [
{"title": "活跃项目", "count": pc, "color": "#3b82f6", "icon": "📁",
"popup_url": "/pipeline_core/sd_projects/index.ui", "popup_title": "项目管理"},
{"title": "进行中迭代", "count": ic, "color": "#10b981", "icon": "🔄",
"popup_url": "/pipeline-sdlc/sd_iterations/index.ui", "popup_title": "迭代管理"},
{"title": "待处理Bug", "count": bc, "color": "#ef4444", "icon": "🐛",
"popup_url": "/pipeline-sdlc/sd_bugs/index.ui", "popup_title": "Bug管理"},
{"title": "待审批", "count": ac, "color": "#f59e0b", "icon": "✅",
"popup_url": "/pipeline-sdlc/sd_iterations/index.ui", "popup_title": "待审批任务"},
]
card_widgets = []
for c in cards:
url = c["popup_url"]
title = c["popup_title"]
card_widgets.append({
"widgettype": "VBox",
"options": {
"css": "card",
"width": "25%",
"bgcolor": c["color"] + "08",
"border": f"1px solid {c['color']}33",
"borderRadius": "10px",
"padding": "14px 16px",
"alignItems": "center",
"gap": "6px",
"hover_border": f"1px solid {c['color']}99",
},
"binds": [{
"wid": "self", "event": "click", "actiontype": "script", "target": "self",
"script": f"var pw=new bricks.PopupWindow({{title:'{title}',cwidth:44,cheight:32,auto_open:true}});bricks.widgetBuild({{widgettype:'urlwidget',options:{{url:'{url}',method:'GET'}}}},pw.content_w).then(function(w){{if(w)pw.content_w.add_widget(w);}});"
}],
"subwidgets": [
{"widgettype": "Text", "options": {"text": c["icon"], "cfontsize": 1.8}},
{"widgettype": "Text", "options": {"text": str(c["count"]), "cfontsize": 1.6, "color": c["color"], "fontWeight": "bold"}},
{"widgettype": "Text", "options": {"text": c["title"], "cfontsize": 0.8, "color": "#475569"}},
]
})
return {
"widgettype": "HBox",
"options": {"width": "100%", "gap": "12px"},
"subwidgets": card_widgets
}