feat: 币种分布按角色拆分(分销商成本收入/客户费用/管理员分布)
This commit is contained in:
parent
18e7dd5afd
commit
a50935f669
@ -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]
|
||||
|
||||
@ -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"
|
||||
}
|
||||
@ -1,20 +1,26 @@
|
||||
{
|
||||
"API Key排行": "APIキーランキング",
|
||||
"供应商性价比": "プロバイダーコストパフォーマンス",
|
||||
"供应商排行": "プロバイダーランキング",
|
||||
"币种分布": "通貨分布",
|
||||
"我的模型(按金额Top5)": "マイモデル(金額Top5)",
|
||||
"模型性能排行": "モデルパフォーマンスランキング",
|
||||
"热门模型": "人気モデル",
|
||||
"用户排行": "ユーザーランキング",
|
||||
"财务概览": "財務概要",
|
||||
"今天调用": "本日",
|
||||
"用户": "ユーザー",
|
||||
"今日调用笔数": "本日コール数",
|
||||
"今日交易金额": "本日取引額",
|
||||
"用户总数": "総ユーザー数",
|
||||
"今日活跃": "本日アクティブ",
|
||||
"在线用户": "オンラインユーザー",
|
||||
"成功率": "成功率",
|
||||
"失败数": "失敗数"
|
||||
}
|
||||
"API Key排行": "APIキーランキング",
|
||||
"供应商性价比": "プロバイダーコストパフォーマンス",
|
||||
"供应商排行": "プロバイダーランキング",
|
||||
"币种分布": "通貨分布",
|
||||
"我的模型(按金额Top5)": "マイモデル(金額Top5)",
|
||||
"模型性能排行": "モデルパフォーマンスランキング",
|
||||
"热门模型": "人気モデル",
|
||||
"用户排行": "ユーザーランキング",
|
||||
"财务概览": "財務概要",
|
||||
"今天调用": "本日",
|
||||
"用户": "ユーザー",
|
||||
"今日调用笔数": "本日コール数",
|
||||
"今日交易金额": "本日取引額",
|
||||
"用户总数": "総ユーザー数",
|
||||
"今日活跃": "本日アクティブ",
|
||||
"在线用户": "オンラインユーザー",
|
||||
"成功率": "成功率",
|
||||
"失败数": "失敗数",
|
||||
"币种成本收入": "通貨コスト収入",
|
||||
"币种费用": "通貨費用",
|
||||
"今天": "今日",
|
||||
"本月": "今月",
|
||||
"本年": "今年",
|
||||
"累计": "累計"
|
||||
}
|
||||
@ -1,20 +1,26 @@
|
||||
{
|
||||
"API Key排行": "API 키 랭킹",
|
||||
"供应商性价比": "공급업체 가성비",
|
||||
"供应商排行": "공급업체 랭킹",
|
||||
"币种分布": "통화 분포",
|
||||
"我的模型(按金额Top5)": "내 모델 (금액 Top5)",
|
||||
"模型性能排行": "모델 성능 랭킹",
|
||||
"热门模型": "인기 모델",
|
||||
"用户排行": "사용자 랭킹",
|
||||
"财务概览": "재무 개요",
|
||||
"今天调用": "오늘",
|
||||
"用户": "사용자",
|
||||
"今日调用笔数": "오늘 호출",
|
||||
"今日交易金额": "오늘 거래액",
|
||||
"用户总数": "전체 사용자",
|
||||
"今日活跃": "오늘 활성",
|
||||
"在线用户": "온라인 사용자",
|
||||
"成功率": "성공률",
|
||||
"失败数": "실패수"
|
||||
}
|
||||
"API Key排行": "API 키 랭킹",
|
||||
"供应商性价比": "공급업체 가성비",
|
||||
"供应商排行": "공급업체 랭킹",
|
||||
"币种分布": "통화 분포",
|
||||
"我的模型(按金额Top5)": "내 모델 (금액 Top5)",
|
||||
"模型性能排行": "모델 성능 랭킹",
|
||||
"热门模型": "인기 모델",
|
||||
"用户排行": "사용자 랭킹",
|
||||
"财务概览": "재무 개요",
|
||||
"今天调用": "오늘",
|
||||
"用户": "사용자",
|
||||
"今日调用笔数": "오늘 호출",
|
||||
"今日交易金额": "오늘 거래액",
|
||||
"用户总数": "전체 사용자",
|
||||
"今日活跃": "오늘 활성",
|
||||
"在线用户": "온라인 사용자",
|
||||
"成功率": "성공률",
|
||||
"失败数": "실패수",
|
||||
"币种成本收入": "통화 비용 수익",
|
||||
"币种费用": "통화 비용",
|
||||
"今天": "오늘",
|
||||
"本月": "이번 달",
|
||||
"本年": "올해",
|
||||
"累计": "누계"
|
||||
}
|
||||
@ -1,20 +1,26 @@
|
||||
{
|
||||
"API Key排行": "API Key排行",
|
||||
"供应商性价比": "供应商性价比",
|
||||
"供应商排行": "供应商排行",
|
||||
"币种分布": "币种分布",
|
||||
"我的模型(按金额Top5)": "我的模型(按金额Top5)",
|
||||
"模型性能排行": "模型性能排行",
|
||||
"热门模型": "热门模型",
|
||||
"用户排行": "用户排行",
|
||||
"财务概览": "财务概览",
|
||||
"今天调用": "今天调用",
|
||||
"用户": "用户",
|
||||
"今日调用笔数": "今日调用笔数",
|
||||
"今日交易金额": "今日交易金额",
|
||||
"用户总数": "用户总数",
|
||||
"今日活跃": "今日活跃",
|
||||
"在线用户": "在线用户",
|
||||
"成功率": "成功率",
|
||||
"失败数": "失败数"
|
||||
}
|
||||
"API Key排行": "API Key排行",
|
||||
"供应商性价比": "供应商性价比",
|
||||
"供应商排行": "供应商排行",
|
||||
"币种分布": "币种分布",
|
||||
"我的模型(按金额Top5)": "我的模型(按金额Top5)",
|
||||
"模型性能排行": "模型性能排行",
|
||||
"热门模型": "热门模型",
|
||||
"用户排行": "用户排行",
|
||||
"财务概览": "财务概览",
|
||||
"今天调用": "今天调用",
|
||||
"用户": "用户",
|
||||
"今日调用笔数": "今日调用笔数",
|
||||
"今日交易金额": "今日交易金额",
|
||||
"用户总数": "用户总数",
|
||||
"今日活跃": "今日活跃",
|
||||
"在线用户": "在线用户",
|
||||
"成功率": "成功率",
|
||||
"失败数": "失败数",
|
||||
"币种成本收入": "币种成本收入",
|
||||
"币种费用": "币种费用",
|
||||
"今天": "今天",
|
||||
"本月": "本月",
|
||||
"本年": "本年",
|
||||
"累计": "累计"
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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 %}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
41
wwwroot/sect_customer_currency.ui
Normal file
41
wwwroot/sect_customer_currency.ui
Normal 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"}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user