fix: visual fixes — dark theme default, sidebar, dashboard cards, timeline dots, header counts
- Set data-theme=dark as default in index.html, useTheme defaults to 'dark' (issues 1, 10) - Rename "Cron" to "Cron 管理" in sidebar (issue 2) - Set card grid gap to 14px per design spec (issue 3) - Show D-grade profile names below health bar chart (issue 4) - Remove R/F/H/OK text from timeline, use colored dots with hover tooltip (issue 5) - Wire live online/running/offline counts via usePolling in header, add offline badge (issue 9) - Fix search placeholder to "搜索 Profile / 任务 / Cron / 事件..." (issue 9) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -62,37 +62,49 @@ function HealthBarChart({
|
||||
const maxVal = Math.max(dist.A, dist.B, dist.C, dist.D, 1)
|
||||
|
||||
return (
|
||||
<div className="space-y-3 mt-2">
|
||||
{GRADE_META.map(({ key, color }) => {
|
||||
const val = dist[key as keyof typeof dist] as number
|
||||
const pct = (val / maxVal) * 100
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
className="flex items-center gap-3 cursor-pointer group"
|
||||
onClick={() => onBarClick(key)}
|
||||
>
|
||||
<span
|
||||
className="w-5 text-center text-[13px] font-bold shrink-0"
|
||||
style={{ color }}
|
||||
<div>
|
||||
<div className="space-y-3 mt-2">
|
||||
{GRADE_META.map(({ key, color }) => {
|
||||
const val = dist[key as keyof typeof dist] as number
|
||||
const pct = (val / maxVal) * 100
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
className="flex items-center gap-3 cursor-pointer group"
|
||||
onClick={() => onBarClick(key)}
|
||||
>
|
||||
{key}
|
||||
</span>
|
||||
<div className="flex-1 h-6 rounded-[var(--radius-sm)] bg-[var(--bg-hover)] overflow-hidden relative">
|
||||
<div
|
||||
className="h-full rounded-[var(--radius-sm)] transition-all duration-500 group-hover:opacity-80"
|
||||
style={{
|
||||
width: `${Math.max(pct, 4)}%`,
|
||||
backgroundColor: color,
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className="w-5 text-center text-[13px] font-bold shrink-0"
|
||||
style={{ color }}
|
||||
>
|
||||
{key}
|
||||
</span>
|
||||
<div className="flex-1 h-6 rounded-[var(--radius-sm)] bg-[var(--bg-hover)] overflow-hidden relative">
|
||||
<div
|
||||
className="h-full rounded-[var(--radius-sm)] transition-all duration-500 group-hover:opacity-80"
|
||||
style={{
|
||||
width: `${Math.max(pct, 4)}%`,
|
||||
backgroundColor: color,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<span className="w-8 text-right text-[13px] shrink-0" style={{ color: 'var(--text-dim)' }}>
|
||||
{val}
|
||||
</span>
|
||||
</div>
|
||||
<span className="w-8 text-right text-[13px] shrink-0" style={{ color: 'var(--text-dim)' }}>
|
||||
{val}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{dist.d_profiles && dist.d_profiles.length > 0 && (
|
||||
<div className="mt-3 pt-3 border-t" style={{ borderColor: 'var(--border)' }}>
|
||||
<span className="text-[12px]" style={{ color: 'var(--text-dim)' }}>D 级 Profile: </span>
|
||||
{dist.d_profiles.map((name) => (
|
||||
<span key={name} className="inline-block text-[12px] px-2 py-0.5 mr-1 mb-1 rounded-[var(--radius-sm)]" style={{ background: 'var(--bg-hover)', color: 'var(--red)' }}>
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -186,28 +198,27 @@ export default function DashboardPage() {
|
||||
}
|
||||
|
||||
/* ---------- trend -> timeline events ---------- */
|
||||
const timelineEvents: TimelineEvent[] = trend.map((item) => ({
|
||||
time: hourLabel(item.hour),
|
||||
type: item.heartbeat_timeouts > 0 ? 'red' : item.feishu_disconnects > 0 ? 'orange' : item.restarts > 0 ? 'orange' : 'green',
|
||||
label: (
|
||||
<span className="flex gap-2 text-[11px]">
|
||||
{item.restarts > 0 && <span style={{ color: 'var(--yellow)' }}>R:{item.restarts}</span>}
|
||||
{item.feishu_disconnects > 0 && <span style={{ color: 'var(--orange)' }}>F:{item.feishu_disconnects}</span>}
|
||||
{item.heartbeat_timeouts > 0 && <span style={{ color: 'var(--red)' }}>H:{item.heartbeat_timeouts}</span>}
|
||||
{item.restarts === 0 && item.feishu_disconnects === 0 && item.heartbeat_timeouts === 0 && (
|
||||
<span style={{ color: 'var(--green)' }}>OK</span>
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
color: trendColor(item),
|
||||
}))
|
||||
const timelineEvents: TimelineEvent[] = trend.map((item) => {
|
||||
const details: string[] = []
|
||||
if (item.heartbeat_timeouts > 0) details.push(`心跳超时 ${item.heartbeat_timeouts}`)
|
||||
if (item.feishu_disconnects > 0) details.push(`飞书断连 ${item.feishu_disconnects}`)
|
||||
if (item.restarts > 0) details.push(`重启 ${item.restarts}`)
|
||||
const tooltipText = details.length > 0 ? details.join(' / ') : '正常'
|
||||
|
||||
return {
|
||||
time: hourLabel(item.hour),
|
||||
type: item.heartbeat_timeouts > 0 ? 'red' : item.feishu_disconnects > 0 ? 'orange' : item.restarts > 0 ? 'orange' : 'green',
|
||||
tooltip: tooltipText,
|
||||
color: trendColor(item),
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 style={{ color: 'var(--text)', fontSize: 18, fontWeight: 600 }}>蜂群总览</h2>
|
||||
|
||||
{/* ---- summary cards ---- */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mt-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-[14px] mt-4">
|
||||
<Card
|
||||
label="在线 Gateway"
|
||||
value={summary.online_count}
|
||||
@@ -237,7 +248,7 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
|
||||
{/* ---- health + trend ---- */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 mt-4">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-[14px] mt-4">
|
||||
{/* health distribution */}
|
||||
<div
|
||||
className="rounded-[var(--radius)] p-4"
|
||||
@@ -281,7 +292,7 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
|
||||
{/* ---- kanban + cron ---- */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 mt-4">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-[14px] mt-4">
|
||||
{/* kanban overview */}
|
||||
<div
|
||||
className="rounded-[var(--radius)] p-4"
|
||||
|
||||
Reference in New Issue
Block a user