fix: 优化docker 镜像

This commit is contained in:
Daniel
2026-03-02 14:10:43 +08:00
parent 783a69dad1
commit 36576592a2
25 changed files with 491 additions and 58 deletions

View File

@@ -1,10 +1,19 @@
import { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { StatCard } from './StatCard'
import { useSituationStore } from '@/store/situationStore'
import { useReplaySituation } from '@/hooks/useReplaySituation'
import { usePlaybackStore } from '@/store/playbackStore'
import { Wifi, WifiOff, Clock, Database } from 'lucide-react'
import { Wifi, WifiOff, Clock, Share2, Heart, Eye } from 'lucide-react'
const STORAGE_LIKES = 'us-iran-dashboard-likes'
function getStoredLikes(): number {
try {
return parseInt(localStorage.getItem(STORAGE_LIKES) ?? '0', 10)
} catch {
return 0
}
}
export function HeaderPanel() {
const situation = useReplaySituation()
@@ -12,12 +21,64 @@ export function HeaderPanel() {
const isReplayMode = usePlaybackStore((s) => s.isReplayMode)
const { usForces, iranForces } = situation
const [now, setNow] = useState(() => new Date())
const [likes, setLikes] = useState(getStoredLikes)
const [liked, setLiked] = useState(false)
const [viewers, setViewers] = useState(0)
const [cumulative, setCumulative] = useState(0)
useEffect(() => {
const timer = setInterval(() => setNow(new Date()), 1000)
return () => clearInterval(timer)
}, [])
const fetchStats = async () => {
try {
const res = await fetch('/api/visit', { method: 'POST' })
const data = await res.json()
if (data.viewers != null) setViewers(data.viewers)
if (data.cumulative != null) setCumulative(data.cumulative)
} catch {
setViewers((v) => (v > 0 ? v : 0))
setCumulative((c) => (c > 0 ? c : 0))
}
}
useEffect(() => {
fetchStats()
const t = setInterval(fetchStats, 30000)
return () => clearInterval(t)
}, [])
const handleShare = async () => {
const url = window.location.href
const title = '美伊军事态势显示'
if (typeof navigator.share === 'function') {
try {
await navigator.share({ title, url })
} catch (e) {
if ((e as Error).name !== 'AbortError') {
await copyToClipboard(url)
}
}
} else {
await copyToClipboard(url)
}
}
const copyToClipboard = (text: string) => {
return navigator.clipboard?.writeText(text) ?? Promise.resolve()
}
const handleLike = () => {
if (liked) return
setLiked(true)
const next = likes + 1
setLikes(next)
try {
localStorage.setItem(STORAGE_LIKES, String(next))
} catch {}
}
const formatDateTime = (d: Date) =>
d.toLocaleString('zh-CN', {
year: 'numeric',
@@ -59,14 +120,33 @@ export function HeaderPanel() {
)}
</div>
</div>
<div className="flex shrink-0 items-center gap-3">
<Link
to="/db"
<div className="flex shrink-0 items-center gap-4">
<div className="flex items-center gap-2 text-military-text-secondary">
<Eye className="h-3.5 w-3.5" />
<span className="text-[10px]"> <b className="text-military-accent tabular-nums">{viewers}</b></span>
<span className="text-[10px] opacity-70">|</span>
<span className="text-[10px]"> <b className="tabular-nums">{cumulative}</b></span>
</div>
<button
type="button"
onClick={handleShare}
className="flex items-center gap-1 rounded border border-military-border px-2 py-1 text-[10px] text-military-text-secondary hover:bg-military-border/30 hover:text-cyan-400"
>
<Database className="h-3 w-3" />
</Link>
<Share2 className="h-3 w-3" />
</button>
<button
type="button"
onClick={handleLike}
className={`flex items-center gap-1 rounded border px-2 py-1 text-[10px] transition-colors ${
liked
? 'border-red-500/50 bg-red-500/20 text-red-400'
: 'border-military-border text-military-text-secondary hover:bg-military-border/30 hover:text-red-400'
}`}
>
<Heart className={`h-3 w-3 ${liked ? 'fill-current' : ''}`} />
{likes > 0 && <span className="tabular-nums">{likes}</span>}
</button>
{isConnected ? (
<>
<Wifi className="h-3.5 w-3.5 text-green-500" />