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,
|
'total_calls': total_calls,
|
||||||
'period': period,
|
'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]
|
||||||
|
|||||||
@ -16,5 +16,11 @@
|
|||||||
"今日活跃": "Today Active",
|
"今日活跃": "Today Active",
|
||||||
"在线用户": "Online Users",
|
"在线用户": "Online Users",
|
||||||
"成功率": "Success Rate",
|
"成功率": "Success Rate",
|
||||||
"失败数": "Failed"
|
"失败数": "Failed",
|
||||||
|
"币种成本收入": "Currency Cost & Revenue",
|
||||||
|
"币种费用": "Currency Expenses",
|
||||||
|
"今天": "Today",
|
||||||
|
"本月": "This Month",
|
||||||
|
"本年": "This Year",
|
||||||
|
"累计": "Cumulative"
|
||||||
}
|
}
|
||||||
@ -16,5 +16,11 @@
|
|||||||
"今日活跃": "本日アクティブ",
|
"今日活跃": "本日アクティブ",
|
||||||
"在线用户": "オンラインユーザー",
|
"在线用户": "オンラインユーザー",
|
||||||
"成功率": "成功率",
|
"成功率": "成功率",
|
||||||
"失败数": "失敗数"
|
"失败数": "失敗数",
|
||||||
|
"币种成本收入": "通貨コスト収入",
|
||||||
|
"币种费用": "通貨費用",
|
||||||
|
"今天": "今日",
|
||||||
|
"本月": "今月",
|
||||||
|
"本年": "今年",
|
||||||
|
"累计": "累計"
|
||||||
}
|
}
|
||||||
@ -16,5 +16,11 @@
|
|||||||
"今日活跃": "오늘 활성",
|
"今日活跃": "오늘 활성",
|
||||||
"在线用户": "온라인 사용자",
|
"在线用户": "온라인 사용자",
|
||||||
"成功率": "성공률",
|
"成功率": "성공률",
|
||||||
"失败数": "실패수"
|
"失败数": "실패수",
|
||||||
|
"币种成本收入": "통화 비용 수익",
|
||||||
|
"币种费用": "통화 비용",
|
||||||
|
"今天": "오늘",
|
||||||
|
"本月": "이번 달",
|
||||||
|
"本年": "올해",
|
||||||
|
"累计": "누계"
|
||||||
}
|
}
|
||||||
@ -16,5 +16,11 @@
|
|||||||
"今日活跃": "今日活跃",
|
"今日活跃": "今日活跃",
|
||||||
"在线用户": "在线用户",
|
"在线用户": "在线用户",
|
||||||
"成功率": "成功率",
|
"成功率": "成功率",
|
||||||
"失败数": "失败数"
|
"失败数": "失败数",
|
||||||
|
"币种成本收入": "币种成本收入",
|
||||||
|
"币种费用": "币种费用",
|
||||||
|
"今天": "今天",
|
||||||
|
"本月": "本月",
|
||||||
|
"本年": "本年",
|
||||||
|
"累计": "累计"
|
||||||
}
|
}
|
||||||
@ -462,6 +462,17 @@ async def j2_is_distributor(request):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return False
|
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 加载 ──
|
# ── 监控组件 j2 函数,每段独立 .ui 通过 RefreshWidget 加载 ──
|
||||||
|
|
||||||
async def j2_model_perf_data(request):
|
async def j2_model_perf_data(request):
|
||||||
@ -581,6 +592,7 @@ def load_sage_datamart():
|
|||||||
env.api_distributor_financial = api_distributor_financial
|
env.api_distributor_financial = api_distributor_financial
|
||||||
env.j2_distributor_financial = j2_distributor_financial
|
env.j2_distributor_financial = j2_distributor_financial
|
||||||
env.j2_is_distributor = j2_is_distributor
|
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_model_perf_data = j2_model_perf_data
|
||||||
env.j2_currency_data = j2_currency_data
|
env.j2_currency_data = j2_currency_data
|
||||||
env.j2_provider_roi_data = j2_provider_roi_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_user_apikeys.ui",
|
||||||
f"/{MOD}/sect_distributor_financial.ui",
|
f"/{MOD}/sect_distributor_financial.ui",
|
||||||
f"/{MOD}/sect_distributor_currency.ui",
|
f"/{MOD}/sect_distributor_currency.ui",
|
||||||
|
f"/{MOD}/sect_customer_currency.ui",
|
||||||
]
|
]
|
||||||
|
|
||||||
def run(role, path):
|
def run(role, path):
|
||||||
|
|||||||
@ -99,8 +99,16 @@
|
|||||||
"widgettype": "VBox",
|
"widgettype": "VBox",
|
||||||
"options": {"css": "card", "width": "40%", "padding": "16px"},
|
"options": {"css": "card", "width": "40%", "padding": "16px"},
|
||||||
"subwidgets": [
|
"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": "Title4", "options": {"fontWeight": "600", "otext": "币种分布", "i18n": true, "marginBottom": "8px"}},
|
||||||
{"widgettype": "RefreshWidget", "options": {"period_seconds": 60, "url": "{{entire_url('sect_currency.ui')}}", "width": "100%"}}
|
{"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