1
0

feat: 优化目标详情 Drawer 性能 — TDesign 生命周期控制、Tab 感知延迟加载、滚动穿透修复

This commit is contained in:
2026-05-15 00:53:41 +08:00
parent 9904f198aa
commit 28e46b8431
7 changed files with 204 additions and 62 deletions

View File

@@ -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}

View File

@@ -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>

View File

@@ -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,