查看关系网接口联调
Showing
7 changed files
with
359 additions
and
172 deletions
| ... | @@ -741,6 +741,7 @@ onMounted(() => { | ... | @@ -741,6 +741,7 @@ onMounted(() => { |
| 741 | toolRef.value.isFull = true | 741 | toolRef.value.isFull = true |
| 742 | } | 742 | } |
| 743 | }, 500) | 743 | }, 500) |
| 744 | return; | ||
| 744 | } | 745 | } |
| 745 | const container: any = containerRef.value; | 746 | const container: any = containerRef.value; |
| 746 | const width = container.clientWidth; | 747 | const width = container.clientWidth; | ... | ... |
| 1 | <template> | 1 | <template> |
| 2 | <div ref="containerRef" className='canvas-wrapper'> | 2 | <div ref="containerRef" className='canvas-wrapper'> |
| 3 | <div class="main" ref="tooltip1Ref" style="display: none;position: absolute;" v-loading="detailLoading"> | 3 | <div class="main" ref="tooltip1Ref" style="display: none;position: absolute;" v-loading="detailLoading"> |
| 4 | <div class="title">{{ detailInfo.name }}</div> | 4 | <div class="title">{{ detailInfoLabel }}</div> |
| 5 | <div class="row" v-for="item in Object.keys(detailInfo)"> | 5 | <div class="row" v-for="item in Object.keys(detailInfo)"> |
| 6 | <span>{{ item + ':' }}</span> | 6 | <span>{{ item + ':' }}</span> |
| 7 | <span>{{ detailInfo[item] }}</span> | 7 | <span>{{ detailInfo[item] }}</span> |
| ... | @@ -14,11 +14,19 @@ | ... | @@ -14,11 +14,19 @@ |
| 14 | import { ref, onMounted } from 'vue' | 14 | import { ref, onMounted } from 'vue' |
| 15 | import G6 from '@antv/g6'; | 15 | import G6 from '@antv/g6'; |
| 16 | import insertCss from 'insert-css'; | 16 | import insertCss from 'insert-css'; |
| 17 | import { | ||
| 18 | getMetaStandardFieldDetail | ||
| 19 | } from '@/api/modules/dataMetaService'; | ||
| 20 | import { ElMessage } from 'element-plus'; | ||
| 17 | 21 | ||
| 18 | const props = defineProps({ | 22 | const props = defineProps({ |
| 19 | treeData: { | 23 | treeData: { |
| 20 | type: Object, | 24 | type: Object, |
| 21 | default: {} | 25 | default: {} |
| 26 | }, | ||
| 27 | noContextMenu: { | ||
| 28 | type: Boolean, | ||
| 29 | default: false | ||
| 22 | } | 30 | } |
| 23 | }) | 31 | }) |
| 24 | 32 | ||
| ... | @@ -27,15 +35,13 @@ const emits = defineEmits([ | ... | @@ -27,15 +35,13 @@ const emits = defineEmits([ |
| 27 | 'contextMenu' | 35 | 'contextMenu' |
| 28 | ]); | 36 | ]); |
| 29 | 37 | ||
| 38 | const { proxy } = getCurrentInstance() as any; | ||
| 39 | |||
| 30 | const detailLoading = ref(false); | 40 | const detailLoading = ref(false); |
| 31 | 41 | ||
| 32 | const detailInfo: any = ref({ | 42 | const detailInfo: any = ref({}); |
| 33 | guid: '1', | 43 | |
| 34 | '标识符': '124', | 44 | const detailInfoLabel = ref(''); |
| 35 | name: '字段12345字段字段字段字段字段字段字段字段字段字段', | ||
| 36 | '中文名称': '字段12345字段字段字段字段字段字段字段字段字段字段', | ||
| 37 | '英文名称': 'fieldName' | ||
| 38 | }); | ||
| 39 | 45 | ||
| 40 | const containerRef = ref(); | 46 | const containerRef = ref(); |
| 41 | 47 | ||
| ... | @@ -44,6 +50,13 @@ const graphRef = ref(); | ... | @@ -44,6 +50,13 @@ const graphRef = ref(); |
| 44 | const resizeObserver = ref(); | 50 | const resizeObserver = ref(); |
| 45 | 51 | ||
| 46 | watch(() => props.treeData, (val) => { | 52 | watch(() => props.treeData, (val) => { |
| 53 | if (!graphRef.value && val?.guid) { | ||
| 54 | initGraph(); | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | if (!graphRef.value) { | ||
| 58 | return; | ||
| 59 | } | ||
| 47 | tooltip1Ref.value.style.display = 'none'; | 60 | tooltip1Ref.value.style.display = 'none'; |
| 48 | if (lastSelectNode.value) { | 61 | if (lastSelectNode.value) { |
| 49 | graphRef.value.updateItem(lastSelectNode.value, { | 62 | graphRef.value.updateItem(lastSelectNode.value, { |
| ... | @@ -130,9 +143,7 @@ insertCss(` | ... | @@ -130,9 +143,7 @@ insertCss(` |
| 130 | 143 | ||
| 131 | const tooltip = ref(); | 144 | const tooltip = ref(); |
| 132 | 145 | ||
| 133 | onMounted(() => { | 146 | const initGraph = () => { |
| 134 | nextTick(() => { | ||
| 135 | if (!graphRef.value) { | ||
| 136 | const container: any = containerRef.value; | 147 | const container: any = containerRef.value; |
| 137 | const width = container.clientWidth; | 148 | const width = container.clientWidth; |
| 138 | const height = container.clientHeight - 10; | 149 | const height = container.clientHeight - 10; |
| ... | @@ -147,7 +158,7 @@ onMounted(() => { | ... | @@ -147,7 +158,7 @@ onMounted(() => { |
| 147 | shouldBegin: (evt: any) => { | 158 | shouldBegin: (evt: any) => { |
| 148 | const { item, target } = evt; | 159 | const { item, target } = evt; |
| 149 | const currentAnchor = target.get('name'); | 160 | const currentAnchor = target.get('name'); |
| 150 | const name = item._cfg.model?.name; | 161 | const name = item._cfg.model?.label; |
| 151 | if (currentAnchor == 'text-shape') { | 162 | if (currentAnchor == 'text-shape') { |
| 152 | if (detectLanguage(name) == 'English') { | 163 | if (detectLanguage(name) == 'English') { |
| 153 | return name?.length > 30; | 164 | return name?.length > 30; |
| ... | @@ -163,7 +174,7 @@ onMounted(() => { | ... | @@ -163,7 +174,7 @@ onMounted(() => { |
| 163 | const outDiv = document.createElement('div'); | 174 | const outDiv = document.createElement('div'); |
| 164 | outDiv.className = 'node'; | 175 | outDiv.className = 'node'; |
| 165 | outDiv.style.width = 'fit-content'; | 176 | outDiv.style.width = 'fit-content'; |
| 166 | const name = item._cfg.model.name; | 177 | const name = item._cfg.model.label; |
| 167 | if (currentAnchor == 'text-shape') { | 178 | if (currentAnchor == 'text-shape') { |
| 168 | outDiv.innerHTML = `<h4>${name}</h4>` | 179 | outDiv.innerHTML = `<h4>${name}</h4>` |
| 169 | } | 180 | } |
| ... | @@ -171,57 +182,6 @@ onMounted(() => { | ... | @@ -171,57 +182,6 @@ onMounted(() => { |
| 171 | }, | 182 | }, |
| 172 | }); | 183 | }); |
| 173 | 184 | ||
| 174 | // tooltip1.value = new G6.Tooltip({ | ||
| 175 | // offsetX: 10, | ||
| 176 | // offsetY: 10, | ||
| 177 | // trigger: 'click', | ||
| 178 | // // 允许出现 tooltip 的 item 类型 | ||
| 179 | // itemTypes: ['node'], | ||
| 180 | // // 自定义 tooltip 内容 | ||
| 181 | // shouldBegin: (evt: any) => { | ||
| 182 | // const { item, target } = evt; | ||
| 183 | // let model = item._cfg.model; | ||
| 184 | // if (model.isField) { | ||
| 185 | // return true | ||
| 186 | // } | ||
| 187 | // return false; | ||
| 188 | // }, | ||
| 189 | // getContent: async (e: any) => { | ||
| 190 | // const { item, target } = e; | ||
| 191 | // let model = item._cfg.model; | ||
| 192 | // if (!model.isField) { | ||
| 193 | // return ''; | ||
| 194 | // } | ||
| 195 | // const template = ` <div class="main" v-loading="detailLoading"> | ||
| 196 | // <div class="title">{{ titleName + ':' }}</div> | ||
| 197 | // <div class="row" v-for="item in Object.keys(detailInfo)"> | ||
| 198 | // <span>{{ item }}</span> | ||
| 199 | // <span>{{ detailInfo[item] }}</span> | ||
| 200 | // </div> | ||
| 201 | // </div>` | ||
| 202 | // await setTimeout(() => { | ||
| 203 | // }, 200); | ||
| 204 | // const outDiv = document.createElement('div'); | ||
| 205 | |||
| 206 | // outDiv.className = 'tooltip-main'; | ||
| 207 | // outDiv.style.width = '320px'; | ||
| 208 | |||
| 209 | // for (const key in detailInfo.value) { | ||
| 210 | // const domRow = document.createElement('div'); | ||
| 211 | // domRow.className = 'row'; | ||
| 212 | // let span1 = document.createElement('span'); | ||
| 213 | // span1.innerHTML = key + ':'; | ||
| 214 | // let span2 = document.createElement('span'); | ||
| 215 | // span2.innerHTML = detailInfo[key]; | ||
| 216 | // domRow.appendChild(span1); | ||
| 217 | // domRow.appendChild(span2); | ||
| 218 | // outDiv.appendChild(domRow); | ||
| 219 | // } | ||
| 220 | // return outDiv; | ||
| 221 | |||
| 222 | // }, | ||
| 223 | // }); | ||
| 224 | |||
| 225 | const contextMenu = new G6.Menu({ | 185 | const contextMenu = new G6.Menu({ |
| 226 | getContent(evt: any) { | 186 | getContent(evt: any) { |
| 227 | const { item, target } = evt; | 187 | const { item, target } = evt; |
| ... | @@ -232,11 +192,17 @@ onMounted(() => { | ... | @@ -232,11 +192,17 @@ onMounted(() => { |
| 232 | </div>` | 192 | </div>` |
| 233 | }, | 193 | }, |
| 234 | shouldBegin: (evt: any) => { | 194 | shouldBegin: (evt: any) => { |
| 195 | if (props.noContextMenu) { | ||
| 196 | return false; | ||
| 197 | } | ||
| 235 | const { item, target } = evt; | 198 | const { item, target } = evt; |
| 236 | let model = item._cfg.model; | 199 | let model = item._cfg.model; |
| 237 | if (model && !model.isField && !model.children?.length) { | 200 | if (model && !model.isField && !model.children?.length) { |
| 238 | return true; | 201 | return true; |
| 239 | } | 202 | } |
| 203 | if (model.children?.length && model.children[0].isField) { | ||
| 204 | return true; | ||
| 205 | } | ||
| 240 | return false; | 206 | return false; |
| 241 | }, | 207 | }, |
| 242 | handleMenuClick: (target, item: any) => { | 208 | handleMenuClick: (target, item: any) => { |
| ... | @@ -271,6 +237,7 @@ onMounted(() => { | ... | @@ -271,6 +237,7 @@ onMounted(() => { |
| 271 | { | 237 | { |
| 272 | type: 'collapse-expand', | 238 | type: 'collapse-expand', |
| 273 | onChange: (item, collapsed) => { | 239 | onChange: (item, collapsed) => { |
| 240 | debugger | ||
| 274 | if (!item) { | 241 | if (!item) { |
| 275 | return; | 242 | return; |
| 276 | } | 243 | } |
| ... | @@ -279,8 +246,9 @@ onMounted(() => { | ... | @@ -279,8 +246,9 @@ onMounted(() => { |
| 279 | return true; | 246 | return true; |
| 280 | }, | 247 | }, |
| 281 | shouldBegin: (e) => { | 248 | shouldBegin: (e) => { |
| 249 | debugger | ||
| 282 | // 若当前操作的节点 id 为 'node1',则不发生 collapse-expand | 250 | // 若当前操作的节点 id 为 'node1',则不发生 collapse-expand |
| 283 | if (e.item && e.item.getModel().id === 'node1') return false; | 251 | if (e.item && e.item.getModel().isLoading == true) return false; |
| 284 | return true; | 252 | return true; |
| 285 | }, | 253 | }, |
| 286 | }, | 254 | }, |
| ... | @@ -327,7 +295,7 @@ onMounted(() => { | ... | @@ -327,7 +295,7 @@ onMounted(() => { |
| 327 | graph.node((node) => { | 295 | graph.node((node) => { |
| 328 | return { | 296 | return { |
| 329 | id: node.guid as string, | 297 | id: node.guid as string, |
| 330 | label: handleLabelLength(node.name as string), | 298 | label: handleLabelLength((node.isField ? node.metaStandardId : node.standardName) as string), |
| 331 | collapsed: node.children?.length ? false : true, | 299 | collapsed: node.children?.length ? false : true, |
| 332 | labelCfg: { | 300 | labelCfg: { |
| 333 | offset: 10, | 301 | offset: 10, |
| ... | @@ -344,18 +312,22 @@ onMounted(() => { | ... | @@ -344,18 +312,22 @@ onMounted(() => { |
| 344 | }; | 312 | }; |
| 345 | }); | 313 | }); |
| 346 | // data不是数组,第一级是根节点 | 314 | // data不是数组,第一级是根节点 |
| 347 | graph.data(props.treeData); | 315 | props.treeData?.guid && graph.data(props.treeData); |
| 348 | graph.render(); | 316 | graph.render(); |
| 349 | graph.fitView(40, { direction: 'both' }); | 317 | graph.fitView(40, { direction: 'both' }); |
| 350 | graph.fitCenter(); | 318 | graph.fitCenter(); |
| 351 | 319 | ||
| 352 | graph.setMinZoom(0.5); | 320 | graph.setMinZoom(0.5); |
| 353 | graph.setMaxZoom(5); | 321 | graph.setMaxZoom(5); |
| 354 | } | 322 | bindEvents(); |
| 355 | |||
| 356 | observeResize(); | 323 | observeResize(); |
| 324 | } | ||
| 357 | 325 | ||
| 358 | bindEvents(); | 326 | onMounted(() => { |
| 327 | nextTick(() => { | ||
| 328 | if (!graphRef.value && props.treeData?.guid) { | ||
| 329 | initGraph(); | ||
| 330 | } | ||
| 359 | }) | 331 | }) |
| 360 | 332 | ||
| 361 | }) | 333 | }) |
| ... | @@ -379,6 +351,7 @@ const observeResize = () => { | ... | @@ -379,6 +351,7 @@ const observeResize = () => { |
| 379 | graphRef.value.setMinZoom(0.5); | 351 | graphRef.value.setMinZoom(0.5); |
| 380 | graphRef.value.setMaxZoom(5); | 352 | graphRef.value.setMaxZoom(5); |
| 381 | }, 500) | 353 | }, 500) |
| 354 | return; | ||
| 382 | } | 355 | } |
| 383 | const container: any = containerRef.value; | 356 | const container: any = containerRef.value; |
| 384 | const width = container.clientWidth; | 357 | const width = container.clientWidth; |
| ... | @@ -413,7 +386,8 @@ function updateTooltipPosition(evt) { | ... | @@ -413,7 +386,8 @@ function updateTooltipPosition(evt) { |
| 413 | x: x4 + graphContainer.offsetLeft + offsetX, | 386 | x: x4 + graphContainer.offsetLeft + offsetX, |
| 414 | y: y4 + graphContainer.offsetTop + offsetY | 387 | y: y4 + graphContainer.offsetTop + offsetY |
| 415 | }; | 388 | }; |
| 416 | let bboxHeight = tooltip1Ref.value.getBoundingClientRect().height; | 389 | let bbox = tooltip1Ref.value.getBoundingClientRect(); |
| 390 | let bboxHeight = bbox.height; | ||
| 417 | if (x4 + 320 + offsetX > width) { | 391 | if (x4 + 320 + offsetX > width) { |
| 418 | res.x -= 320 + offsetX; | 392 | res.x -= 320 + offsetX; |
| 419 | } | 393 | } |
| ... | @@ -432,6 +406,9 @@ const lastSelectNode = ref(null); | ... | @@ -432,6 +406,9 @@ const lastSelectNode = ref(null); |
| 432 | 406 | ||
| 433 | const bindEvents = () => { | 407 | const bindEvents = () => { |
| 434 | let graph = graphRef.value; | 408 | let graph = graphRef.value; |
| 409 | if (!graph) { | ||
| 410 | return; | ||
| 411 | } | ||
| 435 | graph.on('node:click', function (evt) { | 412 | graph.on('node:click', function (evt) { |
| 436 | const item = evt.item; | 413 | const item = evt.item; |
| 437 | if (!item) { | 414 | if (!item) { |
| ... | @@ -459,10 +436,10 @@ const bindEvents = () => { | ... | @@ -459,10 +436,10 @@ const bindEvents = () => { |
| 459 | lastSelectNode.value = null; | 436 | lastSelectNode.value = null; |
| 460 | } | 437 | } |
| 461 | const children = model.children; | 438 | const children = model.children; |
| 462 | if (children?.length && !model.isField) { //是字段级别,就不需要再展开了 | 439 | if (children?.length && !model.isField) { |
| 463 | return; | 440 | return; |
| 464 | } | 441 | } |
| 465 | if (model.isField) { | 442 | if (model.isField) { //是字段级别,就不需要再展开了 |
| 466 | graphRef.value.updateItem(item, { | 443 | graphRef.value.updateItem(item, { |
| 467 | labelCfg: { | 444 | labelCfg: { |
| 468 | style: { | 445 | style: { |
| ... | @@ -478,16 +455,23 @@ const bindEvents = () => { | ... | @@ -478,16 +455,23 @@ const bindEvents = () => { |
| 478 | lastSelectNode.value = item; | 455 | lastSelectNode.value = item; |
| 479 | detailInfo.value.guid = model.guid; | 456 | detailInfo.value.guid = model.guid; |
| 480 | updateTooltipPosition(evt); | 457 | updateTooltipPosition(evt); |
| 481 | detailLoading.value = true; | ||
| 482 | 458 | ||
| 483 | setTimeout(() => { | 459 | detailLoading.value = true; |
| 460 | getMetaStandardFieldDetail(model.guid).then((res: any) => { | ||
| 461 | if (res?.code == proxy.$passCode) { | ||
| 462 | detailInfo.value = res.data?.metaStandardValue || {}; | ||
| 463 | detailInfoLabel.value = model.label; | ||
| 484 | detailLoading.value = false; | 464 | detailLoading.value = false; |
| 485 | }, 500); | 465 | } else { |
| 466 | ElMessage.error(res.msg); | ||
| 467 | } | ||
| 468 | }) | ||
| 486 | return; | 469 | return; |
| 487 | } | 470 | } |
| 488 | emits('nodeItemClick', graph, item); | ||
| 489 | evt.preventDefault(); | 471 | evt.preventDefault(); |
| 490 | evt.stopPropagation(); | 472 | evt.stopPropagation(); |
| 473 | model.isLoading = true; | ||
| 474 | emits('nodeItemClick', graph, item); | ||
| 491 | }); | 475 | }); |
| 492 | graph.on('dragstart', (evt: any) => { | 476 | graph.on('dragstart', (evt: any) => { |
| 493 | if (evt.item?.getType() == 'node') { | 477 | if (evt.item?.getType() == 'node') { |
| ... | @@ -591,7 +575,8 @@ defineExpose({ | ... | @@ -591,7 +575,8 @@ defineExpose({ |
| 591 | padding: 16px; | 575 | padding: 16px; |
| 592 | box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.08); | 576 | box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.08); |
| 593 | background-color: #fff; | 577 | background-color: #fff; |
| 594 | max-width: 320px; | 578 | width: 320px; |
| 579 | min-height: 100px; | ||
| 595 | max-height: 400px; | 580 | max-height: 400px; |
| 596 | overflow-y: auto; | 581 | overflow-y: auto; |
| 597 | 582 | ... | ... |
| ... | @@ -263,6 +263,22 @@ const routes: RouteRecordRaw[] = [ | ... | @@ -263,6 +263,22 @@ const routes: RouteRecordRaw[] = [ |
| 263 | } | 263 | } |
| 264 | }, | 264 | }, |
| 265 | { | 265 | { |
| 266 | path: 'standard-query-view', | ||
| 267 | name: 'metadataStandardQueryView', | ||
| 268 | component: () => import('@/views/data_meta/standard-query-view.vue'), | ||
| 269 | meta: { | ||
| 270 | title: '元数据标准查看', | ||
| 271 | breadcrumb: false, | ||
| 272 | cache: true, | ||
| 273 | activeMenu: '/data-meta/metadata-standard' | ||
| 274 | }, | ||
| 275 | beforeEnter: (to, from) => { | ||
| 276 | if (to.query.name) { | ||
| 277 | to.meta.title = `元数据标准查看-${to.query.name}`; | ||
| 278 | } | ||
| 279 | } | ||
| 280 | }, | ||
| 281 | { | ||
| 266 | path: 'standard-codetable', | 282 | path: 'standard-codetable', |
| 267 | name: 'metadataStandardCodetable', | 283 | name: 'metadataStandardCodetable', |
| 268 | component: () => import('@/views/data_meta/standard-codetable.vue'), | 284 | component: () => import('@/views/data_meta/standard-codetable.vue'), | ... | ... |
| ... | @@ -80,15 +80,23 @@ const containerRef = ref(); | ... | @@ -80,15 +80,23 @@ const containerRef = ref(); |
| 80 | const setChartsOption = () => { | 80 | const setChartsOption = () => { |
| 81 | let option = { | 81 | let option = { |
| 82 | tooltip: { | 82 | tooltip: { |
| 83 | trigger: 'item' | 83 | trigger: 'item', |
| 84 | formatter: (params) => { | ||
| 85 | if (params.data.name) { | ||
| 86 | return null; | ||
| 87 | } | ||
| 88 | return params.data.source + ' --> ' + params.data.target | ||
| 89 | } | ||
| 84 | }, | 90 | }, |
| 91 | color: ["#3DBCBE", "#6b67d1", "#7BBCE0", "#2B8EF3", "#51dca2", "#E19D46"], | ||
| 85 | series: [ | 92 | series: [ |
| 86 | { | 93 | { |
| 87 | type: 'sankey', | 94 | type: 'sankey', |
| 88 | top: 80, | 95 | top: 80, |
| 89 | bottom: 40, | 96 | bottom: 40, |
| 90 | left: 50, | 97 | draggable: false, |
| 91 | right: 50, | 98 | left: 40, |
| 99 | right: 80, | ||
| 92 | data: props.names, | 100 | data: props.names, |
| 93 | links: props.treeData, | 101 | links: props.treeData, |
| 94 | lineStyle: { | 102 | lineStyle: { | ... | ... |
src/views/data_meta/standard-query-view.vue
0 → 100644
| 1 | <route lang="yaml"> | ||
| 2 | name: metadataStandardQueryView | ||
| 3 | </route> | ||
| 4 | |||
| 5 | <template> | ||
| 6 | <div class="main_wrap" v-loading="graphDataLoading"> | ||
| 7 | <div className='g6-component-topbar'> | ||
| 8 | <graphTopbar ref="topBarRef" @displaySwitchChange="displaySwitchChange" :isGraphDisplay="isGraphDisplay" /> | ||
| 9 | </div> | ||
| 10 | <RelationNetwork v-show="graphTreeData?.guid && isGraphDisplay" ref="relationNetworkRef" :tree-data="graphTreeData" :noContextMenu="true" | ||
| 11 | @nodeItemClick="handleNodeItemClick"> | ||
| 12 | </RelationNetwork> | ||
| 13 | <Sankey v-show="!isGraphDisplay && (sankeyNames?.length || sankeyDataLoading)" v-loading="sankeyDataLoading" | ||
| 14 | :tree-data="sankeyData" :names="sankeyNames"> | ||
| 15 | </Sankey> | ||
| 16 | <div v-show="(isGraphDisplay ? !graphTreeData?.guid : (!sankeyDataLoading && !sankeyNames?.length))" | ||
| 17 | class="main-placeholder"> | ||
| 18 | <img src="../../assets/images/no-data.png" :style="{ width: '96px', height: '96px' }" /> | ||
| 19 | <div class="empty-text">暂无数据</div> | ||
| 20 | </div> | ||
| 21 | </div> | ||
| 22 | </template> | ||
| 23 | |||
| 24 | <script lang="ts" setup name="metadataStandardQueryView"> | ||
| 25 | import { | ||
| 26 | getMetaStandardField, | ||
| 27 | getSankeyData, | ||
| 28 | getMetaStandardTreeList | ||
| 29 | } from '@/api/modules/dataMetaService'; | ||
| 30 | import Sankey from './components/Sankey.vue'; | ||
| 31 | import { ElMessage } from 'element-plus'; | ||
| 32 | |||
| 33 | const router = useRouter(); | ||
| 34 | const route = useRoute() | ||
| 35 | |||
| 36 | const metaGuid = ref(route.query.guid); | ||
| 37 | |||
| 38 | const { proxy } = getCurrentInstance() as any; | ||
| 39 | |||
| 40 | const relationNetworkRef = ref(); | ||
| 41 | |||
| 42 | const graphDataLoading = ref(false); | ||
| 43 | |||
| 44 | /** 关系网树形数据 */ | ||
| 45 | const graphTreeData: any = ref({}); | ||
| 46 | |||
| 47 | onBeforeUnmount(() => { | ||
| 48 | relationNetworkRef.value.destroy(); | ||
| 49 | }) | ||
| 50 | |||
| 51 | const sankeyDataLoading = ref(false); | ||
| 52 | |||
| 53 | const sankeyData: any = ref([]); | ||
| 54 | |||
| 55 | const sankeyNames: any = ref([]); | ||
| 56 | |||
| 57 | const isGraphDisplay = ref(true); | ||
| 58 | |||
| 59 | const displaySwitchChange = (val) => { | ||
| 60 | if (val == isGraphDisplay.value) { | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | isGraphDisplay.value = val; | ||
| 64 | if (!val) { | ||
| 65 | getSankeyDataList(); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | const getSankeyDataList = () => { | ||
| 70 | sankeyDataLoading.value = true; | ||
| 71 | getSankeyData(metaGuid.value).then((res: any) => { | ||
| 72 | sankeyDataLoading.value = false; | ||
| 73 | if (res?.code == proxy.$passCode) { | ||
| 74 | sankeyData.value = res.data?.links || []; | ||
| 75 | sankeyNames.value = res.data?.data || []; | ||
| 76 | } else { | ||
| 77 | ElMessage.error(res.msg); | ||
| 78 | } | ||
| 79 | }) | ||
| 80 | } | ||
| 81 | |||
| 82 | const handleNodeItemClick = (graph, nodeItem) => { | ||
| 83 | const nodeId = nodeItem.get('id'); | ||
| 84 | const parentData = graph.findDataById(nodeId); | ||
| 85 | if (!parentData.children) { | ||
| 86 | parentData.children = []; | ||
| 87 | } | ||
| 88 | if (parentData.isHaveData == 'N') { | ||
| 89 | ElMessage.warning('没有可展开的下级字段'); | ||
| 90 | return; | ||
| 91 | } | ||
| 92 | graphDataLoading.value = true; | ||
| 93 | getMetaStandardField(nodeId).then((res: any) => { | ||
| 94 | graphDataLoading.value = false; | ||
| 95 | if (res?.code == proxy.$passCode) { | ||
| 96 | const data = res.data || []; | ||
| 97 | parentData.children = []; | ||
| 98 | if (!data?.length) { | ||
| 99 | parentData.isHaveData = 'N'; | ||
| 100 | ElMessage.warning('没有可展开的下级字段'); | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | data.forEach(d => { | ||
| 104 | parentData.children.push(d); | ||
| 105 | }) | ||
| 106 | parentData.collapsed = false; | ||
| 107 | setTimeout(() => { | ||
| 108 | parentData.isLoading = false; | ||
| 109 | graph.setMaxZoom(1); | ||
| 110 | graph.changeData(graphTreeData.value); | ||
| 111 | graph.setMaxZoom(5); | ||
| 112 | }, 100); | ||
| 113 | } else { | ||
| 114 | parentData.isLoading = false; | ||
| 115 | ElMessage.error(res.msg); | ||
| 116 | } | ||
| 117 | }) | ||
| 118 | } | ||
| 119 | |||
| 120 | onBeforeMount(() => { | ||
| 121 | graphDataLoading.value = true | ||
| 122 | getMetaStandardTreeList(metaGuid.value).then((res: any) => { | ||
| 123 | graphDataLoading.value = false; | ||
| 124 | if (res?.code == proxy.$passCode) { | ||
| 125 | const data = res.data || []; | ||
| 126 | graphTreeData.value = data?.[0] || {}; | ||
| 127 | } else { | ||
| 128 | ElMessage.error(res.msg); | ||
| 129 | } | ||
| 130 | }) | ||
| 131 | }) | ||
| 132 | |||
| 133 | </script> | ||
| 134 | |||
| 135 | <style lang="scss" scoped> | ||
| 136 | .main_wrap { | ||
| 137 | height: 100%; | ||
| 138 | width: 100%; | ||
| 139 | position: relative; | ||
| 140 | |||
| 141 | :deep(.canvas-wrapper) { | ||
| 142 | background-color: #f7f7f9; | ||
| 143 | } | ||
| 144 | |||
| 145 | .main-placeholder { | ||
| 146 | height: 100%; | ||
| 147 | display: flex; | ||
| 148 | justify-content: center; | ||
| 149 | align-items: center; | ||
| 150 | flex-direction: column; | ||
| 151 | |||
| 152 | .empty-text { | ||
| 153 | font-size: 14px; | ||
| 154 | color: #b2b2b2; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | .g6-component-topbar { | ||
| 160 | position: absolute; | ||
| 161 | left: 24px; | ||
| 162 | bottom: unset; | ||
| 163 | top: 14px; | ||
| 164 | padding: 0; | ||
| 165 | text-align: center; | ||
| 166 | z-index: 999; | ||
| 167 | } | ||
| 168 | </style> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -9,16 +9,17 @@ import Sankey from './components/Sankey.vue'; | ... | @@ -9,16 +9,17 @@ import Sankey from './components/Sankey.vue'; |
| 9 | import Tree from '@/components/Tree/index.vue'; | 9 | import Tree from '@/components/Tree/index.vue'; |
| 10 | import RelationNetwork from '@/components/RelationNetwork/index.vue'; | 10 | import RelationNetwork from '@/components/RelationNetwork/index.vue'; |
| 11 | import { | 11 | import { |
| 12 | getMetaStandardTreeList, | ||
| 13 | getMetaStandardField, | ||
| 14 | getSankeyData | ||
| 12 | } from '@/api/modules/dataMetaService'; | 15 | } from '@/api/modules/dataMetaService'; |
| 13 | |||
| 14 | import { useRouter, useRoute } from "vue-router"; | 16 | import { useRouter, useRoute } from "vue-router"; |
| 15 | import useDataMetaStore from "@/store/modules/dataMeta" | 17 | import useDataMetaStore from "@/store/modules/dataMeta" |
| 18 | import { cloneDeep } from 'lodash-es'; | ||
| 16 | 19 | ||
| 17 | const router = useRouter(); | 20 | const router = useRouter(); |
| 18 | const route = useRoute() | 21 | const route = useRoute() |
| 19 | 22 | ||
| 20 | const switchGraphDisplay = ref(true); //true表示关系网,false表示桑基图 | ||
| 21 | |||
| 22 | const { proxy } = getCurrentInstance() as any; | 23 | const { proxy } = getCurrentInstance() as any; |
| 23 | 24 | ||
| 24 | const relationNetworkRef = ref(); | 25 | const relationNetworkRef = ref(); |
| ... | @@ -27,14 +28,14 @@ const treeInfo = ref({ | ... | @@ -27,14 +28,14 @@ const treeInfo = ref({ |
| 27 | id: "data-meta-standard-tree", | 28 | id: "data-meta-standard-tree", |
| 28 | filter: true, | 29 | filter: true, |
| 29 | queryValue: "", | 30 | queryValue: "", |
| 30 | queryPlaceholder: "输入库/表名称搜索", | 31 | queryPlaceholder: "请输入关键字搜索", |
| 31 | props: { | 32 | props: { |
| 32 | label: "name", | 33 | label: "standardName", |
| 33 | value: "guid", | 34 | value: "guid", |
| 34 | isLeaf: "isLeaf", | 35 | isLeaf: "isLeaf", |
| 35 | }, | 36 | }, |
| 36 | nodeKey: 'guid', | 37 | nodeKey: 'guid', |
| 37 | expandedKey: ['1'], | 38 | expandedKey: [], |
| 38 | currentNodeKey: '', | 39 | currentNodeKey: '', |
| 39 | expandOnNodeClick: false, | 40 | expandOnNodeClick: false, |
| 40 | data: <any>[], | 41 | data: <any>[], |
| ... | @@ -44,51 +45,20 @@ const treeInfo = ref({ | ... | @@ -44,51 +45,20 @@ const treeInfo = ref({ |
| 44 | /** 获取左侧树数据. */ | 45 | /** 获取左侧树数据. */ |
| 45 | const getTreeData = async () => { | 46 | const getTreeData = async () => { |
| 46 | treeInfo.value.loading = true | 47 | treeInfo.value.loading = true |
| 47 | // let params = {} | 48 | getMetaStandardTreeList('').then((res: any) => { |
| 48 | // const res: any = await getMetaTreeData(params) | 49 | treeInfo.value.loading = false; |
| 49 | // if (res.code == proxy.$passCode) { | 50 | if (res?.code == proxy.$passCode) { |
| 50 | // const data = res.data || []; | 51 | const data = res.data || []; |
| 51 | // let treeData: any = Object.keys(data).length ? [data] : []; | 52 | treeInfo.value.data = data; |
| 52 | // treeInfo.value.data = treeData; | 53 | if (data.length) { |
| 53 | // allTreeData.value = treeData; | 54 | treeInfo.value.currentNodeKey = data[0].guid; |
| 54 | // if (treeData.length) { | 55 | treeInfo.value.expandedKey = <any>[data[0].guid]; |
| 55 | // treeInfo.value.currentNodeKey = treeData[0].guid; | ||
| 56 | // treeInfo.value.expandedKey = <any>[treeData[0].guid]; | ||
| 57 | // } | ||
| 58 | // } else { | ||
| 59 | // ElMessage.error(res.msg); | ||
| 60 | // } | ||
| 61 | treeInfo.value.data = [{ | ||
| 62 | guid: '1', | ||
| 63 | name: '第一级1', | ||
| 64 | children: [{ | ||
| 65 | guid: '1-1', | ||
| 66 | name: '第二级1-1', | ||
| 67 | children: [{ | ||
| 68 | guid: '1-1-1', | ||
| 69 | name: '第三级1-1-1' | ||
| 70 | }] | ||
| 71 | }, { | ||
| 72 | guid: '1-2', | ||
| 73 | name: '第二级1-2' | ||
| 74 | }, { | ||
| 75 | guid: '1-3', | ||
| 76 | name: '第二级1-3' | ||
| 77 | }] | ||
| 78 | }, { | ||
| 79 | guid: '2', | ||
| 80 | name: '第一级2', | ||
| 81 | children: [{ | ||
| 82 | guid: '2-1', | ||
| 83 | name: '第二级1-1' | ||
| 84 | }, { | ||
| 85 | guid: '2-2', | ||
| 86 | name: '第二级1-2' | ||
| 87 | }] | ||
| 88 | }]; | ||
| 89 | treeInfo.value.loading = false | ||
| 90 | treeInfo.value.currentNodeKey = '1'; | ||
| 91 | nodeClick(treeInfo.value.data[0]) | 56 | nodeClick(treeInfo.value.data[0]) |
| 57 | } | ||
| 58 | } else { | ||
| 59 | ElMessage.error(res.msg); | ||
| 60 | } | ||
| 61 | }) | ||
| 92 | } | 62 | } |
| 93 | /** 左侧树的的组件引用. */ | 63 | /** 左侧树的的组件引用. */ |
| 94 | const treeInfoRef = ref(); | 64 | const treeInfoRef = ref(); |
| ... | @@ -98,22 +68,18 @@ const lastClickNode: any = ref({}); | ... | @@ -98,22 +68,18 @@ const lastClickNode: any = ref({}); |
| 98 | 68 | ||
| 99 | const treeDataLoading = ref(false); | 69 | const treeDataLoading = ref(false); |
| 100 | 70 | ||
| 101 | /** 数据血缘关系图组件 */ | ||
| 102 | const lineageGraph: any = ref(); | ||
| 103 | |||
| 104 | /** 点击左侧树节点,更新对应的血缘关系图. */ | 71 | /** 点击左侧树节点,更新对应的血缘关系图. */ |
| 105 | const nodeClick = (data) => { | 72 | const nodeClick = (data) => { |
| 106 | console.log(data); | ||
| 107 | const ele = <HTMLElement>document.querySelector(".g6-component-contextmenu") | 73 | const ele = <HTMLElement>document.querySelector(".g6-component-contextmenu") |
| 108 | if (ele) { | 74 | if (ele) { |
| 109 | ele.style.display = "none" | 75 | ele.style.display = "none" |
| 110 | } | 76 | } |
| 111 | nextTick(() => { | ||
| 112 | lineageGraph.value?.tooltip1.hide() | ||
| 113 | }) | ||
| 114 | treeInfo.value.currentNodeKey = data.guid; | 77 | treeInfo.value.currentNodeKey = data.guid; |
| 115 | treeInfo.value.expandedKey = <any>[data.guid]; | 78 | treeInfo.value.expandedKey = <any>[data.guid]; |
| 116 | lastClickNode.value = data; | 79 | lastClickNode.value = cloneDeep(data); |
| 80 | if (!isGraphDisplay.value) { | ||
| 81 | getSankeyDataList(); | ||
| 82 | } | ||
| 117 | } | 83 | } |
| 118 | 84 | ||
| 119 | /** 选中树节点后自动滚动到可视范围内. */ | 85 | /** 选中树节点后自动滚动到可视范围内. */ |
| ... | @@ -145,7 +111,6 @@ const processRouter = () => { | ... | @@ -145,7 +111,6 @@ const processRouter = () => { |
| 145 | treeInfo.value.expandedKey = <any>[databaseGuid, guid]; | 111 | treeInfo.value.expandedKey = <any>[databaseGuid, guid]; |
| 146 | lastClickNode.value = { guid: guid, tableName, databaseName, type: 3, databaseChName }; | 112 | lastClickNode.value = { guid: guid, tableName, databaseName, type: 3, databaseChName }; |
| 147 | scrollToNode(guid); | 113 | scrollToNode(guid); |
| 148 | switchGraphDisplay.value = isFL; | ||
| 149 | // if (isFL) { | 114 | // if (isFL) { |
| 150 | // getAllTableFieldLineageMap(); | 115 | // getAllTableFieldLineageMap(); |
| 151 | // } else { | 116 | // } else { |
| ... | @@ -156,20 +121,45 @@ const processRouter = () => { | ... | @@ -156,20 +121,45 @@ const processRouter = () => { |
| 156 | } | 121 | } |
| 157 | 122 | ||
| 158 | onActivated(() => { | 123 | onActivated(() => { |
| 159 | processRouter(); | 124 | //processRouter(); |
| 160 | }); | 125 | }); |
| 161 | 126 | ||
| 162 | onBeforeMount(async () => { | 127 | onBeforeMount(async () => { |
| 163 | await getTreeData() | 128 | await getTreeData() |
| 164 | processRouter(); | 129 | // processRouter(); |
| 165 | }) | 130 | }) |
| 166 | 131 | ||
| 167 | onMounted(() => { }) | 132 | onMounted(() => { }) |
| 168 | 133 | ||
| 134 | const sankeyDataLoading = ref(false); | ||
| 135 | |||
| 136 | const sankeyData: any = ref([]); | ||
| 137 | |||
| 138 | const sankeyNames: any = ref([]); | ||
| 139 | |||
| 169 | const isGraphDisplay = ref(true); | 140 | const isGraphDisplay = ref(true); |
| 170 | 141 | ||
| 171 | const displaySwitchChange = (val) => { | 142 | const displaySwitchChange = (val) => { |
| 143 | if (val == isGraphDisplay.value) { | ||
| 144 | return; | ||
| 145 | } | ||
| 172 | isGraphDisplay.value = val; | 146 | isGraphDisplay.value = val; |
| 147 | if (!val) { | ||
| 148 | getSankeyDataList(); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | const getSankeyDataList = () => { | ||
| 153 | sankeyDataLoading.value = true; | ||
| 154 | getSankeyData(lastClickNode.value.guid).then((res: any) => { | ||
| 155 | sankeyDataLoading.value = false; | ||
| 156 | if (res?.code == proxy.$passCode) { | ||
| 157 | sankeyData.value = res.data?.links || []; | ||
| 158 | sankeyNames.value = res.data?.data || []; | ||
| 159 | } else { | ||
| 160 | ElMessage.error(res.msg); | ||
| 161 | } | ||
| 162 | }) | ||
| 173 | } | 163 | } |
| 174 | 164 | ||
| 175 | const handleNodeItemClick = (graph, nodeItem) => { | 165 | const handleNodeItemClick = (graph, nodeItem) => { |
| ... | @@ -178,35 +168,41 @@ const handleNodeItemClick = (graph, nodeItem) => { | ... | @@ -178,35 +168,41 @@ const handleNodeItemClick = (graph, nodeItem) => { |
| 178 | if (!parentData.children) { | 168 | if (!parentData.children) { |
| 179 | parentData.children = []; | 169 | parentData.children = []; |
| 180 | } | 170 | } |
| 171 | if (parentData.noData) { | ||
| 172 | ElMessage.warning('没有可展开的下级字段'); | ||
| 173 | return; | ||
| 174 | } | ||
| 181 | treeDataLoading.value = true; | 175 | treeDataLoading.value = true; |
| 182 | let childData = [{ | 176 | getMetaStandardField(nodeId).then((res: any) => { |
| 183 | guid: '33', | ||
| 184 | isField: true, | ||
| 185 | name: '字段1' | ||
| 186 | }, { | ||
| 187 | guid: '44', | ||
| 188 | isField: true, | ||
| 189 | name: '字段2字段2字段2字段2字段2字段2字段2字段2字段2xx2字段22字段22字段22字段22字段22字段2' | ||
| 190 | }, { | ||
| 191 | guid: '55', | ||
| 192 | isField: true, | ||
| 193 | name: '字段3' | ||
| 194 | }] | ||
| 195 | // parentData.collapsed = true; | ||
| 196 | // nodeItem.getModel().collapsed = true; | ||
| 197 | parentData.children = childData; | ||
| 198 | setTimeout(() => { | ||
| 199 | treeDataLoading.value = false; | 177 | treeDataLoading.value = false; |
| 200 | graph.changeData(); | 178 | if (res?.code == proxy.$passCode) { |
| 201 | // parentData.collapsed = true; | 179 | const data = res.data || []; |
| 202 | // graph.updateChildren(childData, parentData.id); | 180 | parentData.children = []; |
| 203 | // graph.changeData(lastClickNode.value); | 181 | if (!data?.length) { |
| 204 | //graph.data(lastClickNode.value); | 182 | parentData.noData = true; |
| 205 | }, 2000) | 183 | ElMessage.warning('没有可展开的下级字段'); |
| 184 | return; | ||
| 185 | } | ||
| 186 | data.forEach(d => { | ||
| 187 | parentData.children.push(d); | ||
| 188 | }) | ||
| 189 | parentData.collapsed = false; | ||
| 190 | setTimeout(() => { | ||
| 191 | parentData.isLoading = false; | ||
| 192 | graph.setMaxZoom(1); | ||
| 193 | graph.changeData(lastClickNode.value); | ||
| 194 | graph.setMaxZoom(5); | ||
| 195 | }, 100); | ||
| 196 | } else { | ||
| 197 | parentData.isLoading = false; | ||
| 198 | ElMessage.error(res.msg); | ||
| 199 | } | ||
| 200 | }) | ||
| 206 | } | 201 | } |
| 207 | 202 | ||
| 208 | const handleContextMenu = (nodeData) => { | 203 | const handleContextMenu = (nodeData) => { |
| 209 | //TODO,新建引用数据集 | 204 | //TODO,新建引用数据集 |
| 205 | window.open(''); | ||
| 210 | } | 206 | } |
| 211 | 207 | ||
| 212 | onBeforeUnmount(() => { | 208 | onBeforeUnmount(() => { |
| ... | @@ -218,21 +214,23 @@ onBeforeUnmount(() => { | ... | @@ -218,21 +214,23 @@ onBeforeUnmount(() => { |
| 218 | <template> | 214 | <template> |
| 219 | <div class="container_wrap full flex"> | 215 | <div class="container_wrap full flex"> |
| 220 | <div class="aside_wrap"> | 216 | <div class="aside_wrap"> |
| 221 | <div class="aside_title">数据库目录列表</div> | 217 | <div class="aside_title">元数据标准列表</div> |
| 222 | <Tree ref="treeInfoRef" :treeInfo="treeInfo" @nodeClick="nodeClick" /> | 218 | <Tree ref="treeInfoRef" :treeInfo="treeInfo" @nodeClick="nodeClick" /> |
| 223 | </div> | 219 | </div> |
| 224 | <div class="main_wrap"> | 220 | <div class="main_wrap"> |
| 225 | <div className='g6-component-topbar'> | 221 | <div className='g6-component-topbar'> |
| 226 | <graphTopbar ref="topBarRef" @displaySwitchChange="displaySwitchChange" :isGraphDisplay="isGraphDisplay" /> | 222 | <graphTopbar ref="topBarRef" @displaySwitchChange="displaySwitchChange" :isGraphDisplay="isGraphDisplay" /> |
| 227 | </div> | 223 | </div> |
| 228 | <RelationNetwork v-show="isGraphDisplay" ref="relationNetworkRef" :tree-data="lastClickNode" | 224 | <RelationNetwork v-show="lastClickNode?.guid && isGraphDisplay" ref="relationNetworkRef" |
| 229 | v-loading="treeDataLoading" @nodeItemClick="handleNodeItemClick" @contextMenu="handleContextMenu"> | 225 | :tree-data="lastClickNode" v-loading="treeDataLoading" @nodeItemClick="handleNodeItemClick" |
| 226 | @contextMenu="handleContextMenu"> | ||
| 230 | </RelationNetwork> | 227 | </RelationNetwork> |
| 231 | <Sankey v-show="!isGraphDisplay"></Sankey> | 228 | <Sankey v-show="lastClickNode?.guid && !isGraphDisplay && (sankeyNames?.length || sankeyDataLoading)" v-loading="sankeyDataLoading" :tree-data="sankeyData" :names="sankeyNames"> |
| 232 | <!-- <div v-show="lastClickNode && lastClickNode?.type !== 3 && lastClickNode?.type !== 4" class="main-placeholder"> | 229 | </Sankey> |
| 230 | <div v-show="!lastClickNode?.guid && !treeInfo.data?.length || (!isGraphDisplay && !sankeyDataLoading && !sankeyNames?.length)" class="main-placeholder"> | ||
| 233 | <img src="../../assets/images/no-data.png" :style="{ width: '96px', height: '96px' }" /> | 231 | <img src="../../assets/images/no-data.png" :style="{ width: '96px', height: '96px' }" /> |
| 234 | <div class="empty-text">暂无标准数据</div> | 232 | <div class="empty-text">暂无数据</div> |
| 235 | </div> --> | 233 | </div> |
| 236 | </div> | 234 | </div> |
| 237 | </div> | 235 | </div> |
| 238 | </template> | 236 | </template> | ... | ... |
| ... | @@ -416,6 +416,17 @@ function exportData () { | ... | @@ -416,6 +416,17 @@ function exportData () { |
| 416 | onBeforeMount(() => { | 416 | onBeforeMount(() => { |
| 417 | getTree() | 417 | getTree() |
| 418 | }) | 418 | }) |
| 419 | |||
| 420 | const viewGraph = () => { | ||
| 421 | router.push({ | ||
| 422 | name: 'metadataStandardQueryView', | ||
| 423 | query: { | ||
| 424 | guid: treeInfo.value.currentObj?.guid, | ||
| 425 | name: treeInfo.value.currentObj?.standardName, | ||
| 426 | } | ||
| 427 | }); | ||
| 428 | } | ||
| 429 | |||
| 419 | </script> | 430 | </script> |
| 420 | 431 | ||
| 421 | <template> | 432 | <template> | ... | ... |
-
Please register or sign in to post a comment