监控大屏 API 提供树状层级的消费数据汇总,用于平台监控大屏展示。
层级结构:平台 → 超级管理员 → 租户 → 用户
每条消费记录包含三级折扣及对应金额:用户折扣、企业折扣、超管折扣。
-- 迁移文件:migrations/060_create_super_admin_tenant_table.sql
psql -d your_database -f migrations/060_create_super_admin_tenant_table.sql
-- 迁移文件:migrations/063_create_super_admin_model_discount_table.sql
psql -d your_database -f migrations/063_create_super_admin_model_discount_table.sql
迁移执行后,需要往 super_admin_tenant 表写入关联关系:
-- 示例:将租户 1、2、3 分配给超级管理员 1
INSERT INTO aigcspace.super_admin_tenant (super_admin_id, tenant_id) VALUES
(1, 1),
(1, 2),
(1, 3);
-- 将租户 4、5 分配给超级管理员 2
INSERT INTO aigcspace.super_admin_tenant (super_admin_id, tenant_id) VALUES
(2, 4),
(2, 5);
注意:未关联到任何超级管理员的租户会归入"未分配租户"节点展示。
超管折扣从 crawler API 同步到数据库,可通过爬虫自动同步或手动触发:
# 手动同步(爬虫同步时会自动写入超管折扣表)
python -c "from app.services.crawler_sync_service import _fetch_crawler_discounts_for_sync; print(_fetch_crawler_discounts_for_sync(db))"
或通过超管后台接口手动同步:
POST /api/super/super-admin/discounts/sync
# 开发环境
python main.py
# 生产环境
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8010
GET /api/public/monitoring/dashboard
公共接口,无需鉴权
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
start_date |
string | 否 | 查询开始日期,格式 YYYY-MM-DD,不传则查全部 |
end_date |
string | 否 | 查询结束日期,格式 YYYY-MM-DD,不传则查全部 |
super_admin_id |
integer | 否 | 指定某个超级管理员ID,不传则查全部 |
# 查询全部
curl -X GET "http://localhost:8010/api/public/monitoring/dashboard"
# 按时间范围查询
curl -X GET "http://localhost:8010/api/public/monitoring/dashboard?start_date=2026-01-01&end_date=2026-05-12"
# 查询某个超级管理员
curl -X GET "http://localhost:8010/api/public/monitoring/dashboard?super_admin_id=1"
{
"overview": {
"total_super_admins": 3,
"total_tenants": 15,
"total_users": 200,
"total_consumption": "12500.0000",
"total_tenant_charged": "9800.0000",
"total_balance": "50000.0000"
},
"super_admins": [
{
"super_admin_id": 1,
"username": "admin1",
"nickname": "管理员A",
"tenant_count": 5,
"total_consumption": "8000.0000",
"total_tenant_charged": "6400.0000",
"tenants": [
{
"tenant_id": 1,
"company_name": "成都网讯",
"subdomain": "wangxun",
"total_consumption": "3000.0000",
"total_tenant_charged": "2400.0000",
"balance": "10000.0000",
"user_count": 20,
"users": [
{
"user_id": "u001",
"username": "zhangsan",
"nickname": "张三",
"total_consumption": "500.0000",
"tenant_actual_total": "400.0000",
"consumption_records": [
{
"user_id": "u001",
"username": "zhangsan",
"tenant_name": "成都网讯",
"order_no": "20260508194831_ai_conversation_xxx",
"model_name": "通义千问Plus",
"model_code": "qwen-plus",
"amount": "0.0040",
"created_at": "2026-05-08T19:48:31",
"invoiced": false,
"user_discount": "0.9000",
"user_actual_price": "0.0040",
"tenant_discount": "0.8000",
"tenant_actual_price": "0.0036",
"super_admin_discount": "0.8000",
"super_admin_actual_price": "0.0036"
}
]
}
]
}
]
}
],
"start_date": "2026-01-01",
"end_date": "2026-05-12"
}
overview)| 字段 | 类型 | 说明 |
|---|---|---|
total_super_admins |
integer | 超级管理员数量 |
total_tenants |
integer | 租户总数 |
total_users |
integer | 用户总数 |
total_consumption |
string(Decimal) | 平台总消费金额(元),即所有用户实际支付之和 |
total_tenant_charged |
string(Decimal) | 平台向企业收取总额(元),即用户实际支付 / 用户折扣 × 企业折扣 |
total_balance |
string(Decimal) | 所有企业当前余额合计(元) |
super_admins[])| 字段 | 类型 | 说明 |
|---|---|---|
super_admin_id |
integer | 超级管理员ID |
username |
string | 管理员用户名 |
nickname |
string | 管理员昵称 |
tenant_count |
integer | 管辖的租户数量 |
total_consumption |
string(Decimal) | 管辖范围内所有用户消费总额 |
total_tenant_charged |
string(Decimal) | 管辖范围内平台向企业收取总额 |
tenants |
array | 管辖的租户列表 |
过滤规则:该超管管辖范围内没有任何有消费记录的租户时,该节点仍会返回但
tenants为空数组。
tenants[])| 字段 | 类型 | 说明 |
|---|---|---|
tenant_id |
integer | 租户ID |
company_name |
string | 企业名称 |
subdomain |
string | 二级域名前缀 |
total_consumption |
string(Decimal) | 该租户下所有用户消费总额 |
total_tenant_charged |
string(Decimal) | 平台向该企业收取的总额 |
balance |
string(Decimal) | 企业当前余额 |
user_count |
integer | 用户数量 |
users |
array | 用户消费列表(仅包含有消费记录的用户) |
过滤规则:租户下所有用户在查询时间范围内均无消费记录时,该租户节点被过滤不返回。
users[])| 字段 | 类型 | 说明 |
|---|---|---|
user_id |
string | 用户ID |
username |
string | 用户名 |
nickname |
string | 用户昵称 |
total_consumption |
string(Decimal) | 用户累计消费(用户实际支付金额) |
tenant_actual_total |
string(Decimal) | 企业为该用户实际被平台收取的总额 |
consumption_records |
array | 该用户的消费记录流水(扁平列表) |
过滤规则:用户在查询时间范围内无消费记录时,该用户节点被过滤不返回。
consumption_records[])每条记录包含用户信息、消费明细和三级折扣及金额:
| 字段 | 类型 | 说明 |
|---|---|---|
user_id |
string | 用户ID |
username |
string | 用户名 |
tenant_name |
string | 所属租户名称(NULL表示平台直属用户) |
order_no |
string | 订单号(对应 balance_log.biz_order_no) |
model_name |
string | 模型显示名称 |
model_code |
string | 模型标识(如 qwen-plus) |
amount |
string(Decimal) | 消费金额(用户实际支付) |
created_at |
string(datetime) | 消费时间 |
invoiced |
boolean | 是否已开票 |
user_discount |
string(Decimal) | 用户折扣率(0~1,如 0.9 表示9折) |
user_actual_price |
string(Decimal) | 用户实际支付金额 |
tenant_discount |
string(Decimal) | 企业折扣率(0~1,如 0.8 表示8折) |
tenant_actual_price |
string(Decimal) | 企业实际支付金额 |
super_admin_discount |
string(Decimal) | 超级管理员折扣率(从 crawler API 同步) |
super_admin_actual_price |
string(Decimal) | 平台向超管收取金额 |
平台原价
│
├── 超管折扣率 (super_admin_discount) → 平台向超管收取 (super_admin_actual_price)
│ = amount / user_discount × super_admin_discount
│
├── 企业折扣率 (tenant_discount) → 企业实际支付 (tenant_actual_price)
│ = amount / user_discount × tenant_discount
│
└── 用户折扣率 (user_discount) → 用户实际支付 (user_actual_price)
= amount(user_consumption.amount 已为用户折扣后的价格)
计算公式:
| 层级 | 折扣率来源 | 实际支付计算 |
|---|---|---|
| 用户 | user_model_discount 表 |
user_actual_price = amount |
| 企业 | tenant_model_discount 表 |
tenant_actual_price = amount / user_discount × tenant_discount |
| 超管 | super_admin_model_discount 表(crawler 同步) |
super_admin_actual_price = amount / user_discount × super_admin_discount |
关键区别:
user_actual_price:用户实际掏的钱(用户余额扣减)tenant_actual_price:平台从企业账户扣的钱(企业余额扣减)super_admin_actual_price:平台向超管收取的金额超管折扣存储在 super_admin_model_discount 表中,通过爬虫同步服务自动更新:
model_code = "*"model_code = 具体模型标识*import { ref, onMounted } from 'vue'
const dashboardData = ref(null)
async function fetchDashboard(startDate, endDate) {
const params = new URLSearchParams()
if (startDate) params.append('start_date', startDate)
if (endDate) params.append('end_date', endDate)
const res = await fetch(`/api/public/monitoring/dashboard?${params}`)
dashboardData.value = await res.json()
}
// 扁平化所有用户的消费记录
function flattenRecords(data) {
const records = []
for (const sa of data.super_admins) {
for (const tenant of sa.tenants) {
for (const user of tenant.users) {
for (const record of user.consumption_records) {
records.push(record)
}
}
}
}
return records.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
}
// 从消费记录中按模型聚合
function aggregateByModel(dashboardData) {
const modelMap = {}
for (const sa of dashboardData.super_admins) {
for (const tenant of sa.tenants) {
for (const user of tenant.users) {
for (const record of user.consumption_records) {
const key = record.model_code
if (!modelMap[key]) {
modelMap[key] = {
model_code: record.model_code,
model_name: record.model_name,
total_amount: 0,
user_total: 0,
tenant_total: 0,
super_admin_total: 0,
count: 0
}
}
modelMap[key].total_amount += parseFloat(record.amount)
modelMap[key].user_total += parseFloat(record.user_actual_price)
modelMap[key].tenant_total += parseFloat(record.tenant_actual_price)
modelMap[key].super_admin_total += parseFloat(record.super_admin_actual_price)
modelMap[key].count += 1
}
}
}
}
return Object.values(modelMap).sort((a, b) => b.total_amount - a.total_amount)
}
A: 接口默认过滤 total_consumption = 0 的用户和租户。只有查询时间范围内有真实消费记录的节点才会返回。
A: 如果某个租户没有在 super_admin_tenant 表中关联任何超级管理员,该租户会归入 super_admin_id=0, nickname="未分配租户" 的特殊节点。
A: 折扣率 1.0 表示没有折扣(原价)。0.8 表示8折,用户只需支付原价的80%。
A: 超管折扣通过爬虫服务 sync_from_crawler 自动同步。爬虫每次同步模型数据时,会将折扣写入 super_admin_model_discount 表。也可通过超管后台 POST /api/super/super-admin/discounts/sync 手动触发同步。
A: start_date 和 end_date 过滤 user_consumption 表的 created_at 字段。企业余额是实时快照不受时间过滤。
A: 可以通过 super_admin_id 参数只查某个管理员的数据,减少返回量。