feat: i18n补全 + 币种分布改为收入/成本/毛利图表

1. i18n/zh/msg.txt: 补全所有缺失的英文翻译
2. dashboards.py: 新增 get_financial_summary(period) 平台级财务汇总
3. init.py: 注册 api_financial_summary + 导入
4. sect_currency.ui: 饼图改为累计/当年/当月/当天 收入/成本/毛利柱状图
5. 新增 api/financial_summary.dspy + api/financial_chart.dspy
This commit is contained in:
yumoqing 2026-07-25 10:47:44 +08:00
parent 72c522b5c9
commit 60059b304e
6 changed files with 105 additions and 13 deletions

View File

@ -1 +1 @@
{"模型性能监控":"Model Performance","供应商性价比对比":"Provider ROI","平均 TTFT":"Avg TTFT","成功率":"Success Rate","今日调用":"Today Calls","失败数":"Failures","模型性能":"Model Perf","供应商性价比":"Provider ROI","刷新":"Refresh"}
{"模型性能监控":"Model Performance","供应商性价比对比":"Provider ROI","平均 TTFT":"Avg TTFT","成功率":"Success Rate","今日调用":"Today Calls","失败数":"Failures","模型性能":"Model Perf","供应商性价比":"Provider ROI","刷新":"Refresh","今日调用笔数":"Today's Calls","今日交易金额":"Today's Amount","今日活跃":"Active Today","在线用户":"Online Users","用户总数":"Total Users","用户":"Users","模型性能排行":"Model Performance","币种分布":"Revenue/Cost/Profit","币种成本收入":"Currency Cost/Revenue","币种费用":"Currency Cost","热门模型":"Popular Models","用户排行":"User Ranking","供应商排行":"Supplier Ranking","我的模型(按金额Top5)":"My Models (Top 5)","API Key排行":"API Key Ranking","财务概览":"Financial Overview","收入":"Revenue","成本":"Cost","毛利":"Gross Profit","累计":"Cumulative","当年":"This Year","当月":"This Month","当天":"Today","今天调用":"Today Calls"}

View File

