forked from github/dataease
feat(xpack): 血缘分析
This commit is contained in:
parent
f2ec5a2c0d
commit
f07f00aa56
@ -120,6 +120,12 @@ export const delDatasetTree = async (id): Promise<IResponse> => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const perDelete = async (id): Promise<boolean> => {
|
||||||
|
return request.post({ url: `/datasetTree/perDelete/${id}`, data: {} }).then(res => {
|
||||||
|
return res?.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const getDatasourceList = async (): Promise<IResponse> => {
|
export const getDatasourceList = async (): Promise<IResponse> => {
|
||||||
return request.post({ url: '/datasource/tree', data: { busiFlag: 'datasource' } }).then(res => {
|
return request.post({ url: '/datasource/tree', data: { busiFlag: 'datasource' } }).then(res => {
|
||||||
return res?.data
|
return res?.data
|
||||||
|
@ -91,6 +91,12 @@ export const save = async (data = {}): Promise<Dataset> => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const perDeleteDatasource = async (id): Promise<boolean> => {
|
||||||
|
return request.post({ url: `/datasource//perDelete/${id}`, data: {} }).then(res => {
|
||||||
|
return res?.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const update = async (data = {}): Promise<Dataset> => {
|
export const update = async (data = {}): Promise<Dataset> => {
|
||||||
return request.post({ url: '/datasource/update', data }).then(res => {
|
return request.post({ url: '/datasource/update', data }).then(res => {
|
||||||
return res?.data
|
return res?.data
|
||||||
|
127
core/core-frontend/src/components/relation-chart/index.vue
Normal file
127
core/core-frontend/src/components/relation-chart/index.vue
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive, nextTick } from 'vue'
|
||||||
|
import { XpackComponent } from '@/components/plugin'
|
||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
import {
|
||||||
|
getDatasourceRelationship as getDatasourceRelation,
|
||||||
|
getDatasetRelationship as getDatasetRelation
|
||||||
|
} from '@/api/relation/index'
|
||||||
|
const relationDrawer = ref(false)
|
||||||
|
const chartSize = reactive({
|
||||||
|
height: 0,
|
||||||
|
width: 0
|
||||||
|
})
|
||||||
|
const getChartSize = () => {
|
||||||
|
const dom = document.querySelector('.relation-drawer_content')
|
||||||
|
if (!dom) return
|
||||||
|
Object.assign(chartSize, {
|
||||||
|
height: dom.offsetHeight + 'px',
|
||||||
|
width: dom.offsetWidth + 'px'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const consanguinity = ref()
|
||||||
|
let resRef = null
|
||||||
|
const getDatasourceRelationship = id => {
|
||||||
|
getDatasourceRelation(id)
|
||||||
|
.then(res => {
|
||||||
|
resRef = cloneDeep(res || {})
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
tableLoading.value = false
|
||||||
|
nextTick(() => {
|
||||||
|
consanguinity.value.invokeMethod({
|
||||||
|
methodName: 'getChartData',
|
||||||
|
args: {
|
||||||
|
info: current,
|
||||||
|
res: resRef
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getDatasetRelationship = id => {
|
||||||
|
getDatasetRelation(id)
|
||||||
|
.then(res => {
|
||||||
|
resRef = cloneDeep(res || {})
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
tableLoading.value = false
|
||||||
|
nextTick(() => {
|
||||||
|
consanguinity.value.invokeMethod({
|
||||||
|
methodName: 'getChartData',
|
||||||
|
args: {
|
||||||
|
info: current,
|
||||||
|
res: resRef
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const current = {
|
||||||
|
queryType: '',
|
||||||
|
num: '',
|
||||||
|
label: ''
|
||||||
|
}
|
||||||
|
const tableLoading = ref(false)
|
||||||
|
const getChartData = obj => {
|
||||||
|
Object.assign(current, obj || {})
|
||||||
|
const { queryType, num } = current
|
||||||
|
tableLoading.value = true
|
||||||
|
relationDrawer.value = true
|
||||||
|
nextTick(() => {
|
||||||
|
getChartSize()
|
||||||
|
switch (queryType) {
|
||||||
|
case 'datasource':
|
||||||
|
getDatasourceRelationship(num)
|
||||||
|
break
|
||||||
|
case 'dataset':
|
||||||
|
getDatasetRelationship(num)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
getChartData
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
title="血缘关系图"
|
||||||
|
v-model="relationDrawer"
|
||||||
|
custom-class="de-relation-drawer"
|
||||||
|
size="1200px"
|
||||||
|
direction="rtl"
|
||||||
|
>
|
||||||
|
<div v-loading="tableLoading" class="relation-drawer_content">
|
||||||
|
<XpackComponent
|
||||||
|
ref="consanguinity"
|
||||||
|
:chart-size="chartSize"
|
||||||
|
:current="current"
|
||||||
|
detailDisabled
|
||||||
|
jsname="L21lbnUvc3lzdGVtL2Fzc29jaWF0aW9uL0NoYXJ0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.de-relation-drawer {
|
||||||
|
.ed-drawer__body {
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
.relation-drawer_content {
|
||||||
|
border: 1px solid #dee0e3;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #f5f6f7;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,11 +1,13 @@
|
|||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { ref, reactive, shallowRef, computed, watch, onBeforeMount, nextTick, unref } from 'vue'
|
import { ref, reactive, shallowRef, computed, watch, onBeforeMount, nextTick, unref, h } from 'vue'
|
||||||
import ArrowSide from '@/views/common/DeResourceArrow.vue'
|
import ArrowSide from '@/views/common/DeResourceArrow.vue'
|
||||||
import { useEmbedded } from '@/store/modules/embedded'
|
import { useEmbedded } from '@/store/modules/embedded'
|
||||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||||
|
import relationChart from '@/components/relation-chart/index.vue'
|
||||||
import {
|
import {
|
||||||
ElIcon,
|
ElIcon,
|
||||||
|
ElButton,
|
||||||
ElMessageBox,
|
ElMessageBox,
|
||||||
ElMessage,
|
ElMessage,
|
||||||
type ElMessageBoxOptions,
|
type ElMessageBoxOptions,
|
||||||
@ -18,7 +20,7 @@ import { useMoveLine } from '@/hooks/web/useMoveLine'
|
|||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import CreatDsGroup from './form/CreatDsGroup.vue'
|
import CreatDsGroup from './form/CreatDsGroup.vue'
|
||||||
import type { BusiTreeNode, BusiTreeRequest } from '@/models/tree/TreeNode'
|
import type { BusiTreeNode, BusiTreeRequest } from '@/models/tree/TreeNode'
|
||||||
import { delDatasetTree, getDatasetPreview, barInfoApi } from '@/api/dataset'
|
import { delDatasetTree, getDatasetPreview, barInfoApi, perDelete } from '@/api/dataset'
|
||||||
import EmptyBackground from '@/components/empty-background/src/EmptyBackground.vue'
|
import EmptyBackground from '@/components/empty-background/src/EmptyBackground.vue'
|
||||||
import DeResourceGroupOpt from '@/views/common/DeResourceGroupOpt.vue'
|
import DeResourceGroupOpt from '@/views/common/DeResourceGroupOpt.vue'
|
||||||
import DatasetDetail from './DatasetDetail.vue'
|
import DatasetDetail from './DatasetDetail.vue'
|
||||||
@ -352,7 +354,7 @@ const handleClick = (tabName: TabPaneName) => {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const relationChartRef = ref()
|
||||||
const operation = (cmd: string, data: BusiTreeNode, nodeType: string) => {
|
const operation = (cmd: string, data: BusiTreeNode, nodeType: string) => {
|
||||||
if (cmd === 'copy') {
|
if (cmd === 'copy') {
|
||||||
if (isDataEaseBi.value) {
|
if (isDataEaseBi.value) {
|
||||||
@ -384,17 +386,65 @@ const operation = (cmd: string, data: BusiTreeNode, nodeType: string) => {
|
|||||||
delete options.tip
|
delete options.tip
|
||||||
}
|
}
|
||||||
|
|
||||||
ElMessageBox.confirm(
|
if (nodeType !== 'folder') {
|
||||||
nodeType === 'folder'
|
perDelete(data.id).then(res => {
|
||||||
? t('data_set.delete_this_folder')
|
if (res === true) {
|
||||||
: t('datasource.delete_this_dataset'),
|
const onClick = () => {
|
||||||
options as ElMessageBoxOptions
|
relationChartRef.value.getChartData({
|
||||||
).then(() => {
|
queryType: 'dataset',
|
||||||
delDatasetTree(data.id).then(() => {
|
num: data.id,
|
||||||
getData()
|
label: data.name
|
||||||
ElMessage.success(t('dataset.delete_success'))
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessageBox.confirm('', {
|
||||||
|
confirmButtonType: 'danger',
|
||||||
|
type: 'warning',
|
||||||
|
autofocus: false,
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
showClose: false,
|
||||||
|
dangerouslyUseHTMLString: true,
|
||||||
|
message: h('div', null, [
|
||||||
|
h('p', { style: 'margin-bottom: 8px;' }, '确定删除该数据集吗?'),
|
||||||
|
h(
|
||||||
|
'p',
|
||||||
|
{ class: 'tip' },
|
||||||
|
'该数据集存在如下血缘关系,删除会造成相关仪表板的视图失效,确定删除?'
|
||||||
|
),
|
||||||
|
h(
|
||||||
|
ElButton,
|
||||||
|
{ text: true, onClick: onClick, style: 'margin-left: -4px;' },
|
||||||
|
'查看血缘关系'
|
||||||
|
)
|
||||||
|
])
|
||||||
|
}).then(() => {
|
||||||
|
delDatasetTree(data.id).then(() => {
|
||||||
|
getData()
|
||||||
|
ElMessage.success(t('dataset.delete_success'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessageBox.confirm(
|
||||||
|
t('datasource.delete_this_dataset'),
|
||||||
|
options as ElMessageBoxOptions
|
||||||
|
).then(() => {
|
||||||
|
delDatasetTree(data.id).then(() => {
|
||||||
|
getData()
|
||||||
|
ElMessage.success(t('dataset.delete_success'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
} else {
|
||||||
|
ElMessageBox.confirm(t('data_set.delete_this_folder'), options as ElMessageBoxOptions).then(
|
||||||
|
() => {
|
||||||
|
delDatasetTree(data.id).then(() => {
|
||||||
|
getData()
|
||||||
|
ElMessage.success(t('dataset.delete_success'))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
creatDsFolder.value.createInit(nodeType, data, cmd)
|
creatDsFolder.value.createInit(nodeType, data, cmd)
|
||||||
}
|
}
|
||||||
@ -846,6 +896,7 @@ const getMenuList = (val: boolean) => {
|
|||||||
<empty-background :description="t('deDataset.on_the_left')" img-type="select" />
|
<empty-background :description="t('deDataset.on_the_left')" img-type="select" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
<relationChart ref="relationChartRef"></relationChart>
|
||||||
<de-resource-group-opt
|
<de-resource-group-opt
|
||||||
:cur-canvas-type="curCanvasType"
|
:cur-canvas-type="curCanvasType"
|
||||||
@finish="resourceOptFinish"
|
@finish="resourceOptFinish"
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { computed, unref, reactive, ref, shallowRef, nextTick, watch, onMounted } from 'vue'
|
import { computed, h, unref, reactive, ref, shallowRef, nextTick, watch, onMounted } from 'vue'
|
||||||
import { dsTypes } from '@/views/visualized/data/datasource/form/option'
|
import { dsTypes } from '@/views/visualized/data/datasource/form/option'
|
||||||
import type { TabPaneName, ElMessageBoxOptions } from 'element-plus-secondary'
|
import type { TabPaneName, ElMessageBoxOptions } from 'element-plus-secondary'
|
||||||
import { ElIcon, ElMessageBox, ElMessage, ElScrollbar, ElAside } from 'element-plus-secondary'
|
import {
|
||||||
|
ElIcon,
|
||||||
|
ElButton,
|
||||||
|
ElMessageBox,
|
||||||
|
ElMessage,
|
||||||
|
ElScrollbar,
|
||||||
|
ElAside
|
||||||
|
} from 'element-plus-secondary'
|
||||||
import GridTable from '@/components/grid-table/src/GridTable.vue'
|
import GridTable from '@/components/grid-table/src/GridTable.vue'
|
||||||
import ArrowSide from '@/views/common/DeResourceArrow.vue'
|
import ArrowSide from '@/views/common/DeResourceArrow.vue'
|
||||||
|
import relationChart from '@/components/relation-chart/index.vue'
|
||||||
import { HandleMore } from '@/components/handle-more'
|
import { HandleMore } from '@/components/handle-more'
|
||||||
import { Icon } from '@/components/icon-custom'
|
import { Icon } from '@/components/icon-custom'
|
||||||
import { fieldType } from '@/utils/attr'
|
import { fieldType } from '@/utils/attr'
|
||||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||||
import { getHidePwById, listSyncRecord, uploadFile } from '@/api/datasource'
|
import { getHidePwById, listSyncRecord, uploadFile, perDeleteDatasource } from '@/api/datasource'
|
||||||
import CreatDsGroup from './form/CreatDsGroup.vue'
|
import CreatDsGroup from './form/CreatDsGroup.vue'
|
||||||
import type { Tree } from '../dataset/form/CreatDsGroup.vue'
|
import type { Tree } from '../dataset/form/CreatDsGroup.vue'
|
||||||
import { previewData, getById } from '@/api/datasource'
|
import { previewData, getById } from '@/api/datasource'
|
||||||
@ -738,6 +746,7 @@ const handleDatasourceTree = (cmd: string, data?: Tree) => {
|
|||||||
creatDsFolder.value.createInit(cmd, data || {})
|
creatDsFolder.value.createInit(cmd, data || {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const relationChartRef = ref()
|
||||||
const operation = (cmd: string, data: Tree, nodeType: string) => {
|
const operation = (cmd: string, data: Tree, nodeType: string) => {
|
||||||
if (cmd === 'copy') {
|
if (cmd === 'copy') {
|
||||||
handleCopy(data)
|
handleCopy(data)
|
||||||
@ -758,18 +767,69 @@ const operation = (cmd: string, data: Tree, nodeType: string) => {
|
|||||||
} else {
|
} else {
|
||||||
delete options.tip
|
delete options.tip
|
||||||
}
|
}
|
||||||
ElMessageBox.confirm(
|
|
||||||
nodeType === 'folder' ? '确定删除该文件夹吗' : t('datasource.this_data_source'),
|
if (nodeType !== 'folder') {
|
||||||
options as ElMessageBoxOptions
|
perDeleteDatasource(data.id).then(res => {
|
||||||
).then(() => {
|
if (res === true) {
|
||||||
deleteById(data.id as number).then(() => {
|
const onClick = () => {
|
||||||
if (data.id === nodeInfo.id) {
|
relationChartRef.value.getChartData({
|
||||||
Object.assign(nodeInfo, cloneDeep(defaultInfo))
|
queryType: 'datasource',
|
||||||
|
num: data.id,
|
||||||
|
label: data.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessageBox.confirm('', {
|
||||||
|
confirmButtonType: 'danger',
|
||||||
|
type: 'warning',
|
||||||
|
autofocus: false,
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
showClose: false,
|
||||||
|
dangerouslyUseHTMLString: true,
|
||||||
|
message: h('div', null, [
|
||||||
|
h('p', { style: 'margin-bottom: 8px;' }, '确定删除该数据源吗?'),
|
||||||
|
h('p', { class: 'tip' }, '有数据集正在使用此数据源,删除后数据集不可用,确认删除?'),
|
||||||
|
h(
|
||||||
|
ElButton,
|
||||||
|
{ text: true, onClick: onClick, style: 'margin-left: -4px;' },
|
||||||
|
'查看血缘关系'
|
||||||
|
)
|
||||||
|
])
|
||||||
|
}).then(() => {
|
||||||
|
deleteById(data.id as number).then(() => {
|
||||||
|
if (data.id === nodeInfo.id) {
|
||||||
|
Object.assign(nodeInfo, cloneDeep(defaultInfo))
|
||||||
|
}
|
||||||
|
listDs()
|
||||||
|
ElMessage.success(t('dataset.delete_success'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessageBox.confirm(
|
||||||
|
t('datasource.this_data_source'),
|
||||||
|
options as ElMessageBoxOptions
|
||||||
|
).then(() => {
|
||||||
|
deleteById(data.id as number).then(() => {
|
||||||
|
if (data.id === nodeInfo.id) {
|
||||||
|
Object.assign(nodeInfo, cloneDeep(defaultInfo))
|
||||||
|
}
|
||||||
|
listDs()
|
||||||
|
ElMessage.success(t('dataset.delete_success'))
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
listDs()
|
|
||||||
ElMessage.success(t('dataset.delete_success'))
|
|
||||||
})
|
})
|
||||||
})
|
} else {
|
||||||
|
ElMessageBox.confirm('确定删除该文件夹吗', options as ElMessageBoxOptions).then(() => {
|
||||||
|
deleteById(data.id as number).then(() => {
|
||||||
|
if (data.id === nodeInfo.id) {
|
||||||
|
Object.assign(nodeInfo, cloneDeep(defaultInfo))
|
||||||
|
}
|
||||||
|
listDs()
|
||||||
|
ElMessage.success(t('dataset.delete_success'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
creatDsFolder.value.createInit(nodeType, data, cmd)
|
creatDsFolder.value.createInit(nodeType, data, cmd)
|
||||||
}
|
}
|
||||||
@ -1661,6 +1721,7 @@ const getMenuList = (val: boolean) => {
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<relationChart ref="relationChartRef"></relationChart>
|
||||||
|
|
||||||
<XpackComponent
|
<XpackComponent
|
||||||
jsname="L2NvbXBvbmVudC9wbHVnaW5zLWhhbmRsZXIvRHNDYXRlZ29yeUhhbmRsZXI="
|
jsname="L2NvbXBvbmVudC9wbHVnaW5zLWhhbmRsZXIvRHNDYXRlZ29yeUhhbmRsZXI="
|
||||||
|
Loading…
Reference in New Issue
Block a user