fix dashboard: clickable quick entries, full-data ranking tables, dark bg
1. Quick entry shortcuts: Replace VBox (no native click) with Button widgets for reliable click event handling. Each entry wraps its icon+text in a VBox inside the Button for layout. 2. Ranking tables: Changed get_top_users/ providers queries from today-only (WHERE use_date=today) to all-time data so transaction counts and amounts always display meaningful results. 3. Background color: Added bgcolor=#0B1120 to top-level index.ui VBox so the page background matches the shell theme, eliminating the white-vs-dark-blue contrast.
This commit is contained in:
parent
95d18e7ce0
commit
8ceb769356
@ -95,9 +95,8 @@ async def get_accounting_errors(request):
|
||||
|
||||
|
||||
async def get_top_users_by_amount(request):
|
||||
"""获取当天用户金额前5"""
|
||||
"""获取用户金额前5(全量)"""
|
||||
env = request._run_ns
|
||||
today = env.curDateString()
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
@ -106,12 +105,11 @@ async def get_top_users_by_amount(request):
|
||||
COUNT(*) as cnt
|
||||
FROM llmusage a
|
||||
LEFT JOIN users b ON a.userid = b.id
|
||||
WHERE a.use_date = ${today}$
|
||||
GROUP BY a.userid, b.nick_name, b.username
|
||||
ORDER BY total_amount DESC
|
||||
LIMIT 5
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {'today': today})
|
||||
recs = await sor.sqlExe(sql, {})
|
||||
result = []
|
||||
for r in recs:
|
||||
result.append({
|
||||
@ -123,9 +121,8 @@ async def get_top_users_by_amount(request):
|
||||
|
||||
|
||||
async def get_top_users_by_count(request):
|
||||
"""获取当天用户笔数前5"""
|
||||
"""获取用户笔数前5(全量)"""
|
||||
env = request._run_ns
|
||||
today = env.curDateString()
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
@ -134,12 +131,11 @@ async def get_top_users_by_count(request):
|
||||
COALESCE(SUM(a.amount), 0) as total_amount
|
||||
FROM llmusage a
|
||||
LEFT JOIN users b ON a.userid = b.id
|
||||
WHERE a.use_date = ${today}$
|
||||
GROUP BY a.userid, b.nick_name, b.username
|
||||
ORDER BY cnt DESC
|
||||
LIMIT 5
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {'today': today})
|
||||
recs = await sor.sqlExe(sql, {})
|
||||
result = []
|
||||
for r in recs:
|
||||
result.append({
|
||||
@ -151,9 +147,8 @@ async def get_top_users_by_count(request):
|
||||
|
||||
|
||||
async def get_top_providers_by_amount(request):
|
||||
"""获取模型供应商金额前5"""
|
||||
"""获取模型供应商金额前5(全量)"""
|
||||
env = request._run_ns
|
||||
today = env.curDateString()
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
@ -163,12 +158,11 @@ async def get_top_providers_by_amount(request):
|
||||
FROM llmusage a
|
||||
LEFT JOIN llm b ON a.llmid = b.id
|
||||
LEFT JOIN organization c ON b.providerid = c.id
|
||||
WHERE a.use_date = ${today}$
|
||||
GROUP BY b.providerid, c.orgname
|
||||
ORDER BY total_amount DESC
|
||||
LIMIT 5
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {'today': today})
|
||||
recs = await sor.sqlExe(sql, {})
|
||||
result = []
|
||||
for r in recs:
|
||||
result.append({
|
||||
@ -180,9 +174,8 @@ async def get_top_providers_by_amount(request):
|
||||
|
||||
|
||||
async def get_top_providers_by_count(request):
|
||||
"""获取模型供应商笔数前5"""
|
||||
"""获取模型供应商笔数前5(全量)"""
|
||||
env = request._run_ns
|
||||
today = env.curDateString()
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
@ -192,12 +185,11 @@ async def get_top_providers_by_count(request):
|
||||
FROM llmusage a
|
||||
LEFT JOIN llm b ON a.llmid = b.id
|
||||
LEFT JOIN organization c ON b.providerid = c.id
|
||||
WHERE a.use_date = ${today}$
|
||||
GROUP BY b.providerid, c.orgname
|
||||
ORDER BY cnt DESC
|
||||
LIMIT 5
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {'today': today})
|
||||
recs = await sor.sqlExe(sql, {})
|
||||
result = []
|
||||
for r in recs:
|
||||
result.append({
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"name": "dashboard",
|
||||
"label": "仪表盘",
|
||||
"icon": "fa fa-dashboard",
|
||||
"url": "{{entire_url('index.ui')}}",
|
||||
"url": "{{entire_url('/dashboard_for_sage/index.ui')}}",
|
||||
"target": "app.sage_main_content"
|
||||
},
|
||||
{% if get_user() %}
|
||||
|
||||
147
wwwroot/index.ui
147
wwwroot/index.ui
@ -2,7 +2,8 @@
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"height": "100%"
|
||||
"height": "100%",
|
||||
"bgcolor": "#0B1120"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
@ -216,12 +217,12 @@
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"bgcolor": "#334155",
|
||||
"padding": "16px",
|
||||
"borderRadius": "8px",
|
||||
"cursor": "pointer",
|
||||
"border": "none",
|
||||
"textAlign": "center"
|
||||
},
|
||||
"binds": [
|
||||
@ -238,29 +239,37 @@
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"svg": "<svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#90caf9\" stroke-width=\"2\"><path d=\"M9.75 3.104v5.714a2.25 2.25 0 01-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 014.5 0m0 0v5.714c0 .597.237 1.17.659 1.591L19.8 15.3M14.25 3.104c.251.023.501.05.75.082M19.8 15.3l-1.57.393A9.065 9.065 0 0112 15.75c-2.062 0-4.024-.614-5.67-1.757l-1.57-.393m15.04 0L12 21 5.25 13.893\"/></svg>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "模型管理",
|
||||
"color": "#E2E8F0",
|
||||
"fontSize": "13px",
|
||||
"marginTop": "8px"
|
||||
}
|
||||
"alignItems": "center"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#90caf9\" stroke-width=\"2\"><path d=\"M9.75 3.104v5.714a2.25 2.25 0 01-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 014.5 0m0 0v5.714c0 .597.237 1.17.659 1.591L19.8 15.3M14.25 3.104c.251.023.501.05.75.082M19.8 15.3l-1.57.393A9.065 9.065 0 0112 15.75c-2.062 0-4.024-.614-5.67-1.757l-1.57-.393m15.04 0L12 21 5.25 13.893\"/></svg>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "模型管理",
|
||||
"color": "#E2E8F0",
|
||||
"fontSize": "13px",
|
||||
"marginTop": "8px"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"bgcolor": "#334155",
|
||||
"padding": "16px",
|
||||
"borderRadius": "8px",
|
||||
"cursor": "pointer",
|
||||
"border": "none",
|
||||
"textAlign": "center"
|
||||
},
|
||||
"binds": [
|
||||
@ -277,29 +286,37 @@
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"svg": "<svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#4caf50\" stroke-width=\"2\"><path d=\"M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z\"/></svg>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "用户管理",
|
||||
"color": "#E2E8F0",
|
||||
"fontSize": "13px",
|
||||
"marginTop": "8px"
|
||||
}
|
||||
"alignItems": "center"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#4caf50\" stroke-width=\"2\"><path d=\"M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z\"/></svg>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "用户管理",
|
||||
"color": "#E2E8F0",
|
||||
"fontSize": "13px",
|
||||
"marginTop": "8px"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"bgcolor": "#334155",
|
||||
"padding": "16px",
|
||||
"borderRadius": "8px",
|
||||
"cursor": "pointer",
|
||||
"border": "none",
|
||||
"textAlign": "center"
|
||||
},
|
||||
"binds": [
|
||||
@ -316,29 +333,37 @@
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"svg": "<svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#f59e0b\" stroke-width=\"2\"><path d=\"M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125\"/></svg>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "知识库",
|
||||
"color": "#E2E8F0",
|
||||
"fontSize": "13px",
|
||||
"marginTop": "8px"
|
||||
}
|
||||
"alignItems": "center"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#f59e0b\" stroke-width=\"2\"><path d=\"M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125\"/></svg>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "知识库",
|
||||
"color": "#E2E8F0",
|
||||
"fontSize": "13px",
|
||||
"marginTop": "8px"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"bgcolor": "#334155",
|
||||
"padding": "16px",
|
||||
"borderRadius": "8px",
|
||||
"cursor": "pointer",
|
||||
"border": "none",
|
||||
"textAlign": "center"
|
||||
},
|
||||
"binds": [
|
||||
@ -355,19 +380,27 @@
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"svg": "<svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ef4444\" stroke-width=\"2\"><path d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z\"/></svg>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "异常记录",
|
||||
"color": "#E2E8F0",
|
||||
"fontSize": "13px",
|
||||
"marginTop": "8px"
|
||||
}
|
||||
"alignItems": "center"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ef4444\" stroke-width=\"2\"><path d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z\"/></svg>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "异常记录",
|
||||
"color": "#E2E8F0",
|
||||
"fontSize": "13px",
|
||||
"marginTop": "8px"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user