pipeline-sdlc/wwwroot/api/cockpit_stats.dspy

54 lines
2.1 KiB
Plaintext

# cockpit_stats.dspy - compact stat cards for cockpit (cheight:4)
dbname = get_module_dbname('pipeline-sdlc')
async with DBPools().sqlorContext(dbname) as sor:
proj = await sor.sqlExe("SELECT COUNT(*) as active FROM sd_projects WHERE status='active'", {})
active_projects = proj[0].active if proj else 0
iters = await sor.sqlExe("SELECT COUNT(*) as cnt FROM sd_iterations WHERE status='in_progress'", {})
active_iters = iters[0].cnt if iters else 0
bugs = await sor.sqlExe("SELECT COUNT(*) as cnt FROM sd_bugs WHERE status NOT IN ('closed','resolved')", {})
open_bugs = bugs[0].cnt if bugs else 0
reviews = await sor.sqlExe("SELECT COUNT(*) as cnt FROM pipeline_human_tasks WHERE status='pending'", {})
pending_reviews = reviews[0].cnt if reviews else 0
def card(n, label, color, url):
return {
"widgettype": "HBox",
"options": {
"css": "card", "cwidth": 23, "cheight": 4,
"padding": "8px 14px", "bgcolor": "#fff",
"borderRadius": "8px", "border": "1px solid #e2e8f0",
"alignItems": "center", "gap": "10px", "cursor": "pointer"
},
"binds": [{
"wid": "self", "event": "click",
"actiontype": "urlwidget",
"target": "app.main_content",
"options": {"url": entire_url(url)},
"mode": "replace"
}],
"subwidgets": [
{"widgettype": "Text", "options": {
"text": str(n), "cfontsize": 1.5,
"color": color, "fontWeight": "bold"
}},
{"widgettype": "Text", "options": {
"text": label, "cfontsize": 0.85, "color": "#64748b"
}}
]
}
return {
"widgettype": "ResponsableBox",
"options": {"gap": "12px", "minWidth": "160px", "width": "100%"},
"subwidgets": [
card(active_projects, "活跃项目", "#3b82f6", "/pipeline-sdlc/sd_projects/"),
card(active_iters, "进行中迭代", "#22c55e", "/pipeline-sdlc/sd_iterations/"),
card(open_bugs, "待处理Bug", "#f59e0b", "/pipeline-sdlc/sd_bugs/"),
card(pending_reviews, "待审批", "#8b5cf6", ""),
]
}