feat: 币种分布按角色拆分(分销商成本收入/客户费用/管理员分布)

This commit is contained in:
yumoqing 2026-07-24 15:36:18 +08:00
parent 18e7dd5afd
commit a50935f669
9 changed files with 189 additions and 76 deletions

View File

@ -491,3 +491,30 @@ async def get_distributor_financial(sor, org_filter, period='today'):
'total_calls': total_calls,
'period': period,
}
async def get_customer_currency_stats(sor, org_filter, period='today'):
"""客户费用统计:按币种+时间维度"""
today_str = _date_module_date.today().isoformat()
date_sql = ""
ns = {'org': org_filter, 'today': today_str}
if period == 'month':
date_sql = "AND f.call_date BETWEEN ${month_start}$ AND ${today}$"
ns['month_start'] = today_str[:7] + '-01'
elif period == 'year':
date_sql = "AND f.call_date BETWEEN ${year_start}$ AND ${today}$"
ns['year_start'] = today_str[:4] + '-01-01'
elif period == 'today':
date_sql = "AND f.call_date = ${today}$"
sql = f"""SELECT COALESCE(f.currency, 'CNY') as currency,
COUNT(*) as call_count,
COALESCE(SUM(f.amount), 0) as revenue,
COALESCE(SUM(f.amount_cny), 0) as revenue_cny
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]

View File

@ -1,20 +1,26 @@
{
"API Key排行": "API Key Ranking",
"供应商性价比": "Provider Cost-Performance",
"供应商排行": "Provider Ranking",
"币种分布": "Currency Distribution",
"我的模型(按金额Top5)": "My Models (Top 5 by Amount)",
"模型性能排行": "Model Performance Ranking",
"热门模型": "Popular Models",
"用户排行": "User Ranking",
"财务概览": "Financial Overview",
"今天调用": "Today",
"用户": "Users",
"今日调用笔数": "Today Calls",
"今日交易金额": "Today Amount",
"用户总数": "Total Users",
"今日活跃": "Today Active",
"在线用户": "Online Users",
"成功率": "Success Rate",
"失败数": "Failed"
"API Key排行": "API Key Ranking",
"供应商性价比": "Provider Cost-Performance",
"供应商排行": "Provider Ranking",
"币种分布": "Currency Distribution",
"我的模型(按金额Top5)": "My Models (Top 5 by Amount)",
"模型性能排行": "Model Performance Ranking",
"热门模型": "Popular Models",
"用户排行": "User Ranking",
"财务概览": "Financial Overview",
"今天调用": "Today",
"用户": "Users",
"今日调用笔数": "Today Calls",
"今日交易金额": "Today Amount",
"用户总数": "Total Users",
"今日活跃": "Today Active",
"在线用户": "Online Users",
"成功率": "Success Rate",
"失败数": "Failed",
"币种成本收入": "Currency Cost & Revenue",
"币种费用": "Currency Expenses",
"今天": "Today",
"本月": "This Month",
"本年": "This Year",
"累计": "Cumulative"
}

View File

@ -1,20 +1,26 @@
{
"API Key排行": "APIキーランキング",
"供应商性价比": "プロバイダーコストパフォーマンス",
"供应商排行": "プロバイダーランキング",
"币种分布": "通貨分布",
"我的模型(按金额Top5)": "マイモデル金額Top5",
"模型性能排行": "モデルパフォーマンスランキング",
"热门模型": "人気モデル",
"用户排行": "ユーザーランキング",
"财务概览": "財務概要",
"今天调用": "本日",
"用户": "ユーザー",
"今日调用笔数": "本日コール数",
"今日交易金额": "本日取引額",
"用户总数": "総ユーザー数",
"今日活跃": "本日アクティブ",
"在线用户": "オンラインユーザー",
"成功率": "成功率",
"失败数": "失敗数"
"API Key排行": "APIキーランキング",
"供应商性价比": "プロバイダーコストパフォーマンス",
"供应商排行": "プロバイダーランキング",
"币种分布": "通貨分布",
"我的模型(按金额Top5)": "マイモデル金額Top5",
"模型性能排行": "モデルパフォーマンスランキング",
"热门模型": "人気モデル",
"用户排行": "ユーザーランキング",
"财务概览": "財務概要",
"今天调用": "本日",
"用户": "ユーザー",
"今日调用笔数": "本日コール数",
"今日交易金额": "本日取引額",
"用户总数": "総ユーザー数",
"今日活跃": "本日アクティブ",
"在线用户": "オンラインユーザー",
"成功率": "成功率",
"失败数": "失敗数",
"币种成本收入": "通貨コスト収入",
"币种费用": "通貨費用",
"今天": "今日",
"本月": "今月",
"本年": "今年",
"累计": "累計"
}

View File

@ -1,20 +1,26 @@
{
"API Key排行": "API 키 랭킹",
"供应商性价比": "공급업체 가성비",
"供应商排行": "공급업체 랭킹",
"币种分布": "통화 분포",
"我的模型(按金额Top5)": "내 모델 (금액 Top5)",
"模型性能排行": "모델 성능 랭킹",
"热门模型": "인기 모델",
"用户排行": "사용자 랭킹",
"财务概览": "재무 개요",
"今天调用": "오늘",
"用户": "사용자",
"今日调用笔数": "오늘 호출",
"今日交易金额": "오늘 거래액",
"用户总数": "전체 사용자",
"今日活跃": "오늘 활성",
"在线用户": "온라인 사용자",
"成功率": "성공률",
"失败数": "실패수"
"API Key排行": "API 키 랭킹",
"供应商性价比": "공급업체 가성비",
"供应商排行": "공급업체 랭킹",
"币种分布": "통화 분포",
"我的模型(按金额Top5)": "내 모델 (금액 Top5)",
"模型性能排行": "모델 성능 랭킹",
"热门模型": "인기 모델",
"用户排行": "사용자 랭킹",
"财务概览": "재무 개요",
"今天调用": "오늘",
"用户": "사용자",
"今日调用笔数": "오늘 호출",
"今日交易金额": "오늘 거래액",
"用户总数": "전체 사용자",
"今日活跃": "오늘 활성",
"在线用户": "온라인 사용자",
"成功率": "성공률",
"失败数": "실패수",
"币种成本收入": "통화 비용 수익",
"币种费用": "통화 비용",
"今天": "오늘",
"本月": "이번 달",
"本年": "올해",
"累计": "누계"
}

View File

@ -1,20 +1,26 @@
{
"API Key排行": "API Key排行",
"供应商性价比": "供应商性价比",
"供应商排行": "供应商排行",
"币种分布": "币种分布",
"我的模型(按金额Top5)": "我的模型(按金额Top5)",
"模型性能排行": "模型性能排行",
"热门模型": "热门模型",
"用户排行": "用户排行",
"财务概览": "财务概览",
"今天调用": "今天调用",
"用户": "用户",
"今日调用笔数": "今日调用笔数",
"今日交易金额": "今日交易金额",
"用户总数": "用户总数",
"今日活跃": "今日活跃",
"在线用户": "在线用户",
"成功率": "成功率",
"失败数": "失败数"
"API Key排行": "API Key排行",
"供应商性价比": "供应商性价比",
"供应商排行": "供应商排行",
"币种分布": "币种分布",
"我的模型(按金额Top5)": "我的模型(按金额Top5)",
"模型性能排行": "模型性能排行",
"热门模型": "热门模型",
"用户排行": "用户排行",
"财务概览": "财务概览",
"今天调用": "今天调用",
"用户": "用户",
"今日调用笔数": "今日调用笔数",
"今日交易金额": "今日交易金额",
"用户总数": "用户总数",
"今日活跃": "今日活跃",
"在线用户": "在线用户",
"成功率": "成功率",
"失败数": "失败数",
"币种成本收入": "币种成本收入",
"币种费用": "币种费用",
"今天": "今天",
"本月": "本月",
"本年": "本年",
"累计": "累计"
}

View File

@ -462,6 +462,17 @@ async def j2_is_distributor(request):
except Exception:
return False
async def j2_customer_currency(request, period='today'):
"""Jinja2: 客户币种费用"""
try:
env = request._run_ns
scope, org_filter = await _resolve_view(request)
async with get_sor_context(env, MODULE_NAME) as sor:
return await get_customer_currency_stats(sor, org_filter, period)
except Exception:
return []
# ── 监控组件 j2 函数,每段独立 .ui 通过 RefreshWidget 加载 ──
async def j2_model_perf_data(request):
@ -581,6 +592,7 @@ def load_sage_datamart():
env.api_distributor_financial = api_distributor_financial
env.j2_distributor_financial = j2_distributor_financial
env.j2_is_distributor = j2_is_distributor
env.j2_customer_currency = j2_customer_currency
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

View File

@ -42,6 +42,7 @@ PATHS_LOGINED = [
f"/{MOD}/sect_user_apikeys.ui",
f"/{MOD}/sect_distributor_financial.ui",
f"/{MOD}/sect_distributor_currency.ui",
f"/{MOD}/sect_customer_currency.ui",
]
def run(role, path):

View File

@ -99,8 +99,16 @@
"widgettype": "VBox",
"options": {"css": "card", "width": "40%", "padding": "16px"},
"subwidgets": [
{% if is_distributor %}
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "币种成本收入", "i18n": true, "marginBottom": "8px"}},
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_distributor_currency.ui')}}", "width": "100%"}}
{% elif is_admin %}
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "币种分布", "i18n": true, "marginBottom": "8px"}},
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_currency.ui')}}", "width": "100%"}}
{% else %}
{"widgettype": "Title4", "options": {"fontWeight": "600", "otext": "币种费用", "i18n": true, "marginBottom": "8px"}},
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_customer_currency.ui')}}", "width": "100%"}}
{% endif %}
]
}
]

View File

@ -0,0 +1,41 @@
{% set today_data = j2_customer_currency(request, 'today') %}
{% set month_data = j2_customer_currency(request, 'month') %}
{% set year_data = j2_customer_currency(request, 'year') %}
{% set all_data = j2_customer_currency(request, 'all') %}
{% macro sum_cny(data) %}{% set total = namespace(v=0) %}{% for r in data %}{% set total.v = total.v + r.revenue_cny %}{% endfor %}{{ '%.2f' % total.v }}{% endmacro %}
{
"widgettype": "VBox",
"options": {"width": "100%"},
"subwidgets": [
{"widgettype": "HBox", "options": {"width": "100%", "gap": "10px", "marginBottom": "12px"},
"subwidgets": [
{"widgettype": "VBox", "options": {"css": "card", "padding": "10px", "borderRadius": "6px", "width": "25%"},
"subwidgets": [
{"widgettype": "Text", "options": {"otext": "今天", "i18n": true, "fontWeight": "600", "fontSize": "12px"}},
{"widgettype": "Text", "options": {"text": {{json.dumps('¥' + sum_cny(today_data), ensure_ascii=False)}},"fontWeight": "700", "fontSize": "16px", "marginTop": "4px"}}
]
},
{"widgettype": "VBox", "options": {"css": "card", "padding": "10px", "borderRadius": "6px", "width": "25%"},
"subwidgets": [
{"widgettype": "Text", "options": {"otext": "本月", "i18n": true, "fontWeight": "600", "fontSize": "12px"}},
{"widgettype": "Text", "options": {"text": {{json.dumps('¥' + sum_cny(month_data), ensure_ascii=False)}},"fontWeight": "700", "fontSize": "16px", "marginTop": "4px"}}
]
},
{"widgettype": "VBox", "options": {"css": "card", "padding": "10px", "borderRadius": "6px", "width": "25%"},
"subwidgets": [
{"widgettype": "Text", "options": {"otext": "本年", "i18n": true, "fontWeight": "600", "fontSize": "12px"}},
{"widgettype": "Text", "options": {"text": {{json.dumps('¥' + sum_cny(year_data), ensure_ascii=False)}},"fontWeight": "700", "fontSize": "16px", "marginTop": "4px"}}
]
},
{"widgettype": "VBox", "options": {"css": "card", "padding": "10px", "borderRadius": "6px", "width": "25%"},
"subwidgets": [
{"widgettype": "Text", "options": {"otext": "累计", "i18n": true, "fontWeight": "600", "fontSize": "12px"}},
{"widgettype": "Text", "options": {"text": {{json.dumps('¥' + sum_cny(all_data), ensure_ascii=False)}},"fontWeight": "700", "fontSize": "16px", "marginTop": "4px"}}
]
}
]
}
]
}