feat: 6个监控组件改用RefreshWidget+Jinja2服务端渲染,初始即加载+60s刷新
This commit is contained in:
parent
482c0fac8b
commit
7db361425b
@ -398,6 +398,62 @@ async def j2_avg_ttft(request):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ── 监控组件 j2 函数,每段独立 .ui 通过 RefreshWidget 加载 ──
|
||||||
|
|
||||||
|
async def j2_model_perf_data(request):
|
||||||
|
try:
|
||||||
|
env = request._run_ns
|
||||||
|
async with get_sor_context(env, MODULE_NAME) as sor:
|
||||||
|
return await api_model_perf(sor)
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
async def j2_currency_data(request):
|
||||||
|
try:
|
||||||
|
env = request._run_ns
|
||||||
|
async with get_sor_context(env, MODULE_NAME) as sor:
|
||||||
|
return await get_currency_breakdown(env, sor)
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
async def j2_provider_roi_data(request):
|
||||||
|
try:
|
||||||
|
env = request._run_ns
|
||||||
|
async with get_sor_context(env, MODULE_NAME) as sor:
|
||||||
|
return await api_provider_roi(sor)
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
async def j2_top_models_data(request):
|
||||||
|
try:
|
||||||
|
env = request._run_ns
|
||||||
|
async with get_sor_context(env, MODULE_NAME) as sor:
|
||||||
|
return await get_top_models(env, sor)
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
async def j2_top_users_data(request):
|
||||||
|
try:
|
||||||
|
env = request._run_ns
|
||||||
|
async with get_sor_context(env, MODULE_NAME) as sor:
|
||||||
|
return await get_top_users(env, sor)
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
async def j2_top_providers_data(request):
|
||||||
|
try:
|
||||||
|
env = request._run_ns
|
||||||
|
async with get_sor_context(env, MODULE_NAME) as sor:
|
||||||
|
return await get_top_providers(env, sor)
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
# ── Cron ETL ──
|
# ── Cron ETL ──
|
||||||
|
|
||||||
async def cron_etl_sync(request):
|
async def cron_etl_sync(request):
|
||||||
@ -457,6 +513,12 @@ def load_sage_datamart():
|
|||||||
env.j2_online_users = j2_online_users
|
env.j2_online_users = j2_online_users
|
||||||
env.j2_scoped_success_rate = j2_scoped_success_rate
|
env.j2_scoped_success_rate = j2_scoped_success_rate
|
||||||
env.j2_scoped_fail_count = j2_scoped_fail_count
|
env.j2_scoped_fail_count = j2_scoped_fail_count
|
||||||
|
env.j2_model_perf_data = j2_model_perf_data
|
||||||
|
env.j2_currency_data = j2_currency_data
|
||||||
|
env.j2_provider_roi_data = j2_provider_roi_data
|
||||||
|
env.j2_top_models_data = j2_top_models_data
|
||||||
|
env.j2_top_users_data = j2_top_users_data
|
||||||
|
env.j2_top_providers_data = j2_top_providers_data
|
||||||
env.cron_etl_sync = cron_etl_sync
|
env.cron_etl_sync = cron_etl_sync
|
||||||
env.cron_etl_aggregate = cron_etl_aggregate
|
env.cron_etl_aggregate = cron_etl_aggregate
|
||||||
env.cron_etl_provider_cost = cron_etl_provider_cost
|
env.cron_etl_provider_cost = cron_etl_provider_cost
|
||||||
|
|||||||
@ -35,6 +35,12 @@ PATHS_LOGINED = [
|
|||||||
f"/{MOD}/rt_card_online.ui",
|
f"/{MOD}/rt_card_online.ui",
|
||||||
f"/{MOD}/rt_card_success.ui",
|
f"/{MOD}/rt_card_success.ui",
|
||||||
f"/{MOD}/rt_card_fail.ui",
|
f"/{MOD}/rt_card_fail.ui",
|
||||||
|
f"/{MOD}/sect_model_perf.ui",
|
||||||
|
f"/{MOD}/sect_currency.ui",
|
||||||
|
f"/{MOD}/sect_provider_roi.ui",
|
||||||
|
f"/{MOD}/sect_top_models.ui",
|
||||||
|
f"/{MOD}/sect_top_users.ui",
|
||||||
|
f"/{MOD}/sect_top_providers.ui",
|
||||||
]
|
]
|
||||||
|
|
||||||
def run(role, path):
|
def run(role, path):
|
||||||
|
|||||||
121
wwwroot/index.ui
121
wwwroot/index.ui
@ -20,13 +20,13 @@
|
|||||||
"widgettype": "HBox",
|
"widgettype": "HBox",
|
||||||
"options": {"width": "100%", "gap": "12px", "marginBottom": "16px", "flexWrap": "wrap"},
|
"options": {"width": "100%", "gap": "12px", "marginBottom": "16px", "flexWrap": "wrap"},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{"widgettype": "RefreshWidget", "id": "rt_calls", "options": {"period_seconds": 15, "url": "{{entire_url('rt_card_calls.ui')}}", "width": "13%"}},
|
{"widgettype": "RefreshWidget", "id": "rt_calls", "options": {"period_seconds": 15, "url": "{{entire_url('rt_card_calls.ui')}}", "width": "13%"}},
|
||||||
{"widgettype": "RefreshWidget", "id": "rt_amount", "options": {"period_seconds": 15, "url": "{{entire_url('rt_card_amount.ui')}}", "width": "13%"}},
|
{"widgettype": "RefreshWidget", "id": "rt_amount", "options": {"period_seconds": 15, "url": "{{entire_url('rt_card_amount.ui')}}", "width": "13%"}},
|
||||||
{"widgettype": "RefreshWidget", "id": "rt_users", "options": {"period_seconds": 30, "url": "{{entire_url('rt_card_users.ui')}}", "width": "13%"}},
|
{"widgettype": "RefreshWidget", "id": "rt_users", "options": {"period_seconds": 30, "url": "{{entire_url('rt_card_users.ui')}}", "width": "13%"}},
|
||||||
{"widgettype": "RefreshWidget", "id": "rt_active", "options": {"period_seconds": 30, "url": "{{entire_url('rt_card_active.ui')}}", "width": "13%"}},
|
{"widgettype": "RefreshWidget", "id": "rt_active", "options": {"period_seconds": 30, "url": "{{entire_url('rt_card_active.ui')}}", "width": "13%"}},
|
||||||
{"widgettype": "RefreshWidget", "id": "rt_online", "options": {"period_seconds": 30, "url": "{{entire_url('rt_card_online.ui')}}", "width": "13%"}},
|
{"widgettype": "RefreshWidget", "id": "rt_online", "options": {"period_seconds": 30, "url": "{{entire_url('rt_card_online.ui')}}", "width": "13%"}},
|
||||||
{"widgettype": "RefreshWidget", "id": "rt_success", "options": {"period_seconds": 30, "url": "{{entire_url('rt_card_success.ui')}}", "width": "13%"}},
|
{"widgettype": "RefreshWidget", "id": "rt_success","options": {"period_seconds": 30, "url": "{{entire_url('rt_card_success.ui')}}", "width": "13%"}},
|
||||||
{"widgettype": "RefreshWidget", "id": "rt_fail", "options": {"period_seconds": 30, "url": "{{entire_url('rt_card_fail.ui')}}", "width": "13%"}}
|
{"widgettype": "RefreshWidget", "id": "rt_fail", "options": {"period_seconds": 30, "url": "{{entire_url('rt_card_fail.ui')}}", "width": "13%"}}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -38,25 +38,7 @@
|
|||||||
"options": {"css": "card", "width": "60%", "padding": "16px"},
|
"options": {"css": "card", "width": "60%", "padding": "16px"},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "模型性能排行", "i18n": true, "marginBottom": "8px"}},
|
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "模型性能排行", "i18n": true, "marginBottom": "8px"}},
|
||||||
{
|
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_model_perf.ui')}}", "width": "100%"}}
|
||||||
"widgettype": "Cols",
|
|
||||||
"options": {
|
|
||||||
"col_cwidth": 24,
|
|
||||||
"data_url": "{{entire_url('api/model_perf.dspy')}}",
|
|
||||||
"data_params": {},
|
|
||||||
"record_view": {
|
|
||||||
"widgettype": "HBox",
|
|
||||||
"options": {"cheight": 3, "width": "100%"},
|
|
||||||
"subwidgets": [
|
|
||||||
{"widgettype": "Text", "options": {"text": "${model}", "width": "35%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${avg_ttft_ms}ms", "width": "15%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${success_rate}%", "width": "15%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${total_calls}", "width": "15%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${total_amount_cny}", "width": "20%"}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -64,24 +46,7 @@
|
|||||||
"options": {"css": "card", "width": "40%", "padding": "16px"},
|
"options": {"css": "card", "width": "40%", "padding": "16px"},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "币种分布", "i18n": true, "marginBottom": "8px"}},
|
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "币种分布", "i18n": true, "marginBottom": "8px"}},
|
||||||
{
|
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_currency.ui')}}", "width": "100%"}}
|
||||||
"widgettype": "Cols",
|
|
||||||
"options": {
|
|
||||||
"col_cwidth": 24,
|
|
||||||
"data_url": "{{entire_url('api/currency_stats.dspy')}}",
|
|
||||||
"data_params": {},
|
|
||||||
"record_view": {
|
|
||||||
"widgettype": "HBox",
|
|
||||||
"options": {"cheight": 3, "width": "100%"},
|
|
||||||
"subwidgets": [
|
|
||||||
{"widgettype": "Text", "options": {"text": "${currency}", "width": "20%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${call_count}次", "width": "25%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${amount}", "width": "25%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${amount_cny}", "width": "30%"}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -95,25 +60,7 @@
|
|||||||
"options": {"css": "card", "width": "50%", "padding": "16px"},
|
"options": {"css": "card", "width": "50%", "padding": "16px"},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "供应商性价比", "i18n": true, "marginBottom": "8px"}},
|
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "供应商性价比", "i18n": true, "marginBottom": "8px"}},
|
||||||
{
|
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_provider_roi.ui')}}", "width": "100%"}}
|
||||||
"widgettype": "Cols",
|
|
||||||
"options": {
|
|
||||||
"col_cwidth": 24,
|
|
||||||
"data_url": "{{entire_url('api/provider_roi.dspy')}}",
|
|
||||||
"data_params": {},
|
|
||||||
"record_view": {
|
|
||||||
"widgettype": "HBox",
|
|
||||||
"options": {"cheight": 3, "width": "100%"},
|
|
||||||
"subwidgets": [
|
|
||||||
{"widgettype": "Text", "options": {"text": "${model}", "width": "35%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${unit_price}/t", "width": "20%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${avg_ttft_ms}ms", "width": "15%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${total_calls}次", "width": "15%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${total_amount_cny}", "width": "15%"}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -127,23 +74,7 @@
|
|||||||
"options": {"css": "card", "width": "33%", "padding": "16px"},
|
"options": {"css": "card", "width": "33%", "padding": "16px"},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "热门模型", "i18n": true, "marginBottom": "8px"}},
|
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "热门模型", "i18n": true, "marginBottom": "8px"}},
|
||||||
{
|
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_top_models.ui')}}", "width": "100%"}}
|
||||||
"widgettype": "Cols",
|
|
||||||
"options": {
|
|
||||||
"col_cwidth": 20,
|
|
||||||
"data_url": "{{entire_url('api/top_models.dspy')}}",
|
|
||||||
"data_params": {},
|
|
||||||
"record_view": {
|
|
||||||
"widgettype": "HBox",
|
|
||||||
"options": {"cheight": 3, "width": "100%"},
|
|
||||||
"subwidgets": [
|
|
||||||
{"widgettype": "Text", "options": {"text": "${model_name}", "width": "50%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${cnt}次", "width": "25%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${total_amount}", "width": "25%"}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -151,23 +82,7 @@
|
|||||||
"options": {"css": "card", "width": "33%", "padding": "16px"},
|
"options": {"css": "card", "width": "33%", "padding": "16px"},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "用户排行", "i18n": true, "marginBottom": "8px"}},
|
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "用户排行", "i18n": true, "marginBottom": "8px"}},
|
||||||
{
|
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_top_users.ui')}}", "width": "100%"}}
|
||||||
"widgettype": "Cols",
|
|
||||||
"options": {
|
|
||||||
"col_cwidth": 20,
|
|
||||||
"data_url": "{{entire_url('api/top_users.dspy')}}",
|
|
||||||
"data_params": {},
|
|
||||||
"record_view": {
|
|
||||||
"widgettype": "HBox",
|
|
||||||
"options": {"cheight": 3, "width": "100%"},
|
|
||||||
"subwidgets": [
|
|
||||||
{"widgettype": "Text", "options": {"text": "${user_name}", "width": "50%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${cnt}次", "width": "25%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${total_amount}", "width": "25%"}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -175,23 +90,7 @@
|
|||||||
"options": {"css": "card", "width": "33%", "padding": "16px"},
|
"options": {"css": "card", "width": "33%", "padding": "16px"},
|
||||||
"subwidgets": [
|
"subwidgets": [
|
||||||
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "供应商排行", "i18n": true, "marginBottom": "8px"}},
|
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "供应商排行", "i18n": true, "marginBottom": "8px"}},
|
||||||
{
|
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_top_providers.ui')}}", "width": "100%"}}
|
||||||
"widgettype": "Cols",
|
|
||||||
"options": {
|
|
||||||
"col_cwidth": 20,
|
|
||||||
"data_url": "{{entire_url('api/top_providers.dspy')}}",
|
|
||||||
"data_params": {},
|
|
||||||
"record_view": {
|
|
||||||
"widgettype": "HBox",
|
|
||||||
"options": {"cheight": 3, "width": "100%"},
|
|
||||||
"subwidgets": [
|
|
||||||
{"widgettype": "Text", "options": {"text": "${provider_name}", "width": "50%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${cnt}次", "width": "25%"}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "${total_amount}", "width": "25%"}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
10
wwwroot/sect_currency.ui
Normal file
10
wwwroot/sect_currency.ui
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{% set data = j2_currency_data(request) %}
|
||||||
|
{"widgettype":"VBox","options":{"width":"100%"},"subwidgets":[
|
||||||
|
{% for r in data %}
|
||||||
|
{"widgettype":"HBox","options":{"cheight":3,"width":"100%"},"subwidgets":[
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('currency',''),ensure_ascii=False)}},"width":"20%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps((r.get('call_count',0)|string)+'次',ensure_ascii=False)}},"width":"25%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('amount',0)|string,ensure_ascii=False)}},"width":"25%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('amount_cny',0)|string,ensure_ascii=False)}},"width":"30%"}}
|
||||||
|
]}{% if not loop.last %},{% endif %}{% endfor %}
|
||||||
|
]}
|
||||||
11
wwwroot/sect_model_perf.ui
Normal file
11
wwwroot/sect_model_perf.ui
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% set data = j2_model_perf_data(request) %}
|
||||||
|
{"widgettype":"VBox","options":{"width":"100%"},"subwidgets":[
|
||||||
|
{% for r in data %}
|
||||||
|
{"widgettype":"HBox","options":{"cheight":3,"width":"100%"},"subwidgets":[
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('model',''),ensure_ascii=False)}},"width":"35%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps((r.get('avg_ttft_ms','')|string)+'ms',ensure_ascii=False)}},"width":"15%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps((r.get('success_rate','')|string)+'%',ensure_ascii=False)}},"width":"15%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('total_calls','')|string,ensure_ascii=False)}},"width":"15%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('total_amount_cny','')|string,ensure_ascii=False)}},"width":"20%"}}
|
||||||
|
]}{% if not loop.last %},{% endif %}{% endfor %}
|
||||||
|
]}
|
||||||
11
wwwroot/sect_provider_roi.ui
Normal file
11
wwwroot/sect_provider_roi.ui
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% set data = j2_provider_roi_data(request) %}
|
||||||
|
{"widgettype":"VBox","options":{"width":"100%"},"subwidgets":[
|
||||||
|
{% for r in data %}
|
||||||
|
{"widgettype":"HBox","options":{"cheight":3,"width":"100%"},"subwidgets":[
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('model',''),ensure_ascii=False)}},"width":"35%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps((r.get('unit_price','')|string)+'/t',ensure_ascii=False)}},"width":"20%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps((r.get('avg_ttft_ms','')|string)+'ms',ensure_ascii=False)}},"width":"15%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps((r.get('total_calls',0)|string)+'次',ensure_ascii=False)}},"width":"15%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('total_amount_cny',0)|string,ensure_ascii=False)}},"width":"15%"}}
|
||||||
|
]}{% if not loop.last %},{% endif %}{% endfor %}
|
||||||
|
]}
|
||||||
9
wwwroot/sect_top_models.ui
Normal file
9
wwwroot/sect_top_models.ui
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% set data = j2_top_models_data(request) %}
|
||||||
|
{"widgettype":"VBox","options":{"width":"100%"},"subwidgets":[
|
||||||
|
{% for r in data %}
|
||||||
|
{"widgettype":"HBox","options":{"cheight":3,"width":"100%"},"subwidgets":[
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('model_name',''),ensure_ascii=False)}},"width":"50%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps((r.get('cnt',0)|string)+'次',ensure_ascii=False)}},"width":"25%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('total_amount',0)|string,ensure_ascii=False)}},"width":"25%"}}
|
||||||
|
]}{% if not loop.last %},{% endif %}{% endfor %}
|
||||||
|
]}
|
||||||
9
wwwroot/sect_top_providers.ui
Normal file
9
wwwroot/sect_top_providers.ui
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% set data = j2_top_providers_data(request) %}
|
||||||
|
{"widgettype":"VBox","options":{"width":"100%"},"subwidgets":[
|
||||||
|
{% for r in data %}
|
||||||
|
{"widgettype":"HBox","options":{"cheight":3,"width":"100%"},"subwidgets":[
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('provider_name',''),ensure_ascii=False)}},"width":"50%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps((r.get('cnt',0)|string)+'次',ensure_ascii=False)}},"width":"25%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('total_amount',0)|string,ensure_ascii=False)}},"width":"25%"}}
|
||||||
|
]}{% if not loop.last %},{% endif %}{% endfor %}
|
||||||
|
]}
|
||||||
9
wwwroot/sect_top_users.ui
Normal file
9
wwwroot/sect_top_users.ui
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% set data = j2_top_users_data(request) %}
|
||||||
|
{"widgettype":"VBox","options":{"width":"100%"},"subwidgets":[
|
||||||
|
{% for r in data %}
|
||||||
|
{"widgettype":"HBox","options":{"cheight":3,"width":"100%"},"subwidgets":[
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('user_name',''),ensure_ascii=False)}},"width":"50%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps((r.get('cnt',0)|string)+'次',ensure_ascii=False)}},"width":"25%"}},
|
||||||
|
{"widgettype":"Text","options":{"text":{{json.dumps(r.get('total_amount',0)|string,ensure_ascii=False)}},"width":"25%"}}
|
||||||
|
]}{% if not loop.last %},{% endif %}{% endfor %}
|
||||||
|
]}
|
||||||
Loading…
x
Reference in New Issue
Block a user