import { useEffect, useMemo, useState } from 'react'; import { ChevronRight, Plug } from 'lucide-react'; import { motion, AnimatePresence } from 'motion/react'; import TrendBadge from './TrendBadge'; import { fetchElectricMonthly } from './api'; import type { CustomerType, DateQuickPick, ElectricMonthGroup } from './types'; import RotatingFooterHint from '../../components/RotatingFooterHint'; const QUICK_PICK_OPTIONS: Array<{ id: DateQuickPick; label: string }> = [ { id: 'thisWeek', label: '本周' }, { id: 'thisMonth', label: '本月' }, { id: 'last15', label: '近 15 天' }, ]; export default function ElectricDaily() { const [customer, setCustomer] = useState('lingniu'); const [pick, setPick] = useState('last15'); const [months, setMonths] = useState(null); const [openMonths, setOpenMonths] = useState>(new Set()); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; setError(null); fetchElectricMonthly(customer, pick) .then(m => { if (cancelled) return; setMonths(m); // 默认展开最新一个月 if (m.length > 0) setOpenMonths(prev => prev.size > 0 ? prev : new Set([m[0].month])); }) .catch(e => { if (!cancelled) setError(e instanceof Error ? e.message : String(e)); }); return () => { cancelled = true; }; }, [customer, pick]); const toggleMonth = (m: string) => setOpenMonths(prev => { const next = new Set(prev); next.has(m) ? next.delete(m) : next.add(m); return next; }); const totalKwh = useMemo(() => (months ?? []).reduce((s, m) => s + (m.kwh || 0), 0), [months]); const showExternalEmpty = customer === 'external' && months !== null && totalKwh === 0; return (
{/* 日期速选 */}
{QUICK_PICK_OPTIONS.map(opt => ( ))}
{/* 客户类型 */}
{(['lingniu', 'external'] as const).map(c => ( ))}
{/* 外部车辆 数据未就绪 */} {showExternalEmpty && (
外部车辆 · 数据未就绪
新系统的外部车辆充电数据还在准备中
上线后此处将展示完整明细
)} {/* 月份分组表 */} {!showExternalEmpty && (
月份 / 日期 充电量 (度) 环比
{error ? (
加载失败:{error}
) : months === null ? (
加载中…
) : months.length === 0 ? (
暂无数据
) : months.map(m => { const open = openMonths.has(m.month); return (
{open && ( {m.rows.map(d => { const isAbnormal = Math.abs(d.chainPct) >= 0.3; const abnormalBg = isAbnormal ? d.chainPct > 0 ? 'bg-emerald-50/40' : 'bg-red-50/40' : 'bg-slate-50/50'; return (
{d.date.slice(5)} {d.kwh.toLocaleString('zh-CN', { maximumFractionDigits: 2 })}
); })}
)}
); })}
)}
); }