This is an automated email from the ASF dual-hosted git repository.
dockerzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/inlong.git
The following commit(s) were added to refs/heads/master by this push:
new da568ab768 [INLONG-11894][Dashboard] Added group and stream switching
on the audit page (#11895)
da568ab768 is described below
commit da568ab768be173d7c52d9a04cbe799affb66fd9
Author: kamianlaida <[email protected]>
AuthorDate: Tue Jun 17 18:02:44 2025 +0800
[INLONG-11894][Dashboard] Added group and stream switching on the audit
page (#11895)
---
inlong-dashboard/src/ui/locales/cn.json | 5 +
inlong-dashboard/src/ui/locales/en.json | 5 +
.../src/ui/pages/GroupDetail/Audit/config.tsx | 437 ++++++++++++---------
.../src/ui/pages/GroupDetail/Audit/index.less | 34 ++
.../src/ui/pages/GroupDetail/Audit/index.tsx | 153 +++++---
5 files changed, 402 insertions(+), 232 deletions(-)
diff --git a/inlong-dashboard/src/ui/locales/cn.json
b/inlong-dashboard/src/ui/locales/cn.json
index 26dac255ae..fdcf098fb1 100644
--- a/inlong-dashboard/src/ui/locales/cn.json
+++ b/inlong-dashboard/src/ui/locales/cn.json
@@ -706,6 +706,11 @@
"pages.GroupDetail.Streams": "数据流",
"pages.GroupDetail.Sources": "数据源",
"pages.GroupDetail.Sinks": "数据目标",
+ "pages.GroupDetail.SinkType": "数据目标类型",
+ "pages.GroupDetail.Audit.Count": "数量",
+ "pages.GroupDetail.Audit.Group": "数据流组",
+ "pages.GroupDetail.Audit.Stream": "数据流",
+ "pages.GroupDetail.Audit.Size": "大小",
"pages.GroupDetail.Audit": "审计对账",
"pages.GroupDetail.Resource": "资源详情",
"pages.GroupDetail.Delay": "传输时延",
diff --git a/inlong-dashboard/src/ui/locales/en.json
b/inlong-dashboard/src/ui/locales/en.json
index f6244380d3..6e479235de 100644
--- a/inlong-dashboard/src/ui/locales/en.json
+++ b/inlong-dashboard/src/ui/locales/en.json
@@ -701,6 +701,11 @@
"pages.GroupDetail.Streams": "Streams",
"pages.GroupDetail.Sources": "Sources",
"pages.GroupDetail.Sinks": "Sinks",
+ "pages.GroupDetail.SinkType": "Sink Type",
+ "pages.GroupDetail.Audit.Count": "Count",
+ "pages.GroupDetail.Audit.Group": "Group",
+ "pages.GroupDetail.Audit.Stream": "Stream",
+ "pages.GroupDetail.Audit.Size": "Size",
"pages.GroupDetail.Audit": "Audit",
"pages.GroupDetail.Delay": "Transmission delay",
"pages.GroupDetail.OperationLog": "Operation log",
diff --git a/inlong-dashboard/src/ui/pages/GroupDetail/Audit/config.tsx
b/inlong-dashboard/src/ui/pages/GroupDetail/Audit/config.tsx
index c9bd6f6852..1eef8494e2 100644
--- a/inlong-dashboard/src/ui/pages/GroupDetail/Audit/config.tsx
+++ b/inlong-dashboard/src/ui/pages/GroupDetail/Audit/config.tsx
@@ -119,24 +119,28 @@ export const getSourceDataWithPercent = (sourceKeys,
sourceMap) => {
const keys = Object.keys(source).filter(key => key !== 'logTs');
const firstKey = keys[0];
const firstValue = source[firstKey];
+ const dpValue = source[keys[2]] || 0;
newSource[firstKey] = firstValue.toString();
for (let key of keys.slice(1)) {
- if (key !== 'logTs') {
- let diff = getDiff(firstValue, source[key]);
- newSource[key] = `${source[key]} (${diff})`;
+ let diff = '0%';
+ if (firstValue === 0 && dpValue === 0) {
+ diff = firstValue.toFixed(4) + '%';
+ }
+ if ((key === '4' || key === '5') && firstValue === 0) {
+ diff = firstValue.toFixed(4) + '%';
+ } else {
+ diff = getDiff(firstValue, dpValue, source[key]);
}
+ newSource[key] = `${source[key]} (${diff})`;
}
newSource['logTs'] = source['logTs'];
return newSource;
});
};
-export const getDiff = (first, current) => {
- if (first === 0) {
- return first.toFixed(4) + '%';
- }
+export const getDiff = (first, dpValue, current) => {
let result;
- const diff = (current / first - 1) * 100;
+ const diff = (current / (first === 0 ? dpValue : first) - 1) * 100;
result = diff > 0 ? '+' + diff.toFixed(4) + '%' : diff.toFixed(4) + '%';
return result;
};
@@ -157,6 +161,132 @@ export const getSourceDataWithCommas = sourceData => {
return sourceData;
};
let endTimeVisible = true;
+
+const getCommonFormContent = (initialValues, onSearch, sourceData, csvData,
fileName): any[] => {
+ return [
+ {
+ type: 'datepicker',
+ label: i18n.t('pages.GroupDetail.Audit.StartDate'),
+ name: 'startDate',
+ initialValue: dayjs(initialValues.startDate),
+ props: {
+ allowClear: false,
+ format: 'YYYY-MM-DD',
+ },
+ },
+ {
+ type: 'datepicker',
+ label: i18n.t('pages.GroupDetail.Audit.EndDate'),
+ name: 'endDate',
+ initialValue: dayjs(initialValues.endDate),
+ rules: [
+ { required: true },
+ ({ getFieldValue }) => ({
+ validator(_, value) {
+ const dim = initialValues.timeStaticsDim;
+ if (dim === 'MINUTE') {
+ return Promise.resolve();
+ }
+ const timeDiff = value - getFieldValue('startDate');
+ console.log(timeDiff);
+ if (timeDiff >= 0) {
+ const isHourDiff = dim === 'HOUR' && timeDiff < 1000 * 60 * 60 *
24 * 2;
+ const isDayDiff = dim === 'DAY' && timeDiff < 1000 * 60 * 60 *
24 * 90;
+ if (isHourDiff || isDayDiff) {
+ return Promise.resolve();
+ }
+ }
+ return Promise.reject(new
Error(i18n.t('pages.GroupDetail.Audit.DatepickerRule')));
+ },
+ }),
+ ],
+ props: {
+ allowClear: false,
+ format: 'YYYY-MM-DD',
+ disabled: initialValues.timeStaticsDim === 'MINUTE',
+ disabledDate: current => {
+ const start = dayjs(initialValues.startDate);
+ const dim = initialValues.timeStaticsDim;
+ const tooEarly = current < start.add(-1, 'd').endOf('day');
+ let tooLate;
+ if (dim === 'HOUR') {
+ tooLate = current >= start.add(2, 'd').endOf('day');
+ }
+ if (dim === 'DAY') {
+ tooLate = current >= start.add(90, 'd').endOf('day');
+ }
+ return current && (tooLate || tooEarly);
+ },
+ },
+ },
+ {
+ type: 'select',
+ label: i18n.t('pages.GroupDetail.Audit.TimeStaticsDim'),
+ name: 'timeStaticsDim',
+ initialValue: initialValues.timeStaticsDim,
+ props: {
+ dropdownMatchSelectWidth: false,
+ options: timeStaticsDimList,
+ },
+ },
+ {
+ type: 'select',
+ label: i18n.t('pages.GroupDetail.Audit.Item'),
+ name: 'auditIds',
+ props: {
+ style: {
+ width: 200,
+ },
+ mode: 'multiple',
+ allowClear: true,
+ showSearch: true,
+ dropdownMatchSelectWidth: false,
+ options: {
+ requestAuto: true,
+ requestTrigger: ['onOpen'],
+ requestService: () => {
+ return request('/audit/getAuditBases');
+ },
+ requestParams: {
+ formatResult: result => {
+ return result?.reduce((accumulator, item) => {
+ const existingItem = accumulator.find(
+ (i: { value: any }) => i.value === item.auditId,
+ );
+ if (!existingItem) {
+ accumulator.push({
+ label: i18n?.language === 'cn' ? item.nameInChinese :
item.nameInEnglish,
+ value: item.auditId,
+ });
+ }
+ return accumulator;
+ }, []);
+ },
+ },
+ },
+ filterOption: (keyword: string, option: { label: any }) => {
+ return (option?.label ??
'').toLowerCase().includes(keyword.toLowerCase());
+ },
+ },
+ },
+ {
+ type: (
+ <Button type="primary" onClick={onSearch}>
+ {i18n.t('pages.GroupDetail.Audit.Search')}
+ </Button>
+ ),
+ },
+ {
+ type: (
+ <Button type="primary" disabled={!(sourceData.length > 0)}>
+ <CSVLink data={csvData} filename={fileName}>
+ {i18n.t('pages.GroupDetail.Audit.ExportCSV')}
+ </CSVLink>
+ </Button>
+ ),
+ },
+ ];
+};
export const getFormContent = (
inlongGroupId,
initialValues,
@@ -167,196 +297,127 @@ export const getFormContent = (
fileName,
setInlongStreamID,
inlongStreamId,
-) => [
- {
- type: 'select',
- label: i18n.t('pages.ModuleAudit.config.InlongStreamId'),
- name: 'inlongStreamId',
- props: {
- dropdownMatchSelectWidth: false,
- showSearch: true,
- onChange: (value, option) => {
- setInlongStreamID(value);
- },
- options: {
- requestAuto: true,
- requestTrigger: ['onOpen', 'onSearch'],
- requestService: keyword => ({
- url: '/stream/list',
- method: 'POST',
- data: {
- keyword,
- pageNum: 1,
- pageSize: 100,
- inlongGroupId,
+ key,
+) => {
+ const commonFormContent = getCommonFormContent(
+ initialValues,
+ onSearch,
+ sourceData,
+ csvData,
+ fileName,
+ );
+ if (key === 'stream') {
+ return [
+ {
+ type: 'select',
+ label: i18n.t('pages.ModuleAudit.config.InlongStreamId'),
+ name: 'inlongStreamId',
+ initialValue: inlongStreamId,
+ props: {
+ dropdownMatchSelectWidth: false,
+ showSearch: true,
+ onChange: (value, option) => {
+ setInlongStreamID(value);
+ },
+ options: {
+ requestAuto: true,
+ requestTrigger: ['onOpen', 'onSearch'],
+ requestService: keyword => ({
+ url: '/stream/list',
+ method: 'POST',
+ data: {
+ keyword,
+ pageNum: 1,
+ pageSize: 100,
+ inlongGroupId,
+ },
+ }),
+ requestParams: {
+ formatResult: result =>
+ result?.list.map(item => ({
+ label: item.inlongStreamId,
+ value: item.inlongStreamId,
+ })) || [],
+ onSuccess: onDataStreamSuccess,
+ },
},
- }),
- requestParams: {
- formatResult: result =>
- result?.list.map(item => ({
- label: item.inlongStreamId,
- value: item.inlongStreamId,
- })) || [],
- onSuccess: onDataStreamSuccess,
},
+ rules: [{ required: true }],
},
- },
- rules: [{ required: true }],
- },
- {
- type: 'select',
- label: i18n.t('pages.GroupDetail.Audit.Sink'),
- name: 'sinkId',
- props: values => ({
- dropdownMatchSelectWidth: false,
- showSearch: true,
- options: {
- requestTrigger: ['onOpen', 'onSearch'],
- requestService: keyword => ({
- url: '/sink/list',
- method: 'POST',
- data: {
- keyword,
- pageNum: 1,
- pageSize: 100,
- inlongGroupId,
- inlongStreamId: inlongStreamId,
+ {
+ type: 'select',
+ label: i18n.t('pages.GroupDetail.Audit.Sink'),
+ name: 'sinkId',
+ initialValue: initialValues.sinkId,
+ props: values => ({
+ dropdownMatchSelectWidth: false,
+ showSearch: true,
+ options: {
+ requestTrigger: ['onOpen', 'onSearch'],
+ requestService: keyword => ({
+ url: '/sink/list',
+ method: 'POST',
+ data: {
+ keyword,
+ pageNum: 1,
+ pageSize: 100,
+ inlongGroupId,
+ inlongStreamId: inlongStreamId,
+ },
+ }),
+ requestParams: {
+ formatResult: result =>
+ result?.list.map(item => ({
+ label:
+ item.sinkName + ` ( ${sinks.find(c => c.value ===
item.sinkType)?.label} )`,
+ value: item.id,
+ })) || [],
+ },
+ },
+ filterOption: (keyword: string, option: { label: any }) => {
+ return (option?.label ??
'').toLowerCase().includes(keyword.toLowerCase());
},
}),
- requestParams: {
- formatResult: result =>
- result?.list.map(item => ({
- label: item.sinkName + ` ( ${sinks.find(c => c.value ===
item.sinkType)?.label} )`,
- value: item.id,
- })) || [],
- },
- },
- filterOption: (keyword: string, option: { label: any }) => {
- return (option?.label ??
'').toLowerCase().includes(keyword.toLowerCase());
- },
- }),
- },
- {
- type: 'datepicker',
- label: i18n.t('pages.GroupDetail.Audit.StartDate'),
- name: 'startDate',
- initialValue: dayjs(initialValues.startDate),
- props: {
- allowClear: false,
- format: 'YYYY-MM-DD',
- },
- },
- {
- type: 'datepicker',
- label: i18n.t('pages.GroupDetail.Audit.EndDate'),
- name: 'endDate',
- initialValue: dayjs(initialValues.endDate),
- rules: [
- { required: true },
- ({ getFieldValue }) => ({
- validator(_, value) {
- const dim = initialValues.timeStaticsDim;
- if (dim === 'MINUTE') {
- return Promise.resolve();
- }
- const timeDiff = value - getFieldValue('startDate');
- if (timeDiff >= 0) {
- const isHourDiff = dim === 'HOUR' && timeDiff < 1000 * 60 * 60 *
24 * 3;
- const isDayDiff = dim === 'DAY' && timeDiff < 1000 * 60 * 60 * 24
* 7;
- if (isHourDiff || isDayDiff) {
- return Promise.resolve();
- }
- }
- return Promise.reject(new
Error(i18n.t('pages.GroupDetail.Audit.DatepickerRule')));
- },
- }),
- ],
- props: {
- allowClear: false,
- format: 'YYYY-MM-DD',
- disabled: initialValues.timeStaticsDim === 'MINUTE',
- disabledDate: current => {
- const start = dayjs(initialValues.startDate);
- const dim = initialValues.timeStaticsDim;
- const tooEarly = current < start.add(-1, 'd').endOf('day');
- let tooLate;
- if (dim === 'HOUR') {
- tooLate = current >= start.add(2, 'd').endOf('day');
- }
- if (dim === 'DAY') {
- tooLate = current >= start.add(6, 'd').endOf('day');
- }
- return current && (tooLate || tooEarly);
},
- },
- },
- {
- type: 'select',
- label: i18n.t('pages.GroupDetail.Audit.TimeStaticsDim'),
- name: 'timeStaticsDim',
- initialValue: initialValues.timeStaticsDim,
- props: {
- dropdownMatchSelectWidth: false,
- options: timeStaticsDimList,
- },
- },
- {
- type: 'select',
- label: i18n.t('pages.GroupDetail.Audit.Item'),
- name: 'auditIds',
- props: {
- style: {
- width: 200,
- },
- mode: 'multiple',
- allowClear: true,
- showSearch: true,
- dropdownMatchSelectWidth: false,
- options: {
- requestAuto: true,
- requestTrigger: ['onOpen'],
- requestService: () => {
- return request('/audit/getAuditBases');
- },
- requestParams: {
- formatResult: result => {
- return result?.reduce((accumulator, item) => {
- const existingItem = accumulator.find(
- (i: { value: any }) => i.value === item.auditId,
- );
- if (!existingItem) {
- accumulator.push({
- label: i18n?.language === 'cn' ? item.nameInChinese :
item.nameInEnglish,
- value: item.auditId,
- });
- }
- return accumulator;
- }, []);
+ ].concat(commonFormContent);
+ } else {
+ const sinkTypeList = sinks
+ .filter(item => item.value !== '')
+ .map(item => {
+ return {
+ label: item.label,
+ value: item.value,
+ };
+ });
+ return [
+ {
+ type: 'input',
+ label: i18n.t('meta.Group.InlongGroupId'),
+ name: 'inlongGroupId',
+ initialValue: inlongGroupId,
+ props: {
+ disabled: true,
+ style: {
+ width: 200,
},
},
+ rules: [{ required: true }],
},
- filterOption: (keyword: string, option: { label: any }) => {
- return (option?.label ??
'').toLowerCase().includes(keyword.toLowerCase());
+ {
+ type: 'select',
+ label: i18n.t('pages.GroupDetail.SinkType'),
+ name: 'sinkType',
+ initialValue: initialValues.sinkType,
+ props: {
+ allowClear: true,
+ dropdownMatchSelectWidth: false,
+ showSearch: true,
+ options: sinkTypeList,
+ },
},
- },
- },
- {
- type: (
- <Button type="primary" onClick={onSearch}>
- {i18n.t('pages.GroupDetail.Audit.Search')}
- </Button>
- ),
- },
- {
- type: (
- <Button type="primary" disabled={!(sourceData.length > 0)}>
- <CSVLink data={csvData} filename={fileName}>
- {i18n.t('pages.GroupDetail.Audit.ExportCSV')}
- </CSVLink>
- </Button>
- ),
- },
-];
+ ].concat(commonFormContent);
+ }
+};
export const getTableColumns = (source, dim) => {
const data = source.map(item => ({
diff --git a/inlong-dashboard/src/ui/pages/GroupDetail/Audit/index.less
b/inlong-dashboard/src/ui/pages/GroupDetail/Audit/index.less
new file mode 100644
index 0000000000..dd7b2ff716
--- /dev/null
+++ b/inlong-dashboard/src/ui/pages/GroupDetail/Audit/index.less
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+.audit-container{
+ position: relative;
+
+ .chart-type{
+ position: absolute;
+ top: 10px;
+ right: 0px;
+ height: 30px;
+ }
+
+ .chart-container{
+ padding-top: 50px;
+ }
+}
diff --git a/inlong-dashboard/src/ui/pages/GroupDetail/Audit/index.tsx
b/inlong-dashboard/src/ui/pages/GroupDetail/Audit/index.tsx
index 913d583eb4..9b94eb2ff6 100644
--- a/inlong-dashboard/src/ui/pages/GroupDetail/Audit/index.tsx
+++ b/inlong-dashboard/src/ui/pages/GroupDetail/Audit/index.tsx
@@ -31,20 +31,24 @@ import {
getTableColumns,
timeStaticsDimList,
} from './config';
-import { Table } from 'antd';
+import { Table, Radio, Tabs, TabsProps } from 'antd';
import i18n from '@/i18n';
-
+import './index.less';
type Props = CommonInterface;
-
+const initialQuery = {
+ inlongStreamId: null,
+ startDate: +new Date(),
+ endDate: +new Date(),
+ timeStaticsDim: timeStaticsDimList[0].value,
+ sinkId: null,
+ sinkType: null,
+};
const Comp: React.FC<Props> = ({ inlongGroupId }) => {
const [form] = useForm();
- const [query, setQuery] = useState({
- inlongStreamId: '',
- startDate: +new Date(),
- endDate: +new Date(),
- timeStaticsDim: timeStaticsDimList[0].value,
- });
+ const [query, setQuery] = useState(initialQuery);
const [inlongStreamID, setInlongStreamID] = useState('');
+ const [type, setType] = useState('count');
+ const [subTab, setSubTab] = useState('stream');
const { data: sourceData = [], run } = useRequest(
{
url: '/audit/list',
@@ -57,7 +61,7 @@ const Comp: React.FC<Props> = ({ inlongGroupId }) => {
},
},
{
- ready: Boolean(query.inlongStreamId),
+ refreshDeps: [query],
formatResult: result => result.sort((a, b) => (a.auditId - b.auditId > 0
? 1 : -1)),
},
);
@@ -79,23 +83,39 @@ const Comp: React.FC<Props> = ({ inlongGroupId }) => {
const bT = +new Date(query.timeStaticsDim === 'HOUR' ? `${b.logTs}:00`
: b.logTs);
return aT - bT;
});
- const output = flatArr.reduce((acc, cur) => {
- if (!acc[cur.logTs]) {
- acc[cur.logTs] = {};
- }
- acc[cur.logTs] = {
- ...acc[cur.logTs],
- [cur.auditId]: cur.count,
- };
- return acc;
- }, {});
+ let output: any;
+ if (type === 'count') {
+ output = flatArr.reduce((acc, cur) => {
+ if (!acc[cur.logTs]) {
+ acc[cur.logTs] = {};
+ }
+ acc[cur.logTs] = {
+ ...acc[cur.logTs],
+ [cur.auditId]: cur.count,
+ };
+ return acc;
+ }, {});
+ } else {
+ output = flatArr.reduce((acc, cur) => {
+ if (!acc[cur.logTs]) {
+ acc[cur.logTs] = {};
+ }
+ acc[cur.logTs] = {
+ ...acc[cur.logTs],
+ [cur.auditId]: cur.size,
+ };
+ return acc;
+ }, {});
+ }
return output;
- }, [sourceData, query.timeStaticsDim]);
+ }, [sourceData, query.timeStaticsDim, type]);
const onSearch = async () => {
let values = await form.validateFields();
if (values.timeStaticsDim == 'MINUTE') {
setQuery(prev => ({ ...prev, endDate: prev.startDate }));
+ } else {
+ setQuery(values);
}
run();
};
@@ -109,6 +129,7 @@ const Comp: React.FC<Props> = ({ inlongGroupId }) => {
run();
}
};
+
const numToName = useCallback(
num => {
let obj = {};
@@ -146,9 +167,32 @@ const Comp: React.FC<Props> = ({ inlongGroupId }) => {
const [fileName, setFileName] = useState('audit.csv');
useEffect(() => {
setFileName(`audit_${inlongGroupId}_${inlongStreamID}.csv`);
+ form.setFieldsValue({ sinkId: '' });
}, [inlongGroupId, inlongStreamID]);
+
+ const onChange = e => {
+ setSubTab(e.target.value);
+ setInlongStreamID(undefined);
+ const value = form.getFieldsValue();
+ console.log('form value', value);
+ const tmp = { ...query };
+ if (e.target.value === 'group') {
+ delete tmp.inlongStreamId;
+ delete tmp.sinkId;
+ } else {
+ delete tmp.sinkType;
+ }
+ setQuery(tmp);
+ };
+
return (
<>
+ <div style={{ marginBottom: 20 }}>
+ <Radio.Group defaultValue={subTab} buttonStyle="solid" onChange={e =>
onChange(e)}>
+ <Radio.Button
value="group">{i18n.t('pages.GroupDetail.Audit.Group')}</Radio.Button>
+ <Radio.Button
value="stream">{i18n.t('pages.GroupDetail.Audit.Stream')}</Radio.Button>
+ </Radio.Group>
+ </div>
<div style={{ marginBottom: 40 }}>
<FormGenerator
form={form}
@@ -163,6 +207,7 @@ const Comp: React.FC<Props> = ({ inlongGroupId }) => {
fileName,
setInlongStreamID,
inlongStreamID,
+ subTab,
)}
style={{ marginBottom: 30, gap: 10 }}
onFilter={allValues =>
@@ -173,30 +218,50 @@ const Comp: React.FC<Props> = ({ inlongGroupId }) => {
})
}
/>
- <Charts height={400} option={toChartData(sourceData, sourceDataMap)}
forceUpdate={true} />
</div>
-
- <HighTable
- table={{
- columns: getTableColumns(sourceData, query.timeStaticsDim),
- dataSource: toTableData(sourceData, sourceDataMap),
- rowKey: 'logTs',
- summary: () => (
- <Table.Summary fixed>
- <Table.Summary.Row>
- <Table.Summary.Cell index={0}>
- {i18n.t('pages.GroupDetail.Audit.Total')}
- </Table.Summary.Cell>
- {sourceData.map((row, index) => (
- <Table.Summary.Cell index={index + 1}>
- {row.auditSet.reduce((total, item) => total + item.count,
0).toLocaleString()}
- </Table.Summary.Cell>
- ))}
- </Table.Summary.Row>
- </Table.Summary>
- ),
- }}
- />
+ <div className="audit-container">
+ <div className="chart-type">
+ <Radio.Group
+ defaultValue="count"
+ buttonStyle="solid"
+ onChange={e => setType(e.target.value)}
+ >
+ <Radio.Button
value="size">{i18n.t('pages.GroupDetail.Audit.Size')}</Radio.Button>
+ <Radio.Button
value="count">{i18n.t('pages.GroupDetail.Audit.Count')}</Radio.Button>
+ </Radio.Group>
+ </div>
+ <div className="chart-container">
+ <Charts height={400} option={toChartData(sourceData, sourceDataMap)}
forceUpdate={true} />
+ </div>
+ <div className="table-container">
+ <HighTable
+ table={{
+ columns: getTableColumns(sourceData, query.timeStaticsDim),
+ dataSource: toTableData(sourceData, sourceDataMap),
+ rowKey: 'logTs',
+ pagination: {
+ pageSizeOptions: ['10', '20', '50', '60', '100', '120'],
+ },
+ summary: () => (
+ <Table.Summary fixed>
+ <Table.Summary.Row>
+ <Table.Summary.Cell index={0}>
+ {i18n.t('pages.GroupDetail.Audit.Total')}
+ </Table.Summary.Cell>
+ {sourceData.map((row, index) => (
+ <Table.Summary.Cell index={index + 1}>
+ {row.auditSet
+ .reduce((total, item) => total + item.count, 0)
+ .toLocaleString()}
+ </Table.Summary.Cell>
+ ))}
+ </Table.Summary.Row>
+ </Table.Summary>
+ ),
+ }}
+ />
+ </div>
+ </div>
</>
);
};