@ -514,7 +514,48 @@ async def get_customer_currency_stats(sor, org_filter, period='today'):
FROM dm_model_call_fact f
WHERE f.userorgid = ${{org}}$ {date_sql}
GROUP BY f.currency ORDER BY revenue_cny DESC"""
recs = await sor.sqlExe(sql, ns)
return [{'currency': r.currency, 'call_count': int(r.call_count or 0),
'revenue': round(float(r.revenue or 0), 2),
'revenue_cny': round(float(r.revenue_cny or 0), 2)} for r in recs]
async def get_financial_summary(sor, period='all'):
"""平台级财务汇总:收入/成本/毛利(不分机构)
period: 'today' | 'month' | 'year' | 'all'
"""
today_str = _date_module_date.today().isoformat()
ns = {'today': today_str}
date_sql = ""
if period == 'month':
date_sql = "AND call_date BETWEEN ${month_start}$ AND ${today}$"
ns['month_start'] = today_str[:7] + '-01'
elif period == 'year':
date_sql = "AND call_date BETWEEN ${year_start}$ AND ${today}$"
ns['year_start'] = today_str[:4] + '-01-01'
elif period == 'today':
date_sql = "AND call_date = ${today}$"
sql_rev = f"""SELECT
COALESCE(SUM(amount_cny), 0) as revenue_cny,
COUNT(*) as call_count
FROM dm_model_call_fact
WHERE 1=1 {date_sql}"""
recs = await sor.sqlExe(sql_rev, ns)
total_revenue_cny = round(float(recs[0].revenue_cny or 0), 2) if recs else 0
total_calls = int(recs[0].call_count or 0) if recs else 0
total_cost_cny = 0.0
try:
cost_sql = f"""SELECT COALESCE(SUM(c.total_amount_cny), 0) as total_cost_cny
FROM dm_provider_cost_daily c
WHERE 1=1 {date_sql.replace('call_date', 'c.stat_date')}"""
cost_recs = await sor.sqlExe(cost_sql, ns)
if cost_recs:
total_cost_cny = round(float(cost_recs[0].total_cost_cny or 0), 2)
except Exception:
pass
gross_profit_cny = round(total_revenue_cny - total_cost_cny, 2)
return {
'total_revenue_cny': total_revenue_cny,
'total_cost_cny': total_cost_cny,
'gross_profit_cny': gross_profit_cny,
'total_calls': total_calls,
'period': period,
}

View File

@ -17,6 +17,8 @@ from .dashboards import (
get_distributor_top_customers,
get_scoped_today_usage, get_scoped_today_amount,
get_scoped_success_rate, get_scoped_fail_count,
get_distributor_financial, get_customer_currency_stats,
get_financial_summary,
)
MODULE_NAME = "sage_datamart"
@ -529,6 +531,18 @@ async def j2_top_providers_data(request):
return []
async def api_financial_summary(request):
"""平台级财务汇总 API"""
try:
env = request._run_ns
period = (request._run_ns.params_kw or {}).get('period', 'all')
async with get_sor_context(env, MODULE_NAME) as sor:
return await get_financial_summary(sor, period)
except Exception as e:
debug("sage_datamart API error: " + str(e))
return {}
# ── Cron ETL ──
async def cron_etl_sync(request):
@ -599,6 +613,7 @@ def load_sage_datamart():
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.api_financial_summary = api_financial_summary
env.cron_etl_sync = cron_etl_sync
env.cron_etl_aggregate = cron_etl_aggregate
env.cron_etl_provider_cost = cron_etl_provider_cost

View File

@ -0,0 +1,9 @@
import json
period = (params_kw or {}).get('period', 'all')
data = await request._run_ns.api_financial_summary(request)
chart_data = [
{"metric": "收入", "value": data.get('total_revenue_cny', 0)},
{"metric": "成本", "value": data.get('total_cost_cny', 0)},
{"metric": "毛利", "value": data.get('gross_profit_cny', 0)},
]
return json.dumps(chart_data, ensure_ascii=False)

View File

@ -0,0 +1,5 @@
import json
env = request._run_ns
period = (params_kw or {}).get('period', 'all')
data = await env.api_financial_summary(request)
return json.dumps(data, ensure_ascii=False)

View File

@ -1,10 +1,32 @@
{
"widgettype": "ChartPie",
"options": {
"height": "200px",
"data_url": "/sage_datamart/api/currency_stats.dspy",
"nameField": "currency",
"valueFields": ["call_count"],
"pie_options": {"type": "pie", "radius": "60%"}
}
"widgettype": "VBox",
"options": {"width": "100%", "gap": "8px"},
"subwidgets": [
{
"widgettype": "HBox",
"options": {"gap": "4px"},
"subwidgets": [
{"widgettype": "Button", "id": "btn_all", "options": {"label": "累计", "i18n": true}},
{"widgettype": "Button", "id": "btn_year", "options": {"label": "当年", "i18n": true}},
{"widgettype": "Button", "id": "btn_month", "options": {"label": "当月", "i18n": true}},
{"widgettype": "Button", "id": "btn_today", "options": {"label": "当天", "i18n": true}}
]
},
{
"widgettype": "ChartBar",
"id": "financial_chart",
"options": {
"height": "180px",
"data_url": "{{entire_url('/sage_datamart/api/financial_chart.dspy')}}?period=all",
"nameField": "metric",
"valueFields": ["value"]
}
}
],
"binds": [
{"wid": "btn_all", "event": "click", "actiontype": "urldata", "target": "financial_chart", "options": {"url": "{{entire_url('/sage_datamart/api/financial_chart.dspy')}}?period=all"}},
{"wid": "btn_year", "event": "click", "actiontype": "urldata", "target": "financial_chart", "options": {"url": "{{entire_url('/sage_datamart/api/financial_chart.dspy')}}?period=year"}},
{"wid": "btn_month", "event": "click", "actiontype": "urldata", "target": "financial_chart", "options": {"url": "{{entire_url('/sage_datamart/api/financial_chart.dspy')}}?period=month"}},
{"wid": "btn_today", "event": "click", "actiontype": "urldata", "target": "financial_chart", "options": {"url": "{{entire_url('/sage_datamart/api/financial_chart.dspy')}}?period=today"}}
]
}