mirror of
https://github.com/didi/KnowStreaming.git
synced 2026-01-01 09:42:11 +08:00
324 lines
9.3 KiB
TypeScript
324 lines
9.3 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { Drawer, Button, Space, Divider, AppContainer, ProTable, IconFont } from 'knowdesign';
|
|
import { IindicatorSelectModule } 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;
|
|
}
|
|
|
|
interface MetricInfo {
|
|
name: string;
|
|
unit: string;
|
|
desc: string;
|
|
}
|
|
|
|
interface SelectedMetrics {
|
|
[category: string]: string[];
|
|
}
|
|
|
|
type CategoryData = {
|
|
category: string;
|
|
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',
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
position: 'relative',
|
|
padding: '12px 16px',
|
|
margin: '0 7px',
|
|
border: '1px solid #EFF2F7',
|
|
borderRadius: '8px',
|
|
backgroundColor: '#ffffff',
|
|
}}
|
|
>
|
|
<ProTable
|
|
tableProps={{
|
|
showHeader: false,
|
|
noPagination: true,
|
|
rowKey: 'name',
|
|
columns: innerColumns,
|
|
dataSource: metrics,
|
|
attrs: {
|
|
rowSelection: {
|
|
hideSelectAll: true,
|
|
selectedRowKeys: selectedMetrics,
|
|
onChange: (keys: string[]) => {
|
|
selectedMetricChange(category, keys);
|
|
},
|
|
},
|
|
},
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) => {
|
|
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 columns = [
|
|
{
|
|
title: `${pathname.endsWith('/broker') ? 'Broker' : pathname.endsWith('/topic') ? 'Topic' : 'Cluster'} Metrics`,
|
|
dataIndex: 'category',
|
|
key: 'category',
|
|
},
|
|
];
|
|
|
|
const formateTableData = () => {
|
|
const tableData = indicatorSelectModule.tableData;
|
|
const categoryData: {
|
|
[category: string]: MetricInfo[];
|
|
} = {};
|
|
|
|
tableData.forEach(({ name, desc }) => {
|
|
const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name);
|
|
const returnData = {
|
|
name,
|
|
desc,
|
|
unit: metricDefine?.unit,
|
|
};
|
|
if (metricDefine.category) {
|
|
if (!categoryData[metricDefine.category]) {
|
|
categoryData[metricDefine.category] = [returnData];
|
|
} else {
|
|
categoryData[metricDefine.category].push(returnData);
|
|
}
|
|
}
|
|
});
|
|
|
|
const result = Object.entries(categoryData).map(([category, data]) => ({
|
|
category,
|
|
metrics: data.sort((a, b) => Number(a.name > b.name) - 0.5),
|
|
}));
|
|
setCategoryData(result);
|
|
};
|
|
|
|
const formateSelectedKeys = () => {
|
|
const newKeys = indicatorSelectModule.selectedRows;
|
|
const result: SelectedMetrics = {};
|
|
const selectedCategories: string[] = [];
|
|
|
|
newKeys.forEach((name: string) => {
|
|
const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name);
|
|
if (metricDefine) {
|
|
if (!result[metricDefine.category]) {
|
|
result[metricDefine.category] = [name];
|
|
} else {
|
|
result[metricDefine.category].push(name);
|
|
}
|
|
}
|
|
});
|
|
|
|
Object.entries(result).forEach(([curCategory, metrics]) => {
|
|
if (metrics.length) {
|
|
selectedCategories.push(curCategory);
|
|
}
|
|
});
|
|
|
|
setSelectedCategories(selectedCategories);
|
|
|
|
setChildrenSelectedRowKeys((cur) => ({
|
|
...cur,
|
|
...result,
|
|
}));
|
|
};
|
|
|
|
const rowChange = (newCategorys: string[]) => {
|
|
newCategorys.sort();
|
|
const prevCategories = selectedCategories;
|
|
const addCategories: string[] = [];
|
|
const delCategories: string[] = [];
|
|
// 需要选中的指标
|
|
newCategorys.forEach((name) => !prevCategories.includes(name) && addCategories.push(name));
|
|
// 取消选中的指标
|
|
prevCategories.forEach((name) => !newCategorys.includes(name) && delCategories.push(name));
|
|
|
|
const changedCategories: SelectedMetrics = {};
|
|
// 1. 选中,即选中所有子项
|
|
addCategories.forEach((curCategory) => {
|
|
let childrenData: string[] = [];
|
|
categoryData.some(({ category, metrics }) => {
|
|
if (curCategory === category) {
|
|
childrenData = metrics.map(({ name }) => name);
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
changedCategories[curCategory] = childrenData;
|
|
});
|
|
// 2. 取消选中,取消选中所有子项
|
|
delCategories.forEach((curCategory) => {
|
|
changedCategories[curCategory] = [];
|
|
});
|
|
|
|
setSelectedCategories(newCategorys);
|
|
setChildrenSelectedRowKeys((cur) => ({
|
|
...cur,
|
|
...changedCategories,
|
|
}));
|
|
};
|
|
|
|
const childrenRowChange = (curCategory: string, keys: string[]) => {
|
|
// 更新选中的指标项
|
|
setChildrenSelectedRowKeys((cur) => ({
|
|
...cur,
|
|
[curCategory]: keys,
|
|
}));
|
|
// 更新父级选中状态
|
|
if (keys.length === 0) {
|
|
const i = selectedCategories.indexOf(curCategory);
|
|
if (i !== -1) {
|
|
const newCategories = [...selectedCategories];
|
|
newCategories.splice(i, 1);
|
|
setSelectedCategories(newCategories);
|
|
}
|
|
} else {
|
|
const curCategoryData = categoryData.find((value) => value.category === curCategory);
|
|
if (curCategoryData.metrics.length === keys.length) {
|
|
setSelectedCategories([...selectedCategories, curCategory]);
|
|
}
|
|
}
|
|
};
|
|
|
|
const submitRowKeys = () => {
|
|
setConfirmLoading(true);
|
|
|
|
const allRowKeys: string[] = [];
|
|
Object.entries(childrenSelectedRowKeys).forEach(([, arr]) => allRowKeys.push(...arr));
|
|
|
|
indicatorSelectModule.submitCallback(allRowKeys).then(
|
|
() => {
|
|
setConfirmLoading(false);
|
|
onClose();
|
|
},
|
|
() => {
|
|
setConfirmLoading(false);
|
|
}
|
|
);
|
|
};
|
|
|
|
const rowSelection = {
|
|
selectedRowKeys: selectedCategories,
|
|
onChange: rowChange,
|
|
// getCheckboxProps: (record: any) => indicatorSelectModule.checkboxProps && indicatorSelectModule.checkboxProps(record),
|
|
getCheckboxProps: (record: CategoryData) => {
|
|
const isAllSelected = record.metrics.length === childrenSelectedRowKeys[record.category]?.length;
|
|
const isNotCheck = !childrenSelectedRowKeys[record.category] || childrenSelectedRowKeys[record.category]?.length === 0;
|
|
return {
|
|
indeterminate: !isNotCheck && !isAllSelected,
|
|
};
|
|
},
|
|
};
|
|
|
|
useEffect(formateTableData, [indicatorSelectModule.tableData]);
|
|
|
|
useEffect(() => {
|
|
visible && formateSelectedKeys();
|
|
}, [visible, indicatorSelectModule.selectedRows]);
|
|
|
|
return (
|
|
<>
|
|
<Drawer
|
|
className="indicator-drawer"
|
|
title={indicatorSelectModule.drawerTitle || '指标筛选'}
|
|
width="868px"
|
|
forceRender={true}
|
|
onClose={onClose}
|
|
visible={visible}
|
|
maskClosable={false}
|
|
extra={
|
|
<Space>
|
|
<Button size="small" onClick={onClose}>
|
|
取消
|
|
</Button>
|
|
<Button
|
|
type="primary"
|
|
size="small"
|
|
disabled={Object.entries(childrenSelectedRowKeys).every(([, arr]) => !arr.length)}
|
|
loading={confirmLoading}
|
|
onClick={submitRowKeys}
|
|
>
|
|
确定
|
|
</Button>
|
|
<Divider type="vertical" />
|
|
</Space>
|
|
}
|
|
>
|
|
<ProTable
|
|
tableProps={{
|
|
showHeader: false,
|
|
rowKey: 'category',
|
|
columns: columns,
|
|
dataSource: categoryData,
|
|
attrs: {
|
|
rowSelection: rowSelection,
|
|
expandable: {
|
|
expandRowByClick: true,
|
|
expandedRowRender: (record: CategoryData) => (
|
|
<ExpandedRow
|
|
metrics={record.metrics}
|
|
category={record.category}
|
|
selectedMetrics={childrenSelectedRowKeys[record.category] || []}
|
|
selectedMetricChange={childrenRowChange}
|
|
/>
|
|
),
|
|
expandIcon: ({ expanded, onExpand, record }: any) => {
|
|
return expanded ? (
|
|
<IconFont
|
|
style={{ fontSize: '16px' }}
|
|
type="icon-xia"
|
|
onClick={(e: any) => {
|
|
onExpand(record, e);
|
|
}}
|
|
/>
|
|
) : (
|
|
<IconFont
|
|
style={{ fontSize: '16px' }}
|
|
type="icon-jiantou_1"
|
|
onClick={(e: any) => {
|
|
onExpand(record, e);
|
|
}}
|
|
/>
|
|
);
|
|
},
|
|
},
|
|
},
|
|
}}
|
|
/>
|
|
</Drawer>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default IndicatorDrawer;
|