feat(energy): 氢能总览删除 4 张 KPI 卡,底部加动态幽默提示
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

- 删除:年加氢量 / 年加氢费 / 累计羚牛承担 / 本月-今日 四张顶部 KPI 卡
  (及对应的 Skeleton 占位、未用的 Fuel/Wallet/Coins/CalendarClock import 与 fmt 工具函数)
- 新增 RotatingFooterHint:底部居中蓝色脉冲点 + 6 条幽默文案 4s 轮换淡入
  例如「更多统计维度接入中,欢迎您的建议 ~」「数据科学家正在深夜挖掘新维度…」

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-29 20:10:27 +08:00
parent 23a7722583
commit 3d4d862d73

View File

@@ -1,5 +1,4 @@
import { useEffect, useState } from 'react';
import { Fuel, Wallet, Coins, CalendarClock } from 'lucide-react';
import { BarChart, Bar, XAxis, YAxis, ResponsiveContainer, Cell, PieChart, Pie, Tooltip, LabelList } from 'recharts';
import { fetchHydrogenOverview, type HydrogenOverviewResponse } from './api';
@@ -30,16 +29,15 @@ const REGION_COLORS = [
'#94a3b8',
];
function fmtKg(kg: number) {
if (kg >= 1000) return `${(kg / 1000).toFixed(2)}T`;
return `${kg.toFixed(2)}Kg`;
}
function fmtYuanWan(yuan: number) {
return `¥${(yuan / 10_000).toFixed(2)}`;
}
function fmtYuan(yuan: number) {
return `¥${yuan.toLocaleString('zh-CN', { maximumFractionDigits: 2 })}`;
}
// 幽默动态提示词,每 4 秒轮换一条
const FOOTER_HINTS = [
'更多统计维度接入中,欢迎您的建议 ~',
'下一个图表,可能就是您建议的那个',
'数据科学家正在深夜挖掘新维度…',
'想看哪个角度的数据?告诉我们一下嘛',
'维度灵感正在路上,钉一下产品同学也行',
'数字背后还有故事,等下一次上线揭晓',
];
export default function HydrogenOverview() {
const [data, setData] = useState<HydrogenOverviewResponse | null>(null);
@@ -67,50 +65,6 @@ export default function HydrogenOverview() {
<div className="bg-white rounded-xl border border-slate-100 px-3 py-1.5 text-[11px] text-slate-400">
2025-01-01 1
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
{/* 卡 1年加氢量 */}
<div className="bg-gradient-to-br from-cyan-50 to-blue-50 rounded-2xl border border-slate-100 shadow-sm p-4 flex flex-col gap-2">
<div className="flex items-center justify-between text-[11px] text-slate-500">
<span className="flex items-center gap-1 font-bold"><Fuel size={12} className="text-cyan-600" /></span>
</div>
<div className="text-2xl lg:text-3xl font-bold text-slate-800 leading-tight">{fmtKg(k.yearKg)}</div>
</div>
{/* 卡 2年加氢费 */}
<div className="bg-gradient-to-br from-blue-50 to-violet-50 rounded-2xl border border-slate-100 shadow-sm p-4 flex flex-col gap-2">
<div className="flex items-center justify-between text-[11px] text-slate-500">
<span className="flex items-center gap-1 font-bold"><Wallet size={12} className="text-blue-600" /></span>
</div>
<div className="text-2xl lg:text-3xl font-bold text-slate-800 leading-tight">{fmtYuanWan(k.yearFee)}</div>
</div>
{/* 卡 3累计羚牛承担 */}
<div className="bg-gradient-to-br from-amber-50 to-orange-50 rounded-2xl border border-slate-100 shadow-sm p-4 flex flex-col gap-2">
<div className="flex items-center justify-between text-[11px] text-slate-500">
<span className="flex items-center gap-1 font-bold"><Coins size={12} className="text-amber-600" /></span>
</div>
<div className="text-2xl lg:text-3xl font-bold text-slate-800 leading-tight">{fmtYuanWan(k.lingniuBornFee)}</div>
<div className="text-[11px] text-slate-500 font-bold space-y-0.5">
<div> <span className="text-slate-700">{fmtKg(k.lingniuBornKg)}</span></div>
</div>
</div>
{/* 卡 4本月 / 今日 */}
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-4 flex flex-col gap-2">
<div className="flex items-center justify-between text-[11px] text-slate-500">
<span className="flex items-center gap-1 font-bold"><CalendarClock size={12} className="text-slate-500" /> / </span>
</div>
<div className="grid grid-cols-2 gap-2">
<div>
<div className="text-[10px] text-slate-400 font-bold"></div>
<div className="text-base md:text-lg font-bold text-slate-800">{fmtKg(k.monthKg)}</div>
<div className="text-[11px] text-slate-500 font-bold">{fmtYuanWan(k.monthFee)}</div>
</div>
<div>
<div className="text-[10px] text-slate-400 font-bold"></div>
<div className="text-base md:text-lg font-bold text-slate-800">{fmtKg(k.todayKg)}</div>
<div className="text-[11px] text-slate-500 font-bold">{fmtYuan(k.todayFee)}</div>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{/* Top5 加氢站 */}
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-4">
@@ -194,6 +148,33 @@ export default function HydrogenOverview() {
</div>
</div>
</div>
<RotatingFooterHint />
</div>
);
}
function RotatingFooterHint() {
const [idx, setIdx] = useState(0);
useEffect(() => {
const t = setInterval(() => setIdx(i => (i + 1) % FOOTER_HINTS.length), 4000);
return () => clearInterval(t);
}, []);
return (
<div className="mt-1 flex items-center justify-center gap-1.5 text-[11px] text-slate-400 font-bold">
<span className="inline-block w-1.5 h-1.5 rounded-full bg-blue-400 animate-pulse" />
<span
key={idx}
className="transition-opacity duration-300"
style={{ animation: 'hintFade 0.5s ease' }}
>
{FOOTER_HINTS[idx]}
</span>
<style>{`
@keyframes hintFade {
from { opacity: 0; transform: translateY(2px); }
to { opacity: 1; transform: translateY(0); }
}
`}</style>
</div>
);
}
@@ -206,20 +187,6 @@ function HydrogenOverviewSkeleton() {
<div className="h-3 w-44 bg-slate-100 rounded" />
</div>
{/* 4 张 KPI 卡 */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
{Array.from({ length: 4 }).map((_, i) => (
<div key={i} className="bg-gradient-to-br from-slate-50 to-slate-100/60 rounded-2xl border border-slate-100 shadow-sm p-4 flex flex-col gap-3">
<div className="h-3 w-16 bg-slate-200/70 rounded" />
<div className="h-7 w-24 bg-slate-200 rounded" />
<div className="space-y-1.5 mt-1">
<div className="h-2.5 w-20 bg-slate-100 rounded" />
<div className="h-2.5 w-24 bg-slate-100 rounded" />
</div>
</div>
))}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{/* Top5 占位 */}
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-4">