feat: 管理界面优化 — 移动端自适应 + 数据源 + LLM 配置
移动端自适应: - AdminLayout: 汉堡菜单 + 可折叠侧边栏 + 遮罩层 + ESC 关闭 - 所有页面响应式布局 (grid-cols-1 sm:grid-cols-2 lg:grid-cols-4) - 触摸友好按钮 (min-h-[44px]) - 表格移动端卡片视图 新增页面: - DataSources: 数据源状态 + API Key 脱敏 + 测试连接 - LLMConfig: LLM 配置 + 测试连接 + 使用统计 + 最近预测 增强功能: - Config: 配置列表 + 修改指南 + 快捷导航 - types: 新增 DataSourceStatus, LLMUsageStats 等类型 - dal: 新增 testDataSource, fetchDataSourceStatuses, testLLMConnection 等
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Admin 后台 - 仪表盘
|
||||
*
|
||||
* 响应式布局: 移动端 1 列 → 平板 2 列 → 桌面 4 列
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
@@ -39,7 +41,7 @@ export default function Dashboard() {
|
||||
<p className="mt-1 text-sm">{error}</p>
|
||||
<button
|
||||
onClick={() => window.location.reload()}
|
||||
className="mt-3 rounded bg-red-500/20 px-4 py-1 text-sm hover:bg-red-500/30"
|
||||
className="mt-3 rounded-md bg-red-500/20 px-4 py-2 text-sm hover:bg-red-500/30 min-h-[44px]"
|
||||
>
|
||||
重试
|
||||
</button>
|
||||
@@ -49,18 +51,40 @@ export default function Dashboard() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
||||
<StatCard label="健康状态" value={loading ? '—' : (health?.status === 'healthy' ? '✅ 正常' : '⚠️ 异常')} icon="●" />
|
||||
<StatCard label="联赛数" value={loading ? '—' : data?.leagues.length ?? 0} icon="◫" />
|
||||
<StatCard label="比赛数" value={loading ? '—' : data?.total_matches ?? 0} icon="◆" />
|
||||
<StatCard label="预测数" value={loading ? '—' : data?.total_predictions ?? 0} icon="◇" />
|
||||
{/* 统计卡片: 移动端 1 列 → 平板 2 列 → 桌面 4 列 */}
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
||||
<StatCard
|
||||
label="健康状态"
|
||||
value={loading ? '—' : (health?.status === 'healthy' ? '✅ 正常' : '⚠️ 异常')}
|
||||
icon="●"
|
||||
/>
|
||||
<StatCard
|
||||
label="联赛数"
|
||||
value={loading ? '—' : data?.leagues.length ?? 0}
|
||||
icon="◫"
|
||||
/>
|
||||
<StatCard
|
||||
label="比赛数"
|
||||
value={loading ? '—' : data?.total_matches ?? 0}
|
||||
icon="◆"
|
||||
/>
|
||||
<StatCard
|
||||
label="预测数"
|
||||
value={loading ? '—' : data?.total_predictions ?? 0}
|
||||
icon="◇"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 联赛列表 */}
|
||||
<Card>
|
||||
<CardHeader title="最近联赛" />
|
||||
<CardBody>
|
||||
{loading ? (
|
||||
<p className="text-gray-400">加载中...</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{[1, 2, 3, 4].map(i => (
|
||||
<div key={i} className="h-6 w-20 animate-pulse rounded bg-gray-800" />
|
||||
))}
|
||||
</div>
|
||||
) : data && data.leagues.length > 0 ? (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{data.leagues.map(l => (
|
||||
@@ -74,6 +98,45 @@ export default function Dashboard() {
|
||||
)}
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
{/* 快捷操作 */}
|
||||
<Card>
|
||||
<CardHeader title="快捷操作" />
|
||||
<CardBody>
|
||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<a
|
||||
href="/admin/collection"
|
||||
className="flex items-center gap-3 rounded-lg border border-gray-800 p-4 transition-colors hover:border-gray-700 hover:bg-gray-800/50"
|
||||
>
|
||||
<span className="text-xl">◈</span>
|
||||
<div>
|
||||
<div className="text-sm font-medium text-gray-200">触发采集</div>
|
||||
<div className="text-xs text-gray-500">从数据源获取最新数据</div>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="/admin/predictions"
|
||||
className="flex items-center gap-3 rounded-lg border border-gray-800 p-4 transition-colors hover:border-gray-700 hover:bg-gray-800/50"
|
||||
>
|
||||
<span className="text-xl">◆</span>
|
||||
<div>
|
||||
<div className="text-sm font-medium text-gray-200">新建预测</div>
|
||||
<div className="text-xs text-gray-500">使用 LLM 预测比赛结果</div>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="/admin/backtest"
|
||||
className="flex items-center gap-3 rounded-lg border border-gray-800 p-4 transition-colors hover:border-gray-700 hover:bg-gray-800/50"
|
||||
>
|
||||
<span className="text-xl">◉</span>
|
||||
<div>
|
||||
<div className="text-sm font-medium text-gray-200">运行回测</div>
|
||||
<div className="text-xs text-gray-500">在历史数据上验证策略</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user