forked from xiaohei/taiji-AI-PAD
466 lines
10 KiB
Markdown
466 lines
10 KiB
Markdown
# 计费仪表板概览接口文档
|
||
|
||
## 接口信息
|
||
|
||
**接口路径**: `GET /api/user/dashboard/billing-overview`
|
||
|
||
**功能**: 获取用户计费和资源使用的完整仪表板数据
|
||
|
||
**认证**: 需要 Bearer Token
|
||
|
||
**权限**: 租户用户(user角色)
|
||
|
||
---
|
||
|
||
## 响应数据结构
|
||
|
||
### 完整示例
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "成功获取仪表板数据",
|
||
"data": {
|
||
"currentMonth": {
|
||
"spent": 1250.50,
|
||
"euConsumed": 12505.0,
|
||
"avgDailySpent": 125.05,
|
||
"predictedTotal": 3876.55,
|
||
"daysElapsed": 10,
|
||
"totalDays": 31,
|
||
"currency": "CNY"
|
||
},
|
||
"lastMonth": {
|
||
"spent": 1000.00,
|
||
"euConsumed": 10000.0
|
||
},
|
||
"comparison": {
|
||
"percentage": 25.1,
|
||
"direction": "up"
|
||
},
|
||
"balance": {
|
||
"eu": 50000.0,
|
||
"cash": 50000.0
|
||
},
|
||
"euHistory": [
|
||
{
|
||
"date": "2026-01-01",
|
||
"euConsumed": 1200.5,
|
||
"cost": 120.05,
|
||
"calls": 150
|
||
},
|
||
{
|
||
"date": "2026-01-02",
|
||
"euConsumed": 1350.0,
|
||
"cost": 135.00,
|
||
"calls": 180
|
||
}
|
||
],
|
||
"costBreakdown": {
|
||
"categories": [
|
||
{
|
||
"category": "platform_agent",
|
||
"name": "平台Agent",
|
||
"cost": 450.50,
|
||
"percentage": 36.0
|
||
},
|
||
{
|
||
"category": "custom_agent",
|
||
"name": "自定义Agent",
|
||
"cost": 350.00,
|
||
"percentage": 28.0
|
||
},
|
||
{
|
||
"category": "model_api",
|
||
"name": "模型API",
|
||
"cost": 400.00,
|
||
"percentage": 32.0
|
||
},
|
||
{
|
||
"category": "other",
|
||
"name": "其他",
|
||
"cost": 50.00,
|
||
"percentage": 4.0
|
||
}
|
||
],
|
||
"total": 1250.50
|
||
},
|
||
"resourceUsage": {
|
||
"resources": [
|
||
{
|
||
"type": "cpu",
|
||
"name": "CPU",
|
||
"used": 2.5,
|
||
"limit": 10.0,
|
||
"unit": "核",
|
||
"percentage": 25.0
|
||
},
|
||
{
|
||
"type": "memory",
|
||
"name": "内存",
|
||
"used": 5.0,
|
||
"limit": 20.0,
|
||
"unit": "GB",
|
||
"percentage": 25.0
|
||
},
|
||
{
|
||
"type": "storage",
|
||
"name": "存储",
|
||
"used": 0,
|
||
"limit": 1000,
|
||
"unit": "GB",
|
||
"percentage": 0.0
|
||
},
|
||
{
|
||
"type": "api_calls",
|
||
"name": "API调用",
|
||
"used": 15000,
|
||
"limit": 100000,
|
||
"unit": "次",
|
||
"percentage": 15.0
|
||
}
|
||
]
|
||
},
|
||
"metadata": {
|
||
"timestamp": "2026-01-10T12:30:45.123456",
|
||
"userId": "550e8400-e29b-41d4-a716-446655440000"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 数据字段说明
|
||
|
||
### currentMonth (当前月份统计)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| spent | float | 本月已消费金额(CNY) |
|
||
| euConsumed | float | 本月已消费EU(执行单位) |
|
||
| avgDailySpent | float | 平均每日消费金额 |
|
||
| predictedTotal | float | 预计月底总消费(基于日均值) |
|
||
| daysElapsed | int | 本月已过天数 |
|
||
| totalDays | int | 本月总天数 |
|
||
| currency | string | 货币类型(CNY) |
|
||
|
||
### lastMonth (上月统计)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| spent | float | 上月总消费金额 |
|
||
| euConsumed | float | 上月总消费EU |
|
||
|
||
### comparison (对比数据)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| percentage | float | 与上月对比的百分比变化 |
|
||
| direction | string | 趋势方向:`up`(上升)、`down`(下降)、`stable`(持平) |
|
||
|
||
### balance (余额信息)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| eu | float | 当前EU余额(1 EU = 1 美元) |
|
||
| cash | float | 当前现金余额(美元),与 eu 相等(1 美元 = 1 EU) |
|
||
|
||
### euHistory (EU消费历史)
|
||
|
||
数组,每个元素包含:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| date | string | 日期(ISO格式:YYYY-MM-DD) |
|
||
| euConsumed | float | 当日消费的EU |
|
||
| cost | float | 当日费用 |
|
||
| calls | int | 当日调用次数 |
|
||
|
||
**时间范围**: 最近30天的数据
|
||
|
||
### costBreakdown (费用明细)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| categories | array | 费用分类数组 |
|
||
| total | float | 总费用 |
|
||
|
||
**categories数组元素**:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| category | string | 分类标识:`platform_agent`、`custom_agent`、`model_api`、`other` |
|
||
| name | string | 分类名称 |
|
||
| cost | float | 该分类的费用 |
|
||
| percentage | float | 占总费用的百分比 |
|
||
|
||
### resourceUsage (资源使用)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| resources | array | 资源使用数组 |
|
||
|
||
**resources数组元素**:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| type | string | 资源类型:`cpu`、`memory`、`storage`、`api_calls` |
|
||
| name | string | 资源名称 |
|
||
| used | float/int | 已使用量 |
|
||
| limit | float/int | 配额上限 |
|
||
| unit | string | 单位:`核`、`GB`、`次` |
|
||
| percentage | float | 使用百分比 |
|
||
|
||
### metadata (元数据)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| timestamp | string | 数据生成时间(ISO 8601格式) |
|
||
| userId | string | 用户ID(UUID格式) |
|
||
|
||
---
|
||
|
||
## 前端调用示例
|
||
|
||
### JavaScript/TypeScript
|
||
|
||
```javascript
|
||
// 使用fetch
|
||
async function getBillingOverview() {
|
||
try {
|
||
const response = await fetch('/api/user/dashboard/billing-overview', {
|
||
method: 'GET',
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`,
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
return data.data;
|
||
} else {
|
||
throw new Error(data.message || '获取数据失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('获取计费概览失败:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
// 使用axios
|
||
import axios from 'axios';
|
||
|
||
async function getBillingOverviewAxios() {
|
||
try {
|
||
const response = await axios.get('/api/user/dashboard/billing-overview', {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
|
||
return response.data.data;
|
||
} catch (error) {
|
||
console.error('获取计费概览失败:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
```
|
||
|
||
### React示例
|
||
|
||
```typescript
|
||
import { useState, useEffect } from 'react';
|
||
import axios from 'axios';
|
||
|
||
interface BillingOverview {
|
||
currentMonth: {
|
||
spent: number;
|
||
euConsumed: number;
|
||
avgDailySpent: number;
|
||
predictedTotal: number;
|
||
daysElapsed: number;
|
||
totalDays: number;
|
||
currency: string;
|
||
};
|
||
lastMonth: {
|
||
spent: number;
|
||
euConsumed: number;
|
||
};
|
||
comparison: {
|
||
percentage: number;
|
||
direction: 'up' | 'down' | 'stable';
|
||
};
|
||
balance: {
|
||
eu: number;
|
||
cash: number;
|
||
};
|
||
euHistory: Array<{
|
||
date: string;
|
||
euConsumed: number;
|
||
cost: number;
|
||
calls: number;
|
||
}>;
|
||
costBreakdown: {
|
||
categories: Array<{
|
||
category: string;
|
||
name: string;
|
||
cost: number;
|
||
percentage: number;
|
||
}>;
|
||
total: number;
|
||
};
|
||
resourceUsage: {
|
||
resources: Array<{
|
||
type: string;
|
||
name: string;
|
||
used: number;
|
||
limit: number;
|
||
unit: string;
|
||
percentage: number;
|
||
}>;
|
||
};
|
||
}
|
||
|
||
function BillingDashboard() {
|
||
const [overview, setOverview] = useState<BillingOverview | null>(null);
|
||
const [loading, setLoading] = useState(true);
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
useEffect(() => {
|
||
async function fetchData() {
|
||
try {
|
||
setLoading(true);
|
||
const response = await axios.get('/api/user/dashboard/billing-overview', {
|
||
headers: {
|
||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||
}
|
||
});
|
||
|
||
if (response.data.success) {
|
||
setOverview(response.data.data);
|
||
} else {
|
||
setError(response.data.message || '获取数据失败');
|
||
}
|
||
} catch (err) {
|
||
setError('网络请求失败');
|
||
console.error(err);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
|
||
fetchData();
|
||
}, []);
|
||
|
||
if (loading) return <div>加载中...</div>;
|
||
if (error) return <div>错误: {error}</div>;
|
||
if (!overview) return <div>暂无数据</div>;
|
||
|
||
return (
|
||
<div className="billing-dashboard">
|
||
{/* 本月费用 */}
|
||
<div className="current-month">
|
||
<h2>本月费用</h2>
|
||
<p>已消费: ¥{overview.currentMonth.spent.toFixed(2)}</p>
|
||
<p>平均每日: ¥{overview.currentMonth.avgDailySpent.toFixed(2)}</p>
|
||
<p>预计月底: ¥{overview.currentMonth.predictedTotal.toFixed(2)}</p>
|
||
</div>
|
||
|
||
{/* EU消费历史图表 */}
|
||
<div className="eu-history">
|
||
<h2>EU消费历史</h2>
|
||
{/* 这里可以使用图表库如Chart.js、ECharts等 */}
|
||
{overview.euHistory.map(item => (
|
||
<div key={item.date}>
|
||
{item.date}: {item.euConsumed} EU
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* 费用明细 */}
|
||
<div className="cost-breakdown">
|
||
<h2>费用明细</h2>
|
||
{overview.costBreakdown.categories.map(cat => (
|
||
<div key={cat.category}>
|
||
{cat.name}: ¥{cat.cost.toFixed(2)} ({cat.percentage.toFixed(1)}%)
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* 资源使用 */}
|
||
<div className="resource-usage">
|
||
<h2>资源使用</h2>
|
||
{overview.resourceUsage.resources.map(res => (
|
||
<div key={res.type}>
|
||
<div>{res.name}</div>
|
||
<progress value={res.percentage} max={100}></progress>
|
||
<span>{res.used} / {res.limit} {res.unit}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default BillingDashboard;
|
||
```
|
||
|
||
---
|
||
|
||
## 错误响应
|
||
|
||
### 401 未授权
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"error": {
|
||
"code": "UNAUTHORIZED",
|
||
"message": "未提供有效的认证令牌"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 500 服务器错误
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"error": {
|
||
"code": "INTERNAL_ERROR",
|
||
"message": "服务器内部错误"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 性能优化建议
|
||
|
||
1. **缓存策略**: 建议前端缓存数据5分钟,避免频繁请求
|
||
2. **按需加载**: 可以考虑将历史数据单独请求
|
||
3. **数据轮询**: 如需实时更新,建议轮询间隔不少于30秒
|
||
|
||
---
|
||
|
||
## 更新日志
|
||
|
||
| 版本 | 日期 | 说明 |
|
||
|------|------|------|
|
||
| v1.0.0 | 2026-01-10 | 初始版本,实现完整仪表板数据接口 |
|
||
|
||
---
|
||
|
||
## 相关接口
|
||
|
||
- `GET /api/user/dashboard/stats` - 基础仪表板统计
|
||
- `GET /api/user/billing/balance` - 余额查询
|
||
- `GET /api/user/billing/history` - 计费历史
|