Skip to content

Commit 3aa70fe

Browse files
新增硅基流动余额检测
1 parent 9489227 commit 3aa70fe

File tree

10 files changed

+563
-2
lines changed

10 files changed

+563
-2
lines changed

BALANCE_DETECTION_GUIDE.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# 硅基流动余额检测功能使用指南
2+
3+
## 功能概述
4+
5+
我们为API Key测试工具新增了硅基流动(SiliconCloud)余额检测功能,可以帮助用户实时查看账户余额和用户信息。
6+
7+
## 使用方法
8+
9+
### 1. 选择API类型
10+
- 在API配置区域,将API类型设置为"SiliconCloud"
11+
12+
### 2. 输入API Key
13+
- 在API密钥列表中输入您的硅基流动API Key
14+
- 格式:每行一个密钥
15+
16+
### 3. 开始测试
17+
- 点击"开始测试"按钮进行密钥验证
18+
19+
### 4. 查看余额信息
20+
- 测试完成后,在右侧结果区域中,每个有效的硅基流动密钥下方会自动显示余额信息
21+
- 余额信息包含:
22+
- 💰 账户余额(以人民币显示)
23+
- 👤 用户昵称(如果可用)
24+
- 如果余额查询失败,会显示相应的错误提示
25+
26+
## API接口信息
27+
28+
### 硅基流动余额查询API
29+
- **端点**: `https://api.siliconflow.cn/v1/user/info`
30+
- **方法**: GET
31+
- **认证**: Bearer Token
32+
- **返回数据**: 用户信息包括余额、昵称、邮箱等
33+
34+
### 响应格式示例
35+
```json
36+
{
37+
"data": {
38+
"user_id": "user_12345",
39+
"nickname": "用户昵称",
40+
"email": "[email protected]",
41+
"balance": 100.50,
42+
"currency": "CNY"
43+
}
44+
}
45+
```
46+
47+
## 特性
48+
49+
1. **智能显示**: 只在有效的SiliconCloud密钥测试结果中显示余额信息
50+
2. **自动获取**: 密钥验证成功后自动查询余额,无需手动操作
51+
3. **错误处理**: 当余额查询失败时显示明确的错误提示
52+
4. **多语言支持**: 支持中文和英文界面
53+
5. **响应式设计**: 适配桌面和移动设备
54+
6. **实时更新**: 每个密钥独立查询余额,互不干扰
55+
56+
## 注意事项
57+
58+
- 余额查询功能目前仅支持硅基流动平台
59+
- 需要有效的API Key才能查询余额
60+
- 如果API Key没有权限访问用户信息,会显示相应错误
61+
- 代理设置同样适用于余额查询
62+
63+
## 故障排除
64+
65+
### 常见错误及解决方案
66+
67+
1. **HTTP 401错误**
68+
- 检查API Key是否正确
69+
- 确认API Key有效且未过期
70+
71+
2. **HTTP 403错误**
72+
- API Key可能没有访问用户信息的权限
73+
- 联系硅基流动客服确认权限设置
74+
75+
3. **网络连接错误**
76+
- 检查网络连接
77+
- 如果使用代理,确认代理设置正确
78+
79+
4. **余额不显示**
80+
- 确认已选择SiliconCloud API类型
81+
- 确认已输入有效的API Key
82+
- 尝试点击刷新按钮
83+
84+
## 开发信息
85+
86+
### 文件结构
87+
```
88+
src/
89+
├── components/
90+
│ └── features/
91+
│ ├── BalanceDisplay/
92+
│ │ ├── index.jsx # 原余额显示组件(已移除使用)
93+
│ │ ├── KeyBalanceDisplay.jsx # 单key余额显示组件
94+
│ │ ├── BalanceDisplay.module.css # 原组件样式
95+
│ │ └── KeyBalanceDisplay.module.css # 单key组件样式
96+
│ └── Results/
97+
│ └── VirtualizedList.jsx # 集成余额显示的结果列表
98+
├── services/
99+
│ └── api/
100+
│ ├── base.js # 通用API余额查询函数
101+
│ └── siliconcloud.js # 硅基流动余额查询实现
102+
└── locales/
103+
├── zh.json # 中文翻译
104+
└── en.json # 英文翻译
105+
```
106+
107+
### 集成方式
108+
余额显示组件已集成到Results组件的VirtualizedList中,会在每个有效的SiliconCloud密钥测试结果下方自动显示余额信息。
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
.balanceDisplay {
2+
background: var(--bg-secondary);
3+
border: 1px solid var(--border-color);
4+
border-radius: 8px;
5+
padding: 16px;
6+
margin: 16px 0;
7+
font-family: var(--font-family);
8+
}
9+
10+
.header {
11+
display: flex;
12+
justify-content: space-between;
13+
align-items: center;
14+
margin-bottom: 12px;
15+
}
16+
17+
.header h3 {
18+
margin: 0;
19+
color: var(--text-primary);
20+
font-size: 16px;
21+
font-weight: 600;
22+
}
23+
24+
.refreshButton {
25+
background: var(--primary-color);
26+
color: white;
27+
border: none;
28+
border-radius: 4px;
29+
padding: 6px 12px;
30+
font-size: 12px;
31+
cursor: pointer;
32+
transition: all 0.2s ease;
33+
}
34+
35+
.refreshButton:hover:not(:disabled) {
36+
background: var(--primary-hover);
37+
transform: translateY(-1px);
38+
}
39+
40+
.refreshButton:disabled {
41+
background: var(--text-secondary);
42+
cursor: not-allowed;
43+
transform: none;
44+
}
45+
46+
.error {
47+
display: flex;
48+
align-items: center;
49+
gap: 8px;
50+
color: var(--error-color);
51+
background: var(--error-bg);
52+
border: 1px solid var(--error-border);
53+
border-radius: 4px;
54+
padding: 8px 12px;
55+
font-size: 14px;
56+
}
57+
58+
.errorIcon {
59+
font-size: 16px;
60+
}
61+
62+
.balanceInfo {
63+
background: var(--bg-primary);
64+
border-radius: 6px;
65+
padding: 12px;
66+
}
67+
68+
.balanceItem {
69+
display: flex;
70+
justify-content: space-between;
71+
align-items: center;
72+
padding: 6px 0;
73+
border-bottom: 1px solid var(--border-light);
74+
}
75+
76+
.balanceItem:last-child {
77+
border-bottom: none;
78+
}
79+
80+
.label {
81+
color: var(--text-secondary);
82+
font-size: 14px;
83+
font-weight: 500;
84+
}
85+
86+
.value {
87+
color: var(--text-primary);
88+
font-size: 14px;
89+
font-weight: 600;
90+
}
91+
92+
.userInfo {
93+
margin-top: 8px;
94+
padding-top: 8px;
95+
border-top: 1px solid var(--border-light);
96+
}
97+
98+
.placeholder {
99+
text-align: center;
100+
color: var(--text-secondary);
101+
font-size: 14px;
102+
padding: 16px;
103+
font-style: italic;
104+
}
105+
106+
/* 响应式设计 */
107+
@media (max-width: 768px) {
108+
.balanceDisplay {
109+
padding: 12px;
110+
margin: 12px 0;
111+
}
112+
113+
.header {
114+
flex-direction: column;
115+
gap: 8px;
116+
align-items: stretch;
117+
}
118+
119+
.refreshButton {
120+
width: 100%;
121+
padding: 8px 12px;
122+
}
123+
124+
.balanceItem {
125+
flex-direction: column;
126+
align-items: flex-start;
127+
gap: 4px;
128+
}
129+
}
130+
131+
/* 深色主题适配 */
132+
[data-theme="dark"] .balanceDisplay {
133+
background: var(--dark-bg-secondary);
134+
border-color: var(--dark-border-color);
135+
}
136+
137+
[data-theme="dark"] .header h3 {
138+
color: var(--dark-text-primary);
139+
}
140+
141+
[data-theme="dark"] .label {
142+
color: var(--dark-text-secondary);
143+
}
144+
145+
[data-theme="dark"] .value {
146+
color: var(--dark-text-primary);
147+
}
148+
149+
[data-theme="dark"] .placeholder {
150+
color: var(--dark-text-secondary);
151+
}
152+
153+
[data-theme="dark"] .balanceInfo {
154+
background: var(--dark-bg-primary);
155+
}
156+
157+
[data-theme="dark"] .balanceItem {
158+
border-bottom-color: var(--dark-border-light);
159+
}
160+
161+
[data-theme="dark"] .userInfo {
162+
border-top-color: var(--dark-border-light);
163+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React, { useState, useEffect } from 'react';
2+
import { getApiBalance } from '../../../services/api/base';
3+
import { useLanguage } from '../../../hooks/useLanguage';
4+
5+
const KeyBalanceDisplay = ({ apiKey, apiType, proxyUrl }) => {
6+
const { t } = useLanguage();
7+
const [balanceInfo, setBalanceInfo] = useState(null);
8+
const [loading, setLoading] = useState(false);
9+
const [error, setError] = useState(null);
10+
11+
const fetchBalance = async () => {
12+
if (!apiKey || !apiType) return;
13+
14+
setLoading(true);
15+
setError(null);
16+
17+
try {
18+
const result = await getApiBalance(apiKey, apiType, proxyUrl);
19+
if (result.success) {
20+
setBalanceInfo(result);
21+
setError(null);
22+
} else {
23+
setError(result.error);
24+
setBalanceInfo(null);
25+
}
26+
} catch (err) {
27+
setError(err.message);
28+
setBalanceInfo(null);
29+
} finally {
30+
setLoading(false);
31+
}
32+
};
33+
34+
useEffect(() => {
35+
// 只有当apiType支持余额查询时才自动获取
36+
if (apiType === 'siliconcloud' && apiKey) {
37+
fetchBalance();
38+
}
39+
// eslint-disable-next-line react-hooks/exhaustive-deps
40+
}, [apiKey, apiType, proxyUrl]);
41+
42+
// 如果不是支持余额查询的API类型,则不显示组件
43+
if (apiType !== 'siliconcloud') {
44+
return null;
45+
}
46+
47+
// 根据状态返回相应的显示内容
48+
if (loading) {
49+
return <div className="key-model">{t('balance.title')}: {t('balance.refreshing')}</div>;
50+
}
51+
52+
if (error) {
53+
return <div className="key-model">{t('balance.title')}: {t('balance.fetchFailed')}</div>;
54+
}
55+
56+
if (balanceInfo) {
57+
return <div className="key-model">{t('balance.title')}: ¥{Number(balanceInfo.balance).toFixed(2)}</div>;
58+
}
59+
60+
return null;
61+
};
62+
63+
export default KeyBalanceDisplay;

0 commit comments

Comments
 (0)