mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-08 02:15:27 +08:00
feat: Add token preview and batch progress to admin account management, and expand API tests for admin endpoints.
This commit is contained in:
@@ -10,6 +10,7 @@ export default function AccountManager({ config, onRefresh, onMessage }) {
|
||||
const [validatingAll, setValidatingAll] = useState(false)
|
||||
const [testing, setTesting] = useState({}) // 单个账号测试状态
|
||||
const [testingAll, setTestingAll] = useState(false)
|
||||
const [batchProgress, setBatchProgress] = useState({ current: 0, total: 0, results: [] })
|
||||
const [queueStatus, setQueueStatus] = useState(null)
|
||||
|
||||
// 获取队列状态
|
||||
@@ -137,20 +138,41 @@ export default function AccountManager({ config, onRefresh, onMessage }) {
|
||||
}
|
||||
}
|
||||
|
||||
// 批量验证所有账号
|
||||
// 批量验证所有账号(带进度)
|
||||
const validateAllAccounts = async () => {
|
||||
if (!confirm('确定要验证所有账号?这可能需要一些时间。')) return
|
||||
if (!confirm('确定要验证所有账号?')) return
|
||||
const accounts = config.accounts || []
|
||||
if (accounts.length === 0) return
|
||||
|
||||
setValidatingAll(true)
|
||||
try {
|
||||
const res = await fetch('/admin/accounts/validate-all', { method: 'POST' })
|
||||
const data = await res.json()
|
||||
onMessage('success', `验证完成: ${data.valid}/${data.total} 个账号有效`)
|
||||
onRefresh()
|
||||
} catch (e) {
|
||||
onMessage('error', '批量验证失败: ' + e.message)
|
||||
} finally {
|
||||
setValidatingAll(false)
|
||||
setBatchProgress({ current: 0, total: accounts.length, results: [] })
|
||||
|
||||
let validCount = 0
|
||||
const results = []
|
||||
|
||||
for (let i = 0; i < accounts.length; i++) {
|
||||
const acc = accounts[i]
|
||||
const id = acc.email || acc.mobile
|
||||
|
||||
try {
|
||||
const res = await fetch('/admin/accounts/validate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ identifier: id }),
|
||||
})
|
||||
const data = await res.json()
|
||||
results.push({ id, success: data.valid, message: data.message })
|
||||
if (data.valid) validCount++
|
||||
} catch (e) {
|
||||
results.push({ id, success: false, message: e.message })
|
||||
}
|
||||
|
||||
setBatchProgress({ current: i + 1, total: accounts.length, results: [...results] })
|
||||
}
|
||||
|
||||
onMessage('success', `验证完成: ${validCount}/${accounts.length} 个账号有效`)
|
||||
onRefresh()
|
||||
setValidatingAll(false)
|
||||
}
|
||||
|
||||
// 测试单个账号 API
|
||||
@@ -176,24 +198,41 @@ export default function AccountManager({ config, onRefresh, onMessage }) {
|
||||
}
|
||||
}
|
||||
|
||||
// 批量测试所有账号 API
|
||||
// 批量测试所有账号 API(带进度)
|
||||
const testAllAccounts = async () => {
|
||||
if (!confirm('确定要测试所有账号的 API?这可能需要较长时间。')) return
|
||||
if (!confirm('确定要测试所有账号的 API?')) return
|
||||
const accounts = config.accounts || []
|
||||
if (accounts.length === 0) return
|
||||
|
||||
setTestingAll(true)
|
||||
try {
|
||||
const res = await fetch('/admin/accounts/test-all', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({}),
|
||||
})
|
||||
const data = await res.json()
|
||||
onMessage('success', `API 测试完成: ${data.success}/${data.total} 个账号可用`)
|
||||
onRefresh()
|
||||
} catch (e) {
|
||||
onMessage('error', '批量 API 测试失败: ' + e.message)
|
||||
} finally {
|
||||
setTestingAll(false)
|
||||
setBatchProgress({ current: 0, total: accounts.length, results: [] })
|
||||
|
||||
let successCount = 0
|
||||
const results = []
|
||||
|
||||
for (let i = 0; i < accounts.length; i++) {
|
||||
const acc = accounts[i]
|
||||
const id = acc.email || acc.mobile
|
||||
|
||||
try {
|
||||
const res = await fetch('/admin/accounts/test', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ identifier: id }),
|
||||
})
|
||||
const data = await res.json()
|
||||
results.push({ id, success: data.success, message: data.message, time: data.response_time })
|
||||
if (data.success) successCount++
|
||||
} catch (e) {
|
||||
results.push({ id, success: false, message: e.message })
|
||||
}
|
||||
|
||||
setBatchProgress({ current: i + 1, total: accounts.length, results: [...results] })
|
||||
}
|
||||
|
||||
onMessage('success', `API 测试完成: ${successCount}/${accounts.length} 个账号可用`)
|
||||
onRefresh()
|
||||
setTestingAll(false)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -267,6 +306,31 @@ export default function AccountManager({ config, onRefresh, onMessage }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 批量操作进度条 */}
|
||||
{(testingAll || validatingAll) && batchProgress.total > 0 && (
|
||||
<div className="batch-progress">
|
||||
<div className="progress-header">
|
||||
<span>{testingAll ? '🧪 批量测试中...' : '✅ 批量验证中...'}</span>
|
||||
<span>{batchProgress.current}/{batchProgress.total}</span>
|
||||
</div>
|
||||
<div className="progress-bar">
|
||||
<div
|
||||
className="progress-fill"
|
||||
style={{ width: `${(batchProgress.current / batchProgress.total) * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
{batchProgress.results.length > 0 && (
|
||||
<div className="progress-results">
|
||||
{batchProgress.results.map((r, i) => (
|
||||
<div key={i} className={`progress-result ${r.success ? 'success' : 'failed'}`}>
|
||||
{r.success ? '✓' : '✗'} {r.id} {r.time ? `(${r.time}ms)` : ''}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{config.accounts?.length > 0 ? (
|
||||
<div className="list">
|
||||
{config.accounts.map((acc, i) => {
|
||||
@@ -278,6 +342,11 @@ export default function AccountManager({ config, onRefresh, onMessage }) {
|
||||
<span className={`badge ${acc.has_token ? 'badge-success' : 'badge-warning'}`}>
|
||||
{acc.has_token ? '已登录' : '未登录'}
|
||||
</span>
|
||||
{acc.token_preview && (
|
||||
<span className="token-preview" title="Token 预览">
|
||||
🔑 {acc.token_preview}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="btn-group-inline">
|
||||
<button
|
||||
|
||||
@@ -446,6 +446,65 @@ textarea.form-input {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* Token Preview */
|
||||
.token-preview {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-secondary);
|
||||
font-family: 'Monaco', 'Menlo', monospace;
|
||||
background: var(--bg-tertiary);
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: var(--radius);
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
/* Batch Progress */
|
||||
.batch-progress {
|
||||
margin: 1rem 0;
|
||||
padding: 1rem;
|
||||
background: var(--bg-tertiary);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.progress-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 8px;
|
||||
background: var(--bg-secondary);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--primary), var(--primary-hover));
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.progress-results {
|
||||
margin-top: 0.75rem;
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.progress-result {
|
||||
padding: 0.25rem 0;
|
||||
font-family: 'Monaco', 'Menlo', monospace;
|
||||
}
|
||||
|
||||
.progress-result.success {
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.progress-result.failed {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.app {
|
||||
padding: 1rem;
|
||||
|
||||
Reference in New Issue
Block a user