blob: 4d10eea7b5ad054cc2eda16b7811a7bf2d1052b0 [file] [log] [blame]
/*
* 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.
*/
import React, { useState, useEffect } from "react";
import { Card, Layout, Button, Drawer, Tree, Input, Tooltip, DatePicker, PageHeader, notification, Table } from 'antd';
import { Tree as TreeArborist } from "react-arborist";
import styles from '../style.less'
import { RightOutlined, GroupOutlined, MinusSquareOutlined, PlusSquareOutlined, CopyOutlined, RetweetOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import {
getChunkListUsingPOST, getPageListUsingPOST, getIndexOfTimeseriesIndexTreeUsingPOST
, getPageInfoThroughTimeseriesIndexOffsetUsingPOST, getTimeseriesIndexListNoPagingUsingPOST
} from '@/services/swagger1/tsfileViewerController'
import moment from 'moment';
import { useIntl } from 'umi';
const { Content } = Layout;
const { Search } = Input;
const MoreIndexOfTimeseriesIndex = (props) => {
const [openChunk, setopenChunk] = useState(false)
const [openPage, setopenPage] = useState(false)
const [chunkTreeData, setChunkTreeData] = useState([])
const [indexTreeData, setIndexTreeData] = useState([])
const [columns, setColumns] = useState();
const [columnsLength, setColumnsLength] = useState();
const [pageData, setPageData] = useState()
const [beginDateCache, setBeginDateCache] = useState()
const [endDateCache, setEndDateCache] = useState();
const [beginDate, setBeginDate] = useState()
const [endDate, setEndDate] = useState();
const [deviceNameLike, setDeviceNameLike] = useState()
const [randomFlag, setRandomFlag] = useState()
const [indexTreeHeight, setIndexTreeHeight] = useState()
const { fileName, filePath, cardList, setCardList } = props;
const [treeHeight, setTreeHeight] = useState()
const intl = useIntl();
var pageDataCache;
const gridStyle = {
width: '20%',
height: '100px',
textAlign: 'center',
background: "#f2f2f2",
border: '1px solid grey'
};
const showChunk = async (node) => {
if (!node.isLeaf) {
return
}
let res = await getChunkListUsingPOST({ offset: node.position, filePath: filePath, offsetType: 'TS_INDEX', beginDate: beginDate, endDate: endDate })
if (res.code == 0) {
setRandomFlag(moment(new Date()).valueOf())
let tree = Object.values(res.data).map((node) => {
let tree = {};
tree['name'] = node.measurementId;
tree['id'] = node.measurementId + '-' + node.offset + randomFlag;
// tree['icon'] = <RightOutlined />
tree['isLeaf'] = false;
tree['position'] = node.offset;
tree['timeseriesIndexOffset'] = node.position;
return tree;
})
setChunkTreeData(tree)
setopenChunk(true);
var div = document.getElementById('tree-div');
setTreeHeight(div.offsetHeight)
} else {
notification.error({
message: res.message,
});
}
};
const onChunkSelect = async (info) => {
if (!info.isLeaf) {
return
}
let param = info.pageInfo;
param['timeseriesIndexOffset'] = info.timeseriesIndexOffset;
param['chunkOffset'] = info.chunkOffset;
param['filePath'] = filePath;
param['beginDate'] = beginDate;
param['endDate'] = endDate;
let res = await getPageInfoThroughTimeseriesIndexOffsetUsingPOST(param)
if (res.code == 0) {
//pagedata信息
let cols = [{
title: 'No',
fixed: 'left',
width: '100px',
// render: (text, record, index) => `${index + 1}`, //每一页都从1开始
render: (text, record, index) => {
return index + 1
}
}]
cols.push(...Object.values(res.data.title).map((titleName, key) => {
if (titleName == 'timestamp') {
return {
title: (
<>
{titleName}<span>{'\u00A0\u00A0\u00A0\u00A0'}</span>
<RetweetOutlined
onClick={() => {
pageDataCache = Object.values(pageDataCache).map((item) => {
if ((item[0] + "").indexOf("-") > -1) {
item[0] = moment(item[0], 'YYYY-MM-DD HH:mm:ss.SSS').valueOf()
} else {
item[0] = moment(Number(item[0])).format('YYYY-MM-DD HH:mm:ss.SSS')
}
return item
})
setPageData(pageDataCache)
}}
/>
</>),
dataIndex: titleName,
key: titleName,
fixed: 'left',
width: '250px',
render: (text, record, index) => {
return (
<>
<span id={index}>
{record[key]}
</span>
</>
)
}
}
} else {
return {
title: titleName,
dataIndex: titleName,
key: titleName,
render: (text, record, index) => {
return record[key]
}
}
}
}))
setColumnsLength(cols.length)
setColumns(cols)
setPageData(res.data.values);
pageDataCache = res.data.values;
showPage()
} else {
notification.error({
message: res.message,
});
}
};
const onCloseChunk = () => {
setopenChunk(false);
};
const showPage = () => {
setopenPage(true);
};
const onClosePage = () => {
setopenPage(false);
};
const updateTreeData = (list, id, children) => {
return list.map((node) => {
if (node.id === id) {
return {
...node,
children,
};
}
//这个应该是用来加载子节点的子节点的,应该需要修改children对象
if (node.children) {
return {
...node,
children: updateTreeData(node.children, id, children),
};
}
return node;
});
}
const onLoadTreeData = async (expanded, node) => {
if (expanded && node.children == undefined) {
let res = await getPageListUsingPOST({ offset: node.position, filePath: filePath, beginDate: beginDateCache, endDate: endDateCache })
if (res.code == 0) {
let newTree = Object.values(res.data).map((child) => {
let tree = {};
tree['name'] = child.pageNo;
tree['id'] = child.pageNo + '-' + child.offset + randomFlag;
tree['isLeaf'] = true;
tree['position'] = child.offset;
tree['chunkOffset'] = node.position;
tree['timeseriesIndexOffset'] = node.timeseriesIndexOffset;
tree['pageInfo'] = child;
return tree;
})
let data = chunkTreeData;
let pa = updateTreeData(data, node.id, newTree);
setChunkTreeData(pa)
} else {
notification.error({
message: res.message,
});
}
}
}
const onLoadIndexTreeData = async (expanded, node) => {
if (expanded && node.children == undefined) {
let res = await getIndexOfTimeseriesIndexTreeUsingPOST({ parentOffset: node.position, filePath: filePath })
if (res.code == 0) {
let newTree = Object.values(res.data).map((child) => {
let tree = {};
tree['name'] = child.title;
tree['id'] = child.measurementId + '-' + child.position + randomFlag;
// tree['icon'] = <RightOutlined />
tree['isLeaf'] = child.leaf;
tree['position'] = child.position;
return tree;
})
let data = indexTreeData;
let pa = updateTreeData(data, node.id, newTree);
setIndexTreeData(pa)
} else {
notification.error({
message: res.message,
});
}
}
}
const generateITITrees = async () => {
let res = await getIndexOfTimeseriesIndexTreeUsingPOST({ parentOffset: 0, filePath: filePath })
if (res.code == 0) {
setRandomFlag(moment(new Date()).valueOf())
let tree = Object.values(res.data).map((node) => {
let tree = {};
tree['name'] = node.title;
tree['id'] = node.title + '-' + node.position + randomFlag;
// tree['icon'] = <RightOutlined />
tree['isLeaf'] = node.leaf;
tree['position'] = node.position;
return tree;
})
setIndexTreeData(tree)
} else {
notification.error({
message: res.message,
});
}
}
function Node({ node, style, dragHandle, tree }) {
if (!node.isOpen && !node.data.isLeaf && node.data.children == undefined && node.isSelected) {
onLoadIndexTreeData(!node.isOpen, node.data)
}
/* This node instance can do many things. See the API reference. */
return (
<div style={{ ...style, overflow: "hidden", width: "155vh", textOverflow: "ellipsis", whiteSpace: "nowrap" }} ref={dragHandle} onClick={() => (showChunk(node.data))}>
{node.data.isLeaf ? "" : node.isOpen ? <MinusSquareOutlined onClick={() => (node.toggle())} /> : <PlusSquareOutlined onClick={() => (node.toggle())} />} <span style={{ background: node.isSelected && node.data.isLeaf ? "#FFDFD4" : "white" }}>{node.data.isLeaf ? <RightOutlined /> : ""}{node.data.name}</span>
</div>
);
}
function Node1({ node, style, dragHandle, tree }) {
if (!node.isOpen && !node.data.isLeaf && node.data.children == undefined && node.isSelected) {
onLoadTreeData(!node.isOpen, node.data)
}
/* This node instance can do many things. See the API reference. */
return (
<div style={{ ...style, overflow: "hidden", width: "155vh", textOverflow: "ellipsis", whiteSpace: "nowrap" }} ref={dragHandle} onClick={() => (onChunkSelect(node.data))}>
{node.data.isLeaf ? "" : node.isOpen ? <MinusSquareOutlined onClick={() => (node.toggle())} /> : <PlusSquareOutlined onClick={() => (node.toggle())} />} <span style={{ background: node.isSelected && node.data.isLeaf ? "#FFDFD4" : "white" }}>{node.data.isLeaf ? <CopyOutlined /> : <GroupOutlined />}{node.data.name}</span>
</div>
);
}
const searchIndexTree = async (value) => {
let res = await getTimeseriesIndexListNoPagingUsingPOST({
filePath: filePath, deviceNameLike: value,
beginDate: beginDate, endDate: endDate
});
let treeList = []
if (res.code == 0) {
for (let item in res.data) {
let tree = {};
tree['name'] = item;
tree['id'] = item + randomFlag;
// tree['icon'] = <RightOutlined />
tree['isLeaf'] = false;
tree['children'] = Object.values(res.data[item]).map((arr, key) => {
let node = {};
node['name'] = arr.measurementId;
node['id'] = arr.measurementId + arr.offset + randomFlag;
// node['icon'] = <RightOutlined />
node['isLeaf'] = true;
node['position'] = arr.offset;
return node;
})
treeList.push(tree);
}
setIndexTreeData(treeList)
} else {
notification.error({
message: res.message,
});
}
}
const onSearchIndexTree = async (value) => {
//暂存 开始和结束时间
setBeginDateCache(beginDate)
setEndDateCache(endDate)
if ((beginDate == null || beginDate == undefined || beginDate == '') && (endDate == null || endDate == undefined || endDate == '') && (value == null || value == undefined || value == '')) {
generateITITrees();
} else {
searchIndexTree(value);
}
}
useEffect(() => {
var div = document.getElementById('modal-div');
setIndexTreeHeight(div.offsetHeight)
generateITITrees();
}, [])
return (
<div className={styles.sitedrawerrenderincurrentwrapper}>
<Layout>
<Layout>
<Content width="40%" style={{ height: "60vh" }}>
<PageHeader style={{ background: "white" }}
extra={(
<Button.Group>
<DatePicker
format='YYYY-MM-DD HH:mm:ss'
placeholder={intl.formatMessage({ id: 'tsviewer.more.beginDate', })}
showTime={{ format: 'HH:mm:ss' }}
onChange={(date) => {
if (date != null) {
date = date.set({ millisecond: 0 })
}
setBeginDate(isNaN(moment(date).valueOf()) ? '' : moment(date).valueOf())
}}
/>
<DatePicker
format='YYYY-MM-DD HH:mm:ss'
placeholder={intl.formatMessage({ id: 'tsviewer.more.endDate', })}
showTime={{ format: 'HH:mm:ss' }}
onChange={(date) => {
if (date != null) {
date = date.set({ millisecond: 0 })
}
setEndDate(isNaN(moment(date).valueOf()) ? '' : moment(date).valueOf())
}}
/>
<Search
placeholder="device"
allowClear
onChange={(e) => {
setDeviceNameLike(e.target.value)
}}
onSearch={(value) => onSearchIndexTree(value)}
style={{
width: 400,
}}
/>
{/* <Button type="primary" onClick={() => showChunk(details)}>结构图谱</Button> */}
</Button.Group>
)}
>
</PageHeader>
<div id="modal-div" style={{ height: "60vh", background: "white", margin: '4px 0px 0px 0px' }}>
<TreeArborist
openByDefault={false}
disableDrag={false}
width={"100%"}
height={indexTreeHeight}
// paddingBottom={200}
//height={400}
data={indexTreeData}
>
{Node}
</TreeArborist>
</div>
</Content>
</Layout>
</Layout>
<Drawer
title={<>
<Tooltip placement="bottom" title={<span>
{intl.formatMessage({ id: 'tsviewer.moreChunkGroup.chunk.explanation', })}<br />
{intl.formatMessage({ id: 'tsviewer.moreChunkGroup.chunk.explanation1', })}<br />
{intl.formatMessage({ id: 'tsviewer.moreChunkGroup.chunk.explanation2', })}<br />
</span>}>
<QuestionCircleOutlined />
</Tooltip>
<span>
{"\u00A0\u00A0 ChunkInfo"}
</span>
</>}
width={"80%"}
closable={false}
destroyOnClose={true}
onClose={onCloseChunk}
open={openChunk}
>
<div id="tree-div" style={{ height: "80vh", background: "white", margin: '4px 0px 0px 0px' }}>
<TreeArborist
openByDefault={false}
disableDrag={false}
width={"100%"}
height={treeHeight}
// paddingBottom={200}
//height={400}
data={chunkTreeData}
>
{Node1}
</TreeArborist>
</div>
<Drawer
title={<>
<Tooltip placement="bottom" title={<span>
{intl.formatMessage({ id: 'tsviewer.moreChunkGroup.pageData.explanation', })}<br />
</span>}>
<QuestionCircleOutlined />
</Tooltip>
<span>
{"\u00A0\u00A0 PageData"}
</span>
</>}
width={"75%"}
closable={false}
destroyOnClose={true}
onClose={onClosePage}
open={openPage}
>
<Table columns={columns} dataSource={pageData} scroll={{ x: 150 * columnsLength, y: "80vh" }}
rowKey={(record) => {
return record[0];
}}
pagination={{ defaultPageSize: 100, showQuickJumper: true, position: ["bottomCenter"] }}
bordered />
</Drawer>
</Drawer>
</div>
)
}
export default MoreIndexOfTimeseriesIndex