feat: 优化目标详情 Drawer 性能 — TDesign 生命周期控制、Tab 感知延迟加载、滚动穿透修复
This commit is contained in:
@@ -39,8 +39,10 @@ export function App() {
|
||||
refetch: refetchDashboard,
|
||||
} = useDashboard(dashboardRefetchInterval);
|
||||
const {
|
||||
activeTab,
|
||||
closeDrawer,
|
||||
handlePageChange,
|
||||
handleTabChange,
|
||||
handleTimeChange,
|
||||
historyData,
|
||||
historyLoading,
|
||||
@@ -126,13 +128,14 @@ export function App() {
|
||||
</div>
|
||||
</Content>
|
||||
<TargetDetailDrawer
|
||||
activeTab={activeTab}
|
||||
historyData={historyData}
|
||||
historyLoading={historyLoading}
|
||||
key={selectedTarget?.id}
|
||||
metricsData={metricsData}
|
||||
metricsLoading={metricsLoading}
|
||||
onClose={closeDrawer}
|
||||
onPageChange={handlePageChange}
|
||||
onTabChange={handleTabChange}
|
||||
onTimeChange={handleTimeChange}
|
||||
target={selectedTarget}
|
||||
timeFrom={timeFrom}
|
||||
|
||||
@@ -11,12 +11,14 @@ import { OverviewTab } from "./OverviewTab";
|
||||
import { StatusDot } from "./StatusDot";
|
||||
|
||||
interface TargetDetailDrawerProps {
|
||||
activeTab: string;
|
||||
historyData: HistoryResponse;
|
||||
historyLoading: boolean;
|
||||
metricsData: null | TargetMetricsResponse;
|
||||
metricsLoading: boolean;
|
||||
onClose: () => void;
|
||||
onPageChange: (page: number) => void;
|
||||
onTabChange: (tab: string) => void;
|
||||
onTimeChange: (from: string, to: string) => void;
|
||||
target: null | TargetStatus;
|
||||
timeFrom: string;
|
||||
@@ -31,19 +33,20 @@ const TIME_SHORTCUTS = [
|
||||
] as const;
|
||||
|
||||
export function TargetDetailDrawer({
|
||||
activeTab,
|
||||
historyData,
|
||||
historyLoading,
|
||||
metricsData,
|
||||
metricsLoading,
|
||||
onClose,
|
||||
onPageChange,
|
||||
onTabChange,
|
||||
onTimeChange,
|
||||
target,
|
||||
timeFrom,
|
||||
timeTo,
|
||||
}: TargetDetailDrawerProps) {
|
||||
const [activeShortcut, setActiveShortcut] = useState<string>("24h");
|
||||
const [activeTab, setActiveTab] = useState<TabValue>("overview");
|
||||
|
||||
const handleShortcut = useCallback(
|
||||
(value: string) => {
|
||||
@@ -67,25 +70,29 @@ export function TargetDetailDrawer({
|
||||
[onTimeChange],
|
||||
);
|
||||
|
||||
if (!target) return null;
|
||||
|
||||
const isUp = target.latestCheck?.matched;
|
||||
const isUp = target?.latestCheck?.matched;
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
attach="body"
|
||||
footer={false}
|
||||
header={
|
||||
<Space align="center" size={8}>
|
||||
<StatusDot up={!!isUp} />
|
||||
<Typography.Text strong>{target.name}</Typography.Text>
|
||||
<Tag size="small" theme="primary" variant="light-outline">
|
||||
{target.type}
|
||||
</Tag>
|
||||
</Space>
|
||||
target ? (
|
||||
<Space align="center" size={8}>
|
||||
<StatusDot up={!!isUp} />
|
||||
<Typography.Text strong>{target.name}</Typography.Text>
|
||||
<Tag size="small" theme="primary" variant="light-outline">
|
||||
{target.type}
|
||||
</Tag>
|
||||
</Space>
|
||||
) : undefined
|
||||
}
|
||||
onClose={onClose}
|
||||
placement="right"
|
||||
size="52%"
|
||||
preventScrollThrough
|
||||
showInAttachedElement={false}
|
||||
showOverlay
|
||||
size="55%"
|
||||
visible={!!target}
|
||||
>
|
||||
<Space className="full-width" direction="vertical" size={16}>
|
||||
@@ -109,12 +116,12 @@ export function TargetDetailDrawer({
|
||||
valueType="YYYY-MM-DD HH:mm"
|
||||
/>
|
||||
</div>
|
||||
<Tabs onChange={(val: TabValue) => setActiveTab(val)} value={activeTab}>
|
||||
<Tabs.TabPanel className="tab-panel-padded" label="概览" value="overview">
|
||||
<OverviewTab metricsData={metricsData} metricsLoading={metricsLoading} target={target} />
|
||||
<Tabs onChange={(val: TabValue) => onTabChange(String(val))} value={activeTab}>
|
||||
<Tabs.TabPanel className="tab-panel-padded" destroyOnHide={false} label="概览" value="overview">
|
||||
{target && <OverviewTab metricsData={metricsData} metricsLoading={metricsLoading} target={target} />}
|
||||
</Tabs.TabPanel>
|
||||
|
||||
<Tabs.TabPanel className="tab-panel-padded" label="记录" value="history">
|
||||
<Tabs.TabPanel className="tab-panel-padded" destroyOnHide={false} label="记录" lazy value="history">
|
||||
<HistoryTab historyData={historyData} historyLoading={historyLoading} onPageChange={onPageChange} />
|
||||
</Tabs.TabPanel>
|
||||
</Tabs>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import type { HistoryResponse, TargetStatus } from "../../shared/api";
|
||||
@@ -11,11 +11,11 @@ const detailQueryKeys = {
|
||||
};
|
||||
|
||||
export function useTargetDetail() {
|
||||
const queryClient = useQueryClient();
|
||||
const [selectedTargetId, setSelectedTargetId] = useState<null | number>(null);
|
||||
const [timeFrom, setTimeFrom] = useState("");
|
||||
const [timeTo, setTimeTo] = useState("");
|
||||
const [historyPage, setHistoryPage] = useState(1);
|
||||
const [activeTab, setActiveTab] = useState<string>("overview");
|
||||
|
||||
const { data: dashboardData } = useDashboard(false);
|
||||
const selectedTarget =
|
||||
@@ -26,7 +26,7 @@ export function useTargetDetail() {
|
||||
const metrics = useTargetMetrics(selectedTargetId, timeFrom, timeTo, "1h");
|
||||
|
||||
const history = useQuery({
|
||||
enabled: selectedTargetId !== null && !!timeFrom && !!timeTo,
|
||||
enabled: selectedTargetId !== null && !!timeFrom && !!timeTo && activeTab === "history",
|
||||
queryFn: () => {
|
||||
if (selectedTargetId === null) throw new Error("未选择目标");
|
||||
return fetchJson<HistoryResponse>(
|
||||
@@ -46,13 +46,13 @@ export function useTargetDetail() {
|
||||
setTimeFrom(from.toISOString());
|
||||
setTimeTo(now.toISOString());
|
||||
setHistoryPage(1);
|
||||
setActiveTab("overview");
|
||||
}, []);
|
||||
|
||||
const closeDrawer = useCallback(() => {
|
||||
setSelectedTargetId(null);
|
||||
queryClient.removeQueries({ queryKey: ["metrics"] });
|
||||
queryClient.removeQueries({ queryKey: ["history"] });
|
||||
}, [queryClient]);
|
||||
setActiveTab("overview");
|
||||
}, []);
|
||||
|
||||
const handleTimeChange = useCallback((from: string, to: string) => {
|
||||
setTimeFrom(from);
|
||||
@@ -64,9 +64,15 @@ export function useTargetDetail() {
|
||||
setHistoryPage(page);
|
||||
}, []);
|
||||
|
||||
const handleTabChange = useCallback((tab: string) => {
|
||||
setActiveTab(tab);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
activeTab,
|
||||
closeDrawer,
|
||||
handlePageChange,
|
||||
handleTabChange,
|
||||
handleTimeChange,
|
||||
historyData: history.data ?? { items: [], page: 1, pageSize: 20, total: 0 },
|
||||
historyLoading: history.isLoading,
|
||||
|
||||
Reference in New Issue
Block a user