refactor(dashboard): remove Pyramid and align activity charts

This commit is contained in:
yuxuanhui
2026-09-12 00:36:17 +08:00
parent 16653086c4
commit 849f86fef7
2 changed files with 27 additions and 183 deletions
+18 -147
View File
@@ -3,9 +3,7 @@ import {
Banner,
Button,
Card,
Input,
Spin,
Table,
Tag,
Toast,
Tooltip,
@@ -14,9 +12,7 @@ import {
BarChart3,
CalendarDays,
Clock3,
Layers3,
RefreshCw,
Search,
Send,
ShieldCheck,
} from "lucide-react";
@@ -24,14 +20,6 @@ import { api, post } from "../api";
import type { Account, Job } from "../types";
import "./home.css";
type PyramidRow = {
region: string;
delay: number;
category_id: string;
category_name: string;
value: number | null;
};
type PyramidSnapshot = { items: PyramidRow[]; fetched_at: string };
type ActivityDay = { date: string; count: number | null };
type ActivitySnapshot = {
items: ActivityDay[];
@@ -108,7 +96,6 @@ export function HomePage({
const [sending, setSending] = useState(false);
const [verificationId, setVerificationId] = useState<string | null>(null);
const [verificationError, setVerificationError] = useState("");
const [search, setSearch] = useState("");
useEffect(() => {
const timer = window.setInterval(() => setNow(new Date()), 1000);
return () => clearInterval(timer);
@@ -128,11 +115,6 @@ export function HomePage({
connected,
revision,
);
const multipliers = useResource<PyramidSnapshot>(
"/dashboard/pyramid-multipliers",
connected,
revision,
);
const verification = jobs.find((job) => job.id === verificationId);
const authRunning = jobs.some(
(job) =>
@@ -166,21 +148,6 @@ export function HomePage({
setSending(false);
}
}
const eligible = (multipliers.data?.items ?? [])
.filter((row) => row.value !== null && row.value > 1)
.sort(
(a, b) =>
b.value! - a.value! ||
a.region.localeCompare(b.region) ||
a.delay - b.delay ||
a.category_id.localeCompare(b.category_id),
);
const query = search.trim().toLowerCase();
const rows = eligible.filter((row) =>
`${row.region} D${row.delay} ${row.category_id} ${row.category_name}`
.toLowerCase()
.includes(query),
);
const submittedToday =
submissions.data?.today === today
? submissions.data.items.find((day) => day.date === today)?.count
@@ -191,8 +158,6 @@ export function HomePage({
(sum, day) => sum + day.count!,
0,
);
const unknownMultipliers =
multipliers.data?.items.filter((row) => row.value === null).length ?? 0;
return (
<section className="home-page" aria-label="首页看板">
@@ -286,34 +251,26 @@ export function HomePage({
}
loading={simulations.loading}
/>
<Metric
label="Pyramid 加成类别"
icon={<Layers3 size={18} aria-hidden="true" />}
value={multipliers.data ? eligible.length : null}
unit="类"
hint="当前乘数 > 1 的地区 / 延迟 / 类别"
loading={multipliers.loading}
/>
</div>
<Card
className="home-card home-calendar-card"
title={
<PanelTitle
icon={<CalendarDays size={18} aria-hidden="true" />}
title="Alpha 提交日历"
/>
}
headerExtraContent={<Tag>近 26 周</Tag>}
>
<ResourceContent
state={submissions}
connected={connected}
name="提交日历"
>
{submissions.data && <SubmissionCalendar data={submissions.data} />}
</ResourceContent>
</Card>
<div className="home-panels">
<Card
className="home-card home-calendar-card"
title={
<PanelTitle
icon={<CalendarDays size={18} aria-hidden="true" />}
title="Alpha 提交日历"
/>
}
headerExtraContent={<Tag>近 26 周</Tag>}
>
<ResourceContent
state={submissions}
connected={connected}
name="提交日历"
>
{submissions.data && <SubmissionCalendar data={submissions.data} />}
</ResourceContent>
</Card>
<Card
className="home-card"
title={
@@ -332,92 +289,6 @@ export function HomePage({
{simulations.data && <SimulationChart data={simulations.data} />}
</ResourceContent>
</Card>
<Card
className="home-card home-pyramid-card"
title={
<PanelTitle
icon={<Layers3 size={18} aria-hidden="true" />}
title="Pyramid 乘数"
/>
}
headerExtraContent={<Tag color="blue">乘数 &gt; 1</Tag>}
>
<ResourceContent
state={multipliers}
connected={connected}
name="Pyramid 乘数"
>
{multipliers.data && (
<>
<div className="home-table-tools">
<Input
aria-label="搜索 Pyramid 类别"
prefix={<Search size={16} aria-hidden="true" />}
value={search}
onChange={setSearch}
showClear
placeholder="搜索地区、延迟或类别"
/>
<span>{rows.length} 类</span>
</div>
<div className="home-table-wrap">
<Table<PyramidRow>
dataSource={rows}
rowKey={(row) =>
row ? `${row.region}:${row.delay}:${row.category_id}` : ""
}
pagination={false}
size="small"
sticky
empty={
eligible.length
? "没有匹配的 Pyramid 类别"
: "当前没有乘数大于 1 的类别"
}
columns={[
{
title: "数据类别",
dataIndex: "category_name",
render: (_, row) => (
<div className="home-category">
<strong>{row.category_name}</strong>
<small>{row.category_id}</small>
</div>
),
},
{ title: "地区", dataIndex: "region", width: 68 },
{
title: "延迟",
key: "delay",
width: 58,
render: (_, row) => `D${row.delay}`,
},
{
title: "乘数",
key: "value",
width: 80,
align: "right",
render: (_, row) => (
<Tag color="blue">
{row.value?.toLocaleString("zh-CN")}×
</Tag>
),
},
]}
/>
</div>
<p className="home-footnote">
按乘数从高到低排列
{unknownMultipliers
? ` · ${unknownMultipliers} 类乘数未知,未列入`
: ""}{" "}
· 更新于 {easternTime(new Date(multipliers.data.fetched_at))}{" "}
美东
</p>
</>
)}
</ResourceContent>
</Card>
</div>
</section>
);
+9 -36
View File
@@ -43,7 +43,7 @@
}
.home-metrics {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
margin-bottom: 20px;
}
@@ -107,14 +107,11 @@
color: var(--muted);
flex-shrink: 0;
}
.home-calendar-card {
margin-bottom: 20px;
}
.home-panels {
display: grid;
grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
gap: 20px;
align-items: start;
align-items: stretch;
}
.home-connect {
display: flex;
@@ -170,15 +167,15 @@
.home-calendar {
display: flex;
gap: 10px;
min-width: 550px;
min-width: 510px;
max-width: 840px;
margin: 0 auto;
}
.home-weekdays {
display: grid;
grid-template-rows: repeat(7, 1fr);
gap: 5px;
padding-top: 25px;
gap: 4px;
padding-top: 24px;
color: var(--muted);
font-size: 11px;
}
@@ -188,15 +185,17 @@
}
.home-calendar-weeks {
display: grid;
min-width: 0;
grid-auto-flow: column;
grid-auto-columns: minmax(14px, 1fr);
gap: 5px;
gap: 4px;
flex: 1;
}
.home-calendar-week {
display: grid;
min-width: 0;
grid-template-rows: 20px repeat(7, 1fr);
gap: 5px;
gap: 4px;
}
.home-month {
color: var(--muted);
@@ -282,32 +281,6 @@ body[theme-mode="dark"] .heat-4 {
.home-legend > span {
margin: 0 4px;
}
.home-table-tools {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.home-table-tools > span {
color: var(--muted);
font-size: 12px;
flex-shrink: 0;
}
.home-table-wrap {
max-height: 300px;
overflow: auto;
}
.home-category {
overflow-wrap: anywhere;
}
.home-category strong {
font-weight: 400;
}
.home-category small {
display: block;
margin-top: 3px;
color: var(--muted);
}
.home-footnote {
color: var(--muted);
font-size: 11px;