# 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-sdlc/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 }