mirror of
https://github.com/didi/KnowStreaming.git
synced 2026-01-13 19:42:15 +08:00
初始化3.0.0版本
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import { getBasicChartConfig } from '@src/constants/chartConfig';
|
||||
import moment from 'moment';
|
||||
|
||||
const DEFAULT_METRIC = 'MessagesIn';
|
||||
|
||||
// 图表 tooltip 展示的样式
|
||||
const messagesInTooltipFormatter = (date: any, arr: any) => {
|
||||
// 面积图只有一条线,这里直接取 arr 的第 0 项
|
||||
const params = arr[0];
|
||||
// MessageIn 的指标数据存放在 data 数组第 3 项
|
||||
const metricsData = params.data[2];
|
||||
|
||||
const str = `<div style="margin: 3px 0;">
|
||||
<div style="display:flex;align-items:center;">
|
||||
<div style="margin-right:4px;width:8px;height:2px;background-color:${params.color};"></div>
|
||||
<div style="flex:1;display:flex;justify-content:space-between;align-items:center;overflow: hidden;">
|
||||
<span style="flex: 1;font-size:12px;color:#74788D;pointer-events:auto;margin-left:2px;line-height: 18px;font-family: HelveticaNeue;overflow: hidden; text-overflow: ellipsis; white-space: no-wrap;">
|
||||
${params.seriesName}
|
||||
</span>
|
||||
<span style="font-size:12px;color:#212529;line-height:18px;font-family:HelveticaNeue-Medium;margin-left: 10px;">
|
||||
${parseFloat(Number(params.value[1]).toFixed(3))}
|
||||
<span style="font-family: PingFangSC-Regular;color: #495057;">${metricsData[DEFAULT_METRIC]?.unit || ''}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
return `<div style="margin: 0px 0 0; position: relative; z-index: 99;width: fit-content;">
|
||||
<div style="padding: 8px 0;height: 100%;">
|
||||
<div style="font-size:12px;padding: 0 12px;color:#212529;line-height:20px;font-family: HelveticaNeue;">
|
||||
${date}
|
||||
</div>
|
||||
<div style="margin: 4px 0 0 0;padding: 0 12px;">
|
||||
${str}
|
||||
<div style="width: 100%; height: 1px; background: #EFF2F7;margin: 8px 0;"></div>
|
||||
${metricsData
|
||||
.map(({ key, value, unit }: { key: string; value: number; unit: string }) => {
|
||||
if (key === DEFAULT_METRIC) return '';
|
||||
return `
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="font-size:12px;color:#74788D;pointer-events:auto;margin-left:2px;line-height: 18px;font-family: HelveticaNeue;margin-right: 10px;">
|
||||
${key}
|
||||
</span>
|
||||
<span style="font-size:12px;color:#212529;pointer-events:auto;margin-left:2px;line-height: 18px;font-family: HelveticaNeue;">
|
||||
${parseFloat(Number(value).toFixed(3))}
|
||||
<span style="font-family: PingFangSC-Regular;color: #495057;">${unit}</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
.join('')}
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
||||
|
||||
export const getChartConfig = (props: any) => {
|
||||
const { metricName, lineColor, isDefaultMetric = false } = props;
|
||||
return {
|
||||
option: getBasicChartConfig({
|
||||
// TODO: time 轴图表联动有问题,先切换为 category
|
||||
// xAxis: { type: 'time', boundaryGap: isDefaultMetric ? ['2%', '2%'] : ['5%', '5%'] },
|
||||
title: { show: false },
|
||||
legend: { show: false },
|
||||
grid: { top: 24, bottom: 12 },
|
||||
lineColor: [lineColor],
|
||||
tooltip: isDefaultMetric
|
||||
? {
|
||||
formatter: function (params: any) {
|
||||
let res = '';
|
||||
if (params != null && params.length > 0) {
|
||||
res += messagesInTooltipFormatter(moment(Number(params[0].axisValue)).format('YYYY-MM-DD HH:mm'), params);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
}
|
||||
: {},
|
||||
}),
|
||||
seriesCallback: (lineList: { name: string; data: [number, string | number][] }[]) => {
|
||||
// 补充线条配置
|
||||
return lineList.map((line) => {
|
||||
return {
|
||||
...line,
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
},
|
||||
symbol: 'emptyCircle',
|
||||
symbolSize: 4,
|
||||
// 面积图样式
|
||||
areaStyle: {
|
||||
color: lineColor,
|
||||
opacity: 0.06,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,135 @@
|
||||
.cluster-container-border {
|
||||
background: #ffffff;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.01), 0 3px 6px 3px rgba(0, 0, 0, 0.01), 0 2px 6px 0 rgba(0, 0, 0, 0.03);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.cluster-detail-container {
|
||||
width: 100%;
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
|
||||
.refresh-icon-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
|
||||
.refresh-icon {
|
||||
font-size: 14px;
|
||||
color: #74788d;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #21252904;
|
||||
|
||||
.refresh-icon {
|
||||
color: #495057;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-main {
|
||||
.header-chart-container {
|
||||
&-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
width: 100%;
|
||||
height: 244px;
|
||||
margin-bottom: 12px;
|
||||
.cluster-container-border();
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: calc(100vh - 404px);
|
||||
min-height: 526px;
|
||||
|
||||
.multiple-chart-container {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
.cluster-container-border();
|
||||
> div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 16px;
|
||||
overflow: hidden auto;
|
||||
}
|
||||
&-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chart-box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 244px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
|
||||
.expand-icon-box {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
top: 14px;
|
||||
right: 16px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
.expand-icon {
|
||||
color: #adb5bc;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(33, 37, 41, 0.06);
|
||||
.expand-icon {
|
||||
color: #74788d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.config-change-records-container {
|
||||
width: 240px;
|
||||
height: 100%;
|
||||
margin-left: 12px;
|
||||
.cluster-container-border();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chart-box-title {
|
||||
padding: 18px 0 0 20px;
|
||||
font-family: @font-family-bold;
|
||||
line-height: 16px;
|
||||
.name {
|
||||
font-size: 14px;
|
||||
color: #212529;
|
||||
}
|
||||
.unit {
|
||||
font-size: 12px;
|
||||
color: #495057;
|
||||
}
|
||||
> span {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
import { Col, Row, SingleChart, IconFont, Utils, Modal, Spin, Empty, AppContainer, Tooltip } from 'knowdesign';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
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';
|
||||
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';
|
||||
|
||||
type ChartFilterOptions = Omit<KsHeaderOptions, 'gridNum'>;
|
||||
interface MetricInfo {
|
||||
type: number;
|
||||
name: string;
|
||||
desc: string;
|
||||
set: boolean;
|
||||
support: boolean;
|
||||
}
|
||||
|
||||
interface MessagesInDefaultData {
|
||||
aggType: string | null;
|
||||
createTime: string | null;
|
||||
updateTime: string | null;
|
||||
timeStamp: number;
|
||||
values: {
|
||||
[metric: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
type MessagesInMetric = {
|
||||
name: 'MessagesIn';
|
||||
unit: string;
|
||||
data: (readonly [number, number | string, { key: string; value: number; unit: string }[]])[];
|
||||
};
|
||||
|
||||
const { EventBus } = Utils;
|
||||
const busInstance = new EventBus();
|
||||
|
||||
// 图表颜色定义 & 计算
|
||||
const CHART_LINE_COLORS = ['#556EE6', '#3991FF'];
|
||||
const calculateChartColor = (i: number) => {
|
||||
const isEvenRow = ((i / 2) | 0) % 2;
|
||||
const isEvenCol = i % 2;
|
||||
return CHART_LINE_COLORS[isEvenRow ^ isEvenCol];
|
||||
};
|
||||
|
||||
const DEFAULT_METRIC = 'MessagesIn';
|
||||
// 默认指标图表固定需要获取展示的指标项
|
||||
const DEFUALT_METRIC_NEED_METRICS = [DEFAULT_METRIC, 'TotalLogSize', 'TotalProduceRequests', 'Topics', 'Partitions'];
|
||||
|
||||
const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
|
||||
const [global] = AppContainer.useGlobalValue();
|
||||
const { clusterId } = useParams<{ clusterId: string }>();
|
||||
const [metricList, setMetricList] = useState<MetricInfo[]>([]); // 指标列表
|
||||
const [selectedMetricNames, setSelectedMetricNames] = useState<(string | number)[]>([]); // 默认选中的指标的列表
|
||||
const [metricDataList, setMetricDataList] = useState<any>([]);
|
||||
const [messagesInMetricData, setMessagesInMetricData] = useState<MessagesInMetric>({
|
||||
name: 'MessagesIn',
|
||||
unit: '',
|
||||
data: [],
|
||||
});
|
||||
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 curFetchingTimestamp = useRef({
|
||||
messagesIn: 0,
|
||||
other: 0,
|
||||
});
|
||||
|
||||
// 筛选项变化或者点击刷新按钮
|
||||
const ksHeaderChange = (ksOptions: KsHeaderOptions) => {
|
||||
// 如果为相对时间,则当前时间减去 1 分钟,避免最近一分钟的数据还没采集到时前端多补一个点
|
||||
if (ksOptions.isRelativeRangeTime) {
|
||||
ksOptions.rangeTime = ksOptions.rangeTime.map((timestamp) => timestamp - 60 * 1000) as [number, number];
|
||||
}
|
||||
setCurHeaderOptions({
|
||||
isRelativeRangeTime: ksOptions.isRelativeRangeTime,
|
||||
isAutoReload: ksOptions.isAutoReload,
|
||||
rangeTime: ksOptions.rangeTime,
|
||||
});
|
||||
};
|
||||
|
||||
// 获取指标列表
|
||||
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);
|
||||
!selectedMetrics.includes(DEFAULT_METRIC) && selectedMetrics.push(DEFAULT_METRIC);
|
||||
setMetricList(showMetrics);
|
||||
setSelectedMetricNames(selectedMetrics);
|
||||
});
|
||||
};
|
||||
|
||||
// 更新指标
|
||||
const updateMetricList = (metricsSet: { [name: string]: boolean }) => {
|
||||
return Utils.request(api.getDashboardMetricList(clusterId, MetricType.Cluster), {
|
||||
method: 'POST',
|
||||
data: {
|
||||
metricsSet,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 指标选中项更新回调
|
||||
const indicatorChangeCallback = (newMetricNames: (string | number)[]) => {
|
||||
const updateMetrics: { [name: string]: boolean } = {};
|
||||
// 需要选中的指标
|
||||
newMetricNames.forEach((name) => !selectedMetricNames.includes(name) && (updateMetrics[name] = true));
|
||||
// 取消选中的指标
|
||||
selectedMetricNames.forEach((name) => !newMetricNames.includes(name) && (updateMetrics[name] = false));
|
||||
|
||||
const requestPromise = Object.keys(updateMetrics).length ? updateMetricList(updateMetrics) : Promise.resolve();
|
||||
requestPromise.then(
|
||||
() => getMetricList(),
|
||||
() => getMetricList()
|
||||
);
|
||||
|
||||
return requestPromise;
|
||||
};
|
||||
|
||||
// 获取 metric 列表的图表数据
|
||||
const getMetricData = () => {
|
||||
if (!selectedMetricNames.length) return;
|
||||
!curHeaderOptions.isAutoReload && setChartLoading(true);
|
||||
const [startTime, endTime] = curHeaderOptions.rangeTime;
|
||||
|
||||
const curTimestamp = Date.now();
|
||||
curFetchingTimestamp.current = {
|
||||
...curFetchingTimestamp.current,
|
||||
messagesIn: curTimestamp,
|
||||
};
|
||||
Utils.request(api.getClusterMetricDataList(), {
|
||||
method: 'POST',
|
||||
data: {
|
||||
startTime,
|
||||
endTime,
|
||||
clusterPhyIds: [clusterId],
|
||||
metricsNames: selectedMetricNames.filter((name) => name !== DEFAULT_METRIC),
|
||||
},
|
||||
}).then(
|
||||
(res: MetricDefaultChartDataType[]) => {
|
||||
// 如果当前请求不是最新请求,则不做任何操作
|
||||
if (curFetchingTimestamp.current.messagesIn !== curTimestamp) {
|
||||
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
|
||||
);
|
||||
formattedMetricData.forEach((data) => (data.metricLines[0].name = data.metricName));
|
||||
setMetricDataList(formattedMetricData);
|
||||
setChartLoading(false);
|
||||
},
|
||||
() => setChartLoading(false)
|
||||
);
|
||||
};
|
||||
|
||||
// 获取默认展示指标的图表数据
|
||||
const getDefaultMetricData = () => {
|
||||
!curHeaderOptions.isAutoReload && setDefaultChartLoading(true);
|
||||
|
||||
const curTimestamp = Date.now();
|
||||
curFetchingTimestamp.current = {
|
||||
...curFetchingTimestamp.current,
|
||||
other: curTimestamp,
|
||||
};
|
||||
Utils.request(api.getClusterDefaultMetricData(), {
|
||||
method: 'POST',
|
||||
data: {
|
||||
startTime: curHeaderOptions.rangeTime[0],
|
||||
endTime: curHeaderOptions.rangeTime[1],
|
||||
clusterPhyIds: [clusterId],
|
||||
metricsNames: DEFUALT_METRIC_NEED_METRICS,
|
||||
},
|
||||
}).then(
|
||||
(res: MessagesInDefaultData[]) => {
|
||||
// 如果当前请求不是最新请求,则不做任何操作
|
||||
if (curFetchingTimestamp.current.other !== curTimestamp) {
|
||||
return;
|
||||
}
|
||||
// TODO: 这里直接将指标数据放到数组第三项中,之后可以尝试优化,优化需要注意 tooltipFormatter 函数也要修改
|
||||
let maxValue = -1;
|
||||
const result = res.map((item) => {
|
||||
const { timeStamp, values } = item;
|
||||
let parsedValue: string | number = Number(values.MessagesIn);
|
||||
if (Number.isNaN(parsedValue)) {
|
||||
parsedValue = values.MessagesIn;
|
||||
} else {
|
||||
if (maxValue < parsedValue) maxValue = parsedValue;
|
||||
}
|
||||
const valuesWithUnit = Object.entries(values).map(([key, value]) => {
|
||||
let valueWithUnit = Number(value);
|
||||
let unit = ((global.getMetricDefine && global.getMetricDefine(MetricType.Cluster, key)?.unit) || '') as string;
|
||||
if (unit.toLowerCase().includes('byte')) {
|
||||
const [unitName, unitSize]: [string, number] = getUnit(Number(value));
|
||||
unit = unit.toLowerCase().replace('byte', unitName);
|
||||
valueWithUnit /= unitSize;
|
||||
}
|
||||
const returnValue = {
|
||||
key,
|
||||
value: valueWithUnit,
|
||||
unit,
|
||||
};
|
||||
return returnValue;
|
||||
});
|
||||
return [timeStamp, values.MessagesIn || '0', valuesWithUnit] as [number, number | string, typeof valuesWithUnit];
|
||||
});
|
||||
result.sort((a, b) => (a[0] as number) - (b[0] as number));
|
||||
const line = {
|
||||
name: 'MessagesIn' as const,
|
||||
unit: global.getMetricDefine(MetricType.Cluster, 'MessagesIn')?.unit,
|
||||
data: result as any,
|
||||
};
|
||||
if (maxValue > 0) {
|
||||
const [unitName, unitSize]: [string, number] = getDataNumberUnit(maxValue);
|
||||
line.unit = `${unitName}${line.unit}`;
|
||||
result.forEach((point) => ((point[1] as number) /= unitSize));
|
||||
}
|
||||
|
||||
// 补充缺少的图表点
|
||||
const extraMetrics = result[0][2].map((info) => ({
|
||||
...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) => {
|
||||
point.push(extraMetrics as any);
|
||||
return point;
|
||||
});
|
||||
|
||||
setMessagesInMetricData(line);
|
||||
setDefaultChartLoading(false);
|
||||
},
|
||||
() => setDefaultChartLoading(false)
|
||||
);
|
||||
};
|
||||
|
||||
// 监听盒子宽度变化,重置图表宽度
|
||||
const observeDashboardWidthChange = () => {
|
||||
const targetNode = document.getElementsByClassName('dcd-two-columns-layout-sider-footer')[0];
|
||||
targetNode && targetNode.addEventListener('click', () => busInstance.emit('chartResize'));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getMetricData();
|
||||
}, [selectedMetricNames]);
|
||||
|
||||
useEffect(() => {
|
||||
if (curHeaderOptions && curHeaderOptions?.rangeTime.join(',') !== '0,0') {
|
||||
getDefaultMetricData();
|
||||
getMetricData();
|
||||
}
|
||||
}, [curHeaderOptions]);
|
||||
|
||||
useEffect(() => {
|
||||
getMetricList();
|
||||
setTimeout(() => observeDashboardWidthChange());
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="cluster-detail-container">
|
||||
<SingleChartHeader
|
||||
onChange={ksHeaderChange}
|
||||
hideNodeScope={true}
|
||||
hideGridSelect={true}
|
||||
indicatorSelectModule={{
|
||||
hide: false,
|
||||
metricType: MetricType.Cluster,
|
||||
tableData: metricList,
|
||||
selectedRows: selectedMetricNames,
|
||||
checkboxProps: (record: MetricInfo) => {
|
||||
return record.name === DEFAULT_METRIC
|
||||
? {
|
||||
disabled: true,
|
||||
}
|
||||
: {};
|
||||
},
|
||||
submitCallback: indicatorChangeCallback,
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="cluster-detail-container-main">
|
||||
{/* MessageIn 图表 */}
|
||||
<div className={`header-chart-container ${!messagesInMetricData.data.length ? 'header-chart-container-loading' : ''}`}>
|
||||
<Spin spinning={defaultChartLoading}>
|
||||
{/* TODO: 暂时通过判断是否有图表数据来修复,有时间可以查找下宽度溢出的原因 */}
|
||||
{messagesInMetricData.data.length ? (
|
||||
<>
|
||||
<div className="chart-box-title">
|
||||
<Tooltip
|
||||
placement="topLeft"
|
||||
title={() => {
|
||||
let content = '';
|
||||
const metricDefine = global.getMetricDefine(MetricType.Cluster, messagesInMetricData.name);
|
||||
if (metricDefine) {
|
||||
content = metricDefine.desc;
|
||||
}
|
||||
return content;
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<span className="name">{messagesInMetricData.name}</span>
|
||||
<span className="unit">({messagesInMetricData.unit})</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<SingleChart
|
||||
chartKey="messagesIn"
|
||||
chartTypeProp="line"
|
||||
showHeader={false}
|
||||
wrapStyle={{
|
||||
width: 'auto',
|
||||
height: 210,
|
||||
}}
|
||||
connectEventName="clusterChart"
|
||||
eventBus={busInstance}
|
||||
propChartData={[messagesInMetricData]}
|
||||
{...getChartConfig({
|
||||
// metricName: `${messagesInMetricData.name}{unit|(${messagesInMetricData.unit})}`,
|
||||
lineColor: CHART_LINE_COLORS[0],
|
||||
isDefaultMetric: true,
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</Spin>
|
||||
</div>
|
||||
|
||||
<div className="content">
|
||||
{/* 其余指标图表 */}
|
||||
<div className="multiple-chart-container">
|
||||
<div className={!metricDataList.length ? 'multiple-chart-container-loading' : ''}>
|
||||
<Spin spinning={chartLoading}>
|
||||
<Row gutter={[16, 16]}>
|
||||
{metricDataList.length ? (
|
||||
metricDataList.map((data: any, i: number) => {
|
||||
const { metricName, metricUnit, metricLines } = data;
|
||||
return (
|
||||
<Col key={metricName} span={12}>
|
||||
<div className="chart-box">
|
||||
<div className="chart-box-title">
|
||||
<Tooltip
|
||||
placement="topLeft"
|
||||
title={() => {
|
||||
let content = '';
|
||||
const metricDefine = global.getMetricDefine(MetricType.Cluster, metricName);
|
||||
if (metricDefine) {
|
||||
content = metricDefine.desc;
|
||||
}
|
||||
return content;
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<span className="name">{metricName}</span>
|
||||
<span className="unit">({metricUnit})</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div
|
||||
className="expand-icon-box"
|
||||
onClick={() => {
|
||||
setChartDetail(data);
|
||||
setShowChartDetailModal(true);
|
||||
}}
|
||||
>
|
||||
<IconFont type="icon-chuangkoufangda" className="expand-icon" />
|
||||
</div>
|
||||
<SingleChart
|
||||
chartKey={metricName}
|
||||
showHeader={false}
|
||||
chartTypeProp="line"
|
||||
wrapStyle={{
|
||||
width: 'auto',
|
||||
height: 210,
|
||||
}}
|
||||
connectEventName="clusterChart"
|
||||
eventBus={busInstance}
|
||||
propChartData={metricLines}
|
||||
{...getChartConfig({
|
||||
metricName: `${metricName}{unit|(${metricUnit})}`,
|
||||
lineColor: calculateChartColor(i),
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
);
|
||||
})
|
||||
) : chartLoading ? (
|
||||
<></>
|
||||
) : (
|
||||
<Empty description="请先选择指标或刷新" style={{ width: '100%', height: '100%' }} />
|
||||
)}
|
||||
</Row>
|
||||
</Spin>
|
||||
</div>
|
||||
</div>
|
||||
{/* 历史配置变更记录内容 */}
|
||||
<div className="config-change-records-container">{props.children}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 图表详情 */}
|
||||
<Modal
|
||||
width={1080}
|
||||
visible={showChartDetailModal}
|
||||
centered={true}
|
||||
footer={null}
|
||||
closable={false}
|
||||
onCancel={() => setShowChartDetailModal(false)}
|
||||
>
|
||||
<div className="chart-detail-modal-container">
|
||||
<div className="expand-icon-box" onClick={() => setShowChartDetailModal(false)}>
|
||||
<IconFont type="icon-chuangkousuoxiao" className="expand-icon" />
|
||||
</div>
|
||||
{chartDetail && (
|
||||
<SingleChart
|
||||
chartTypeProp="line"
|
||||
wrapStyle={{
|
||||
width: 'auto',
|
||||
height: 462,
|
||||
}}
|
||||
propChartData={chartDetail.metricLines}
|
||||
{...getChartConfig({
|
||||
metricName: `${chartDetail.metricName}{unit|(${chartDetail.metricUnit})}`,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DetailChart;
|
||||
Reference in New Issue
Block a user