yumoqing d2210a2996 refactor: use RefreshWidget for stat cards + fix .dspy import violations
Architecture:
- index.ui: title + RefreshWidget(cards) + ChartBar with refresh_period
- RefreshWidget wraps dashboard_cards.dspy → returns full card widget tree
  with live data (cnt, amount, total_users, concurrent_users)
- ChartBar handles its own auto-refresh via refresh_period: 10
- No more JS polling file needed

.dspy import fixes:
- get_today_usage.dspy: remove import json, from datetime import date
- get_user_stats.dspy: remove from datetime import datetime, timedelta
- get_top_models.dspy: remove from datetime import date
- All use pre-loaded datetime module (datetime.date.today(), etc.)
- dashboard_cards.dspy: same pattern, no imports

Permission:
- load_path.py: add dashboard_cards.dspy logined
2026-05-24 16:45:45 +08:00

66 lines
2.0 KiB
XML

{
"widgettype": "VBox",
"options": {
"width": "100%",
"height": "100%",
"padding": "20px",
"bgcolor": "#f0f2f5"
},
"subwidgets": [
{
"widgettype": "Text",
"options": {
"text": "Dashboard",
"fontSize": "24px",
"fontWeight": "bold",
"color": "#333",
"marginBottom": "20px"
}
},
{
"widgettype": "RefreshWidget",
"id": "cards_refresh",
"options": {
"period_seconds": 10,
"url": "{{entire_url('api/dashboard_cards.dspy')}}"
}
},
{
"widgettype": "VBox",
"id": "chart_section",
"options": {
"bgcolor": "#FFFFFF",
"padding": "24px",
"borderRadius": "8px",
"marginTop": "20px",
"minHeight": "350px",
"boxShadow": "0 2px 8px rgba(0,0,0,0.1)"
},
"subwidgets": [
{
"widgettype": "Text",
"options": {
"text": "Top 3 模型(今日)",
"fontSize": "18px",
"fontWeight": "bold",
"color": "#333",
"marginBottom": "16px"
}
},
{
"widgettype": "ChartBar",
"id": "top_models_chart",
"options": {
"height": "300px",
"width": "100%",
"data_url": "{{entire_url('api/get_top_models.dspy')}}",
"nameField": "model_name",
"valueFields": ["cnt", "total_amount"],
"refresh_period": 10
}
}
]
}
]
}