fix: 优化数据

This commit is contained in:
Daniel
2026-03-02 11:28:13 +08:00
parent 4a8fff5a00
commit 004d10b283
39 changed files with 1106 additions and 56 deletions

View File

@@ -68,6 +68,7 @@ export function Dashboard() {
usLosses={situation.usForces.combatLosses}
iranLosses={situation.iranForces.combatLosses}
conflictStats={situation.conflictStats}
civilianTotal={situation.civilianCasualtiesTotal}
className="min-w-0 flex-1 py-1"
/>
<EventTimelinePanel updates={situation.recentUpdates} conflictEvents={situation.conflictEvents} className="min-w-0 shrink-0 min-h-[80px] overflow-hidden lg:min-w-[240px]" />

161
src/pages/DbDashboard.tsx Normal file
View File

@@ -0,0 +1,161 @@
import { useEffect, useState } from 'react'
import { Database, Table, ArrowLeft, RefreshCw } from 'lucide-react'
import { Link } from 'react-router-dom'
interface TableData {
[table: string]: Record<string, unknown>[] | { error: string }
}
export function DbDashboard() {
const [data, setData] = useState<TableData | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [expanded, setExpanded] = useState<Set<string>>(new Set(['situation_update', 'combat_losses', 'conflict_stats']))
useEffect(() => {
fetchData()
const t = setInterval(fetchData, 30000)
return () => clearInterval(t)
}, [])
const fetchData = async () => {
setLoading(true)
setError(null)
try {
const res = await fetch('/api/db/dashboard')
if (!res.ok) throw new Error(res.statusText)
const json = await res.json()
setData(json)
} catch (e) {
setError(e instanceof Error ? e.message : '加载失败')
} finally {
setLoading(false)
}
}
const toggle = (name: string) => {
setExpanded((s) => {
const next = new Set(s)
if (next.has(name)) next.delete(name)
else next.add(name)
return next
})
}
if (loading && !data) {
return (
<div className="flex min-h-screen items-center justify-center bg-military-dark text-military-text-secondary">
<RefreshCw className="h-6 w-6 animate-spin" />
</div>
)
}
return (
<div className="min-h-screen bg-military-dark font-db text-military-text-primary">
<header className="sticky top-0 z-10 flex items-center justify-between border-b border-military-border bg-military-panel/95 px-4 py-3">
<div className="flex items-center gap-4">
<Link
to="/"
className="flex items-center gap-2 rounded border border-military-border px-3 py-1.5 text-sm text-military-text-secondary hover:bg-military-border/30 hover:text-military-text-primary"
>
<ArrowLeft className="h-4 w-4" />
</Link>
<span className="flex items-center gap-2 text-lg">
<Database className="h-5 w-5 text-cyan-400" />
</span>
</div>
<button
onClick={fetchData}
disabled={loading}
className="flex items-center gap-2 rounded border border-military-border px-3 py-1.5 text-sm text-military-text-secondary hover:bg-military-border/30 disabled:opacity-50"
>
<RefreshCw className={`h-4 w-4 ${loading ? 'animate-spin' : ''}`} />
</button>
</header>
{error && (
<div className="mx-4 mt-4 rounded border border-amber-600/50 bg-amber-950/30 px-4 py-2 text-amber-400">
{error} API npm run api
</div>
)}
<main className="max-w-6xl space-y-4 p-4">
{data &&
Object.entries(data).map(([name, rows]) => {
const isExpanded = expanded.has(name)
const isError = rows && typeof rows === 'object' && 'error' in rows
const arr = Array.isArray(rows) ? rows : []
return (
<section
key={name}
className="rounded border border-military-border bg-military-panel/80 overflow-hidden"
>
<button
onClick={() => toggle(name)}
className="flex w-full items-center justify-between px-4 py-3 text-left hover:bg-military-border/20"
>
<span className="flex items-center gap-2 font-medium">
<Table className="h-4 w-4 text-cyan-400" />
{name}
<span className="text-military-text-secondary font-normal">
{isError ? '(错误)' : `(${arr.length} 条)`}
</span>
</span>
<span className="text-military-text-secondary">{isExpanded ? '▼' : '▶'}</span>
</button>
{isExpanded && (
<div className="border-t border-military-border overflow-x-auto">
{isError ? (
<pre className="p-4 text-sm text-amber-400">{(rows as { error: string }).error}</pre>
) : arr.length === 0 ? (
<p className="p-4 text-sm text-military-text-secondary"></p>
) : (
<table className="w-full text-left text-sm">
<thead>
<tr className="border-b border-military-border bg-military-dark/50">
{Object.keys(arr[0] as object).map((col) => (
<th
key={col}
className="whitespace-nowrap px-3 py-2 font-medium text-cyan-400"
>
{col}
</th>
))}
</tr>
</thead>
<tbody>
{arr.map((row, i) => (
<tr
key={i}
className="border-b border-military-border/50 hover:bg-military-border/10"
>
{Object.values(row as object).map((v, j) => (
<td
key={j}
className="max-w-xs truncate px-3 py-2 text-military-text-secondary"
title={String(v ?? '')}
>
{v === null || v === undefined
? '—'
: typeof v === 'object'
? JSON.stringify(v)
: String(v)}
</td>
))}
</tr>
))}
</tbody>
</table>
)}
</div>
)}
</section>
)
})}
</main>
</div>
)
}