refactor: refactor chart render and perf pageview data handle logic
This commit is contained in:
parent
e79c4b4819
commit
4fe61a6d7c
46
src/client/components/TimeEventChart.tsx
Normal file
46
src/client/components/TimeEventChart.tsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useTheme } from '../hooks/useTheme';
|
||||||
|
import { DateUnit } from '@tianji/shared';
|
||||||
|
import React from 'react';
|
||||||
|
import { formatDate, formatDateWithUnit } from '../utils/date';
|
||||||
|
import { Column, ColumnConfig } from '@ant-design/charts';
|
||||||
|
|
||||||
|
export const TimeEventChart: React.FC<{
|
||||||
|
data: { x: string; y: number; type: string }[];
|
||||||
|
unit: DateUnit;
|
||||||
|
}> = React.memo((props) => {
|
||||||
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
const config = useMemo(
|
||||||
|
() =>
|
||||||
|
({
|
||||||
|
data: props.data,
|
||||||
|
isStack: true,
|
||||||
|
xField: 'x',
|
||||||
|
yField: 'y',
|
||||||
|
seriesField: 'type',
|
||||||
|
label: {
|
||||||
|
position: 'middle' as const,
|
||||||
|
style: {
|
||||||
|
fill: '#FFFFFF',
|
||||||
|
opacity: 0.6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
title: (t) => formatDate(t),
|
||||||
|
},
|
||||||
|
color: [colors.chart.pv, colors.chart.uv],
|
||||||
|
xAxis: {
|
||||||
|
label: {
|
||||||
|
autoHide: true,
|
||||||
|
autoRotate: false,
|
||||||
|
formatter: (text) => formatDateWithUnit(text, props.unit),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies ColumnConfig),
|
||||||
|
[props.data, props.unit]
|
||||||
|
);
|
||||||
|
|
||||||
|
return <Column {...config} />;
|
||||||
|
});
|
||||||
|
TimeEventChart.displayName = 'TimeEventChart';
|
@ -1,19 +1,12 @@
|
|||||||
import { Button, message, Spin, Switch } from 'antd';
|
import { Button, message, Spin, Switch } from 'antd';
|
||||||
import React, { useMemo } from 'react';
|
import React from 'react';
|
||||||
import { Column, ColumnConfig } from '@ant-design/charts';
|
|
||||||
import { SyncOutlined } from '@ant-design/icons';
|
import { SyncOutlined } from '@ant-design/icons';
|
||||||
import { DateFilter } from '../DateFilter';
|
import { DateFilter } from '../DateFilter';
|
||||||
import { WebsiteInfo } from '../../api/model/website';
|
import { WebsiteInfo } from '../../api/model/website';
|
||||||
import {
|
import { getDateArray } from '../../utils/date';
|
||||||
DateUnit,
|
|
||||||
formatDate,
|
|
||||||
formatDateWithUnit,
|
|
||||||
getDateArray,
|
|
||||||
} from '../../utils/date';
|
|
||||||
import { useEvent } from '../../hooks/useEvent';
|
import { useEvent } from '../../hooks/useEvent';
|
||||||
import { MetricCard } from './MetricCard';
|
import { MetricCard } from './MetricCard';
|
||||||
import { formatNumber, formatShortTime } from '../../utils/common';
|
import { formatNumber, formatShortTime } from '../../utils/common';
|
||||||
import { useTheme } from '../../hooks/useTheme';
|
|
||||||
import { WebsiteOnlineCount } from './WebsiteOnlineCount';
|
import { WebsiteOnlineCount } from './WebsiteOnlineCount';
|
||||||
import { useGlobalRangeDate } from '../../hooks/useGlobalRangeDate';
|
import { useGlobalRangeDate } from '../../hooks/useGlobalRangeDate';
|
||||||
import { MonitorHealthBar } from '../monitor/MonitorHealthBar';
|
import { MonitorHealthBar } from '../monitor/MonitorHealthBar';
|
||||||
@ -22,6 +15,7 @@ import { AppRouterOutput, trpc } from '../../api/trpc';
|
|||||||
import { getUserTimezone } from '../../api/model/user';
|
import { getUserTimezone } from '../../api/model/user';
|
||||||
import { useGlobalStateStore } from '../../store/global';
|
import { useGlobalStateStore } from '../../store/global';
|
||||||
import { useTranslation } from '@i18next-toolkit/react';
|
import { useTranslation } from '@i18next-toolkit/react';
|
||||||
|
import { TimeEventChart } from '../TimeEventChart';
|
||||||
|
|
||||||
export const WebsiteOverview: React.FC<{
|
export const WebsiteOverview: React.FC<{
|
||||||
website: WebsiteInfo;
|
website: WebsiteInfo;
|
||||||
@ -37,18 +31,32 @@ export const WebsiteOverview: React.FC<{
|
|||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data: chartData = [],
|
||||||
isLoading: isLoadingPageview,
|
isLoading: isLoadingPageview,
|
||||||
refetch: refetchPageview,
|
refetch: refetchPageview,
|
||||||
} = trpc.website.pageviews.useQuery({
|
} = trpc.website.pageviews.useQuery(
|
||||||
workspaceId: website.workspaceId,
|
{
|
||||||
websiteId: website.id,
|
workspaceId: website.workspaceId,
|
||||||
startAt: startDate.valueOf(),
|
websiteId: website.id,
|
||||||
endAt: endDate.valueOf(),
|
startAt: startDate.valueOf(),
|
||||||
unit,
|
endAt: endDate.valueOf(),
|
||||||
});
|
unit,
|
||||||
const pageviews = data?.pageviews ?? [];
|
},
|
||||||
const sessions = data?.sessions ?? [];
|
{
|
||||||
|
select(data) {
|
||||||
|
const pageviews = data.pageviews ?? [];
|
||||||
|
const sessions = data.sessions ?? [];
|
||||||
|
|
||||||
|
const pageviewsArr = getDateArray(pageviews, startDate, endDate, unit);
|
||||||
|
const sessionsArr = getDateArray(sessions, startDate, endDate, unit);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...pageviewsArr.map((item) => ({ ...item, type: 'pageview' })),
|
||||||
|
...sessionsArr.map((item) => ({ ...item, type: 'session' })),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: stats,
|
data: stats,
|
||||||
@ -71,16 +79,6 @@ export const WebsiteOverview: React.FC<{
|
|||||||
message.success(t('Refreshed'));
|
message.success(t('Refreshed'));
|
||||||
});
|
});
|
||||||
|
|
||||||
const chartData = useMemo(() => {
|
|
||||||
const pageviewsArr = getDateArray(pageviews, startDate, endDate, unit);
|
|
||||||
const sessionsArr = getDateArray(sessions, startDate, endDate, unit);
|
|
||||||
|
|
||||||
return [
|
|
||||||
...pageviewsArr.map((item) => ({ ...item, type: 'pageview' })),
|
|
||||||
...sessionsArr.map((item) => ({ ...item, type: 'session' })),
|
|
||||||
];
|
|
||||||
}, [pageviews, sessions, unit]);
|
|
||||||
|
|
||||||
const loading = isLoadingPageview || isLoadingStats;
|
const loading = isLoadingPageview || isLoadingStats;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -145,7 +143,7 @@ export const WebsiteOverview: React.FC<{
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<StatsChart data={chartData} unit={unit} />
|
<TimeEventChart data={chartData} unit={unit} />
|
||||||
</div>
|
</div>
|
||||||
</Spin>
|
</Spin>
|
||||||
);
|
);
|
||||||
@ -216,43 +214,3 @@ export const MetricsBar: React.FC<{
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
MetricsBar.displayName = 'MetricsBar';
|
MetricsBar.displayName = 'MetricsBar';
|
||||||
|
|
||||||
export const StatsChart: React.FC<{
|
|
||||||
data: { x: string; y: number; type: string }[];
|
|
||||||
unit: DateUnit;
|
|
||||||
}> = React.memo((props) => {
|
|
||||||
const { colors } = useTheme();
|
|
||||||
|
|
||||||
const config = useMemo(
|
|
||||||
() =>
|
|
||||||
({
|
|
||||||
data: props.data,
|
|
||||||
isStack: true,
|
|
||||||
xField: 'x',
|
|
||||||
yField: 'y',
|
|
||||||
seriesField: 'type',
|
|
||||||
label: {
|
|
||||||
position: 'middle' as const,
|
|
||||||
style: {
|
|
||||||
fill: '#FFFFFF',
|
|
||||||
opacity: 0.6,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
title: (t) => formatDate(t),
|
|
||||||
},
|
|
||||||
color: [colors.chart.pv, colors.chart.uv],
|
|
||||||
xAxis: {
|
|
||||||
label: {
|
|
||||||
autoHide: true,
|
|
||||||
autoRotate: false,
|
|
||||||
formatter: (text) => formatDateWithUnit(text, props.unit),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies ColumnConfig),
|
|
||||||
[props.data, props.unit]
|
|
||||||
);
|
|
||||||
|
|
||||||
return <Column {...config} />;
|
|
||||||
});
|
|
||||||
StatsChart.displayName = 'StatsChart';
|
|
||||||
|
Loading…
Reference in New Issue
Block a user