perf:优化webui交互体验,优化统计逻辑,优化log展示
This commit is contained in:
@@ -56,6 +56,8 @@ import { RestartOverlay } from '@/components/restart-overlay'
|
||||
import { ExpressionReviewer } from '@/components/expression-reviewer'
|
||||
import { getBotConfig, getModelConfig } from '@/lib/config-api'
|
||||
import { getReviewStats } from '@/lib/expression-api'
|
||||
import { getDashboardVersionStatus, type DashboardVersionStatus } from '@/lib/system-api'
|
||||
import { APP_VERSION } from '@/lib/version'
|
||||
import { ZoomableChart } from '@/components/ui/zoomable-chart'
|
||||
|
||||
// 主导出组件:包装 RestartProvider
|
||||
@@ -75,6 +77,11 @@ interface BotStatus {
|
||||
start_time: string
|
||||
}
|
||||
|
||||
interface ReleaseStatus {
|
||||
version: string
|
||||
url: string
|
||||
}
|
||||
|
||||
interface StatisticsSummary {
|
||||
total_requests: number
|
||||
total_cost: number
|
||||
@@ -156,10 +163,13 @@ function IndexPageContent() {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [loadingProgress, setLoadingProgress] = useState(0)
|
||||
const [timeRange, setTimeRange] = useState(24) // 默认24小时
|
||||
const [autoRefresh, setAutoRefresh] = useState(true)
|
||||
const [autoRefresh, setAutoRefresh] = useState(false)
|
||||
const [hitokoto, setHitokoto] = useState<{ hitokoto: string; from: string } | null>(null)
|
||||
const [hitokotoLoading, setHitokotoLoading] = useState(true)
|
||||
const [botStatus, setBotStatus] = useState<BotStatus | null>(null)
|
||||
const [maibotStableRelease, setMaibotStableRelease] = useState<ReleaseStatus | null>(null)
|
||||
const [maibotTestRelease, setMaibotTestRelease] = useState<ReleaseStatus | null>(null)
|
||||
const [dashboardVersionStatus, setDashboardVersionStatus] = useState<DashboardVersionStatus | null>(null)
|
||||
const [featureStatus, setFeatureStatus] = useState<FeatureStatus>({
|
||||
memoryEnabled: false,
|
||||
visualEnabled: false,
|
||||
@@ -186,6 +196,61 @@ function IndexPageContent() {
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true
|
||||
|
||||
const loadLatestVersions = async () => {
|
||||
try {
|
||||
const response = await fetch('https://api.github.com/repos/Mai-with-u/MaiBot/releases?per_page=20', {
|
||||
headers: { Accept: 'application/vnd.github+json' },
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error(`GitHub release status ${response.status}`)
|
||||
}
|
||||
const releases = await response.json() as Array<{
|
||||
draft?: boolean
|
||||
prerelease?: boolean
|
||||
tag_name?: string
|
||||
html_url?: string
|
||||
}>
|
||||
const visibleReleases = releases.filter((release) => !release.draft)
|
||||
const stableRelease = visibleReleases.find((release) => !release.prerelease)
|
||||
const testRelease = visibleReleases[0]
|
||||
if (mounted) {
|
||||
if (stableRelease?.tag_name) {
|
||||
setMaibotStableRelease({
|
||||
version: String(stableRelease.tag_name).replace(/^v/i, '').trim(),
|
||||
url: stableRelease.html_url || 'https://github.com/Mai-with-u/MaiBot/releases',
|
||||
})
|
||||
}
|
||||
if (testRelease?.tag_name) {
|
||||
setMaibotTestRelease({
|
||||
version: String(testRelease.tag_name).replace(/^v/i, '').trim(),
|
||||
url: testRelease.html_url || 'https://github.com/Mai-with-u/MaiBot/releases',
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.debug('检查 MaiBot 最新版本失败:', error)
|
||||
}
|
||||
|
||||
try {
|
||||
const status = await getDashboardVersionStatus(APP_VERSION)
|
||||
if (mounted) {
|
||||
setDashboardVersionStatus(status)
|
||||
}
|
||||
} catch (error) {
|
||||
console.debug('妫€鏌?WebUI 鐗堟湰鏇存柊澶辫触:', error)
|
||||
}
|
||||
}
|
||||
|
||||
void loadLatestVersions()
|
||||
|
||||
return () => {
|
||||
mounted = false
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 获取审核统计
|
||||
const fetchReviewStats = useCallback(async () => {
|
||||
try {
|
||||
@@ -538,8 +603,85 @@ function IndexPageContent() {
|
||||
</div>
|
||||
|
||||
{/* 机器人状态和快速操作 */}
|
||||
<div className="grid gap-4 grid-cols-1 lg:grid-cols-3">
|
||||
<div className="grid gap-4 grid-cols-1 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1.4fr)_max-content]">
|
||||
{/* 机器人状态卡片 */}
|
||||
<Card className="lg:col-span-1">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||
<FileText className="h-4 w-4" />
|
||||
麦麦版本
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<span className="text-sm text-muted-foreground">主程序版本</span>
|
||||
<Badge variant="secondary" className="border border-primary/20 bg-primary/10 px-2 py-0.5 font-semibold text-primary">
|
||||
{botStatus?.version ? `v${botStatus.version}` : '未知'}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<span className="text-sm text-muted-foreground">WebUI 版本</span>
|
||||
<Badge variant="secondary" className="border border-primary/20 bg-primary/10 px-2 py-0.5 font-semibold text-primary">
|
||||
v{APP_VERSION}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="hidden">
|
||||
最新版本 v{dashboardVersionStatus?.latest_version || APP_VERSION}
|
||||
</div>
|
||||
<div className="hidden">
|
||||
<a
|
||||
href={maibotTestRelease?.url || 'https://github.com/Mai-with-u/MaiBot/releases'}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 transition-colors hover:text-muted-foreground"
|
||||
>
|
||||
最新版本 {maibotTestRelease ? `v${maibotTestRelease.version}` : 'GitHub Releases'}
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
</a>
|
||||
</div>
|
||||
<div className="space-y-1 border-t border-border/50 pt-2 text-xs text-muted-foreground/60">
|
||||
<a
|
||||
href={maibotStableRelease?.url || 'https://github.com/Mai-with-u/MaiBot/releases'}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center justify-between gap-2 transition-colors hover:text-muted-foreground"
|
||||
>
|
||||
<span>正式版最新</span>
|
||||
<span className="inline-flex items-center gap-1">
|
||||
{maibotStableRelease ? `v${maibotStableRelease.version}` : 'GitHub Releases'}
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
href={maibotTestRelease?.url || 'https://github.com/Mai-with-u/MaiBot/releases'}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center justify-between gap-2 transition-colors hover:text-muted-foreground"
|
||||
>
|
||||
<span>测试版最新</span>
|
||||
<span className="inline-flex items-center gap-1">
|
||||
{maibotTestRelease ? `v${maibotTestRelease.version}` : 'GitHub Releases'}
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
href={dashboardVersionStatus?.pypi_url || 'https://pypi.org/project/maibot-dashboard/'}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center justify-between gap-2 transition-colors hover:text-muted-foreground"
|
||||
>
|
||||
<span>WebUI 最新</span>
|
||||
<span className="inline-flex items-center gap-1">
|
||||
v{dashboardVersionStatus?.latest_version || APP_VERSION}
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="lg:col-span-1">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||
@@ -549,12 +691,12 @@ function IndexPageContent() {
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex flex-wrap items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
{botStatus?.running ? (
|
||||
<>
|
||||
<div className="h-3 w-3 rounded-full bg-green-500 animate-pulse" />
|
||||
<Badge variant="outline" className="text-green-600 border-green-300 bg-green-50">
|
||||
<Badge variant="outline" className="whitespace-nowrap text-green-600 border-green-300 bg-green-50">
|
||||
<CheckCircle2 className="h-3 w-3 mr-1" />
|
||||
{t('home.botStatus.running')}
|
||||
</Badge>
|
||||
@@ -562,7 +704,7 @@ function IndexPageContent() {
|
||||
) : (
|
||||
<>
|
||||
<div className="h-3 w-3 rounded-full bg-red-500" />
|
||||
<Badge variant="outline" className="text-red-600 border-red-300 bg-red-50">
|
||||
<Badge variant="outline" className="whitespace-nowrap text-red-600 border-red-300 bg-red-50">
|
||||
<AlertCircle className="h-3 w-3 mr-1" />
|
||||
{t('home.botStatus.stopped')}
|
||||
</Badge>
|
||||
@@ -570,11 +712,7 @@ function IndexPageContent() {
|
||||
)}
|
||||
</div>
|
||||
{botStatus && (
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||
<Badge variant="secondary" className="border border-primary/20 bg-primary/10 px-2 py-0.5 font-semibold text-primary">
|
||||
v{botStatus.version}
|
||||
</Badge>
|
||||
<span className="mx-2">|</span>
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<span>{t('home.botStatus.uptime', { time: formatTime(botStatus.uptime) })}</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -651,25 +789,22 @@ function IndexPageContent() {
|
||||
</Card>
|
||||
|
||||
{/* 问卷调查卡片 */}
|
||||
<Card>
|
||||
<Card className="lg:w-[190px]">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||
<ClipboardList className="h-4 w-4" />
|
||||
{t('home.survey.title')}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-xs">
|
||||
{t('home.survey.description')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button variant="outline" size="sm" asChild className="gap-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button variant="outline" size="sm" asChild className="w-full justify-start gap-2">
|
||||
<Link to="/survey/webui-feedback">
|
||||
<FileText className="h-4 w-4" />
|
||||
{t('home.survey.webui')}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" asChild className="gap-2">
|
||||
<Button variant="outline" size="sm" asChild className="w-full justify-start gap-2">
|
||||
<Link to="/survey/maibot-feedback">
|
||||
<MessageSquare className="h-4 w-4" />
|
||||
{t('home.survey.maibot')}
|
||||
|
||||
Reference in New Issue
Block a user