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
32 lines
991 B
Plaintext
32 lines
991 B
Plaintext
"""获取当前用户总数和并发用户数(近5分钟有活跃记录的用户)"""
|
||
# datetime, json, DBPools 由 ahserver 预加载,无需 import
|
||
|
||
now = datetime.datetime.now()
|
||
five_min_ago = (now - datetime.timedelta(minutes=5)).strftime('%Y-%m-%d %H:%M:%S')
|
||
today = now.strftime('%Y-%m-%d')
|
||
|
||
sql_users = "SELECT COUNT(*) as total_users FROM users"
|
||
|
||
sql_concurrent = """
|
||
SELECT COUNT(DISTINCT userid) as concurrent_users
|
||
FROM llmusage
|
||
WHERE use_date = ${today}$
|
||
AND use_time >= ${five_min_ago}$
|
||
"""
|
||
|
||
db = DBPools()
|
||
async with db.sqlorContext('sage') as sor:
|
||
user_recs = await sor.sqlExe(sql_users, {})
|
||
total_users = int(user_recs[0].get('total_users', 0)) if user_recs else 0
|
||
|
||
conc_recs = await sor.sqlExe(sql_concurrent, {
|
||
'today': today,
|
||
'five_min_ago': five_min_ago
|
||
})
|
||
concurrent_users = int(conc_recs[0].get('concurrent_users', 0)) if conc_recs else 0
|
||
|
||
return {
|
||
'total_users': total_users,
|
||
'concurrent_users': concurrent_users
|
||
}
|