fix(energy): 日期速选并入 sticky 头部,避免滚动时被遮挡
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
之前「本周/本月/近 15 天」放在 HydrogenDaily/ElectricDaily 的
内容区第一行,sticky 头部独占顶部。滚动后这一行会从 sticky
头部下方钻过去,露出半截,看起来像被切。
修复:把日期速选行也放进 sticky 头部白卡里:
- EnergyModule 持有 hydroPick / electricPick state
- 头部第三行(border-t 分割)渲染速选按钮,仅 daily 模式显示
- HydrogenView/ElectricView/ElectricDaily/HydrogenDaily 改为
通过 pick prop 接收,组件内不再 useState
现在头部「Top Tab + Sub Tab + 日期速选」是同一张白卡,
滚动时整体一起 sticky,不再有半截遮挡。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,15 +6,12 @@ import { fetchElectricMonthly } from './api';
|
|||||||
import type { CustomerType, DateQuickPick, ElectricMonthGroup } from './types';
|
import type { CustomerType, DateQuickPick, ElectricMonthGroup } from './types';
|
||||||
import RotatingFooterHint from '../../components/RotatingFooterHint';
|
import RotatingFooterHint from '../../components/RotatingFooterHint';
|
||||||
|
|
||||||
const QUICK_PICK_OPTIONS: Array<{ id: DateQuickPick; label: string }> = [
|
interface Props {
|
||||||
{ id: 'thisWeek', label: '本周' },
|
pick: DateQuickPick;
|
||||||
{ id: 'thisMonth', label: '本月' },
|
}
|
||||||
{ id: 'last15', label: '近 15 天' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function ElectricDaily() {
|
export default function ElectricDaily({ pick }: Props) {
|
||||||
const [customer, setCustomer] = useState<CustomerType>('lingniu');
|
const [customer, setCustomer] = useState<CustomerType>('lingniu');
|
||||||
const [pick, setPick] = useState<DateQuickPick>('last15');
|
|
||||||
const [months, setMonths] = useState<ElectricMonthGroup[] | null>(null);
|
const [months, setMonths] = useState<ElectricMonthGroup[] | null>(null);
|
||||||
const [openMonths, setOpenMonths] = useState<Set<string>>(new Set());
|
const [openMonths, setOpenMonths] = useState<Set<string>>(new Set());
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
@@ -44,23 +41,6 @@ export default function ElectricDaily() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
{/* 日期速选 */}
|
|
||||||
<div className="flex items-center gap-2 overflow-x-auto -mx-1 px-1 pb-1 snap-x">
|
|
||||||
{QUICK_PICK_OPTIONS.map(opt => (
|
|
||||||
<button
|
|
||||||
key={opt.id}
|
|
||||||
onClick={() => setPick(opt.id)}
|
|
||||||
className={`shrink-0 snap-start rounded-xl px-3 py-1.5 text-[11px] font-bold border transition-colors ${
|
|
||||||
pick === opt.id
|
|
||||||
? 'bg-blue-50 text-blue-600 border-blue-200'
|
|
||||||
: 'bg-white text-slate-500 border-slate-200 hover:bg-slate-50'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{opt.label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 客户类型 */}
|
{/* 客户类型 */}
|
||||||
<div className="bg-slate-100 rounded-xl p-1 grid grid-cols-2 gap-1">
|
<div className="bg-slate-100 rounded-xl p-1 grid grid-cols-2 gap-1">
|
||||||
{(['lingniu', 'external'] as const).map(c => (
|
{(['lingniu', 'external'] as const).map(c => (
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import ElectricOverview from './ElectricOverview';
|
import ElectricOverview from './ElectricOverview';
|
||||||
import ElectricDaily from './ElectricDaily';
|
import ElectricDaily from './ElectricDaily';
|
||||||
|
import type { DateQuickPick } from './types';
|
||||||
|
|
||||||
export type ElectricSubTab = 'daily' | 'overview';
|
export type ElectricSubTab = 'daily' | 'overview';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
sub: ElectricSubTab;
|
sub: ElectricSubTab;
|
||||||
|
pick: DateQuickPick;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ElectricView({ sub }: Props) {
|
export default function ElectricView({ sub, pick }: Props) {
|
||||||
return sub === 'overview' ? <ElectricOverview /> : <ElectricDaily />;
|
return sub === 'overview' ? <ElectricOverview /> : <ElectricDaily pick={pick} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,13 @@ import { motion } from 'motion/react';
|
|||||||
import HydrogenView, { type HydrogenSubTab } from './HydrogenView';
|
import HydrogenView, { type HydrogenSubTab } from './HydrogenView';
|
||||||
import ElectricView, { type ElectricSubTab } from './ElectricView';
|
import ElectricView, { type ElectricSubTab } from './ElectricView';
|
||||||
import ETCView from './ETCView';
|
import ETCView from './ETCView';
|
||||||
|
import type { DateQuickPick } from './types';
|
||||||
|
|
||||||
|
const QUICK_PICK_OPTIONS: Array<{ id: DateQuickPick; label: string }> = [
|
||||||
|
{ id: 'thisWeek', label: '本周' },
|
||||||
|
{ id: 'thisMonth', label: '本月' },
|
||||||
|
{ id: 'last15', label: '近 15 天' },
|
||||||
|
];
|
||||||
|
|
||||||
type TopTab = 'hydrogen' | 'electric' | 'etc';
|
type TopTab = 'hydrogen' | 'electric' | 'etc';
|
||||||
type SubTabId = HydrogenSubTab | ElectricSubTab; // 'daily' | 'overview'
|
type SubTabId = HydrogenSubTab | ElectricSubTab; // 'daily' | 'overview'
|
||||||
@@ -23,9 +30,16 @@ export default function EnergyModule() {
|
|||||||
const [activeTab, setActiveTab] = useState<TopTab>('hydrogen');
|
const [activeTab, setActiveTab] = useState<TopTab>('hydrogen');
|
||||||
const [hydroSub, setHydroSub] = useState<HydrogenSubTab>('daily');
|
const [hydroSub, setHydroSub] = useState<HydrogenSubTab>('daily');
|
||||||
const [electricSub, setElectricSub] = useState<ElectricSubTab>('daily');
|
const [electricSub, setElectricSub] = useState<ElectricSubTab>('daily');
|
||||||
|
const [hydroPick, setHydroPick] = useState<DateQuickPick>('last15');
|
||||||
|
const [electricPick, setElectricPick] = useState<DateQuickPick>('last15');
|
||||||
const showSubTabs = activeTab === 'hydrogen' || activeTab === 'electric';
|
const showSubTabs = activeTab === 'hydrogen' || activeTab === 'electric';
|
||||||
const currentSub: SubTabId = activeTab === 'electric' ? electricSub : hydroSub;
|
const currentSub: SubTabId = activeTab === 'electric' ? electricSub : hydroSub;
|
||||||
const setSub = (id: SubTabId) => activeTab === 'electric' ? setElectricSub(id) : setHydroSub(id);
|
const setSub = (id: SubTabId) => activeTab === 'electric' ? setElectricSub(id) : setHydroSub(id);
|
||||||
|
// 是否在 daily 模式(需要在 sticky 头部展示日期速选)
|
||||||
|
const showQuickPick = (activeTab === 'hydrogen' && hydroSub === 'daily')
|
||||||
|
|| (activeTab === 'electric' && electricSub === 'daily');
|
||||||
|
const currentPick: DateQuickPick = activeTab === 'electric' ? electricPick : hydroPick;
|
||||||
|
const setPick = (id: DateQuickPick) => activeTab === 'electric' ? setElectricPick(id) : setHydroPick(id);
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[#F8F9FB] text-gray-800 font-sans p-3 md:p-6 relative" style={{ overflowX: 'clip' }}>
|
<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="max-w-6xl mx-auto flex flex-col gap-3 pb-16 landscape:pb-0 landscape:h-full landscape:flex-1 landscape:overflow-hidden">
|
||||||
@@ -74,11 +88,32 @@ export default function EnergyModule() {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{/* 日期速选:daily 模式时跟着 sticky,避免滚动后被遮挡 */}
|
||||||
|
{showQuickPick && (
|
||||||
|
<div className="px-2 pb-2 pt-1 border-t border-slate-50 flex items-center gap-2 overflow-x-auto">
|
||||||
|
{QUICK_PICK_OPTIONS.map(opt => {
|
||||||
|
const active = currentPick === opt.id;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={opt.id}
|
||||||
|
onClick={() => setPick(opt.id)}
|
||||||
|
className={`shrink-0 rounded-lg px-3 py-1 text-[11px] font-bold border transition-colors ${
|
||||||
|
active
|
||||||
|
? 'bg-blue-50 text-blue-600 border-blue-200'
|
||||||
|
: 'bg-white text-slate-500 border-slate-200 hover:bg-slate-50'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{opt.label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{activeTab === 'hydrogen' && <HydrogenView sub={hydroSub} />}
|
{activeTab === 'hydrogen' && <HydrogenView sub={hydroSub} pick={hydroPick} />}
|
||||||
{activeTab === 'electric' && <ElectricView sub={electricSub} />}
|
{activeTab === 'electric' && <ElectricView sub={electricSub} pick={electricPick} />}
|
||||||
{activeTab === 'etc' && <ETCView />}
|
{activeTab === 'etc' && <ETCView />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,14 +7,11 @@ import { fetchHydrogenDaily } from './api';
|
|||||||
import type { CustomerType, DateQuickPick, HydrogenDailyRow } from './types';
|
import type { CustomerType, DateQuickPick, HydrogenDailyRow } from './types';
|
||||||
import RotatingFooterHint from '../../components/RotatingFooterHint';
|
import RotatingFooterHint from '../../components/RotatingFooterHint';
|
||||||
|
|
||||||
const QUICK_PICK_OPTIONS: Array<{ id: DateQuickPick; label: string }> = [
|
interface Props {
|
||||||
{ id: 'thisWeek', label: '本周' },
|
pick: DateQuickPick;
|
||||||
{ id: 'thisMonth', label: '本月' },
|
}
|
||||||
{ id: 'last15', label: '近 15 天' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function HydrogenDaily() {
|
export default function HydrogenDaily({ pick }: Props) {
|
||||||
const [pick, setPick] = useState<DateQuickPick>('last15');
|
|
||||||
const [customer, setCustomer] = useState<CustomerType>('lingniu');
|
const [customer, setCustomer] = useState<CustomerType>('lingniu');
|
||||||
const [expanded, setExpanded] = useState<Set<string>>(new Set());
|
const [expanded, setExpanded] = useState<Set<string>>(new Set());
|
||||||
const [rows, setRows] = useState<HydrogenDailyRow[] | null>(null);
|
const [rows, setRows] = useState<HydrogenDailyRow[] | null>(null);
|
||||||
@@ -41,23 +38,6 @@ export default function HydrogenDaily() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
{/* 日期速选 */}
|
|
||||||
<div className="flex items-center gap-2 overflow-x-auto -mx-1 px-1 pb-1 snap-x">
|
|
||||||
{QUICK_PICK_OPTIONS.map(opt => (
|
|
||||||
<button
|
|
||||||
key={opt.id}
|
|
||||||
onClick={() => setPick(opt.id)}
|
|
||||||
className={`shrink-0 snap-start rounded-xl px-3 py-1.5 text-[11px] font-bold border transition-colors ${
|
|
||||||
pick === opt.id
|
|
||||||
? 'bg-blue-50 text-blue-600 border-blue-200'
|
|
||||||
: 'bg-white text-slate-500 border-slate-200 hover:bg-slate-50'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{opt.label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 客户类型 segmented */}
|
{/* 客户类型 segmented */}
|
||||||
<div className="bg-slate-100 rounded-xl p-1 grid grid-cols-2 gap-1">
|
<div className="bg-slate-100 rounded-xl p-1 grid grid-cols-2 gap-1">
|
||||||
{(['lingniu', 'external'] as const).map(c => (
|
{(['lingniu', 'external'] as const).map(c => (
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import HydrogenOverview from './HydrogenOverview';
|
import HydrogenOverview from './HydrogenOverview';
|
||||||
import HydrogenDaily from './HydrogenDaily';
|
import HydrogenDaily from './HydrogenDaily';
|
||||||
|
import type { DateQuickPick } from './types';
|
||||||
|
|
||||||
export type HydrogenSubTab = 'daily' | 'overview';
|
export type HydrogenSubTab = 'daily' | 'overview';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
sub: HydrogenSubTab;
|
sub: HydrogenSubTab;
|
||||||
|
pick: DateQuickPick;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function HydrogenView({ sub }: Props) {
|
export default function HydrogenView({ sub, pick }: Props) {
|
||||||
return sub === 'overview' ? <HydrogenOverview /> : <HydrogenDaily />;
|
return sub === 'overview' ? <HydrogenOverview /> : <HydrogenDaily pick={pick} />;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user