Commit e1ac798f by zhaochengxiang

数据地图

parent 3287dfa9
......@@ -16,6 +16,7 @@
"crypto-js": "^4.0.0",
"less": "^4.1.1",
"less-loader": "^8.0.0",
"lodash": "^4.17.21",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-redux": "^7.1.0",
......
......@@ -5,9 +5,6 @@ export function* getAllTopics() {
return yield call(service.getAllTopics);
}
export function* getTableAndTreeModelByTid(payload) {
const tables = yield call(service.getTableModelByTid, payload);
const trees = yield call(service.getTreeModel);
return {tables: tables||[], trees: ((trees||[]).length>0)?trees[0]:{}};
export function* getTableModelByDirIid(payload) {
return yield call(service.getTableModelByDirId, payload);
}
......@@ -4,10 +4,6 @@ export function getAllTopics() {
return GetJSON("/datacatalog/countCtrl/queryAllTopics");
}
export function getTableModelByTid(payload) {
export function getTableModelByDirId(payload) {
return GetJSON("/datacatalog/countCtrl/getTableModelInfoByDirId", payload);
}
export function getTreeModel() {
return GetJSON("/datacatalog/countCtrl/queryAllDirAsTree");
}
\ No newline at end of file
......@@ -18,38 +18,18 @@ const colors = [
const globalFontSize = 12;
let graph = null;
class Relation extends React.Component {
componentDidMount() {
const { data, type, history } = this.props;
const { type, loadMoreData , history } = this.props;
setTimeout(() => {
const container = document.getElementById(`container${type||''}`);
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const fittingString = (str, maxWidth, fontSize) => {
const ellipsis = '...';
const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
let currentWidth = 0;
let res = str;
const pattern = new RegExp('[\u4E00-\u9FA5]+'); // distinguish the Chinese charactors and letters
str.split('').forEach((letter, i) => {
if (currentWidth > maxWidth - ellipsisLength) return;
if (pattern.test(letter)) {
// Chinese charactors
currentWidth += fontSize;
} else {
// get the width of single letter according to the fontSize
currentWidth += G6.Util.getLetterWidth(letter, fontSize);
}
if (currentWidth > maxWidth - ellipsisLength) {
res = `${str.substr(0, i)}${ellipsis}`;
}
});
return res;
};
function refreshDragedNodePosition(e) {
const model = e.item.get('model');
model.fx = e.x;
......@@ -75,7 +55,7 @@ class Relation extends React.Component {
},
});
const graph = new G6.Graph({
graph = new G6.Graph({
container: `container${type||''}`,
width,
height,
......@@ -104,6 +84,73 @@ class Relation extends React.Component {
},
});
this.layoutGraph();
graph.on('node:dragstart', function (e) {
graph.layout();
refreshDragedNodePosition(e);
});
graph.on('node:drag', function (e) {
refreshDragedNodePosition(e);
});
graph.on('node:dragend', function (e) {
e.item.get('model').fx = null;
e.item.get('model').fy = null;
});
graph.on('node:click', function (e) {
const node = e.item;
const model = node.getModel();
if (model.dbType==='Dir') {
const children = model.children;
if (!children && loadMoreData) {
loadMoreData(model.dirId||'');
}
} else {
//通过资产id跳转到资产详情页
// model.tableModelId
// history && history.push(`${ContextPath}/home`);
}
});
if (typeof window !== 'undefined') {
window.onresize = () => {
if (!graph || graph.get('destroyed')) return;
if (!container || !container.scrollWidth || !container.scrollHeight) return;
graph.changeSize(container.scrollWidth, container.scrollHeight);
};
}
}, 100);
}
layoutGraph = () => {
const { data } = this.props;
if(graph){
const fittingString = (str, maxWidth, fontSize) => {
const ellipsis = '...';
const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
let currentWidth = 0;
let res = str;
const pattern = new RegExp('[\u4E00-\u9FA5]+'); // distinguish the Chinese charactors and letters
str.split('').forEach((letter, i) => {
if (currentWidth > maxWidth - ellipsisLength) return;
if (pattern.test(letter)) {
// Chinese charactors
currentWidth += fontSize;
} else {
// get the width of single letter according to the fontSize
currentWidth += G6.Util.getLetterWidth(letter, fontSize);
}
if (currentWidth > maxWidth - ellipsisLength) {
res = `${str.substr(0, i)}${ellipsis}`;
}
});
return res;
};
const nodes = data.nodes;
const clusterMap = new Map();
let clusterId = 0;
......@@ -121,7 +168,7 @@ class Relation extends React.Component {
});
data.nodes.forEach(function (node) {
node.label = fittingString(node.label, node.size, globalFontSize);
node.label = fittingString(node.label||'', node.size, globalFontSize);
});
graph.data({
......@@ -132,34 +179,11 @@ class Relation extends React.Component {
}),
});
graph.render();
}
}
graph.on('node:dragstart', function (e) {
graph.layout();
refreshDragedNodePosition(e);
});
graph.on('node:drag', function (e) {
refreshDragedNodePosition(e);
});
graph.on('node:dragend', function (e) {
e.item.get('model').fx = null;
e.item.get('model').fy = null;
});
graph.on('node:click', function (e) {
// const node = e.item;
// const model = node.getModel();
history && history.push(`${ContextPath}/home`);
});
if (typeof window !== 'undefined') {
window.onresize = () => {
if (!graph || graph.get('destroyed')) return;
if (!container || !container.scrollWidth || !container.scrollHeight) return;
graph.changeSize(container.scrollWidth, container.scrollHeight);
};
}
}, 100);
componentDidUpdate(prevProps, prevState){
this.layoutGraph();
}
render() {
......
......@@ -5,22 +5,40 @@ class SquareItem extends React.Component {
onItemClick = () => {
const { item, onClick } = this.props;
if (onClick) {
onClick(item);
if (onClick && item) {
if (item.dbType==='Dir') {
onClick(item);
} else {
//通过资产id跳转到资产详情页
// item.tableModelId
}
}
}
render() {
const { item } = this.props;
return (
<Card title={
<div className='pointer' onClick={this.onItemClick}>
{item.dirName||''}
</div>
}>
<p>{`数据资产: ${item.tableModelCount}`}</p>
<p>{`资产编目: ${item.subDirCount}`}</p>
</Card>
<>
{
item && (
item.dbType==='Dir' ? <Card title={
<div className='pointer' onClick={this.onItemClick}>
{item.dirName||''}
</div>
}>
<p>{`数据资产: ${item.tableModelCount}`}</p>
<p>{`资产编目: ${item.subDirCount}`}</p>
</Card> : <Card title={
<div className='pointer' onClick={this.onItemClick}>
{item.name||''}
</div>
}>
<p>{`所属系统: ${item.system||''}`}</p>
<p>{`描述: ${item.remarks||''}`}</p>
</Card>
)
}
</>
);
}
}
......
......@@ -3,15 +3,17 @@ import G6 from '@antv/g6';
import { ContextPath } from '../../../../util';
let graph = null;
class Tree extends React.Component {
componentDidMount() {
const { data, type, history } = this.props;
const { type, loadMoreData, history } = this.props;
const container = document.getElementById(`container${type||''}`);
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const graph = new G6.TreeGraph({
graph = new G6.TreeGraph({
container: `container${type||''}`,
width,
height,
......@@ -57,15 +59,23 @@ class Tree extends React.Component {
};
});
graph.data(data);
graph.render();
graph.fitView();
this.layoutGraph();
graph.on('node:click', function (e) {
// const node = e.item;
// const model = node.getModel();
// history && history.push(`${ContextPath}/home`);
const node = e.item;
const model = node.getModel();
if (model.dbType==='Dir') {
const children = model.children;
if (!children && loadMoreData) {
loadMoreData(model.dirId||'');
}
} else {
//通过资产id跳转到资产详情页
// model.tableModelId
// history && history.push(`${ContextPath}/home`);
}
});
if (typeof window !== 'undefined') {
......@@ -78,6 +88,20 @@ class Tree extends React.Component {
}
}
layoutGraph = () => {
const { data } = this.props;
if(graph){
graph.data(data);
graph.render();
graph.fitView();
}
}
componentDidUpdate(prevProps, prevState){
this.layoutGraph();
}
render() {
const { type } = this.props;
return (
......
......@@ -6,6 +6,7 @@ import SquareItem from './Component/SquareItem';
import Tree from './Component/Tree';
import Relation from './Component/Relation';
import { dispatchLatest } from '../../../model';
import lodash from 'lodash';
const column = 3;
......@@ -24,27 +25,52 @@ class MapContent extends React.Component {
}
componentDidMount() {
const { tid } = this.props;
const { topic } = this.props;
this.setState({ loading: true }, () => {
dispatchLatest({
type: 'map.getTableAndTreeModelByTid',
payload: { dirId: tid },
type: 'map.getTableModelByDirIid',
payload: { dirId: topic.id },
callback: data => {
this.convertRemoteData(data);
this.setState({
loading: false,
tableModelData: data.tables||[],
curTableModelData: data.tables||[],
treeModelData: data.trees||{},
relationModelData: this.convertRelationModelData(data.trees||{}),
breadcrumbContents: [{ data: data.tables||[] }]
tableModelData: data||[],
curTableModelData: data||[],
breadcrumbContents: [{ data: data||[] }]
}, () => {
this.setTreeAndRelationState(data||[]);
});
}
})
})
}
convertRemoteData = (data) => {
data.forEach((item, index) => {
if (item.dbType==='Dir') {
item.text = item.dirName||'';
item.id = `d${item.dirId||''}`
} else {
item.text = item.name||'';
item.id = `t${item.tableModelId||''}`;
}
})
}
convertTreeModelData = (data) => {
const { topic } = this.props;
return {
text: topic.name||'',
id: `t${topic.id}`,
children: data
};
}
convertRelationModelData = (data) => {
const _relationData = {
nodes: [],
edges: []
......@@ -62,34 +88,71 @@ class MapContent extends React.Component {
_cluster = cluster;
}
_relationData.nodes.push({ id: item.nodeId, text: item.text||'', label: item.text||'', size: (80-depth*20)>20?(80-depth*20):20, cluster: _cluster, isLeaf: (item.childSize===null || item.childSize===0) });
_relationData.edges.push({ source: sid, target: item.nodeId });
recursionTreeData(item.children||[], item.nodeId, depth+1, _cluster);
_relationData.nodes.push({...item, ...{ label: item.text||'', size: (80-depth*20)>20?(80-depth*20):20, cluster: _cluster, isLeaf: (item.childSize===null || item.childSize===0)}});
_relationData.edges.push({ source: sid, target: item.id });
recursionTreeData(item.children||[], item.id, depth+1, _cluster);
})
}
if (data && data.nodeId) {
_relationData.nodes.push({ id: data.nodeId, text: data.text||'', label: data.text||'', size: 80, cluster: '0', isLeaf: (data.childSize===null || data.childSize===0) });
recursionTreeData(data.children||[], data.nodeId, 1);
if (data && data.id) {
_relationData.nodes.push({...data, ...{ label: data.text||'', size: 80, cluster: '0', isLeaf: (data.childSize===null || data.childSize===0)}});
recursionTreeData(data.children||[], data.id, 1);
}
return _relationData;
}
onSquareItemClick = (item) => {
setSquareGraphState = (item) => {
const { breadcrumbContents } = this.state;
if ((item.children||[]).length===0) return;
this.setState({
breadcrumbContents: [...breadcrumbContents, { name: item.dirName||'', data: item.children||[] }],
curTableModelData: item.children||[],
});
}
onSquareItemClick = (item) => {
const { tableModelData } = this.state;
if (!item.children) {
// dispatchLatest({
// type: 'map.getTableModelByDirIid',
// payload: { dirId: item.dirId },
// callback: data => {
// this.convertRemoteData(data||[]);
// item.children = (data||[]);
// this.setSquareGraphState(item);
// this.setTreeAndRelationState(tableModelData);
// }
// })
// return;
item.children = [
{
"subDirCount": 0,
"dbType": "Dir",
"dirId": "5f2a63e89cfac536601fb2a6",
"tableModelCount": 0,
"dirName": "公司"
},
{
"tableModelId": "1",
"name": "table",
"system": "8月5",
"remarks": "对外"
}
]
this.convertRemoteData(item.children);
this.setSquareGraphState(item);
this.setTreeAndRelationState(tableModelData);
return;
}
this.setSquareGraphState(item);
this.setTreeAndRelationState(tableModelData);
}
onBreadcrumbItemClick = (content, index) => {
const { breadcrumbContents } = this.state;
const { breadcrumbContents } = this.state;
this.setState({
breadcrumbContents: breadcrumbContents.splice(0, index===0?1:(index+1)),
......@@ -97,6 +160,76 @@ class MapContent extends React.Component {
})
}
loadMoreData = (id) => {
const { tableModelData } = this.state;
// dispatchLatest({
// type: 'map.getTableModelByDirIid',
// payload: { dirId: id },
// callback: data => {
// this.convertRemoteData(data||[]);
// function recursionData(_data) {
// if ((_data||[]).length === 0) return;
// _data.forEach((item, index) => {
// if (item.dirId === id) {
// item.children = data;
// } else {
// recursionData(item.children||[]);
// }
// })
// }
// recursionData(tableModelData);
// this.setTreeAndRelationState(tableModelData);
// }
// })
const data = [
{
"subDirCount": 0,
"dbType": "Dir",
"dirId": "5f2a63e89cfac536601fb2a6",
"tableModelCount": 0,
"dirName": "公司"
},
{
"tableModelId": "1",
"name": "table",
"system": "8月5",
"remarks": "对外"
}
]
this.convertRemoteData(data);
function recursionData(_data) {
if ((_data||[]).length === 0) return;
_data.forEach((item, index) => {
if (item.dirId === id) {
item.children = data;
} else {
recursionData(item.children||[]);
}
})
}
recursionData(tableModelData);
this.setTreeAndRelationState(tableModelData);
}
setTreeAndRelationState = (tableModelData) => {
const _treeData = this.convertTreeModelData(tableModelData);
this.setState({
treeModelData: lodash.cloneDeep(_treeData),
relationModelData: this.convertRelationModelData(lodash.cloneDeep(_treeData))
});
}
render() {
const { diagram, type } = this.props;
const { curTableModelData, breadcrumbContents, treeModelData, relationModelData, loading } = this.state;
......@@ -151,10 +284,10 @@ class MapContent extends React.Component {
</>
}
{
diagram==='tree' && <Tree data={treeModelData} type={type} {...this.props} />
diagram==='tree' && <Tree data={treeModelData} type={type} {...this.props} loadMoreData={this.loadMoreData} />
}
{
diagram==='relation' && <Relation data={relationModelData} type={type} {...this.props} />
diagram==='relation' && <Relation data={relationModelData} type={type} {...this.props} loadMoreData={this.loadMoreData} />
}
</>
}
......
......@@ -66,8 +66,8 @@ class Map extends React.Component {
{
topics && topics.map((topic, index) => {
return (
<TabPane tab='业务' key={index.toString()} className='p-3' style={{ height: '100%' }}>
{ tabKey===index.toString() && <MapContent diagram={diagram} tid={topic.id||''} type='business' {...this.props} /> }
<TabPane tab={topic.name||''} key={index.toString()} className='p-3' style={{ height: '100%' }}>
{ tabKey===index.toString() && <MapContent diagram={diagram} topic={topic} type='business' {...this.props} /> }
</TabPane>
);
})
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment