feat: 图表支持存储拖拽排序 & 补点逻辑优化

This commit is contained in:
GraceWalk
2022-09-29 10:42:44 +08:00
parent 8c8c362c54
commit ff9dde163a
7 changed files with 306 additions and 240 deletions

View File

@@ -1,30 +1,26 @@
import { Col, Row, SingleChart, IconFont, Utils, Modal, Spin, Empty, AppContainer, Tooltip } from 'knowdesign';
import { Col, Row, SingleChart, Utils, Modal, Spin, Empty, AppContainer, Tooltip } from 'knowdesign';
import { IconFont } from '@knowdesign/icons';
import React, { useEffect, useRef, useState } from 'react';
import { arrayMoveImmutable } from 'array-move';
import api from '@src/api';
import { getChartConfig } from './config';
import './index.less';
import { useParams } from 'react-router-dom';
import {
MetricDefaultChartDataType,
MetricChartDataType,
formatChartData,
supplementaryPoints,
} from '@src/components/DashboardDragChart/config';
resolveMetricsRank,
MetricInfo,
} from '@src/constants/chartConfig';
import { MetricType } from '@src/api';
import { getDataNumberUnit, getUnit } from '@src/constants/chartConfig';
import SingleChartHeader, { KsHeaderOptions } from '@src/components/SingleChartHeader';
import { MAX_TIME_RANGE_WITH_SMALL_POINT_INTERVAL } from '@src/constants/common';
import RenderEmpty from '@src/components/RenderEmpty';
import DragGroup from '@src/components/DragGroup';
import { getChartConfig } from './config';
import './index.less';
type ChartFilterOptions = Omit<KsHeaderOptions, 'gridNum'>;
interface MetricInfo {
type: number;
name: string;
desc: string;
set: boolean;
support: boolean;
}
interface MessagesInDefaultData {
aggType: string | null;
@@ -71,8 +67,7 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
const [curHeaderOptions, setCurHeaderOptions] = useState<ChartFilterOptions>();
const [defaultChartLoading, setDefaultChartLoading] = useState<boolean>(true);
const [chartLoading, setChartLoading] = useState<boolean>(true);
const [showChartDetailModal, setShowChartDetailModal] = useState<boolean>(false);
const [chartDetail, setChartDetail] = useState<any>();
const metricRankList = useRef<string[]>([]);
const curFetchingTimestamp = useRef({
messagesIn: 0,
other: 0,
@@ -91,36 +86,53 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
});
};
// 更新 rank
const updateRank = (metricList: MetricInfo[]) => {
const { list, listInfo, shouldUpdate } = resolveMetricsRank(metricList);
metricRankList.current = list;
if (shouldUpdate) {
updateMetricList(listInfo);
}
};
// 获取指标列表
const getMetricList = () => {
Utils.request(api.getDashboardMetricList(clusterId, MetricType.Cluster)).then((res: MetricInfo[] | null) => {
if (!res) return;
const showMetrics = res.filter((metric) => metric.support);
const selectedMetrics = showMetrics.filter((metric) => metric.set).map((metric) => metric.name);
const supportMetrics = res.filter((metric) => metric.support);
const selectedMetrics = supportMetrics.filter((metric) => metric.set).map((metric) => metric.name);
!selectedMetrics.includes(DEFAULT_METRIC) && selectedMetrics.push(DEFAULT_METRIC);
setMetricList(showMetrics);
updateRank([...supportMetrics]);
setMetricList(supportMetrics);
setSelectedMetricNames(selectedMetrics);
});
};
// 更新指标
const updateMetricList = (metricsSet: { [name: string]: boolean }) => {
const updateMetricList = (metricDetailDTOList: { metric: string; rank: number; set: boolean }[]) => {
return Utils.request(api.getDashboardMetricList(clusterId, MetricType.Cluster), {
method: 'POST',
data: {
metricsSet,
metricDetailDTOList,
},
});
};
// 指标选中项更新回调
const indicatorChangeCallback = (newMetricNames: (string | number)[]) => {
const updateMetrics: { [name: string]: boolean } = {};
const updateMetrics: { metric: string; set: boolean; rank: number }[] = [];
// 需要选中的指标
newMetricNames.forEach((name) => !selectedMetricNames.includes(name) && (updateMetrics[name] = true));
newMetricNames.forEach(
(name) =>
!selectedMetricNames.includes(name) &&
updateMetrics.push({ metric: name as string, set: true, rank: metricList.find(({ name: metric }) => metric === name)?.rank })
);
// 取消选中的指标
selectedMetricNames.forEach((name) => !newMetricNames.includes(name) && (updateMetrics[name] = false));
selectedMetricNames.forEach(
(name) =>
!newMetricNames.includes(name) &&
updateMetrics.push({ metric: name as string, set: false, rank: metricList.find(({ name: metric }) => metric === name)?.rank })
);
const requestPromise = Object.keys(updateMetrics).length ? updateMetricList(updateMetrics) : Promise.resolve();
requestPromise.then(
() => getMetricList(),
@@ -156,15 +168,16 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
return;
}
const supplementaryInterval = (endTime - startTime > MAX_TIME_RANGE_WITH_SMALL_POINT_INTERVAL ? 10 : 1) * 60 * 1000;
const formattedMetricData: MetricChartDataType[] = formatChartData(
res,
global.getMetricDefine || {},
MetricType.Cluster,
curHeaderOptions.rangeTime,
supplementaryInterval
curHeaderOptions.rangeTime
);
formattedMetricData.forEach((data) => (data.metricLines[0].name = data.metricName));
// 指标排序
formattedMetricData.sort((a, b) => metricRankList.current.indexOf(a.metricName) - metricRankList.current.indexOf(b.metricName));
setMetricDataList(formattedMetricData);
setChartLoading(false);
},
@@ -242,9 +255,7 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
...info,
value: 0,
}));
const supplementaryInterval =
(curHeaderOptions.rangeTime[1] - curHeaderOptions.rangeTime[0] > MAX_TIME_RANGE_WITH_SMALL_POINT_INTERVAL ? 10 : 1) * 60 * 1000;
supplementaryPoints([line], curHeaderOptions.rangeTime, supplementaryInterval, (point) => {
supplementaryPoints([line], curHeaderOptions.rangeTime, (point) => {
point.push(extraMetrics as any);
return point;
});
@@ -263,6 +274,22 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
targetNode && targetNode.addEventListener('click', () => busInstance.emit('chartResize'));
};
// 拖拽开始回调,触发图表的 onDrag 事件( 设置为 true ),禁止同步展示图表的 tooltip
const dragStart = () => {
busInstance.emit('onDrag', true);
};
// 拖拽结束回调,更新图表顺序,并触发图表的 onDrag 事件( 设置为 false ),允许同步展示图表的 tooltip
const dragEnd = ({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }) => {
busInstance.emit('onDrag', false);
const originFrom = metricRankList.current.indexOf(metricDataList[oldIndex].metricName);
const originTarget = metricRankList.current.indexOf(metricDataList[newIndex].metricName);
const newList = arrayMoveImmutable(metricRankList.current, originFrom, originTarget);
metricRankList.current = newList;
updateMetricList(newList.map((metric, rank) => ({ metric, rank, set: metricList.find(({ name }) => metric === name)?.set || false })));
setMetricDataList(arrayMoveImmutable(metricDataList, oldIndex, newIndex));
};
useEffect(() => {
getMetricData();
}, [selectedMetricNames]);
@@ -359,10 +386,10 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
<div className="no-group-con">
<DragGroup
sortableContainerProps={{
onSortStart: () => 0,
onSortEnd: () => 0,
onSortStart: dragStart,
onSortEnd: dragEnd,
axis: 'xy',
useDragHandle: false,
useDragHandle: true,
}}
gridProps={{
span: 12,

View File

@@ -3,7 +3,7 @@ import { useParams } from 'react-router-dom';
import { AppContainer, Button, Divider, Drawer, Form, InputNumber, notification, SingleChart, Space, Spin, Utils } from 'knowdesign';
import Api, { MetricType } from '@src/api/index';
import { getBasicChartConfig, getUnit } from '@src/constants/chartConfig';
import { formatChartData, MetricDefaultChartDataType } from '@src/components/DashboardDragChart/config';
import { formatChartData, MetricDefaultChartDataType } from '@src/constants/chartConfig';
const ExpandPartition = (props: { record: any; onConfirm: () => void }) => {
const [global] = AppContainer.useGlobalValue();
@@ -74,8 +74,7 @@ const ExpandPartition = (props: { record: any; onConfirm: () => void }) => {
],
global?.getMetricDefine || {},
MetricType.Topic,
[startStamp, endStamp],
10 * 60 * 1000
[startStamp, endStamp]
);
setMinByteInOut(minByteInOut < empiricalMinValue ? empiricalMinValue : minByteInOut);