feat(energy): hydrogen daily — period bar chart with anomaly coloring

Mirrors the electric-view treatment: a 时段每日加氢量 bar chart sits
between the customer toggle and the table. Bars use the cyan→blue
gradient by default; days where |chainPct| >= 30% render in solid
emerald (positive) or red (negative), giving an at-a-glance view of
anomalous days that's reinforced by the table's row tinting below.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-28 12:32:40 +08:00
parent d9b9ff495e
commit 313325553d

View File

@@ -1,6 +1,7 @@
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { ChevronRight } from 'lucide-react'; import { ChevronRight } from 'lucide-react';
import { motion, AnimatePresence } from 'motion/react'; import { motion, AnimatePresence } from 'motion/react';
import { BarChart, Bar, XAxis, YAxis, ResponsiveContainer, Cell, Tooltip } from 'recharts';
import TrendBadge from './TrendBadge'; import TrendBadge from './TrendBadge';
import { HYDROGEN_DAILY } from './mock'; import { HYDROGEN_DAILY } from './mock';
import type { CustomerType, DateQuickPick, HydrogenDailyRow } from './types'; import type { CustomerType, DateQuickPick, HydrogenDailyRow } from './types';
@@ -57,6 +58,9 @@ export default function HydrogenDaily() {
.sort((a, b) => b.date.localeCompare(a.date)); .sort((a, b) => b.date.localeCompare(a.date));
}, [pick, customer]); }, [pick, customer]);
// 柱图:按日期升序,用于"从左到右时间流"
const trendData = useMemo(() => [...rows].sort((a, b) => a.date.localeCompare(b.date)), [rows]);
const totalKg = rows.reduce((a, r) => a + r.totalKg, 0); const totalKg = rows.reduce((a, r) => a + r.totalKg, 0);
const toggle = (date: string) => setExpanded(prev => { const toggle = (date: string) => setExpanded(prev => {
@@ -99,6 +103,51 @@ export default function HydrogenDaily() {
))} ))}
</div> </div>
{/* 时段加氢量柱图 */}
{trendData.length > 0 && (
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-4">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-bold text-slate-700"></span>
<span className="text-[11px] text-slate-400 font-bold"> Kg</span>
</div>
<ResponsiveContainer width="100%" height={160}>
<BarChart data={trendData} margin={{ top: 8, right: 4, bottom: 0, left: 0 }}>
<XAxis
dataKey="date"
tickFormatter={(v: string) => v.slice(5)}
tick={{ fontSize: 10, fill: '#94a3b8' }}
tickLine={false}
axisLine={false}
interval="preserveStartEnd"
minTickGap={8}
/>
<YAxis hide />
<Tooltip
formatter={(v) => [`${Number(v ?? 0).toLocaleString('zh-CN', { maximumFractionDigits: 2 })} Kg`, '加氢量']}
labelFormatter={(d) => `日期 ${d}`}
contentStyle={{ borderRadius: 12, fontSize: 12 }}
cursor={{ fill: 'rgba(34, 211, 238, 0.06)' }}
/>
<Bar dataKey="totalKg" radius={[4, 4, 0, 0]}>
{trendData.map((r, i) => {
const isAbnormal = Math.abs(r.chainPct) >= 0.3;
const fill = isAbnormal
? r.chainPct > 0 ? '#10b981' : '#ef4444'
: 'url(#hydrogenBarGrad)';
return <Cell key={i} fill={fill} />;
})}
</Bar>
<defs>
<linearGradient id="hydrogenBarGrad" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stopColor="#22d3ee" />
<stop offset="100%" stopColor="#3b82f6" />
</linearGradient>
</defs>
</BarChart>
</ResponsiveContainer>
</div>
)}
{/* 表格 */} {/* 表格 */}
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm overflow-hidden"> <div className="bg-white rounded-2xl border border-slate-100 shadow-sm overflow-hidden">
{/* 表头 */} {/* 表头 */}