512 lines
12 KiB
Markdown
512 lines
12 KiB
Markdown
# API调用记录和钱包交易记录前端功能说明
|
||
|
||
## 概述
|
||
|
||
本文档描述了新增的API调用记录和钱包交易记录前端页面功能,包括页面设计、交互逻辑和技术实现。
|
||
|
||
## 页面功能
|
||
|
||
### 1. API调用记录页面 (`/api/usage`)
|
||
|
||
#### 页面布局
|
||
- **标题**: "调用记录"
|
||
- **副标题**: "查看您的API调用历史记录"
|
||
- **布局组件**: `ListPageLayout`
|
||
|
||
#### 功能模块
|
||
|
||
##### 1.1 统计信息区域
|
||
- **总调用次数**: 显示用户的总API调用次数
|
||
- **成功率**: 显示API调用的成功率百分比
|
||
- **样式**: 卡片式设计,带有渐变背景和阴影效果
|
||
|
||
##### 1.2 筛选功能
|
||
- **搜索调用**: 支持按交易ID或产品名称搜索
|
||
- **调用状态**: 下拉选择(全部/成功/失败/处理中)
|
||
- **时间范围**: 日期时间范围选择器
|
||
- **操作按钮**: 重置筛选、应用筛选
|
||
|
||
##### 1.3 数据表格
|
||
**列定义**:
|
||
- **交易ID**: 显示API调用的唯一标识
|
||
- **接口名称**: 显示调用的API接口名称和ID
|
||
- **状态**: 状态标签(成功/失败/处理中)
|
||
- **费用**: 显示调用产生的费用
|
||
- **客户端IP**: 显示调用来源IP
|
||
- **调用时间**: 显示API调用的开始时间
|
||
- **完成时间**: 显示API调用的完成时间
|
||
- **操作**: 查看详情按钮
|
||
|
||
##### 1.4 详情弹窗
|
||
**显示内容**:
|
||
- **基本信息**: 交易ID、状态、接口名称、费用、客户端IP
|
||
- **时间信息**: 调用时间、完成时间
|
||
- **错误信息**: 错误类型和错误消息(如果有)
|
||
- **请求参数**: JSON格式的请求参数
|
||
- **响应数据**: JSON格式的响应数据
|
||
|
||
##### 1.5 分页功能
|
||
- **分页器**: 支持页码跳转、每页数量选择
|
||
- **统计信息**: 显示总记录数和当前页信息
|
||
|
||
#### 交互逻辑
|
||
|
||
##### 搜索功能
|
||
```javascript
|
||
// 防抖搜索,避免频繁请求
|
||
const handleSearch = () => {
|
||
if (searchTimer) {
|
||
clearTimeout(searchTimer)
|
||
}
|
||
searchTimer = setTimeout(() => {
|
||
currentPage.value = 1
|
||
loadApiCalls()
|
||
}, 500)
|
||
}
|
||
```
|
||
|
||
##### 筛选功能
|
||
```javascript
|
||
// 处理筛选变化
|
||
const handleFilterChange = () => {
|
||
currentPage.value = 1
|
||
loadApiCalls()
|
||
}
|
||
|
||
// 处理时间范围变化
|
||
const handleDateRangeChange = (range) => {
|
||
if (range && range.length === 2) {
|
||
filters.start_time = range[0]
|
||
filters.end_time = range[1]
|
||
} else {
|
||
filters.start_time = ''
|
||
filters.end_time = ''
|
||
}
|
||
currentPage.value = 1
|
||
loadApiCalls()
|
||
}
|
||
```
|
||
|
||
##### 数据加载
|
||
```javascript
|
||
// 加载API调用记录
|
||
const loadApiCalls = async () => {
|
||
loading.value = true
|
||
try {
|
||
const params = {
|
||
page: currentPage.value,
|
||
page_size: pageSize.value,
|
||
...filters
|
||
}
|
||
|
||
const response = await apiApi.getUserApiCalls(params)
|
||
apiCalls.value = response.data?.items || []
|
||
total.value = response.data?.total || 0
|
||
} catch (error) {
|
||
console.error('加载API调用记录失败:', error)
|
||
ElMessage.error('加载API调用记录失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 钱包交易记录页面 (`/finance/transactions`)
|
||
|
||
#### 页面布局
|
||
- **标题**: "消费记录"
|
||
- **副标题**: "查看您的钱包消费历史记录"
|
||
- **布局组件**: `ListPageLayout`
|
||
|
||
#### 功能模块
|
||
|
||
##### 2.1 统计信息区域
|
||
- **总消费次数**: 显示用户的总消费次数
|
||
- **总消费金额**: 显示用户的总消费金额
|
||
- **样式**: 卡片式设计,金额显示为红色突出
|
||
|
||
##### 2.2 筛选功能
|
||
- **搜索交易**: 支持按API调用ID搜索
|
||
- **金额范围**: 最小金额和最大金额输入框
|
||
- **时间范围**: 日期时间范围选择器
|
||
- **操作按钮**: 重置筛选、应用筛选
|
||
|
||
##### 2.3 数据表格
|
||
**列定义**:
|
||
- **交易ID**: 显示钱包交易的唯一标识
|
||
- **API调用ID**: 显示关联的API调用ID
|
||
- **消费金额**: 显示消费金额(红色突出)
|
||
- **消费时间**: 显示交易创建时间
|
||
- **更新时间**: 显示交易最后更新时间
|
||
- **操作**: 查看详情按钮
|
||
|
||
##### 2.4 详情弹窗
|
||
**显示内容**:
|
||
- **基本信息**: 交易ID、用户ID、API调用ID、消费金额
|
||
- **时间信息**: 创建时间、更新时间
|
||
- **交易说明**: 解释交易记录的用途和含义
|
||
|
||
##### 2.5 分页功能
|
||
- **分页器**: 支持页码跳转、每页数量选择
|
||
- **统计信息**: 显示总记录数和当前页信息
|
||
|
||
#### 交互逻辑
|
||
|
||
##### 数据加载
|
||
```javascript
|
||
// 加载钱包交易记录
|
||
const loadTransactions = async () => {
|
||
loading.value = true
|
||
try {
|
||
const params = {
|
||
page: currentPage.value,
|
||
page_size: pageSize.value,
|
||
...filters
|
||
}
|
||
|
||
const response = await financeApi.getUserWalletTransactions(params)
|
||
transactions.value = response.data?.items || []
|
||
total.value = response.data?.total || 0
|
||
} catch (error) {
|
||
console.error('加载钱包交易记录失败:', error)
|
||
ElMessage.error('加载钱包交易记录失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
```
|
||
|
||
##### 统计计算
|
||
```javascript
|
||
// 加载统计数据
|
||
const loadStats = async () => {
|
||
try {
|
||
// 计算统计数据
|
||
const totalAmount = transactions.value.reduce((sum, transaction) => {
|
||
return sum + Number(transaction.amount || 0)
|
||
}, 0)
|
||
|
||
stats.value = {
|
||
total_transactions: total.value,
|
||
total_amount: totalAmount
|
||
}
|
||
} catch (error) {
|
||
console.error('加载统计数据失败:', error)
|
||
}
|
||
}
|
||
```
|
||
|
||
## 技术实现
|
||
|
||
### 1. 组件架构
|
||
|
||
#### 通用组件
|
||
- **ListPageLayout**: 列表页面布局组件
|
||
- **FilterSection**: 筛选区域组件
|
||
- **FilterItem**: 筛选项组件
|
||
- **LoadingSpinner**: 加载动画组件
|
||
|
||
#### 页面组件
|
||
- **Usage.vue**: API调用记录页面
|
||
- **Transactions.vue**: 钱包交易记录页面
|
||
|
||
### 2. API接口
|
||
|
||
#### API调用记录接口
|
||
```javascript
|
||
// API相关接口
|
||
export const apiApi = {
|
||
// 用户API调用记录
|
||
getUserApiCalls: (params) => request.get('/api/v1/my/api-calls', { params })
|
||
}
|
||
```
|
||
|
||
#### 钱包交易记录接口
|
||
```javascript
|
||
// 财务相关接口
|
||
export const financeApi = {
|
||
// 钱包交易记录
|
||
getUserWalletTransactions: (params) => request.get('/finance/wallet/transactions', { params })
|
||
}
|
||
```
|
||
|
||
### 3. 状态管理
|
||
|
||
#### 响应式数据
|
||
```javascript
|
||
// 页面数据
|
||
const loading = ref(false)
|
||
const apiCalls = ref([])
|
||
const total = ref(0)
|
||
const currentPage = ref(1)
|
||
const pageSize = ref(10)
|
||
|
||
// 筛选条件
|
||
const filters = reactive({
|
||
keyword: '',
|
||
status: '',
|
||
start_time: '',
|
||
end_time: ''
|
||
})
|
||
|
||
// 统计数据
|
||
const stats = ref({
|
||
total_calls: 0,
|
||
success_rate: '0%'
|
||
})
|
||
```
|
||
|
||
### 4. 工具函数
|
||
|
||
#### 格式化函数
|
||
```javascript
|
||
// 格式化价格
|
||
const formatPrice = (price) => {
|
||
if (!price) return '0.00'
|
||
return Number(price).toFixed(2)
|
||
}
|
||
|
||
// 格式化日期
|
||
const formatDate = (date) => {
|
||
if (!date) return '-'
|
||
return new Date(date).toLocaleDateString('zh-CN')
|
||
}
|
||
|
||
// 格式化时间
|
||
const formatTime = (date) => {
|
||
if (!date) return '-'
|
||
return new Date(date).toLocaleTimeString('zh-CN', {
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
})
|
||
}
|
||
|
||
// 格式化JSON
|
||
const formatJson = (jsonString) => {
|
||
try {
|
||
return JSON.stringify(JSON.parse(jsonString), null, 2)
|
||
} catch {
|
||
return jsonString
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 状态处理函数
|
||
```javascript
|
||
// 获取状态类型
|
||
const getStatusType = (status) => {
|
||
switch (status) {
|
||
case 'success':
|
||
return 'success'
|
||
case 'failed':
|
||
return 'danger'
|
||
case 'pending':
|
||
return 'warning'
|
||
default:
|
||
return 'info'
|
||
}
|
||
}
|
||
|
||
// 获取状态文本
|
||
const getStatusText = (status) => {
|
||
switch (status) {
|
||
case 'success':
|
||
return '成功'
|
||
case 'failed':
|
||
return '失败'
|
||
case 'pending':
|
||
return '处理中'
|
||
default:
|
||
return '未知'
|
||
}
|
||
}
|
||
```
|
||
|
||
## 样式设计
|
||
|
||
### 1. 统计卡片样式
|
||
```css
|
||
.stat-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 16px 24px;
|
||
background: rgba(255, 255, 255, 0.8);
|
||
backdrop-filter: blur(10px);
|
||
border: 1px solid rgba(226, 232, 240, 0.6);
|
||
border-radius: 12px;
|
||
min-width: 120px;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
color: #1e293b;
|
||
line-height: 1;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 13px;
|
||
color: #64748b;
|
||
font-weight: 500;
|
||
}
|
||
```
|
||
|
||
### 2. 详情弹窗样式
|
||
```css
|
||
.detail-dialog :deep(.el-dialog) {
|
||
border-radius: 16px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.detail-dialog :deep(.el-dialog__header) {
|
||
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
||
border-bottom: 1px solid rgba(226, 232, 240, 0.6);
|
||
padding: 20px 24px;
|
||
}
|
||
|
||
.detail-dialog :deep(.el-dialog__body) {
|
||
padding: 24px;
|
||
}
|
||
```
|
||
|
||
### 3. 表格样式优化
|
||
```css
|
||
:deep(.el-table) {
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
:deep(.el-table th) {
|
||
background: #f8fafc !important;
|
||
border-bottom: 1px solid #e2e8f0;
|
||
}
|
||
|
||
:deep(.el-table td) {
|
||
border-bottom: 1px solid #f1f5f9;
|
||
}
|
||
|
||
:deep(.el-table tr:hover > td) {
|
||
background: #f8fafc !important;
|
||
}
|
||
```
|
||
|
||
### 4. 响应式设计
|
||
```css
|
||
/* 响应式设计 */
|
||
@media (max-width: 768px) {
|
||
.stat-item {
|
||
padding: 12px 16px;
|
||
min-width: 100px;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 12px;
|
||
}
|
||
|
||
.detail-item {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.detail-label {
|
||
font-size: 13px;
|
||
}
|
||
|
||
.detail-value {
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 用户体验优化
|
||
|
||
### 1. 加载状态
|
||
- **加载动画**: 使用Element Plus的LoadingSpinner组件
|
||
- **骨架屏**: 数据加载时显示占位内容
|
||
- **错误处理**: 友好的错误提示信息
|
||
|
||
### 2. 交互反馈
|
||
- **防抖搜索**: 避免频繁的API请求
|
||
- **即时反馈**: 操作后立即更新界面状态
|
||
- **确认操作**: 重要操作需要用户确认
|
||
|
||
### 3. 数据展示
|
||
- **分页加载**: 避免一次性加载大量数据
|
||
- **虚拟滚动**: 大数据量时的性能优化
|
||
- **数据缓存**: 减少重复请求
|
||
|
||
### 4. 移动端适配
|
||
- **响应式布局**: 适配不同屏幕尺寸
|
||
- **触摸友好**: 按钮和交互元素适合触摸操作
|
||
- **性能优化**: 移动端性能优化
|
||
|
||
## 错误处理
|
||
|
||
### 1. 网络错误
|
||
```javascript
|
||
try {
|
||
const response = await apiApi.getUserApiCalls(params)
|
||
// 处理成功响应
|
||
} catch (error) {
|
||
console.error('加载API调用记录失败:', error)
|
||
ElMessage.error('加载API调用记录失败')
|
||
}
|
||
```
|
||
|
||
### 2. 数据验证
|
||
```javascript
|
||
// 验证时间格式
|
||
const handleDateRangeChange = (range) => {
|
||
if (range && range.length === 2) {
|
||
// 验证时间格式
|
||
const startTime = new Date(range[0])
|
||
const endTime = new Date(range[1])
|
||
|
||
if (isNaN(startTime.getTime()) || isNaN(endTime.getTime())) {
|
||
ElMessage.warning('时间格式不正确')
|
||
return
|
||
}
|
||
|
||
filters.start_time = range[0]
|
||
filters.end_time = range[1]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 边界情况
|
||
```javascript
|
||
// 处理空数据
|
||
<div v-else-if="apiCalls.length === 0" class="text-center py-12">
|
||
<el-empty description="暂无调用记录">
|
||
<el-button type="primary" @click="$router.push('/api')">
|
||
前往开发者中心
|
||
</el-button>
|
||
</el-empty>
|
||
</div>
|
||
```
|
||
|
||
## 性能优化
|
||
|
||
### 1. 组件优化
|
||
- **懒加载**: 路由级别的组件懒加载
|
||
- **缓存**: 使用keep-alive缓存页面状态
|
||
- **虚拟化**: 大数据列表的虚拟滚动
|
||
|
||
### 2. 请求优化
|
||
- **防抖**: 搜索输入防抖处理
|
||
- **缓存**: API响应数据缓存
|
||
- **预加载**: 关键数据的预加载
|
||
|
||
### 3. 渲染优化
|
||
- **v-show vs v-if**: 合理使用条件渲染
|
||
- **key属性**: 列表渲染时使用唯一key
|
||
- **计算属性**: 复杂计算的缓存
|
||
|
||
## 总结
|
||
|
||
API调用记录和钱包交易记录前端页面提供了完整的用户界面和交互体验,通过合理的组件设计、状态管理和样式优化,确保了良好的用户体验和系统性能。页面支持响应式设计,适配不同设备,并提供了丰富的筛选和查看功能。 |