feat: 添加客户专属监控 - 组织级每日/每月模型调用统计
- 新增5个后端函数: customer_daily/monthly_models, daily/monthly_summary, daily_trend - 新增customer_usage.ui主页面: 4个汇总卡片 + 日趋势折线图 + 日/月模型柱状图 - 新增3个API端点(.dspy)和3个图表UI组件 - index.ui添加客户专属监控入口卡片 - RBAC权限配置已更新(load_path.py)
This commit is contained in:
parent
69b7ec5cd0
commit
929ee0e319
@ -269,6 +269,178 @@ async def get_user_today_models(request):
|
||||
return result
|
||||
|
||||
|
||||
# ── Customer (org-level) monitoring functions ──
|
||||
|
||||
|
||||
async def _get_org_id(request):
|
||||
"""Helper: get current user's org_id from request context."""
|
||||
env = request._run_ns
|
||||
org_id = await env.get_userorgid()
|
||||
return org_id or '0'
|
||||
|
||||
|
||||
async def get_customer_daily_models(request):
|
||||
"""获取当前客户组织当天各模型调用次数和金额"""
|
||||
env = request._run_ns
|
||||
org_id = await _get_org_id(request)
|
||||
today = env.curDateString()
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
COALESCE(b.name, 'Unknown') as model_name,
|
||||
COUNT(*) as cnt,
|
||||
COALESCE(SUM(a.amount), 0) as total_amount
|
||||
FROM llmusage a
|
||||
LEFT JOIN llm b ON a.llmid = b.id
|
||||
WHERE a.use_date = ${today}$
|
||||
AND a.userorgid = ${org_id}$
|
||||
GROUP BY a.llmid, b.name
|
||||
ORDER BY cnt DESC
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {'today': today, 'org_id': org_id})
|
||||
result = []
|
||||
for r in recs:
|
||||
result.append({
|
||||
'model_name': r.get('model_name', 'Unknown'),
|
||||
'cnt': int(r.get('cnt', 0)),
|
||||
'total_amount': round(float(r.get('total_amount', 0)), 4)
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
async def get_customer_monthly_models(request):
|
||||
"""获取当前客户组织当月各模型调用次数和金额"""
|
||||
env = request._run_ns
|
||||
org_id = await _get_org_id(request)
|
||||
now = datetime.now()
|
||||
month_start = now.strftime('%Y-%m-01')
|
||||
if now.month == 12:
|
||||
month_end = f'{now.year + 1}-01-01'
|
||||
else:
|
||||
month_end = f'{now.year}-{now.month + 1:02d}-01'
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
COALESCE(b.name, 'Unknown') as model_name,
|
||||
COUNT(*) as cnt,
|
||||
COALESCE(SUM(a.amount), 0) as total_amount
|
||||
FROM llmusage a
|
||||
LEFT JOIN llm b ON a.llmid = b.id
|
||||
WHERE a.use_date >= ${month_start}$
|
||||
AND a.use_date < ${month_end}$
|
||||
AND a.userorgid = ${org_id}$
|
||||
GROUP BY a.llmid, b.name
|
||||
ORDER BY cnt DESC
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {
|
||||
'month_start': month_start,
|
||||
'month_end': month_end,
|
||||
'org_id': org_id
|
||||
})
|
||||
result = []
|
||||
for r in recs:
|
||||
result.append({
|
||||
'model_name': r.get('model_name', 'Unknown'),
|
||||
'cnt': int(r.get('cnt', 0)),
|
||||
'total_amount': round(float(r.get('total_amount', 0)), 4)
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
async def get_customer_daily_summary(request):
|
||||
"""获取当前客户组织今日汇总(调用次数+金额)"""
|
||||
env = request._run_ns
|
||||
org_id = await _get_org_id(request)
|
||||
today = env.curDateString()
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
COUNT(*) as cnt,
|
||||
COALESCE(SUM(a.amount), 0) as total_amount
|
||||
FROM llmusage a
|
||||
WHERE a.use_date = ${today}$
|
||||
AND a.userorgid = ${org_id}$
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {'today': today, 'org_id': org_id})
|
||||
if recs:
|
||||
return {
|
||||
'cnt': int(recs[0].get('cnt', 0)),
|
||||
'total_amount': round(float(recs[0].get('total_amount', 0)), 4)
|
||||
}
|
||||
return {'cnt': 0, 'total_amount': 0}
|
||||
|
||||
|
||||
async def get_customer_month_summary(request):
|
||||
"""获取当前客户组织当月汇总(调用次数+金额)"""
|
||||
env = request._run_ns
|
||||
org_id = await _get_org_id(request)
|
||||
now = datetime.now()
|
||||
month_start = now.strftime('%Y-%m-01')
|
||||
if now.month == 12:
|
||||
month_end = f'{now.year + 1}-01-01'
|
||||
else:
|
||||
month_end = f'{now.year}-{now.month + 1:02d}-01'
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
COUNT(*) as cnt,
|
||||
COALESCE(SUM(a.amount), 0) as total_amount
|
||||
FROM llmusage a
|
||||
WHERE a.use_date >= ${month_start}$
|
||||
AND a.use_date < ${month_end}$
|
||||
AND a.userorgid = ${org_id}$
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {
|
||||
'month_start': month_start,
|
||||
'month_end': month_end,
|
||||
'org_id': org_id
|
||||
})
|
||||
if recs:
|
||||
return {
|
||||
'cnt': int(recs[0].get('cnt', 0)),
|
||||
'total_amount': round(float(recs[0].get('total_amount', 0)), 4)
|
||||
}
|
||||
return {'cnt': 0, 'total_amount': 0}
|
||||
|
||||
|
||||
async def get_customer_daily_trend(request):
|
||||
"""获取当前客户组织当月每日调用趋势(每天的调用次数和金额)"""
|
||||
env = request._run_ns
|
||||
org_id = await _get_org_id(request)
|
||||
now = datetime.now()
|
||||
month_start = now.strftime('%Y-%m-01')
|
||||
if now.month == 12:
|
||||
month_end = f'{now.year + 1}-01-01'
|
||||
else:
|
||||
month_end = f'{now.year}-{now.month + 1:02d}-01'
|
||||
async with get_sor_context(env, 'sage') as sor:
|
||||
sql = """
|
||||
SELECT
|
||||
a.use_date as date,
|
||||
COUNT(*) as cnt,
|
||||
COALESCE(SUM(a.amount), 0) as total_amount
|
||||
FROM llmusage a
|
||||
WHERE a.use_date >= ${month_start}$
|
||||
AND a.use_date < ${month_end}$
|
||||
AND a.userorgid = ${org_id}$
|
||||
GROUP BY a.use_date
|
||||
ORDER BY a.use_date ASC
|
||||
"""
|
||||
recs = await sor.sqlExe(sql, {
|
||||
'month_start': month_start,
|
||||
'month_end': month_end,
|
||||
'org_id': org_id
|
||||
})
|
||||
result = []
|
||||
for r in recs:
|
||||
result.append({
|
||||
'date': r.get('date', ''),
|
||||
'cnt': int(r.get('cnt', 0)),
|
||||
'total_amount': round(float(r.get('total_amount', 0)), 4)
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def load_dashboard():
|
||||
"""Register dashboard functions on ServerEnv"""
|
||||
g = ServerEnv()
|
||||
@ -286,3 +458,8 @@ def load_dashboard():
|
||||
g.get_new_users_month = get_new_users_month
|
||||
g.get_total_orgs = get_total_orgs
|
||||
g.get_user_today_models = get_user_today_models
|
||||
g.get_customer_daily_models = get_customer_daily_models
|
||||
g.get_customer_monthly_models = get_customer_monthly_models
|
||||
g.get_customer_daily_summary = get_customer_daily_summary
|
||||
g.get_customer_month_summary = get_customer_month_summary
|
||||
g.get_customer_daily_trend = get_customer_daily_trend
|
||||
|
||||
@ -69,9 +69,18 @@ paths = [
|
||||
("/dashboard_for_sage/top_models_chart.ui", "logined"),
|
||||
("/dashboard_for_sage/user_today_models_chart.ui", "logined"),
|
||||
|
||||
# Customer monitoring
|
||||
("/dashboard_for_sage/customer_usage.ui", "logined"),
|
||||
("/dashboard_for_sage/customer_daily_chart.ui", "logined"),
|
||||
("/dashboard_for_sage/customer_monthly_chart.ui", "logined"),
|
||||
("/dashboard_for_sage/customer_daily_trend.ui", "logined"),
|
||||
|
||||
# API endpoints
|
||||
("/dashboard_for_sage/api/top_models.dspy", "logined"),
|
||||
("/dashboard_for_sage/api/user_today_models.dspy", "logined"),
|
||||
("/dashboard_for_sage/api/customer_daily_models.dspy", "logined"),
|
||||
("/dashboard_for_sage/api/customer_monthly_models.dspy", "logined"),
|
||||
("/dashboard_for_sage/api/customer_daily_trend.dspy", "logined"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
6
wwwroot/api/customer_daily_models.dspy
Normal file
6
wwwroot/api/customer_daily_models.dspy
Normal file
@ -0,0 +1,6 @@
|
||||
# coding=utf-8
|
||||
"""Customer daily per-model usage data API for ChartBar"""
|
||||
import json
|
||||
|
||||
models = await get_customer_daily_models(request)
|
||||
return json.dumps(models, ensure_ascii=False, default=str)
|
||||
6
wwwroot/api/customer_daily_trend.dspy
Normal file
6
wwwroot/api/customer_daily_trend.dspy
Normal file
@ -0,0 +1,6 @@
|
||||
# coding=utf-8
|
||||
"""Customer daily trend data API for ChartLine (current month)"""
|
||||
import json
|
||||
|
||||
trend = await get_customer_daily_trend(request)
|
||||
return json.dumps(trend, ensure_ascii=False, default=str)
|
||||
6
wwwroot/api/customer_monthly_models.dspy
Normal file
6
wwwroot/api/customer_monthly_models.dspy
Normal file
@ -0,0 +1,6 @@
|
||||
# coding=utf-8
|
||||
"""Customer monthly per-model usage data API for ChartBar"""
|
||||
import json
|
||||
|
||||
models = await get_customer_monthly_models(request)
|
||||
return json.dumps(models, ensure_ascii=False, default=str)
|
||||
11
wwwroot/customer_daily_chart.ui
Normal file
11
wwwroot/customer_daily_chart.ui
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"widgettype": "ChartBar",
|
||||
"options": {
|
||||
"height": "300px",
|
||||
"width": "100%",
|
||||
"data_url": "{{entire_url('api/customer_daily_models.dspy')}}",
|
||||
"nameField": "model_name",
|
||||
"valueFields": ["cnt", "total_amount"],
|
||||
"refresh_period": 60
|
||||
}
|
||||
}
|
||||
11
wwwroot/customer_daily_trend.ui
Normal file
11
wwwroot/customer_daily_trend.ui
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"widgettype": "ChartLine",
|
||||
"options": {
|
||||
"height": "280px",
|
||||
"width": "100%",
|
||||
"data_url": "{{entire_url('api/customer_daily_trend.dspy')}}",
|
||||
"nameField": "date",
|
||||
"valueFields": ["cnt", "total_amount"],
|
||||
"refresh_period": 120
|
||||
}
|
||||
}
|
||||
11
wwwroot/customer_monthly_chart.ui
Normal file
11
wwwroot/customer_monthly_chart.ui
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"widgettype": "ChartBar",
|
||||
"options": {
|
||||
"height": "300px",
|
||||
"width": "100%",
|
||||
"data_url": "{{entire_url('api/customer_monthly_models.dspy')}}",
|
||||
"nameField": "model_name",
|
||||
"valueFields": ["cnt", "total_amount"],
|
||||
"refresh_period": 120
|
||||
}
|
||||
}
|
||||
462
wwwroot/customer_usage.ui
Normal file
462
wwwroot/customer_usage.ui
Normal file
@ -0,0 +1,462 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"height": "100%"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VScrollPanel",
|
||||
"options": {
|
||||
"css": "filler"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"alignItems": "center",
|
||||
"marginBottom": "24px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title2",
|
||||
"options": {
|
||||
"fontWeight": "700",
|
||||
"otext": "客户专属监控",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "返回首页",
|
||||
"borderRadius": "6px",
|
||||
"padding": "6px 16px",
|
||||
"fontSize": "13px"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sage_main_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('/dashboard_for_sage/index.ui')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "ResponsableBox",
|
||||
"options": {
|
||||
"gap": "16px",
|
||||
"minWidth": "220px",
|
||||
"marginBottom": "24px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "stat-card",
|
||||
"padding": "20px",
|
||||
"borderRadius": "12px",
|
||||
"flex": "1",
|
||||
"minHeight": "110px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"alignItems": "center",
|
||||
"marginBottom": "12px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 3v18h18\"/><path d=\"M18 17V9\"/><path d=\"M13 17V5\"/><path d=\"M8 17v-3\"/></svg>",
|
||||
"width": "24px",
|
||||
"height": "24px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "stat-value",
|
||||
"text": "{{get_customer_daily_summary(request).cnt}}",
|
||||
"fontSize": "32px",
|
||||
"fontWeight": "700",
|
||||
"lineHeight": "1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "stat-label",
|
||||
"fontSize": "14px",
|
||||
"marginTop": "4px",
|
||||
"otext": "今日调用次数",
|
||||
"i18n": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "stat-card",
|
||||
"padding": "20px",
|
||||
"borderRadius": "12px",
|
||||
"flex": "1",
|
||||
"minHeight": "110px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"alignItems": "center",
|
||||
"marginBottom": "12px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 6v12m6-6H6\"/></svg>",
|
||||
"width": "24px",
|
||||
"height": "24px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "stat-value",
|
||||
"text": "¥{{get_customer_daily_summary(request).total_amount|round(2)}}",
|
||||
"fontSize": "32px",
|
||||
"fontWeight": "700",
|
||||
"lineHeight": "1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "stat-label",
|
||||
"fontSize": "14px",
|
||||
"marginTop": "4px",
|
||||
"otext": "今日消费金额",
|
||||
"i18n": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "stat-card",
|
||||
"padding": "20px",
|
||||
"borderRadius": "12px",
|
||||
"flex": "1",
|
||||
"minHeight": "110px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"alignItems": "center",
|
||||
"marginBottom": "12px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"/><line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"/><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"/></svg>",
|
||||
"width": "24px",
|
||||
"height": "24px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "stat-value",
|
||||
"text": "{{get_customer_month_summary(request).cnt}}",
|
||||
"fontSize": "32px",
|
||||
"fontWeight": "700",
|
||||
"lineHeight": "1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "stat-label",
|
||||
"fontSize": "14px",
|
||||
"marginTop": "4px",
|
||||
"otext": "本月调用次数",
|
||||
"i18n": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "stat-card",
|
||||
"padding": "20px",
|
||||
"borderRadius": "12px",
|
||||
"flex": "1",
|
||||
"minHeight": "110px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"alignItems": "center",
|
||||
"marginBottom": "12px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"23\"/><path d=\"M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6\"/></svg>",
|
||||
"width": "24px",
|
||||
"height": "24px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "stat-value",
|
||||
"text": "¥{{get_customer_month_summary(request).total_amount|round(2)}}",
|
||||
"fontSize": "32px",
|
||||
"fontWeight": "700",
|
||||
"lineHeight": "1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"css": "stat-label",
|
||||
"fontSize": "14px",
|
||||
"marginTop": "4px",
|
||||
"otext": "本月消费金额",
|
||||
"i18n": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"width": "100%",
|
||||
"borderRadius": "12px",
|
||||
"padding": "20px",
|
||||
"marginBottom": "20px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"alignItems": "center",
|
||||
"marginBottom": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"fontWeight": "600",
|
||||
"otext": "本月每日调用趋势",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "刷新",
|
||||
"border": "none",
|
||||
"borderRadius": "6px",
|
||||
"padding": "4px 12px",
|
||||
"fontSize": "12px"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "method",
|
||||
"target": "-@ChartLine",
|
||||
"method": "render_urldata",
|
||||
"params": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "urlwidget",
|
||||
"options": {
|
||||
"url": "{{entire_url('customer_daily_trend.ui')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"gap": "20px",
|
||||
"marginBottom": "20px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"width": "50%",
|
||||
"borderRadius": "12px",
|
||||
"padding": "20px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"alignItems": "center",
|
||||
"marginBottom": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"fontWeight": "600",
|
||||
"otext": "今日各模型调用",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "刷新",
|
||||
"border": "none",
|
||||
"borderRadius": "6px",
|
||||
"padding": "4px 12px",
|
||||
"fontSize": "12px"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "method",
|
||||
"target": "-@ChartBar",
|
||||
"method": "render_urldata",
|
||||
"params": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "urlwidget",
|
||||
"options": {
|
||||
"url": "{{entire_url('customer_daily_chart.ui')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"width": "50%",
|
||||
"borderRadius": "12px",
|
||||
"padding": "20px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"alignItems": "center",
|
||||
"marginBottom": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"fontWeight": "600",
|
||||
"otext": "本月各模型调用",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "刷新",
|
||||
"border": "none",
|
||||
"borderRadius": "6px",
|
||||
"padding": "4px 12px",
|
||||
"fontSize": "12px"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "method",
|
||||
"target": "-@ChartBar",
|
||||
"method": "render_urldata",
|
||||
"params": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "urlwidget",
|
||||
"options": {
|
||||
"url": "{{entire_url('customer_monthly_chart.ui')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -471,6 +471,82 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"width": "100%",
|
||||
"borderRadius": "12px",
|
||||
"padding": "20px",
|
||||
"marginTop": "20px",
|
||||
"cursor": "pointer"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sage_main_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('/dashboard_for_sage/customer_usage.ui')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"alignItems": "center"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 3v18h18\"/><path d=\"M18 17V9\"/><path d=\"M13 17V5\"/><path d=\"M8 17v-3\"/></svg>",
|
||||
"width": "28px",
|
||||
"height": "28px",
|
||||
"marginRight": "12px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"fontWeight": "600",
|
||||
"otext": "客户专属监控",
|
||||
"i18n": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"fontSize": "13px",
|
||||
"otext": "查看本组织各模型每日/每月调用次数与金额统计",
|
||||
"i18n": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
},
|
||||
{
|
||||
"widgettype": "Svg",
|
||||
"options": {
|
||||
"svg": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"9 18 15 12 9 6\"/></svg>",
|
||||
"width": "24px",
|
||||
"height": "24px"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user