feat: 管理界面报刊风统一改造 — 移除独立暗色主题,预测/回测/监控/配置页增强

This commit is contained in:
shangfangjian
2026-09-18 10:42:14 +08:00
parent 91e406f5ee
commit cf0751d1ff
15 changed files with 1275 additions and 828 deletions
+38 -61
View File
@@ -1,17 +1,17 @@
/**
* Admin 后台 - 数据源管理页面
* Admin 后台 - 数据源管理页面(报刊风)
*
* 功能:
* - 显示当前数据源状态 (bzzoiro / understat / injuries)
* - 显示 API Key 配置状态脱敏显示
* - 测试连接按钮调用采集 API 测试)
* - 采集历史记录
* - 显示 API Key 配置状态(脱敏显示)
* - 测试连接按钮(调用采集 API 验证)
* - 数据源说明
*/
import { useEffect, useState, useCallback } from 'react'
import { fetchDataSourceStatuses, testDataSource } from '../dal'
import type { DataSourceStatus } from '../types'
import { Card, CardBody, CardHeader, Badge, SectionHeader } from '../components'
import { Card, CardBody, CardHeader, Badge, SectionHeader, Alert, Spinner, SkeletonBlock } from '../components'
export default function DataSourcesPage() {
const [sources, setSources] = useState<DataSourceStatus[]>([])
@@ -37,7 +37,7 @@ export default function DataSourcesPage() {
setTestingSource(sourceName)
setTestResults(prev => ({ ...prev, [sourceName]: { success: false, message: '测试中...' } }))
try {
await testDataSource(sourceName as any)
await testDataSource(sourceName as 'bzzoiro' | 'understat' | 'injuries')
setTestResults(prev => ({ ...prev, [sourceName]: { success: true, message: '连接成功' } }))
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : '连接失败'
@@ -51,7 +51,7 @@ export default function DataSourcesPage() {
<div className="space-y-6">
<SectionHeader
title="数据源管理"
description="管理数据采集源配置与连接状态"
description="数据采集源配置状态与连通性测试。"
/>
{/* 数据源卡片 */}
@@ -60,10 +60,10 @@ export default function DataSourcesPage() {
{[1, 2, 3].map(i => (
<Card key={i}>
<CardBody>
<div className="animate-pulse space-y-3">
<div className="h-4 w-24 rounded bg-gray-800" />
<div className="h-3 w-32 rounded bg-gray-800" />
<div className="h-8 w-full rounded bg-gray-800" />
<div className="space-y-3">
<SkeletonBlock className="h-4 w-24" />
<SkeletonBlock className="h-3 w-32" />
<SkeletonBlock className="h-8 w-full" />
</div>
</CardBody>
</Card>
@@ -77,47 +77,41 @@ export default function DataSourcesPage() {
<Card key={source.name}>
<CardBody className="space-y-4">
{/* 头部 */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<h3 className="text-sm font-medium text-white">{source.label}</h3>
<Badge status={source.keyConfigured ? 'success' : 'failed'}>
{source.keyConfigured ? '已配置' : '未配置'}
</Badge>
</div>
<div className="flex items-center justify-between border-b border-ink-200 pb-3">
<h3 className="font-serif text-sm font-bold text-ink-900">{source.label}</h3>
<Badge status={source.keyConfigured ? 'success' : 'error'}>
{source.keyConfigured ? '已配置' : '未配置'}
</Badge>
</div>
{/* API Key 状态 */}
<div className="space-y-2">
<div className="flex items-center justify-between text-xs">
<span className="text-gray-500">API Key</span>
<span className="font-mono text-gray-400">{source.maskedKey}</span>
<span className="text-ink-400">API Key</span>
<span className="font-mono text-ink-600">{source.maskedKey}</span>
</div>
<div className="flex items-center justify-between text-xs">
<span className="text-gray-500"></span>
<span className="text-gray-400">{source.lastIngestion || '暂无记录'}</span>
<span className="text-ink-400"></span>
<span className="text-ink-600">{source.lastIngestion || '暂无记录'}</span>
</div>
</div>
{/* 测试结果 */}
{result && (
<div
className={`rounded p-2 text-xs ${
result.success
? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/30'
: 'bg-red-500/10 text-red-400 border border-red-500/30'
}`}
>
{result.message}
</div>
<Alert
kind={result.success ? 'ok' : 'error'}
title={result.success ? '连接成功' : '连接失败'}
message={result.success ? undefined : result.message}
/>
)}
{/* 操作按钮 */}
<button
onClick={() => handleTest(source.name)}
disabled={testingSource === source.name}
className="w-full rounded-md border border-gray-700 bg-gray-800 px-4 py-2.5 text-sm text-gray-300 transition-colors hover:bg-gray-700 hover:text-white disabled:opacity-50 min-h-[44px]"
className="btn btn-sm w-full"
>
{testingSource === source.name ? '测试中...' : '测试连接'}
{testingSource === source.name ? (<><Spinner /> </>) : '测试连接'}
</button>
</CardBody>
</Card>
@@ -130,45 +124,28 @@ export default function DataSourcesPage() {
<Card>
<CardHeader title="数据源说明" />
<CardBody>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
<div className="rounded-lg border border-gray-800 p-4">
<div className="flex items-center gap-2 mb-2">
<Badge status="info">Bzzoiro</Badge>
</div>
<p className="text-xs text-gray-400">
<div className="grid gap-x-6 gap-y-3 sm:grid-cols-3">
<div className="border-t border-ink-200 pt-3">
<Badge status="info">Bzzoiro</Badge>
<p className="mt-2 text-xs leading-relaxed text-ink-600">
, API Key
</p>
</div>
<div className="rounded-lg border border-gray-800 p-4">
<div className="flex items-center gap-2 mb-2">
<Badge status="info">Understat</Badge>
</div>
<p className="text-xs text-gray-400">
xG () , API Key,
<div className="border-t border-ink-200 pt-3">
<Badge status="info">Understat</Badge>
<p className="mt-2 text-xs leading-relaxed text-ink-600">
xG(), API Key,
</p>
</div>
<div className="rounded-lg border border-gray-800 p-4">
<div className="flex items-center gap-2 mb-2">
<Badge status="info">Injuries</Badge>
</div>
<p className="text-xs text-gray-400">
<div className="border-t border-ink-200 pt-3">
<Badge status="info">Injuries</Badge>
<p className="mt-2 text-xs leading-relaxed text-ink-600">
, API Key
</p>
</div>
</div>
</CardBody>
</Card>
{/* 采集历史 */}
<Card>
<CardHeader title="采集历史" />
<CardBody>
<div className="text-center py-8 text-sm text-gray-500">
<p></p>
<p className="mt-1 text-xs">,</p>
</div>
</CardBody>
</Card>
</div>
)
}