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):
|
async def get_top_users_by_amount(request):
|
||||||
"""获取当天用户金额前5"""
|
"""获取用户金额前5(全量)"""
|
||||||
env = request._run_ns
|
env = request._run_ns
|
||||||
today = env.curDateString()
|
|
||||||
async with get_sor_context(env, 'sage') as sor:
|
async with get_sor_context(env, 'sage') as sor:
|
||||||
sql = """
|
sql = """
|
||||||
SELECT
|
SELECT
|
||||||
@ -106,12 +105,11 @@ async def get_top_users_by_amount(request):
|
|||||||
COUNT(*) as cnt
|
COUNT(*) as cnt
|
||||||
FROM llmusage a
|
FROM llmusage a
|
||||||
LEFT JOIN users b ON a.userid = b.id
|
LEFT JOIN users b ON a.userid = b.id
|
||||||
WHERE a.use_date = ${today}$
|
|
||||||
GROUP BY a.userid, b.nick_name, b.username
|
GROUP BY a.userid, b.nick_name, b.username
|
||||||
ORDER BY total_amount DESC
|
ORDER BY total_amount DESC
|
||||||
LIMIT 5
|
LIMIT 5
|
||||||
"""
|
"""
|
||||||
recs = await sor.sqlExe(sql, {'today': today})
|
recs = await sor.sqlExe(sql, {})
|
||||||
result = []
|
result = []
|
||||||
for r in recs:
|
for r in recs:
|
||||||
result.append({
|
result.append({
|
||||||
@ -123,9 +121,8 @@ async def get_top_users_by_amount(request):
|
|||||||
|
|
||||||
|
|
||||||
async def get_top_users_by_count(request):
|
async def get_top_users_by_count(request):
|
||||||
"""获取当天用户笔数前5"""
|
"""获取用户笔数前5(全量)"""
|
||||||
env = request._run_ns
|
env = request._run_ns
|
||||||
today = env.curDateString()
|
|
||||||
async with get_sor_context(env, 'sage') as sor:
|
async with get_sor_context(env, 'sage') as sor:
|
||||||
sql = """
|
sql = """
|
||||||
SELECT
|
SELECT
|
||||||
@ -134,12 +131,11 @@ async def get_top_users_by_count(request):
|
|||||||
COALESCE(SUM(a.amount), 0) as total_amount
|
COALESCE(SUM(a.amount), 0) as total_amount
|
||||||
FROM llmusage a
|
FROM llmusage a
|
||||||
LEFT JOIN users b ON a.userid = b.id
|
LEFT JOIN users b ON a.userid = b.id
|
||||||
WHERE a.use_date = ${today}$
|
|
||||||
GROUP BY a.userid, b.nick_name, b.username
|
GROUP BY a.userid, b.nick_name, b.username
|
||||||
ORDER BY cnt DESC
|
ORDER BY cnt DESC
|
||||||
LIMIT 5
|
LIMIT 5
|
||||||
"""
|
"""
|
||||||
recs = await sor.sqlExe(sql, {'today': today})
|
recs = await sor.sqlExe(sql, {})
|
||||||
result = []
|
result = []
|
||||||
for r in recs:
|
for r in recs:
|
||||||
result.append({
|
result.append({
|
||||||
@ -151,9 +147,8 @@ async def get_top_users_by_count(request):
|
|||||||
|
|
||||||
|
|
||||||
async def get_top_providers_by_amount(request):
|
async def get_top_providers_by_amount(request):
|
||||||
"""获取模型供应商金额前5"""
|
"""获取模型供应商金额前5(全量)"""
|
||||||
env = request._run_ns
|
env = request._run_ns
|
||||||
today = env.curDateString()
|
|
||||||
async with get_sor_context(env, 'sage') as sor:
|
async with get_sor_context(env, 'sage') as sor:
|
||||||
sql = """
|
sql = """
|
||||||
SELECT
|
SELECT
|
||||||
@ -163,12 +158,11 @@ async def get_top_providers_by_amount(request):
|
|||||||
FROM llmusage a
|
FROM llmusage a
|
||||||
LEFT JOIN llm b ON a.llmid = b.id
|
LEFT JOIN llm b ON a.llmid = b.id
|
||||||
LEFT JOIN organization c ON b.providerid = c.id
|
LEFT JOIN organization c ON b.providerid = c.id
|
||||||
WHERE a.use_date = ${today}$
|
|
||||||
GROUP BY b.providerid, c.orgname
|
GROUP BY b.providerid, c.orgname
|
||||||
ORDER BY total_amount DESC
|
ORDER BY total_amount DESC
|
||||||
LIMIT 5
|
LIMIT 5
|
||||||
"""
|
"""
|
||||||
recs = await sor.sqlExe(sql, {'today': today})
|
recs = await sor.sqlExe(sql, {})
|
||||||
result = []
|
result = []
|
||||||
for r in recs:
|
for r in recs:
|
||||||
result.append({
|
result.append({
|
||||||
@ -180,9 +174,8 @@ async def get_top_providers_by_amount(request):
|
|||||||
|
|
||||||
|
|
||||||
async def get_top_providers_by_count(request):
|
async def get_top_providers_by_count(request):
|
||||||
"""获取模型供应商笔数前5"""
|
"""获取模型供应商笔数前5(全量)"""
|
||||||
env = request._run_ns
|
env = request._run_ns
|
||||||
today = env.curDateString()
|
|
||||||
async with get_sor_context(env, 'sage') as sor:
|
async with get_sor_context(env, 'sage') as sor:
|
||||||
sql = """
|
sql = """
|
||||||
SELECT
|
SELECT
|
||||||
@ -192,12 +185,11 @@ async def get_top_providers_by_count(request):
|
|||||||
FROM llmusage a
|
FROM llmusage a
|
||||||
LEFT JOIN llm b ON a.llmid = b.id
|
LEFT JOIN llm b ON a.llmid = b.id
|
||||||
LEFT JOIN organization c ON b.providerid = c.id
|
LEFT JOIN organization c ON b.providerid = c.id
|
||||||
WHERE a.use_date = ${today}$
|
|
||||||
GROUP BY b.providerid, c.orgname
|
GROUP BY b.providerid, c.orgname
|
||||||
ORDER BY cnt DESC
|
ORDER BY cnt DESC
|
||||||
LIMIT 5
|
LIMIT 5
|
||||||
"""
|
"""
|
||||||
recs = await sor.sqlExe(sql, {'today': today})
|
recs = await sor.sqlExe(sql, {})
|
||||||
result = []
|
result = []
|
||||||
for r in recs:
|
for r in recs:
|
||||||
result.append({
|
result.append({
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
"name": "dashboard",
|
"name": "dashboard",
|
||||||
"label": "仪表盘",
|
"label": "仪表盘",
|
||||||
"icon": "fa fa-dashboard",
|
"icon": "fa fa-dashboard",
|
||||||
"url": "{{entire_url('index.ui')}}",
|
"url": "{{entire_url('/dashboard_for_sage/index.ui')}}",
|
||||||
"target": "app.sage_main_content"
|
"target": "app.sage_main_content"
|
||||||
},
|
},
|
||||||
{% if get_user() %}
|
{% if get_user() %}
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
"widgettype": "VBox",
|
"widgettype": "VBox",
|
||||||
"options": {
|
"options": {
|
||||||
"width": "100%",
|
"width": "100%",
|
||||||
"height": "100%"
|
"height": "100%",
|
||||||
|
"bgcolor": "#0B1120"
|
||||||
},
|
},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{
|
{
|
||||||
@ -216,12 +217,12 @@
|
|||||||
},
|
},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{
|
{
|
||||||
"widgettype": "VBox",
|
"widgettype": "Button",
|
||||||
"options": {
|
"options": {
|
||||||
"bgcolor": "#334155",
|
"bgcolor": "#334155",
|
||||||
"padding": "16px",
|
"padding": "16px",
|
||||||
"borderRadius": "8px",
|
"borderRadius": "8px",
|
||||||
"cursor": "pointer",
|
"border": "none",
|
||||||
"textAlign": "center"
|
"textAlign": "center"
|
||||||
},
|
},
|
||||||
"binds": [
|
"binds": [
|
||||||
@ -236,6 +237,12 @@
|
|||||||
"mode": "replace"
|
"mode": "replace"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{
|
{
|
||||||
"widgettype": "Svg",
|
"widgettype": "Svg",
|
||||||
@ -253,14 +260,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"widgettype": "VBox",
|
"widgettype": "Button",
|
||||||
"options": {
|
"options": {
|
||||||
"bgcolor": "#334155",
|
"bgcolor": "#334155",
|
||||||
"padding": "16px",
|
"padding": "16px",
|
||||||
"borderRadius": "8px",
|
"borderRadius": "8px",
|
||||||
"cursor": "pointer",
|
"border": "none",
|
||||||
"textAlign": "center"
|
"textAlign": "center"
|
||||||
},
|
},
|
||||||
"binds": [
|
"binds": [
|
||||||
@ -275,6 +284,12 @@
|
|||||||
"mode": "replace"
|
"mode": "replace"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{
|
{
|
||||||
"widgettype": "Svg",
|
"widgettype": "Svg",
|
||||||
@ -292,14 +307,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"widgettype": "VBox",
|
"widgettype": "Button",
|
||||||
"options": {
|
"options": {
|
||||||
"bgcolor": "#334155",
|
"bgcolor": "#334155",
|
||||||
"padding": "16px",
|
"padding": "16px",
|
||||||
"borderRadius": "8px",
|
"borderRadius": "8px",
|
||||||
"cursor": "pointer",
|
"border": "none",
|
||||||
"textAlign": "center"
|
"textAlign": "center"
|
||||||
},
|
},
|
||||||
"binds": [
|
"binds": [
|
||||||
@ -314,6 +331,12 @@
|
|||||||
"mode": "replace"
|
"mode": "replace"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{
|
{
|
||||||
"widgettype": "Svg",
|
"widgettype": "Svg",
|
||||||
@ -331,14 +354,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"widgettype": "VBox",
|
"widgettype": "Button",
|
||||||
"options": {
|
"options": {
|
||||||
"bgcolor": "#334155",
|
"bgcolor": "#334155",
|
||||||
"padding": "16px",
|
"padding": "16px",
|
||||||
"borderRadius": "8px",
|
"borderRadius": "8px",
|
||||||
"cursor": "pointer",
|
"border": "none",
|
||||||
"textAlign": "center"
|
"textAlign": "center"
|
||||||
},
|
},
|
||||||
"binds": [
|
"binds": [
|
||||||
@ -353,6 +378,12 @@
|
|||||||
"mode": "replace"
|
"mode": "replace"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "VBox",
|
||||||
|
"options": {
|
||||||
|
"alignItems": "center"
|
||||||
|
},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{
|
{
|
||||||
"widgettype": "Svg",
|
"widgettype": "Svg",
|
||||||
@ -376,6 +407,8 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"widgettype": "VBox",
|
"widgettype": "VBox",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user