feat(energy): 能源管理新增 ETC tab,建设中占位页
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

- EnergyModule TopTab 加 'etc',用 lucide Receipt 图标
- TABS 数据驱动渲染,加新 tab 不用复制粘贴
- 新增 ETCView:可爱的「建设中」占位
    - 大号 Construction 图标 + 顶上的 Hammer 摆动动画
    - 文案「ETC 模块建设中」+ 副标说明
    - 4 步进度(需求评审/数据对接/页面开发/正式上线)
      已完成项绿点、进行中项黄点 + 脉冲,未来项灰点
    - 底部专属 RotatingFooterHint,5 条 ETC 上下文文案

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-30 14:42:00 +08:00
parent 8d861538af
commit 234b44ea03
2 changed files with 108 additions and 23 deletions

View File

@@ -1,10 +1,17 @@
import { useState } from 'react';
import { Fuel, BatteryCharging } from 'lucide-react';
import { Fuel, BatteryCharging, Receipt } from 'lucide-react';
import { motion } from 'motion/react';
import HydrogenView from './HydrogenView';
import ElectricView from './ElectricView';
import ETCView from './ETCView';
type TopTab = 'hydrogen' | 'electric';
type TopTab = 'hydrogen' | 'electric' | 'etc';
const TABS: { key: TopTab; label: string; icon: typeof Fuel }[] = [
{ key: 'hydrogen', label: '氢能', icon: Fuel },
{ key: 'electric', label: '电能', icon: BatteryCharging },
{ key: 'etc', label: 'ETC', icon: Receipt },
];
export default function EnergyModule() {
const [activeTab, setActiveTab] = useState<TopTab>('hydrogen');
@@ -12,28 +19,27 @@ export default function EnergyModule() {
<div className="min-h-screen bg-[#F8F9FB] text-gray-800 font-sans p-3 md:p-6 relative" style={{ overflowX: 'clip' }}>
<div className="max-w-6xl mx-auto flex flex-col gap-3 pb-16 landscape:pb-0 landscape:h-full landscape:flex-1 landscape:overflow-hidden">
<div className="bg-white px-4 py-2 rounded-2xl border border-slate-100 shadow-sm flex items-center gap-6 sticky top-0 z-30">
<button
onClick={() => setActiveTab('hydrogen')}
className={`flex items-center gap-2 py-1 transition-all relative ${activeTab === 'hydrogen' ? 'text-blue-600' : 'text-slate-400'}`}
>
<Fuel size={14} />
<span className="text-[11px] font-bold"></span>
{activeTab === 'hydrogen' && (
<motion.div layoutId="activeEnergyTopTab" className="absolute -bottom-2 left-0 right-0 h-0.5 bg-blue-600 rounded-full" />
)}
</button>
<button
onClick={() => setActiveTab('electric')}
className={`flex items-center gap-2 py-1 transition-all relative ${activeTab === 'electric' ? 'text-blue-600' : 'text-slate-400'}`}
>
<BatteryCharging size={14} />
<span className="text-[11px] font-bold"></span>
{activeTab === 'electric' && (
<motion.div layoutId="activeEnergyTopTab" className="absolute -bottom-2 left-0 right-0 h-0.5 bg-blue-600 rounded-full" />
)}
</button>
{TABS.map(tab => {
const Icon = tab.icon;
const active = activeTab === tab.key;
return (
<button
key={tab.key}
onClick={() => setActiveTab(tab.key)}
className={`flex items-center gap-2 py-1 transition-all relative ${active ? 'text-blue-600' : 'text-slate-400'}`}
>
<Icon size={14} />
<span className="text-[11px] font-bold">{tab.label}</span>
{active && (
<motion.div layoutId="activeEnergyTopTab" className="absolute -bottom-2 left-0 right-0 h-0.5 bg-blue-600 rounded-full" />
)}
</button>
);
})}
</div>
{activeTab === 'hydrogen' ? <HydrogenView /> : <ElectricView />}
{activeTab === 'hydrogen' && <HydrogenView />}
{activeTab === 'electric' && <ElectricView />}
{activeTab === 'etc' && <ETCView />}
</div>
</div>
);