Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
csbr-daop
/
fe-data-trusted-space
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
8957880b
authored
2025-06-24 14:34:39 +0800
by
lihua
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
查看关系网接口联调
1 parent
a4f209d4
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
515 additions
and
328 deletions
src/components/LineageGraph/index.vue
src/components/RelationNetwork/index.vue
src/router/modules/dataMeta.ts
src/views/data_meta/components/Sankey.vue
src/views/data_meta/standard-query-view.vue
src/views/data_meta/standard-query.vue
src/views/data_meta/standard.vue
src/components/LineageGraph/index.vue
View file @
8957880
...
...
@@ -741,6 +741,7 @@ onMounted(() => {
toolRef
.
value
.
isFull
=
true
}
},
500
)
return
;
}
const
container
:
any
=
containerRef
.
value
;
const
width
=
container
.
clientWidth
;
...
...
src/components/RelationNetwork/index.vue
View file @
8957880
<
template
>
<div
ref=
"containerRef"
className=
'canvas-wrapper'
>
<div
class=
"main"
ref=
"tooltip1Ref"
style=
"display: none;position: absolute;"
v-loading=
"detailLoading"
>
<div
class=
"title"
>
{{
detailInfo
.
name
}}
</div>
<div
class=
"title"
>
{{
detailInfo
Label
}}
</div>
<div
class=
"row"
v-for=
"item in Object.keys(detailInfo)"
>
<span>
{{
item
+
':'
}}
</span>
<span>
{{
detailInfo
[
item
]
}}
</span>
...
...
@@ -14,11 +14,19 @@
import
{
ref
,
onMounted
}
from
'vue'
import
G6
from
'@antv/g6'
;
import
insertCss
from
'insert-css'
;
import
{
getMetaStandardFieldDetail
}
from
'@/api/modules/dataMetaService'
;
import
{
ElMessage
}
from
'element-plus'
;
const
props
=
defineProps
({
treeData
:
{
type
:
Object
,
default
:
{}
},
noContextMenu
:
{
type
:
Boolean
,
default
:
false
}
})
...
...
@@ -27,15 +35,13 @@ const emits = defineEmits([
'contextMenu'
]);
const
{
proxy
}
=
getCurrentInstance
()
as
any
;
const
detailLoading
=
ref
(
false
);
const
detailInfo
:
any
=
ref
({
guid
:
'1'
,
'标识符'
:
'124'
,
name
:
'字段12345字段字段字段字段字段字段字段字段字段字段'
,
'中文名称'
:
'字段12345字段字段字段字段字段字段字段字段字段字段'
,
'英文名称'
:
'fieldName'
});
const
detailInfo
:
any
=
ref
({});
const
detailInfoLabel
=
ref
(
''
);
const
containerRef
=
ref
();
...
...
@@ -44,6 +50,13 @@ const graphRef = ref();
const
resizeObserver
=
ref
();
watch
(()
=>
props
.
treeData
,
(
val
)
=>
{
if
(
!
graphRef
.
value
&&
val
?.
guid
)
{
initGraph
();
return
;
}
if
(
!
graphRef
.
value
)
{
return
;
}
tooltip1Ref
.
value
.
style
.
display
=
'none'
;
if
(
lastSelectNode
.
value
)
{
graphRef
.
value
.
updateItem
(
lastSelectNode
.
value
,
{
...
...
@@ -130,232 +143,191 @@ insertCss(`
const
tooltip
=
ref
();
onMounted
(()
=>
{
nextTick
(()
=>
{
if
(
!
graphRef
.
value
)
{
const
container
:
any
=
containerRef
.
value
;
const
width
=
container
.
clientWidth
;
const
height
=
container
.
clientHeight
-
10
;
tooltip
.
value
=
new
G6
.
Tooltip
({
offsetX
:
10
,
offsetY
:
10
,
trigger
:
'mouseenter'
,
// 允许出现 tooltip 的 item 类型
itemTypes
:
[
'node'
],
// 自定义 tooltip 内容
shouldBegin
:
(
evt
:
any
)
=>
{
const
{
item
,
target
}
=
evt
;
const
currentAnchor
=
target
.
get
(
'name'
);
const
name
=
item
.
_cfg
.
model
?.
name
;
if
(
currentAnchor
==
'text-shape'
)
{
if
(
detectLanguage
(
name
)
==
'English'
)
{
return
name
?.
length
>
30
;
}
return
name
?.
length
>
16
;
}
return
false
;
},
getContent
:
(
e
:
any
)
=>
{
const
{
item
,
target
}
=
e
;
const
currentAnchor
=
target
.
get
(
'name'
);
const
outDiv
=
document
.
createElement
(
'div'
);
outDiv
.
className
=
'node'
;
outDiv
.
style
.
width
=
'fit-content'
;
const
name
=
item
.
_cfg
.
model
.
name
;
if
(
currentAnchor
==
'text-shape'
)
{
outDiv
.
innerHTML
=
`<h4>
${
name
}
</h4>`
}
return
outDiv
;
},
});
const
initGraph
=
()
=>
{
const
container
:
any
=
containerRef
.
value
;
const
width
=
container
.
clientWidth
;
const
height
=
container
.
clientHeight
-
10
;
tooltip
.
value
=
new
G6
.
Tooltip
({
offsetX
:
10
,
offsetY
:
10
,
trigger
:
'mouseenter'
,
// 允许出现 tooltip 的 item 类型
itemTypes
:
[
'node'
],
// 自定义 tooltip 内容
shouldBegin
:
(
evt
:
any
)
=>
{
const
{
item
,
target
}
=
evt
;
const
currentAnchor
=
target
.
get
(
'name'
);
const
name
=
item
.
_cfg
.
model
?.
label
;
if
(
currentAnchor
==
'text-shape'
)
{
if
(
detectLanguage
(
name
)
==
'English'
)
{
return
name
?.
length
>
30
;
}
return
name
?.
length
>
16
;
}
return
false
;
},
getContent
:
(
e
:
any
)
=>
{
const
{
item
,
target
}
=
e
;
const
currentAnchor
=
target
.
get
(
'name'
);
const
outDiv
=
document
.
createElement
(
'div'
);
outDiv
.
className
=
'node'
;
outDiv
.
style
.
width
=
'fit-content'
;
const
name
=
item
.
_cfg
.
model
.
label
;
if
(
currentAnchor
==
'text-shape'
)
{
outDiv
.
innerHTML
=
`<h4>
${
name
}
</h4>`
}
return
outDiv
;
},
});
// tooltip1.value = new G6.Tooltip({
// offsetX: 10,
// offsetY: 10,
// trigger: 'click',
// // 允许出现 tooltip 的 item 类型
// itemTypes: ['node'],
// // 自定义 tooltip 内容
// shouldBegin: (evt: any) => {
// const { item, target } = evt;
// let model = item._cfg.model;
// if (model.isField) {
// return true
// }
// return false;
// },
// getContent: async (e: any) => {
// const { item, target } = e;
// let model = item._cfg.model;
// if (!model.isField) {
// return '';
// }
// const template = ` <div class="main" v-loading="detailLoading">
// <div class="title">{{ titleName + ':' }}</div>
// <div class="row" v-for="item in Object.keys(detailInfo)">
// <span>{{ item }}</span>
// <span>{{ detailInfo[item] }}</span>
// </div>
// </div>`
// await setTimeout(() => {
// }, 200);
// const outDiv = document.createElement('div');
// outDiv.className = 'tooltip-main';
// outDiv.style.width = '320px';
// for (const key in detailInfo.value) {
// const domRow = document.createElement('div');
// domRow.className = 'row';
// let span1 = document.createElement('span');
// span1.innerHTML = key + ':';
// let span2 = document.createElement('span');
// span2.innerHTML = detailInfo[key];
// domRow.appendChild(span1);
// domRow.appendChild(span2);
// outDiv.appendChild(domRow);
// }
// return outDiv;
// },
// });
const
contextMenu
=
new
G6
.
Menu
({
getContent
(
evt
:
any
)
{
const
{
item
,
target
}
=
evt
;
let
model
=
item
.
_cfg
.
model
;
return
`
const
contextMenu
=
new
G6
.
Menu
({
getContent
(
evt
:
any
)
{
const
{
item
,
target
}
=
evt
;
let
model
=
item
.
_cfg
.
model
;
return
`
<div class='context-menu'>
<span class='menu-item'>引用标准新建数据集</span>
</div>`
},
shouldBegin
:
(
evt
:
any
)
=>
{
const
{
item
,
target
}
=
evt
;
let
model
=
item
.
_cfg
.
model
;
if
(
model
&&
!
model
.
isField
&&
!
model
.
children
?.
length
)
{
return
true
;
}
return
false
;
},
handleMenuClick
:
(
target
,
item
:
any
)
=>
{
let
model
=
item
.
_cfg
?.
model
;
if
(
!
model
)
{
return
;
}
emits
(
'contextMenu'
,
model
);
},
// offsetX and offsetY include the padding of the parent container
// 需要加上父级容器的 padding-left 16 与自身偏移量 10
offsetX
:
16
,
// 需要加上父级容器的 padding-top 24 、画布兄弟元素高度、与自身偏移量 10
offsetY
:
0
,
// the types of items that allow the menu show up
// 在哪些类型的元素上响应
itemTypes
:
[
'node'
],
});
},
shouldBegin
:
(
evt
:
any
)
=>
{
if
(
props
.
noContextMenu
)
{
return
false
;
}
const
{
item
,
target
}
=
evt
;
let
model
=
item
.
_cfg
.
model
;
if
(
model
&&
!
model
.
isField
&&
!
model
.
children
?.
length
)
{
return
true
;
}
if
(
model
.
children
?.
length
&&
model
.
children
[
0
].
isField
)
{
return
true
;
}
return
false
;
},
handleMenuClick
:
(
target
,
item
:
any
)
=>
{
let
model
=
item
.
_cfg
?.
model
;
if
(
!
model
)
{
return
;
}
emits
(
'contextMenu'
,
model
);
},
// offsetX and offsetY include the padding of the parent container
// 需要加上父级容器的 padding-left 16 与自身偏移量 10
offsetX
:
16
,
// 需要加上父级容器的 padding-top 24 、画布兄弟元素高度、与自身偏移量 10
offsetY
:
0
,
// the types of items that allow the menu show up
// 在哪些类型的元素上响应
itemTypes
:
[
'node'
],
});
const
graph
=
new
G6
.
TreeGraph
({
container
:
container
,
width
,
height
,
plugins
:
[
contextMenu
,
tooltip
.
value
],
fitCenter
:
true
,
fitView
:
true
,
fitViewPadding
:
40
,
minZoom
:
0.5
,
maxZoom
:
1
,
modes
:
{
default
:
[
{
type
:
'collapse-expand'
,
onChange
:
(
item
,
collapsed
)
=>
{
if
(
!
item
)
{
return
;
}
const
data
=
item
.
getModel
();
data
.
collapsed
=
collapsed
;
return
true
;
},
shouldBegin
:
(
e
)
=>
{
// 若当前操作的节点 id 为 'node1',则不发生 collapse-expand
if
(
e
.
item
&&
e
.
item
.
getModel
().
id
===
'node1'
)
return
false
;
return
true
;
},
},
'drag-canvas'
,
'zoom-canvas'
,
],
},
defaultNode
:
{
size
:
24
,
anchorPoints
:
[
[
0
,
0.5
],
[
1
,
0.5
],
],
style
:
{
// stroke: '#4fa1a4',
fill
:
'#ebf6f7'
,
cursor
:
'pointer'
},
},
defaultEdge
:
{
type
:
'cubic-horizontal'
,
},
layout
:
{
type
:
'compactBox'
,
direction
:
'LR'
,
getId
:
function
getId
(
d
)
{
return
d
.
id
;
},
getHeight
:
function
getHeight
()
{
return
16
;
},
getWidth
:
function
getWidth
()
{
return
16
;
},
getVGap
:
function
getVGap
()
{
return
30
;
const
graph
=
new
G6
.
TreeGraph
({
container
:
container
,
width
,
height
,
plugins
:
[
contextMenu
,
tooltip
.
value
],
fitCenter
:
true
,
fitView
:
true
,
fitViewPadding
:
40
,
minZoom
:
0.5
,
maxZoom
:
1
,
modes
:
{
default
:
[
{
type
:
'collapse-expand'
,
onChange
:
(
item
,
collapsed
)
=>
{
debugger
if
(
!
item
)
{
return
;
}
const
data
=
item
.
getModel
();
data
.
collapsed
=
collapsed
;
return
true
;
},
getHGap
:
function
getHGap
()
{
return
120
;
shouldBegin
:
(
e
)
=>
{
debugger
// 若当前操作的节点 id 为 'node1',则不发生 collapse-expand
if
(
e
.
item
&&
e
.
item
.
getModel
().
isLoading
==
true
)
return
false
;
return
true
;
},
},
});
graphRef
.
value
=
graph
;
graph
.
node
((
node
)
=>
{
return
{
id
:
node
.
guid
as
string
,
label
:
handleLabelLength
(
node
.
name
as
string
),
collapsed
:
node
.
children
?.
length
?
false
:
true
,
labelCfg
:
{
offset
:
10
,
style
:
{
fontSize
:
16
,
fill
:
'#212121'
,
},
position
:
!
node
.
isField
?
'left'
:
'right'
,
//只有字段是最后一层级,不需要展开
},
style
:
{
stroke
:
'#4fa1a4'
,
cursor
:
'pointer'
}
};
});
// data不是数组,第一级是根节点
graph
.
data
(
props
.
treeData
);
graph
.
render
();
graph
.
fitView
(
40
,
{
direction
:
'both'
});
graph
.
fitCenter
();
graph
.
setMinZoom
(
0.5
);
graph
.
setMaxZoom
(
5
);
}
'drag-canvas'
,
'zoom-canvas'
,
],
},
defaultNode
:
{
size
:
24
,
anchorPoints
:
[
[
0
,
0.5
],
[
1
,
0.5
],
],
style
:
{
// stroke: '#4fa1a4',
fill
:
'#ebf6f7'
,
cursor
:
'pointer'
},
},
defaultEdge
:
{
type
:
'cubic-horizontal'
,
},
layout
:
{
type
:
'compactBox'
,
direction
:
'LR'
,
getId
:
function
getId
(
d
)
{
return
d
.
id
;
},
getHeight
:
function
getHeight
()
{
return
16
;
},
getWidth
:
function
getWidth
()
{
return
16
;
},
getVGap
:
function
getVGap
()
{
return
30
;
},
getHGap
:
function
getHGap
()
{
return
120
;
},
},
});
graphRef
.
value
=
graph
;
graph
.
node
((
node
)
=>
{
return
{
id
:
node
.
guid
as
string
,
label
:
handleLabelLength
((
node
.
isField
?
node
.
metaStandardId
:
node
.
standardName
)
as
string
),
collapsed
:
node
.
children
?.
length
?
false
:
true
,
labelCfg
:
{
offset
:
10
,
style
:
{
fontSize
:
16
,
fill
:
'#212121'
,
},
position
:
!
node
.
isField
?
'left'
:
'right'
,
//只有字段是最后一层级,不需要展开
},
style
:
{
stroke
:
'#4fa1a4'
,
cursor
:
'pointer'
}
};
});
// data不是数组,第一级是根节点
props
.
treeData
?.
guid
&&
graph
.
data
(
props
.
treeData
);
graph
.
render
();
graph
.
fitView
(
40
,
{
direction
:
'both'
});
graph
.
fitCenter
();
observeResize
();
graph
.
setMinZoom
(
0.5
);
graph
.
setMaxZoom
(
5
);
bindEvents
();
observeResize
();
}
bindEvents
();
onMounted
(()
=>
{
nextTick
(()
=>
{
if
(
!
graphRef
.
value
&&
props
.
treeData
?.
guid
)
{
initGraph
();
}
})
})
...
...
@@ -379,6 +351,7 @@ const observeResize = () => {
graphRef
.
value
.
setMinZoom
(
0.5
);
graphRef
.
value
.
setMaxZoom
(
5
);
},
500
)
return
;
}
const
container
:
any
=
containerRef
.
value
;
const
width
=
container
.
clientWidth
;
...
...
@@ -413,7 +386,8 @@ function updateTooltipPosition(evt) {
x
:
x4
+
graphContainer
.
offsetLeft
+
offsetX
,
y
:
y4
+
graphContainer
.
offsetTop
+
offsetY
};
let
bboxHeight
=
tooltip1Ref
.
value
.
getBoundingClientRect
().
height
;
let
bbox
=
tooltip1Ref
.
value
.
getBoundingClientRect
();
let
bboxHeight
=
bbox
.
height
;
if
(
x4
+
320
+
offsetX
>
width
)
{
res
.
x
-=
320
+
offsetX
;
}
...
...
@@ -432,6 +406,9 @@ const lastSelectNode = ref(null);
const
bindEvents
=
()
=>
{
let
graph
=
graphRef
.
value
;
if
(
!
graph
)
{
return
;
}
graph
.
on
(
'node:click'
,
function
(
evt
)
{
const
item
=
evt
.
item
;
if
(
!
item
)
{
...
...
@@ -459,10 +436,10 @@ const bindEvents = () => {
lastSelectNode
.
value
=
null
;
}
const
children
=
model
.
children
;
if
(
children
?.
length
&&
!
model
.
isField
)
{
//是字段级别,就不需要再展开了
if
(
children
?.
length
&&
!
model
.
isField
)
{
return
;
}
if
(
model
.
isField
)
{
if
(
model
.
isField
)
{
//是字段级别,就不需要再展开了
graphRef
.
value
.
updateItem
(
item
,
{
labelCfg
:
{
style
:
{
...
...
@@ -478,16 +455,23 @@ const bindEvents = () => {
lastSelectNode
.
value
=
item
;
detailInfo
.
value
.
guid
=
model
.
guid
;
updateTooltipPosition
(
evt
);
detailLoading
.
value
=
true
;
setTimeout
(()
=>
{
detailLoading
.
value
=
false
;
},
500
);
detailLoading
.
value
=
true
;
getMetaStandardFieldDetail
(
model
.
guid
).
then
((
res
:
any
)
=>
{
if
(
res
?.
code
==
proxy
.
$passCode
)
{
detailInfo
.
value
=
res
.
data
?.
metaStandardValue
||
{};
detailInfoLabel
.
value
=
model
.
label
;
detailLoading
.
value
=
false
;
}
else
{
ElMessage
.
error
(
res
.
msg
);
}
})
return
;
}
emits
(
'nodeItemClick'
,
graph
,
item
);
evt
.
preventDefault
();
evt
.
stopPropagation
();
model
.
isLoading
=
true
;
emits
(
'nodeItemClick'
,
graph
,
item
);
});
graph
.
on
(
'dragstart'
,
(
evt
:
any
)
=>
{
if
(
evt
.
item
?.
getType
()
==
'node'
)
{
...
...
@@ -591,7 +575,8 @@ defineExpose({
padding
:
16px
;
box-shadow
:
0px
2px
8px
0px
rgba
(
0
,
0
,
0
,
0.08
);
background-color
:
#fff
;
max-width
:
320px
;
width
:
320px
;
min-height
:
100px
;
max-height
:
400px
;
overflow-y
:
auto
;
...
...
src/router/modules/dataMeta.ts
View file @
8957880
...
...
@@ -263,6 +263,22 @@ const routes: RouteRecordRaw[] = [
}
},
{
path
:
'standard-query-view'
,
name
:
'metadataStandardQueryView'
,
component
:
()
=>
import
(
'@/views/data_meta/standard-query-view.vue'
),
meta
:
{
title
:
'元数据标准查看'
,
breadcrumb
:
false
,
cache
:
true
,
activeMenu
:
'/data-meta/metadata-standard'
},
beforeEnter
:
(
to
,
from
)
=>
{
if
(
to
.
query
.
name
)
{
to
.
meta
.
title
=
`元数据标准查看-
${
to
.
query
.
name
}
`
;
}
}
},
{
path
:
'standard-codetable'
,
name
:
'metadataStandardCodetable'
,
component
:
()
=>
import
(
'@/views/data_meta/standard-codetable.vue'
),
...
...
src/views/data_meta/components/Sankey.vue
View file @
8957880
...
...
@@ -80,15 +80,23 @@ const containerRef = ref();
const
setChartsOption
=
()
=>
{
let
option
=
{
tooltip
:
{
trigger
:
'item'
trigger
:
'item'
,
formatter
:
(
params
)
=>
{
if
(
params
.
data
.
name
)
{
return
null
;
}
return
params
.
data
.
source
+
' --> '
+
params
.
data
.
target
}
},
color
:
[
"#3DBCBE"
,
"#6b67d1"
,
"#7BBCE0"
,
"#2B8EF3"
,
"#51dca2"
,
"#E19D46"
],
series
:
[
{
type
:
'sankey'
,
top
:
80
,
bottom
:
40
,
left
:
50
,
right
:
50
,
draggable
:
false
,
left
:
40
,
right
:
80
,
data
:
props
.
names
,
links
:
props
.
treeData
,
lineStyle
:
{
...
...
src/views/data_meta/standard-query-view.vue
0 → 100644
View file @
8957880
<route
lang=
"yaml"
>
name: metadataStandardQueryView
</route>
<
template
>
<div
class=
"main_wrap"
v-loading=
"graphDataLoading"
>
<div
className=
'g6-component-topbar'
>
<graphTopbar
ref=
"topBarRef"
@
displaySwitchChange=
"displaySwitchChange"
:isGraphDisplay=
"isGraphDisplay"
/>
</div>
<RelationNetwork
v-show=
"graphTreeData?.guid && isGraphDisplay"
ref=
"relationNetworkRef"
:tree-data=
"graphTreeData"
:noContextMenu=
"true"
@
nodeItemClick=
"handleNodeItemClick"
>
</RelationNetwork>
<Sankey
v-show=
"!isGraphDisplay && (sankeyNames?.length || sankeyDataLoading)"
v-loading=
"sankeyDataLoading"
:tree-data=
"sankeyData"
:names=
"sankeyNames"
>
</Sankey>
<div
v-show=
"(isGraphDisplay ? !graphTreeData?.guid : (!sankeyDataLoading && !sankeyNames?.length))"
class=
"main-placeholder"
>
<img
src=
"../../assets/images/no-data.png"
:style=
"
{ width: '96px', height: '96px' }" />
<div
class=
"empty-text"
>
暂无数据
</div>
</div>
</div>
</
template
>
<
script
lang=
"ts"
setup
name=
"metadataStandardQueryView"
>
import
{
getMetaStandardField
,
getSankeyData
,
getMetaStandardTreeList
}
from
'@/api/modules/dataMetaService'
;
import
Sankey
from
'./components/Sankey.vue'
;
import
{
ElMessage
}
from
'element-plus'
;
const
router
=
useRouter
();
const
route
=
useRoute
()
const
metaGuid
=
ref
(
route
.
query
.
guid
);
const
{
proxy
}
=
getCurrentInstance
()
as
any
;
const
relationNetworkRef
=
ref
();
const
graphDataLoading
=
ref
(
false
);
/** 关系网树形数据 */
const
graphTreeData
:
any
=
ref
({});
onBeforeUnmount
(()
=>
{
relationNetworkRef
.
value
.
destroy
();
})
const
sankeyDataLoading
=
ref
(
false
);
const
sankeyData
:
any
=
ref
([]);
const
sankeyNames
:
any
=
ref
([]);
const
isGraphDisplay
=
ref
(
true
);
const
displaySwitchChange
=
(
val
)
=>
{
if
(
val
==
isGraphDisplay
.
value
)
{
return
;
}
isGraphDisplay
.
value
=
val
;
if
(
!
val
)
{
getSankeyDataList
();
}
}
const
getSankeyDataList
=
()
=>
{
sankeyDataLoading
.
value
=
true
;
getSankeyData
(
metaGuid
.
value
).
then
((
res
:
any
)
=>
{
sankeyDataLoading
.
value
=
false
;
if
(
res
?.
code
==
proxy
.
$passCode
)
{
sankeyData
.
value
=
res
.
data
?.
links
||
[];
sankeyNames
.
value
=
res
.
data
?.
data
||
[];
}
else
{
ElMessage
.
error
(
res
.
msg
);
}
})
}
const
handleNodeItemClick
=
(
graph
,
nodeItem
)
=>
{
const
nodeId
=
nodeItem
.
get
(
'id'
);
const
parentData
=
graph
.
findDataById
(
nodeId
);
if
(
!
parentData
.
children
)
{
parentData
.
children
=
[];
}
if
(
parentData
.
isHaveData
==
'N'
)
{
ElMessage
.
warning
(
'没有可展开的下级字段'
);
return
;
}
graphDataLoading
.
value
=
true
;
getMetaStandardField
(
nodeId
).
then
((
res
:
any
)
=>
{
graphDataLoading
.
value
=
false
;
if
(
res
?.
code
==
proxy
.
$passCode
)
{
const
data
=
res
.
data
||
[];
parentData
.
children
=
[];
if
(
!
data
?.
length
)
{
parentData
.
isHaveData
=
'N'
;
ElMessage
.
warning
(
'没有可展开的下级字段'
);
return
;
}
data
.
forEach
(
d
=>
{
parentData
.
children
.
push
(
d
);
})
parentData
.
collapsed
=
false
;
setTimeout
(()
=>
{
parentData
.
isLoading
=
false
;
graph
.
setMaxZoom
(
1
);
graph
.
changeData
(
graphTreeData
.
value
);
graph
.
setMaxZoom
(
5
);
},
100
);
}
else
{
parentData
.
isLoading
=
false
;
ElMessage
.
error
(
res
.
msg
);
}
})
}
onBeforeMount
(()
=>
{
graphDataLoading
.
value
=
true
getMetaStandardTreeList
(
metaGuid
.
value
).
then
((
res
:
any
)
=>
{
graphDataLoading
.
value
=
false
;
if
(
res
?.
code
==
proxy
.
$passCode
)
{
const
data
=
res
.
data
||
[];
graphTreeData
.
value
=
data
?.[
0
]
||
{};
}
else
{
ElMessage
.
error
(
res
.
msg
);
}
})
})
</
script
>
<
style
lang=
"scss"
scoped
>
.main_wrap
{
height
:
100%
;
width
:
100%
;
position
:
relative
;
:deep(.canvas-wrapper)
{
background-color
:
#f7f7f9
;
}
.main-placeholder
{
height
:
100%
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
flex-direction
:
column
;
.empty-text
{
font-size
:
14px
;
color
:
#b2b2b2
;
}
}
}
.g6-component-topbar
{
position
:
absolute
;
left
:
24px
;
bottom
:
unset
;
top
:
14px
;
padding
:
0
;
text-align
:
center
;
z-index
:
999
;
}
</
style
>
\ No newline at end of file
src/views/data_meta/standard-query.vue
View file @
8957880
...
...
@@ -9,16 +9,17 @@ import Sankey from './components/Sankey.vue';
import
Tree
from
'@/components/Tree/index.vue'
;
import
RelationNetwork
from
'@/components/RelationNetwork/index.vue'
;
import
{
getMetaStandardTreeList
,
getMetaStandardField
,
getSankeyData
}
from
'@/api/modules/dataMetaService'
;
import
{
useRouter
,
useRoute
}
from
"vue-router"
;
import
useDataMetaStore
from
"@/store/modules/dataMeta"
import
{
cloneDeep
}
from
'lodash-es'
;
const
router
=
useRouter
();
const
route
=
useRoute
()
const
switchGraphDisplay
=
ref
(
true
);
//true表示关系网,false表示桑基图
const
{
proxy
}
=
getCurrentInstance
()
as
any
;
const
relationNetworkRef
=
ref
();
...
...
@@ -27,14 +28,14 @@ const treeInfo = ref({
id
:
"data-meta-standard-tree"
,
filter
:
true
,
queryValue
:
""
,
queryPlaceholder
:
"
输入库/表名称
搜索"
,
queryPlaceholder
:
"
请输入关键字
搜索"
,
props
:
{
label
:
"
n
ame"
,
label
:
"
standardN
ame"
,
value
:
"guid"
,
isLeaf
:
"isLeaf"
,
},
nodeKey
:
'guid'
,
expandedKey
:
[
'1'
],
expandedKey
:
[],
currentNodeKey
:
''
,
expandOnNodeClick
:
false
,
data
:
<
any
>
[],
...
...
@@ -44,51 +45,20 @@ const treeInfo = ref({
/** 获取左侧树数据. */
const
getTreeData
=
async
()
=>
{
treeInfo
.
value
.
loading
=
true
// let params = {}
// const res: any = await getMetaTreeData(params)
// if (res.code == proxy.$passCode) {
// const data = res.data || [];
// let treeData: any = Object.keys(data).length ? [data] : [];
// treeInfo.value.data = treeData;
// allTreeData.value = treeData;
// if (treeData.length) {
// treeInfo.value.currentNodeKey = treeData[0].guid;
// treeInfo.value.expandedKey = <any>[treeData[0].guid];
// }
// } else {
// ElMessage.error(res.msg);
// }
treeInfo
.
value
.
data
=
[{
guid
:
'1'
,
name
:
'第一级1'
,
children
:
[{
guid
:
'1-1'
,
name
:
'第二级1-1'
,
children
:
[{
guid
:
'1-1-1'
,
name
:
'第三级1-1-1'
}]
},
{
guid
:
'1-2'
,
name
:
'第二级1-2'
},
{
guid
:
'1-3'
,
name
:
'第二级1-3'
}]
},
{
guid
:
'2'
,
name
:
'第一级2'
,
children
:
[{
guid
:
'2-1'
,
name
:
'第二级1-1'
},
{
guid
:
'2-2'
,
name
:
'第二级1-2'
}]
}];
treeInfo
.
value
.
loading
=
false
treeInfo
.
value
.
currentNodeKey
=
'1'
;
nodeClick
(
treeInfo
.
value
.
data
[
0
])
getMetaStandardTreeList
(
''
).
then
((
res
:
any
)
=>
{
treeInfo
.
value
.
loading
=
false
;
if
(
res
?.
code
==
proxy
.
$passCode
)
{
const
data
=
res
.
data
||
[];
treeInfo
.
value
.
data
=
data
;
if
(
data
.
length
)
{
treeInfo
.
value
.
currentNodeKey
=
data
[
0
].
guid
;
treeInfo
.
value
.
expandedKey
=
<
any
>
[
data
[
0
].
guid
];
nodeClick
(
treeInfo
.
value
.
data
[
0
])
}
}
else
{
ElMessage
.
error
(
res
.
msg
);
}
})
}
/** 左侧树的的组件引用. */
const
treeInfoRef
=
ref
();
...
...
@@ -98,22 +68,18 @@ const lastClickNode: any = ref({});
const
treeDataLoading
=
ref
(
false
);
/** 数据血缘关系图组件 */
const
lineageGraph
:
any
=
ref
();
/** 点击左侧树节点,更新对应的血缘关系图. */
const
nodeClick
=
(
data
)
=>
{
console
.
log
(
data
);
const
ele
=
<
HTMLElement
>
document
.
querySelector
(
".g6-component-contextmenu"
)
if
(
ele
)
{
ele
.
style
.
display
=
"none"
}
nextTick
(()
=>
{
lineageGraph
.
value
?.
tooltip1
.
hide
()
})
treeInfo
.
value
.
currentNodeKey
=
data
.
guid
;
treeInfo
.
value
.
expandedKey
=
<
any
>
[
data
.
guid
];
lastClickNode
.
value
=
data
;
lastClickNode
.
value
=
cloneDeep
(
data
);
if
(
!
isGraphDisplay
.
value
)
{
getSankeyDataList
();
}
}
/** 选中树节点后自动滚动到可视范围内. */
...
...
@@ -145,7 +111,6 @@ const processRouter = () => {
treeInfo
.
value
.
expandedKey
=
<
any
>
[
databaseGuid
,
guid
];
lastClickNode
.
value
=
{
guid
:
guid
,
tableName
,
databaseName
,
type
:
3
,
databaseChName
};
scrollToNode
(
guid
);
switchGraphDisplay
.
value
=
isFL
;
// if (isFL) {
// getAllTableFieldLineageMap();
// } else {
...
...
@@ -156,20 +121,45 @@ const processRouter = () => {
}
onActivated
(()
=>
{
processRouter
();
//
processRouter();
});
onBeforeMount
(
async
()
=>
{
await
getTreeData
()
processRouter
();
//
processRouter();
})
onMounted
(()
=>
{
})
const
sankeyDataLoading
=
ref
(
false
);
const
sankeyData
:
any
=
ref
([]);
const
sankeyNames
:
any
=
ref
([]);
const
isGraphDisplay
=
ref
(
true
);
const
displaySwitchChange
=
(
val
)
=>
{
if
(
val
==
isGraphDisplay
.
value
)
{
return
;
}
isGraphDisplay
.
value
=
val
;
if
(
!
val
)
{
getSankeyDataList
();
}
}
const
getSankeyDataList
=
()
=>
{
sankeyDataLoading
.
value
=
true
;
getSankeyData
(
lastClickNode
.
value
.
guid
).
then
((
res
:
any
)
=>
{
sankeyDataLoading
.
value
=
false
;
if
(
res
?.
code
==
proxy
.
$passCode
)
{
sankeyData
.
value
=
res
.
data
?.
links
||
[];
sankeyNames
.
value
=
res
.
data
?.
data
||
[];
}
else
{
ElMessage
.
error
(
res
.
msg
);
}
})
}
const
handleNodeItemClick
=
(
graph
,
nodeItem
)
=>
{
...
...
@@ -178,35 +168,41 @@ const handleNodeItemClick = (graph, nodeItem) => {
if
(
!
parentData
.
children
)
{
parentData
.
children
=
[];
}
if
(
parentData
.
noData
)
{
ElMessage
.
warning
(
'没有可展开的下级字段'
);
return
;
}
treeDataLoading
.
value
=
true
;
let
childData
=
[{
guid
:
'33'
,
isField
:
true
,
name
:
'字段1'
},
{
guid
:
'44'
,
isField
:
true
,
name
:
'字段2字段2字段2字段2字段2字段2字段2字段2字段2xx2字段22字段22字段22字段22字段22字段2'
},
{
guid
:
'55'
,
isField
:
true
,
name
:
'字段3'
}]
// parentData.collapsed = true;
// nodeItem.getModel().collapsed = true;
parentData
.
children
=
childData
;
setTimeout
(()
=>
{
getMetaStandardField
(
nodeId
).
then
((
res
:
any
)
=>
{
treeDataLoading
.
value
=
false
;
graph
.
changeData
();
// parentData.collapsed = true;
// graph.updateChildren(childData, parentData.id);
// graph.changeData(lastClickNode.value);
//graph.data(lastClickNode.value);
},
2000
)
if
(
res
?.
code
==
proxy
.
$passCode
)
{
const
data
=
res
.
data
||
[];
parentData
.
children
=
[];
if
(
!
data
?.
length
)
{
parentData
.
noData
=
true
;
ElMessage
.
warning
(
'没有可展开的下级字段'
);
return
;
}
data
.
forEach
(
d
=>
{
parentData
.
children
.
push
(
d
);
})
parentData
.
collapsed
=
false
;
setTimeout
(()
=>
{
parentData
.
isLoading
=
false
;
graph
.
setMaxZoom
(
1
);
graph
.
changeData
(
lastClickNode
.
value
);
graph
.
setMaxZoom
(
5
);
},
100
);
}
else
{
parentData
.
isLoading
=
false
;
ElMessage
.
error
(
res
.
msg
);
}
})
}
const
handleContextMenu
=
(
nodeData
)
=>
{
//TODO,新建引用数据集
window
.
open
(
''
);
}
onBeforeUnmount
(()
=>
{
...
...
@@ -218,21 +214,23 @@ onBeforeUnmount(() => {
<
template
>
<div
class=
"container_wrap full flex"
>
<div
class=
"aside_wrap"
>
<div
class=
"aside_title"
>
数据库目录
列表
</div>
<div
class=
"aside_title"
>
元数据标准
列表
</div>
<Tree
ref=
"treeInfoRef"
:treeInfo=
"treeInfo"
@
nodeClick=
"nodeClick"
/>
</div>
<div
class=
"main_wrap"
>
<div
className=
'g6-component-topbar'
>
<graphTopbar
ref=
"topBarRef"
@
displaySwitchChange=
"displaySwitchChange"
:isGraphDisplay=
"isGraphDisplay"
/>
</div>
<RelationNetwork
v-show=
"isGraphDisplay"
ref=
"relationNetworkRef"
:tree-data=
"lastClickNode"
v-loading=
"treeDataLoading"
@
nodeItemClick=
"handleNodeItemClick"
@
contextMenu=
"handleContextMenu"
>
<RelationNetwork
v-show=
"lastClickNode?.guid && isGraphDisplay"
ref=
"relationNetworkRef"
:tree-data=
"lastClickNode"
v-loading=
"treeDataLoading"
@
nodeItemClick=
"handleNodeItemClick"
@
contextMenu=
"handleContextMenu"
>
</RelationNetwork>
<Sankey
v-show=
"!isGraphDisplay"
></Sankey>
<!--
<div
v-show=
"lastClickNode && lastClickNode?.type !== 3 && lastClickNode?.type !== 4"
class=
"main-placeholder"
>
<Sankey
v-show=
"lastClickNode?.guid && !isGraphDisplay && (sankeyNames?.length || sankeyDataLoading)"
v-loading=
"sankeyDataLoading"
:tree-data=
"sankeyData"
:names=
"sankeyNames"
>
</Sankey>
<div
v-show=
"!lastClickNode?.guid && !treeInfo.data?.length || (!isGraphDisplay && !sankeyDataLoading && !sankeyNames?.length)"
class=
"main-placeholder"
>
<img
src=
"../../assets/images/no-data.png"
:style=
"
{ width: '96px', height: '96px' }" />
<div
class=
"empty-text"
>
暂无
标准
数据
</div>
</div>
-->
<div
class=
"empty-text"
>
暂无数据
</div>
</div>
</div>
</div>
</
template
>
...
...
src/views/data_meta/standard.vue
View file @
8957880
...
...
@@ -416,6 +416,17 @@ function exportData () {
onBeforeMount
(()
=>
{
getTree
()
})
const
viewGraph
=
()
=>
{
router
.
push
({
name
:
'metadataStandardQueryView'
,
query
:
{
guid
:
treeInfo
.
value
.
currentObj
?.
guid
,
name
:
treeInfo
.
value
.
currentObj
?.
standardName
,
}
});
}
</
script
>
<
template
>
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment