mirror of
https://github.com/didi/KnowStreaming.git
synced 2026-01-04 03:42:08 +08:00
fix: 图表逻辑 & 展示优化
This commit is contained in:
@@ -1,15 +1,12 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Drawer, Button, Space, Divider, AppContainer, ProTable } from 'knowdesign';
|
||||
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
||||
import { Drawer, Button, Space, Divider, AppContainer, ProTable, Utils } from 'knowdesign';
|
||||
import { IconFont } from '@knowdesign/icons';
|
||||
import { IindicatorSelectModule } from './index';
|
||||
import { MetricSelect } from './index';
|
||||
import './style/indicator-drawer.less';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
interface PropsType extends React.HTMLAttributes<HTMLDivElement> {
|
||||
onClose: () => void;
|
||||
visible: boolean;
|
||||
isGroup?: boolean; // 是否分组
|
||||
indicatorSelectModule: IindicatorSelectModule;
|
||||
metricSelect: MetricSelect;
|
||||
}
|
||||
|
||||
interface MetricInfo {
|
||||
@@ -27,25 +24,25 @@ type CategoryData = {
|
||||
metrics: MetricInfo[];
|
||||
};
|
||||
|
||||
const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange }: any) => {
|
||||
const innerColumns = [
|
||||
{
|
||||
title: '指标名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '单位',
|
||||
dataIndex: 'unit',
|
||||
key: 'unit',
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'desc',
|
||||
key: 'desc',
|
||||
},
|
||||
];
|
||||
const expandedRowColumns = [
|
||||
{
|
||||
title: '指标名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '单位',
|
||||
dataIndex: 'unit',
|
||||
key: 'unit',
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'desc',
|
||||
key: 'desc',
|
||||
},
|
||||
];
|
||||
|
||||
const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange }: any) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -62,7 +59,7 @@ const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange
|
||||
showHeader: false,
|
||||
noPagination: true,
|
||||
rowKey: 'name',
|
||||
columns: innerColumns,
|
||||
columns: expandedRowColumns,
|
||||
dataSource: metrics,
|
||||
attrs: {
|
||||
rowSelection: {
|
||||
@@ -79,13 +76,14 @@ const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange
|
||||
);
|
||||
};
|
||||
|
||||
const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) => {
|
||||
const MetricSelect = forwardRef(({ metricSelect }: PropsType, ref) => {
|
||||
const [global] = AppContainer.useGlobalValue();
|
||||
const { pathname } = useLocation();
|
||||
const [confirmLoading, setConfirmLoading] = useState<boolean>(false);
|
||||
const [categoryData, setCategoryData] = useState<CategoryData[]>([]);
|
||||
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
|
||||
const [childrenSelectedRowKeys, setChildrenSelectedRowKeys] = useState<SelectedMetrics>({});
|
||||
const [visible, setVisible] = useState<boolean>(false);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@@ -96,13 +94,13 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
||||
];
|
||||
|
||||
const formateTableData = () => {
|
||||
const tableData = indicatorSelectModule.tableData;
|
||||
const tableData = metricSelect.tableData;
|
||||
const categoryData: {
|
||||
[category: string]: MetricInfo[];
|
||||
} = {};
|
||||
|
||||
tableData.forEach(({ name, desc }) => {
|
||||
const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name);
|
||||
const metricDefine = global.getMetricDefine(metricSelect?.metricType, name);
|
||||
const returnData = {
|
||||
name,
|
||||
desc,
|
||||
@@ -125,12 +123,12 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
||||
};
|
||||
|
||||
const formateSelectedKeys = () => {
|
||||
const newKeys = indicatorSelectModule.selectedRows;
|
||||
const newKeys = metricSelect.selectedRows;
|
||||
const result: SelectedMetrics = {};
|
||||
const selectedCategories: string[] = [];
|
||||
|
||||
newKeys.forEach((name: string) => {
|
||||
const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name);
|
||||
const metricDefine = global.getMetricDefine(metricSelect?.metricType, name);
|
||||
if (metricDefine) {
|
||||
if (!result[metricDefine.category]) {
|
||||
result[metricDefine.category] = [name];
|
||||
@@ -217,10 +215,10 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
||||
const allRowKeys: string[] = [];
|
||||
Object.entries(childrenSelectedRowKeys).forEach(([, arr]) => allRowKeys.push(...arr));
|
||||
|
||||
indicatorSelectModule.submitCallback(allRowKeys).then(
|
||||
metricSelect.submitCallback(allRowKeys).then(
|
||||
() => {
|
||||
setConfirmLoading(false);
|
||||
onClose();
|
||||
setVisible(false);
|
||||
},
|
||||
() => {
|
||||
setConfirmLoading(false);
|
||||
@@ -231,7 +229,7 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
||||
const rowSelection = {
|
||||
selectedRowKeys: selectedCategories,
|
||||
onChange: rowChange,
|
||||
// getCheckboxProps: (record: any) => indicatorSelectModule.checkboxProps && indicatorSelectModule.checkboxProps(record),
|
||||
// getCheckboxProps: (record: any) => metricSelect.checkboxProps && metricSelect.checkboxProps(record),
|
||||
getCheckboxProps: (record: CategoryData) => {
|
||||
const isAllSelected = record.metrics.length === childrenSelectedRowKeys[record.category]?.length;
|
||||
const isNotCheck = !childrenSelectedRowKeys[record.category] || childrenSelectedRowKeys[record.category]?.length === 0;
|
||||
@@ -241,25 +239,33 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
||||
},
|
||||
};
|
||||
|
||||
useEffect(formateTableData, [indicatorSelectModule.tableData]);
|
||||
useEffect(formateTableData, [metricSelect.tableData]);
|
||||
|
||||
useEffect(() => {
|
||||
visible && formateSelectedKeys();
|
||||
}, [visible, indicatorSelectModule.selectedRows]);
|
||||
}, [visible, metricSelect.selectedRows]);
|
||||
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => ({
|
||||
open: () => setVisible(true),
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Drawer
|
||||
className="indicator-drawer"
|
||||
title={indicatorSelectModule.drawerTitle || '指标筛选'}
|
||||
title={metricSelect.drawerTitle || '指标筛选'}
|
||||
width="868px"
|
||||
forceRender={true}
|
||||
onClose={onClose}
|
||||
onClose={() => setVisible(false)}
|
||||
visible={visible}
|
||||
maskClosable={false}
|
||||
extra={
|
||||
<Space>
|
||||
<Button size="small" onClick={onClose}>
|
||||
<Button size="small" onClick={() => setVisible(false)}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
@@ -281,6 +287,7 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
||||
rowKey: 'category',
|
||||
columns: columns,
|
||||
dataSource: categoryData,
|
||||
noPagination: true,
|
||||
attrs: {
|
||||
rowSelection: rowSelection,
|
||||
expandable: {
|
||||
@@ -319,6 +326,6 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export default IndicatorDrawer;
|
||||
export default MetricSelect;
|
||||
@@ -26,6 +26,7 @@ const OptionsDefault = [
|
||||
|
||||
const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
const {
|
||||
hasCustomScope,
|
||||
customScopeList: customList,
|
||||
scopeName = '',
|
||||
scopeLabel = '自定义范围',
|
||||
@@ -128,51 +129,53 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
</div>
|
||||
<div className="flx_r">
|
||||
<h6 className="time_title">{scopeLabel}</h6>
|
||||
<div className="custom-scope">
|
||||
<div className="check-row">
|
||||
<Checkbox className="check-all" indeterminate={indeterminate} onChange={onCheckAllChange} checked={checkAll}>
|
||||
全选
|
||||
</Checkbox>
|
||||
<Input
|
||||
className="search-input"
|
||||
suffix={<IconFont type="icon-fangdajing" style={{ fontSize: '16px' }} />}
|
||||
size="small"
|
||||
placeholder={searchPlaceholder}
|
||||
onChange={(e) => setScopeSearchValue(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="fixed-height">
|
||||
<Checkbox.Group style={{ width: '100%' }} onChange={checkChange} value={checkedListTemp}>
|
||||
<Row gutter={[10, 12]}>
|
||||
{customList
|
||||
.filter((item) => item.label.includes(scopeSearchValue))
|
||||
.map((item) => (
|
||||
<Col span={12} key={item.value}>
|
||||
<Checkbox value={item.value}>{item.label}</Checkbox>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</Checkbox.Group>
|
||||
</div>
|
||||
{hasCustomScope && (
|
||||
<div className="flx_r">
|
||||
<h6 className="time_title">{scopeLabel}</h6>
|
||||
<div className="custom-scope">
|
||||
<div className="check-row">
|
||||
<Checkbox className="check-all" indeterminate={indeterminate} onChange={onCheckAllChange} checked={checkAll}>
|
||||
全选
|
||||
</Checkbox>
|
||||
<Input
|
||||
className="search-input"
|
||||
suffix={<IconFont type="icon-fangdajing" style={{ fontSize: '16px' }} />}
|
||||
size="small"
|
||||
placeholder={searchPlaceholder}
|
||||
onChange={(e) => setScopeSearchValue(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="fixed-height">
|
||||
<Checkbox.Group style={{ width: '100%' }} onChange={checkChange} value={checkedListTemp}>
|
||||
<Row gutter={[10, 12]}>
|
||||
{customList
|
||||
.filter((item) => item.label.includes(scopeSearchValue))
|
||||
.map((item) => (
|
||||
<Col span={12} key={item.value}>
|
||||
<Checkbox value={item.value}>{item.label}</Checkbox>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</Checkbox.Group>
|
||||
</div>
|
||||
|
||||
<div className="btn-con">
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
className="btn-sure"
|
||||
onClick={customSure}
|
||||
disabled={checkedListTemp?.length > 0 ? false : true}
|
||||
>
|
||||
确定
|
||||
</Button>
|
||||
<Button size="small" onClick={customCancel}>
|
||||
取消
|
||||
</Button>
|
||||
<div className="btn-con">
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
className="btn-sure"
|
||||
onClick={customSure}
|
||||
disabled={checkedListTemp?.length > 0 ? false : true}
|
||||
>
|
||||
确定
|
||||
</Button>
|
||||
<Button size="small" onClick={customCancel}>
|
||||
取消
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -185,7 +188,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||
visible={popVisible}
|
||||
content={clickContent}
|
||||
placement="bottomRight"
|
||||
overlayClassName="d-node-scope-popover"
|
||||
overlayClassName={`d-node-scope-popover ${hasCustomScope ? 'large-size' : ''}`}
|
||||
onVisibleChange={visibleChange}
|
||||
>
|
||||
<span className="input-span">
|
||||
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
@@ -1,9 +1,9 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Tooltip, Select, Utils, Divider, Button } from 'knowdesign';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Select, Divider, Button } from 'knowdesign';
|
||||
import { IconFont } from '@knowdesign/icons';
|
||||
import moment from 'moment';
|
||||
import { DRangeTime } from 'knowdesign';
|
||||
import IndicatorDrawer from './IndicatorDrawer';
|
||||
import MetricSelect from './MetricSelect';
|
||||
import NodeScope from './NodeScope';
|
||||
|
||||
import './style/index.less';
|
||||
@@ -24,8 +24,8 @@ export interface KsHeaderOptions {
|
||||
data: number | number[];
|
||||
};
|
||||
}
|
||||
export interface IindicatorSelectModule {
|
||||
metricType?: MetricType;
|
||||
export interface MetricSelect {
|
||||
metricType: MetricType;
|
||||
hide?: boolean;
|
||||
drawerTitle?: string;
|
||||
selectedRows: (string | number)[];
|
||||
@@ -47,20 +47,27 @@ export interface IcustomScope {
|
||||
}
|
||||
|
||||
export interface InodeScopeModule {
|
||||
hasCustomScope: boolean;
|
||||
customScopeList: IcustomScope[];
|
||||
scopeName?: string;
|
||||
scopeLabel?: string;
|
||||
searchPlaceholder?: string;
|
||||
change?: () => void;
|
||||
}
|
||||
|
||||
interface PropsType {
|
||||
indicatorSelectModule?: IindicatorSelectModule;
|
||||
metricSelect?: MetricSelect;
|
||||
hideNodeScope?: boolean;
|
||||
hideGridSelect?: boolean;
|
||||
nodeScopeModule?: InodeScopeModule;
|
||||
onChange: (options: KsHeaderOptions) => void;
|
||||
}
|
||||
|
||||
interface ScopeData {
|
||||
isTop: boolean;
|
||||
data: any;
|
||||
}
|
||||
|
||||
// 列布局选项
|
||||
const GRID_SIZE_OPTIONS = [
|
||||
{
|
||||
@@ -77,15 +84,17 @@ const GRID_SIZE_OPTIONS = [
|
||||
},
|
||||
];
|
||||
|
||||
const SingleChartHeader = ({
|
||||
indicatorSelectModule,
|
||||
const MetricOperateBar = ({
|
||||
metricSelect,
|
||||
nodeScopeModule = {
|
||||
hasCustomScope: false,
|
||||
customScopeList: [],
|
||||
},
|
||||
hideNodeScope = false,
|
||||
hideGridSelect = false,
|
||||
onChange: onChangeCallback,
|
||||
}: PropsType): JSX.Element => {
|
||||
const metricSelectRef = useRef(null);
|
||||
const [gridNum, setGridNum] = useState<number>(GRID_SIZE_OPTIONS[1].value);
|
||||
const [rangeTime, setRangeTime] = useState<[number, number]>(() => {
|
||||
const curTimeStamp = moment().valueOf();
|
||||
@@ -93,16 +102,35 @@ const SingleChartHeader = ({
|
||||
});
|
||||
const [isRelativeRangeTime, setIsRelativeRangeTime] = useState(true);
|
||||
const [isAutoReload, setIsAutoReload] = useState(false);
|
||||
const [indicatorDrawerVisible, setIndicatorDrawerVisible] = useState(false);
|
||||
|
||||
const [scopeData, setScopeData] = useState<{
|
||||
isTop: boolean;
|
||||
data: any;
|
||||
}>({
|
||||
const [scopeData, setScopeData] = useState<ScopeData>({
|
||||
isTop: true,
|
||||
data: 5,
|
||||
});
|
||||
|
||||
const sizeChange = (value: number) => setGridNum(value);
|
||||
|
||||
const timeChange = (curRangeTime: [number, number], isRelative: boolean) => {
|
||||
setRangeTime([...curRangeTime]);
|
||||
setIsRelativeRangeTime(isRelative);
|
||||
};
|
||||
|
||||
const reloadRangeTime = () => {
|
||||
if (isRelativeRangeTime) {
|
||||
const timeLen = rangeTime[1] - rangeTime[0] || 0;
|
||||
const curTimeStamp = moment().valueOf();
|
||||
setRangeTime([curTimeStamp - timeLen, curTimeStamp]);
|
||||
} else {
|
||||
setRangeTime([...rangeTime]);
|
||||
}
|
||||
};
|
||||
|
||||
const nodeScopeChange = (data: any, isTop?: any) => {
|
||||
setScopeData({
|
||||
isTop,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
onChangeCallback({
|
||||
rangeTime,
|
||||
@@ -129,68 +157,37 @@ const SingleChartHeader = ({
|
||||
};
|
||||
}, [isRelativeRangeTime, rangeTime]);
|
||||
|
||||
const sizeChange = (value: number) => {
|
||||
setGridNum(value);
|
||||
};
|
||||
|
||||
const timeChange = (curRangeTime: [number, number], isRelative: boolean) => {
|
||||
setRangeTime([...curRangeTime]);
|
||||
setIsRelativeRangeTime(isRelative);
|
||||
};
|
||||
|
||||
const reloadRangeTime = () => {
|
||||
if (isRelativeRangeTime) {
|
||||
const timeLen = rangeTime[1] - rangeTime[0] || 0;
|
||||
const curTimeStamp = moment().valueOf();
|
||||
setRangeTime([curTimeStamp - timeLen, curTimeStamp]);
|
||||
} else {
|
||||
setRangeTime([...rangeTime]);
|
||||
}
|
||||
};
|
||||
|
||||
const openIndicatorDrawer = () => {
|
||||
setIndicatorDrawerVisible(true);
|
||||
};
|
||||
|
||||
const closeIndicatorDrawer = () => {
|
||||
setIndicatorDrawerVisible(false);
|
||||
};
|
||||
|
||||
const nodeScopeChange = (data: any, isTop?: any) => {
|
||||
setScopeData({
|
||||
isTop,
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="ks-chart-container">
|
||||
<div className="ks-chart-container-header">
|
||||
<div className="header-left">
|
||||
{/* 刷新 */}
|
||||
<div className="icon-box" onClick={reloadRangeTime}>
|
||||
<IconFont className="icon" type="icon-shuaxin1" />
|
||||
</div>
|
||||
<Divider type="vertical" style={{ height: 20, top: 0 }} />
|
||||
{/* 时间选择 */}
|
||||
<DRangeTime timeChange={timeChange} rangeTimeArr={rangeTime} />
|
||||
</div>
|
||||
<div className="header-right">
|
||||
{/* 节点范围 */}
|
||||
{!hideNodeScope && <NodeScope nodeScopeModule={nodeScopeModule} change={nodeScopeChange} />}
|
||||
{/* 分栏 */}
|
||||
{!hideGridSelect && (
|
||||
<Select className="grid-select" style={{ width: 70 }} value={gridNum} options={GRID_SIZE_OPTIONS} onChange={sizeChange} />
|
||||
)}
|
||||
{(!hideNodeScope || !hideGridSelect) && <Divider type="vertical" style={{ height: 20, top: 0 }} />}
|
||||
<Button type="primary" onClick={openIndicatorDrawer}>
|
||||
<Button type="primary" onClick={() => metricSelectRef.current.open()}>
|
||||
指标筛选
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{!indicatorSelectModule?.hide && (
|
||||
<IndicatorDrawer visible={indicatorDrawerVisible} onClose={closeIndicatorDrawer} indicatorSelectModule={indicatorSelectModule} />
|
||||
)}
|
||||
{/* 指标筛选 */}
|
||||
{!metricSelect?.hide && <MetricSelect ref={metricSelectRef} metricSelect={metricSelect} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SingleChartHeader;
|
||||
export default MetricOperateBar;
|
||||
@@ -1,13 +1,8 @@
|
||||
@root-entry-name: 'default';
|
||||
@import '~knowdesign/es/basic/style/themes/index';
|
||||
@import '~knowdesign/es/basic/style/mixins/index';
|
||||
|
||||
|
||||
.indicator-drawer{
|
||||
.dcloud-drawer-body{
|
||||
padding-top: 2px !important;
|
||||
}
|
||||
.indicator-drawer {
|
||||
.dcloud-drawer-body {
|
||||
padding-top: 2px !important;
|
||||
}
|
||||
}
|
||||
// .dd-indicator-drawer {
|
||||
// @drawerItemH: 27px;
|
||||
// @primary-color: #556ee6;
|
||||
@@ -63,9 +63,16 @@
|
||||
}
|
||||
.@{ant-prefix}-popover-inner-content {
|
||||
padding: 16px 24px;
|
||||
width: 479px;
|
||||
width: 200px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
&.large-size {
|
||||
.@{ant-prefix}-popover-inner-content {
|
||||
padding: 16px 24px;
|
||||
width: 479px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
&.@{ant-prefix}-popover-placement-bottomRight {
|
||||
// padding-top: 0;
|
||||
}
|
||||
@@ -2,11 +2,10 @@ import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, use
|
||||
import { AppContainer, Drawer, Spin, Table, SingleChart, Utils, Tooltip } from 'knowdesign';
|
||||
import moment from 'moment';
|
||||
import api, { MetricType } from '@src/api';
|
||||
import { MetricDefaultChartDataType, MetricChartDataType, formatChartData } from '@src/constants/chartConfig';
|
||||
import { OriginMetricData, FormattedMetricData, formatChartData } from '@src/constants/chartConfig';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { debounce } from 'lodash';
|
||||
import { getDetailChartConfig } from './config';
|
||||
import { UNIT_MAP } from '@src/constants/chartConfig';
|
||||
import RenderEmpty from '../RenderEmpty';
|
||||
|
||||
interface ChartDetailProps {
|
||||
@@ -35,7 +34,7 @@ interface ChartInfo {
|
||||
curTimeRange?: readonly [number, number];
|
||||
sliderPos?: readonly [number, number];
|
||||
transformUnit?: [string, number];
|
||||
fullMetricData?: MetricChartDataType;
|
||||
fullMetricData?: FormattedMetricData;
|
||||
oldDataZoomOption?: any;
|
||||
}
|
||||
|
||||
@@ -79,7 +78,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
||||
isLoadingAdditionData: false,
|
||||
isLoadedFullData: false,
|
||||
fullTimeRange: curTimeRange,
|
||||
fullMetricData: {} as MetricChartDataType,
|
||||
fullMetricData: {} as FormattedMetricData,
|
||||
curTimeRange,
|
||||
oldDataZoomOption: {},
|
||||
sliderPos: [0, 0],
|
||||
@@ -90,7 +89,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
// 当前展示的图表数据
|
||||
const [curMetricData, setCurMetricData] = useState<MetricChartDataType>();
|
||||
const [curMetricData, setCurMetricData] = useState<FormattedMetricData>();
|
||||
// 图表数据的各项计算指标
|
||||
const [tableInfo, setTableInfo] = useState<MetricTableInfo[]>([]);
|
||||
const [linesStatus, setLinesStatus] = useState<{
|
||||
@@ -329,7 +328,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
||||
if (i === DEFAULT_REQUEST_COUNT - 1) {
|
||||
Promise.all(requestArr).then((resList) => {
|
||||
// 填充增量的图表数据
|
||||
resList.forEach((res: MetricDefaultChartDataType[], i) => {
|
||||
resList.forEach((res: OriginMetricData[], i) => {
|
||||
// 最后一个请求返回数据为空时,认为已获取到全部图表数据
|
||||
if (!res?.length) {
|
||||
// 标记数据已经全部加载完毕
|
||||
@@ -368,7 +367,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
||||
};
|
||||
|
||||
// 处理增量图表数据
|
||||
const resolveAdditionChartData = (res: MetricDefaultChartDataType[], timeRange: [number, number]) => {
|
||||
const resolveAdditionChartData = (res: OriginMetricData[], timeRange: [number, number]) => {
|
||||
// 格式化图表需要的数据
|
||||
const formattedMetricData = formatChartData(
|
||||
res,
|
||||
@@ -376,7 +375,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
||||
metricType,
|
||||
timeRange,
|
||||
chartInfo.current.transformUnit
|
||||
) as MetricChartDataType[];
|
||||
) as FormattedMetricData[];
|
||||
// 增量填充图表数据
|
||||
const additionMetricPoints = formattedMetricData[0].metricLines;
|
||||
Object.values(additionMetricPoints).forEach((additionLine) => {
|
||||
@@ -536,9 +535,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
||||
// 如果图表返回数据
|
||||
if (res?.length) {
|
||||
// 格式化图表需要的数据
|
||||
const formattedMetricData = (
|
||||
formatChartData(res, global.getMetricDefine || {}, metricType, curTimeRange) as MetricChartDataType[]
|
||||
)[0];
|
||||
const formattedMetricData = formatChartData(res, global.getMetricDefine || {}, metricType, curTimeRange)[0];
|
||||
// 填充图表数据
|
||||
let initFullTimeRange = curTimeRange;
|
||||
const pointsOfFirstLine = formattedMetricData.metricLines.find((line) => line.data.length).data;
|
||||
@@ -549,14 +546,6 @@ const ChartDetail = (props: ChartDetailProps) => {
|
||||
] as const;
|
||||
}
|
||||
|
||||
// 获取单位保存起来
|
||||
let transformUnit = undefined;
|
||||
Object.entries(UNIT_MAP).forEach((unit) => {
|
||||
if (formattedMetricData.metricUnit.includes(unit[0])) {
|
||||
transformUnit = unit;
|
||||
}
|
||||
});
|
||||
|
||||
updateChartInfo({
|
||||
fullMetricData: formattedMetricData,
|
||||
fullTimeRange: [...initFullTimeRange],
|
||||
@@ -565,7 +554,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
||||
initFullTimeRange[1] - (initFullTimeRange[1] - initFullTimeRange[0]) * DATA_ZOOM_DEFAULT_SCALE,
|
||||
initFullTimeRange[1],
|
||||
],
|
||||
transformUnit,
|
||||
transformUnit: formattedMetricData.targetUnit,
|
||||
});
|
||||
setCurMetricData(formattedMetricData);
|
||||
const newLinesStatus: { [lineName: string]: boolean } = {};
|
||||
@@ -1,11 +1,22 @@
|
||||
import api, { MetricType } from '@src/api';
|
||||
import { getBasicChartConfig, CHART_COLOR_LIST } from '@src/constants/chartConfig';
|
||||
|
||||
const METRIC_DASHBOARD_REQ_MAP = {
|
||||
[MetricType.Broker]: (clusterId: string) => api.getDashboardMetricChartData(clusterId, MetricType.Broker),
|
||||
[MetricType.Topic]: (clusterId: string) => api.getDashboardMetricChartData(clusterId, MetricType.Topic),
|
||||
[MetricType.Zookeeper]: (clusterId: string) => '',
|
||||
};
|
||||
|
||||
export const getMetricDashboardReq = (clusterId: string, type: MetricType.Broker | MetricType.Topic | MetricType.Zookeeper) =>
|
||||
METRIC_DASHBOARD_REQ_MAP[type](clusterId);
|
||||
|
||||
const seriesCallback = (lines: { name: string; data: [number, string | number][] }[]) => {
|
||||
const len = CHART_COLOR_LIST.length;
|
||||
// series 配置
|
||||
return lines.map((line, i) => {
|
||||
return {
|
||||
...line,
|
||||
z: len - i,
|
||||
lineStyle: {
|
||||
width: 1.5,
|
||||
},
|
||||
@@ -13,6 +24,7 @@ const seriesCallback = (lines: { name: string; data: [number, string | number][]
|
||||
symbol: 'emptyCircle',
|
||||
symbolSize: 4,
|
||||
smooth: 0.25,
|
||||
color: CHART_COLOR_LIST[i % len],
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
@@ -38,17 +50,13 @@ const seriesCallback = (lines: { name: string; data: [number, string | number][]
|
||||
};
|
||||
|
||||
// 返回图表配置
|
||||
export const getChartConfig = (title: string, metricLength: number) => {
|
||||
export const getChartConfig = (title: string, metricLength: number, showLegend = true) => {
|
||||
return {
|
||||
option: getBasicChartConfig({
|
||||
title: { show: false },
|
||||
grid: { top: 24 },
|
||||
grid: { top: 24, bottom: showLegend ? 40 : 20 },
|
||||
tooltip: { enterable: metricLength > 9, legendContextMaxHeight: 192 },
|
||||
color: CHART_COLOR_LIST,
|
||||
// xAxis: {
|
||||
// type: 'time',
|
||||
// boundaryGap: ['5%', '5%'],
|
||||
// },
|
||||
legend: { show: showLegend },
|
||||
}),
|
||||
seriesCallback,
|
||||
};
|
||||
@@ -67,7 +75,6 @@ export const getDetailChartConfig = (title: string, sliderPos: readonly [number,
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
color: CHART_COLOR_LIST,
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
@@ -1,5 +1,5 @@
|
||||
.topic-dashboard {
|
||||
height: calc(100% - 160px);
|
||||
height: calc(100% - 162px);
|
||||
padding-bottom: 10px;
|
||||
.ks-chart-container-header {
|
||||
margin-top: 12px;
|
||||
@@ -4,17 +4,11 @@ import { Utils, Empty, Spin, AppContainer, SingleChart, Tooltip } from 'knowdesi
|
||||
import { IconFont } from '@knowdesign/icons';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import api, { MetricType } from '@src/api';
|
||||
import {
|
||||
MetricInfo,
|
||||
MetricDefaultChartDataType,
|
||||
MetricChartDataType,
|
||||
formatChartData,
|
||||
resolveMetricsRank,
|
||||
} from '@src/constants/chartConfig';
|
||||
import SingleChartHeader, { KsHeaderOptions } from '../SingleChartHeader';
|
||||
import { MetricInfo, OriginMetricData, FormattedMetricData, formatChartData, resolveMetricsRank } from '@src/constants/chartConfig';
|
||||
import ChartOperateBar, { KsHeaderOptions } from '../ChartOperateBar';
|
||||
import DragGroup from '../DragGroup';
|
||||
import ChartDetail from './ChartDetail';
|
||||
import { getChartConfig } from './config';
|
||||
import ChartDetail from './Detail';
|
||||
import { getChartConfig, getMetricDashboardReq } from './config';
|
||||
import './index.less';
|
||||
|
||||
interface IcustomScope {
|
||||
@@ -33,7 +27,7 @@ const busInstance = new EventBus();
|
||||
|
||||
const DRAG_GROUP_GUTTER_NUM: [number, number] = [16, 16];
|
||||
|
||||
const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
const DraggableCharts = (props: PropsType): JSX.Element => {
|
||||
const [global] = AppContainer.useGlobalValue();
|
||||
const { type: dashboardType } = props;
|
||||
const { clusterId } = useParams<{
|
||||
@@ -44,7 +38,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
const [metricsList, setMetricsList] = useState<MetricInfo[]>([]); // 指标列表
|
||||
const [selectedMetricNames, setSelectedMetricNames] = useState<(string | number)[]>([]); // 默认选中的指标的列表
|
||||
const [curHeaderOptions, setCurHeaderOptions] = useState<ChartFilterOptions>();
|
||||
const [metricChartData, setMetricChartData] = useState<MetricChartDataType[]>([]); // 指标图表数据列表
|
||||
const [metricChartData, setMetricChartData] = useState<FormattedMetricData[]>([]); // 指标图表数据列表
|
||||
const [gridNum, setGridNum] = useState<number>(12); // 图表列布局
|
||||
const metricRankList = useRef<string[]>([]);
|
||||
const chartDetailRef = useRef(null);
|
||||
@@ -85,6 +79,9 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
updateRank([...supportMetrics]);
|
||||
setMetricsList(supportMetrics);
|
||||
setSelectedMetricNames(selectedMetrics);
|
||||
if (!selectedMetrics.length) {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -106,16 +103,24 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
const curTimestamp = Date.now();
|
||||
curFetchingTimestamp.current = curTimestamp;
|
||||
|
||||
Utils.post(api.getDashboardMetricChartData(clusterId, dashboardType), {
|
||||
startTime,
|
||||
endTime,
|
||||
metricsNames: selectedMetricNames,
|
||||
topNu: curHeaderOptions?.scopeData?.isTop ? curHeaderOptions.scopeData.data : null,
|
||||
[dashboardType === MetricType.Broker ? 'brokerIds' : 'topics']: curHeaderOptions?.scopeData?.isTop
|
||||
? null
|
||||
: curHeaderOptions.scopeData.data,
|
||||
}).then(
|
||||
(res: MetricDefaultChartDataType[] | null) => {
|
||||
const reqBody = Object.assign(
|
||||
{
|
||||
startTime,
|
||||
endTime,
|
||||
metricsNames: selectedMetricNames,
|
||||
topNu: curHeaderOptions?.scopeData?.isTop ? curHeaderOptions.scopeData.data : null,
|
||||
},
|
||||
dashboardType === MetricType.Broker || dashboardType === MetricType.Topic
|
||||
? {
|
||||
[dashboardType === MetricType.Broker ? 'brokerIds' : 'topics']: curHeaderOptions?.scopeData?.isTop
|
||||
? null
|
||||
: curHeaderOptions.scopeData.data,
|
||||
}
|
||||
: {}
|
||||
);
|
||||
|
||||
Utils.post(getMetricDashboardReq(clusterId, dashboardType as any), reqBody).then(
|
||||
(res: OriginMetricData[] | null) => {
|
||||
// 如果当前请求不是最新请求,则不做任何操作
|
||||
if (curFetchingTimestamp.current !== curTimestamp) {
|
||||
return;
|
||||
@@ -131,7 +136,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
global.getMetricDefine || {},
|
||||
dashboardType,
|
||||
curHeaderOptions.rangeTime
|
||||
) as MetricChartDataType[];
|
||||
) as FormattedMetricData[];
|
||||
// 指标排序
|
||||
formattedMetricData.sort((a, b) => metricRankList.current.indexOf(a.metricName) - metricRankList.current.indexOf(b.metricName));
|
||||
|
||||
@@ -164,7 +169,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
};
|
||||
|
||||
// 指标选中项更新回调
|
||||
const indicatorChangeCallback = (newMetricNames: (string | number)[]) => {
|
||||
const metricSelectCallback = (newMetricNames: (string | number)[]) => {
|
||||
const updateMetrics: { metric: string; set: boolean; rank: number }[] = [];
|
||||
// 需要选中的指标
|
||||
newMetricNames.forEach(
|
||||
@@ -218,7 +223,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
|
||||
useEffect(() => {
|
||||
// 初始化页面,获取 scope 和 metric 信息
|
||||
getScopeList();
|
||||
(dashboardType === MetricType.Broker || dashboardType === MetricType.Topic) && getScopeList();
|
||||
getMetricList();
|
||||
|
||||
setTimeout(() => observeDashboardWidthChange());
|
||||
@@ -226,19 +231,22 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
|
||||
return (
|
||||
<div id="dashboard-drag-chart" className="topic-dashboard">
|
||||
<SingleChartHeader
|
||||
<ChartOperateBar
|
||||
onChange={ksHeaderChange}
|
||||
nodeScopeModule={{
|
||||
hasCustomScope: !(dashboardType === MetricType.Zookeeper),
|
||||
customScopeList: scopeList,
|
||||
scopeName: dashboardType === MetricType.Broker ? 'Broker' : 'Topic',
|
||||
scopeLabel: `自定义 ${dashboardType === MetricType.Broker ? 'Broker' : 'Topic'} 范围`,
|
||||
scopeName: dashboardType === MetricType.Broker ? 'Broker' : dashboardType === MetricType.Topic ? 'Topic' : 'Zookeeper',
|
||||
scopeLabel: `自定义 ${
|
||||
dashboardType === MetricType.Broker ? 'Broker' : dashboardType === MetricType.Topic ? 'Topic' : 'Zookeeper'
|
||||
} 范围`,
|
||||
}}
|
||||
indicatorSelectModule={{
|
||||
metricSelect={{
|
||||
hide: false,
|
||||
metricType: dashboardType,
|
||||
tableData: metricsList,
|
||||
selectedRows: selectedMetricNames,
|
||||
submitCallback: indicatorChangeCallback,
|
||||
submitCallback: metricSelectCallback,
|
||||
}}
|
||||
/>
|
||||
<div className="topic-dashboard-container">
|
||||
@@ -258,7 +266,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
}}
|
||||
>
|
||||
{metricChartData.map((data) => {
|
||||
const { metricName, metricUnit, metricLines } = data;
|
||||
const { metricName, metricUnit, metricLines, showLegend } = data;
|
||||
|
||||
return (
|
||||
<div key={metricName} className="dashboard-drag-item-box">
|
||||
@@ -301,7 +309,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
eventBus={busInstance}
|
||||
propChartData={metricLines}
|
||||
optionMergeProps={{ replaceMerge: curHeaderOptions.isAutoReload ? ['xAxis'] : ['series'] }}
|
||||
{...getChartConfig(`${metricName}{unit|(${metricUnit})}`, metricLines.length)}
|
||||
{...getChartConfig(`${metricName}{unit|(${metricUnit})}`, metricLines.length, showLegend)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -321,4 +329,4 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardDragChart;
|
||||
export default DraggableCharts;
|
||||
Reference in New Issue
Block a user