feat: add user statistics cards to dashboard
- Add get_active_users_today(), get_new_users_month(), get_total_orgs() to load_dashboard.py - Create stat_active_users.ui, stat_new_users_month.ui, stat_total_orgs.ui widgets - Add active users card to main stats row - Add new row with new users this month and total organizations cards
This commit is contained in:
parent
ffdc7fc983
commit
be1ac95ac7
@ -208,6 +208,44 @@ async def get_top_providers_by_count(request):
|
||||
return result
|
||||
|
||||
|
||||
async def get_active_users_today(request):
|
||||
"""获取今日活跃用户数(今日有llmusage记录的去重用户)"""
|
||||
env = request._run_ns
|
||||
today = env.curDateString()
|
||||
tomorrow = (datetime.now() + timedelta(days=1)).strftime('%Y-%m-%d')
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT COUNT(DISTINCT userid) as cnt FROM llmusage
|
||||
WHERE use_date >= ${today}$ AND use_date < ${tomorrow}$
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {'today': today, 'tomorrow': tomorrow})
|
||||
cnt = int(recs[0].get('cnt', 0)) if recs else 0
|
||||
return cnt
|
||||
|
||||
|
||||
async def get_new_users_month(request):
|
||||
"""获取本月新增用户数"""
|
||||
env = request._run_ns
|
||||
month_start = datetime.now().strftime('%Y-%m-01')
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT COUNT(*) as cnt FROM users WHERE created_date >= ${month_start}$
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {'month_start': month_start})
|
||||
cnt = int(recs[0].get('cnt', 0)) if recs else 0
|
||||
return cnt
|
||||
|
||||
|
||||
async def get_total_orgs(request):
|
||||
"""获取组织机构总数"""
|
||||
env = request._run_ns
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = "SELECT COUNT(*) as cnt FROM organization"
|
||||
recs = await sor.sqlExe(sql, {})
|
||||
cnt = int(recs[0].get('cnt', 0)) if recs else 0
|
||||
return cnt
|
||||
|
||||
|
||||
def load_dashboard():
|
||||
"""Register dashboard functions on ServerEnv"""
|
||||
g = ServerEnv()
|
||||
@ -221,3 +259,6 @@ def load_dashboard():
|
||||
g.get_top_users_by_count = get_top_users_by_count
|
||||
g.get_top_providers_by_amount = get_top_providers_by_amount
|
||||
g.get_top_providers_by_count = get_top_providers_by_count
|
||||
g.get_active_users_today = get_active_users_today
|
||||
g.get_new_users_month = get_new_users_month
|
||||
g.get_total_orgs = get_total_orgs
|
||||
|
||||
@ -66,6 +66,14 @@
|
||||
"url": "{{entire_url('stat_total_users.ui')}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "RefreshWidget",
|
||||
"id": "stat_active_users",
|
||||
"options": {
|
||||
"period_seconds": 60,
|
||||
"url": "{{entire_url('stat_active_users.ui')}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "RefreshWidget",
|
||||
"id": "stat_concurrent",
|
||||
@ -84,6 +92,32 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "ResponsableBox",
|
||||
"options": {
|
||||
"gap": "16px",
|
||||
"minWidth": "220px",
|
||||
"marginBottom": "24px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "RefreshWidget",
|
||||
"id": "stat_new_users_month",
|
||||
"options": {
|
||||
"period_seconds": 120,
|
||||
"url": "{{entire_url('stat_new_users_month.ui')}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "RefreshWidget",
|
||||
"id": "stat_total_orgs",
|
||||
"options": {
|
||||
"period_seconds": 120,
|
||||
"url": "{{entire_url('stat_total_orgs.ui')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
|
||||
52
wwwroot/stat_active_users.ui
Normal file
52
wwwroot/stat_active_users.ui
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"bgcolor": "#1E293B",
|
||||
"padding": "20px",
|
||||
"borderRadius": "12px",
|
||||
"border": "1px solid #334155",
|
||||
"flex": "1",
|
||||
"minHeight": "110px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"alignItems": "center",
|
||||
"marginBottom": "12px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#22C55E\" stroke-width=\"2\"><path d=\"M15.91 11.672a.375.375 0 010 .656l-5.603 3.113a.375.375 0 01-.557-.328V8.887c0-.286.307-.466.557-.327l5.603 3.112z\"/><path d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"/></svg>",
|
||||
"width": "24px",
|
||||
"height": "24px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "{{get_active_users_today(request)}}",
|
||||
"fontSize": "32px",
|
||||
"fontWeight": "700",
|
||||
"color": "#F1F5F9",
|
||||
"lineHeight": "1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "今日活跃用户",
|
||||
"fontSize": "14px",
|
||||
"color": "#94A3B8",
|
||||
"marginTop": "4px"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
52
wwwroot/stat_new_users_month.ui
Normal file
52
wwwroot/stat_new_users_month.ui
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"bgcolor": "#1E293B",
|
||||
"padding": "20px",
|
||||
"borderRadius": "12px",
|
||||
"border": "1px solid #334155",
|
||||
"flex": "1",
|
||||
"minHeight": "110px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"alignItems": "center",
|
||||
"marginBottom": "12px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#10B981\" stroke-width=\"2\"><path d=\"M19 7.5v3m0 0v3m0 0v3m0 0v3m0 0h-3m0 0h-3m0 0h-3m0 0h-3m0 0v-3m0 0V12m0 0V7.5M5 21h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v14a2 2 0 002 2z\"/></svg>",
|
||||
"width": "24px",
|
||||
"height": "24px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "{{get_new_users_month(request)}}",
|
||||
"fontSize": "32px",
|
||||
"fontWeight": "700",
|
||||
"color": "#F1F5F9",
|
||||
"lineHeight": "1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "本月新增用户",
|
||||
"fontSize": "14px",
|
||||
"color": "#94A3B8",
|
||||
"marginTop": "4px"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
52
wwwroot/stat_total_orgs.ui
Normal file
52
wwwroot/stat_total_orgs.ui
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"bgcolor": "#1E293B",
|
||||
"padding": "20px",
|
||||
"borderRadius": "12px",
|
||||
"border": "1px solid #334155",
|
||||
"flex": "1",
|
||||
"minHeight": "110px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"alignItems": "center",
|
||||
"marginBottom": "12px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#8B5CF6\" stroke-width=\"2\"><path d=\"M3.75 21h16.5M4.5 3h15M5.25 3v18m13.5-18v18M9 6.75h1.5m-1.5 3h1.5m-1.5 3h1.5m3-6H15m-1.5 3H15m-1.5 3H15M9 21v-3.375c0-.621.504-1.125 1.125-1.125h3.75c.621 0 1.125.504 1.125 1.125V21\"/></svg>",
|
||||
"width": "24px",
|
||||
"height": "24px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "{{get_total_orgs(request)}}",
|
||||
"fontSize": "32px",
|
||||
"fontWeight": "700",
|
||||
"color": "#F1F5F9",
|
||||
"lineHeight": "1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "组织机构数",
|
||||
"fontSize": "14px",
|
||||
"color": "#94A3B8",
|
||||
"marginTop": "4px"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user