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> => {
|
||||
return request.post({ url: '/datasource/tree', data: { busiFlag: 'datasource' } }).then(res => {
|
||||
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> => {
|
||||
return request.post({ url: '/datasource/update', data }).then(res => {
|
||||
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>
|
||||
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 { useEmbedded } from '@/store/modules/embedded'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import relationChart from '@/components/relation-chart/index.vue'
|
||||
import {
|
||||
ElIcon,
|
||||
ElButton,
|
||||
ElMessageBox,
|
||||
ElMessage,
|
||||
type ElMessageBoxOptions,
|
||||
@ -18,7 +20,7 @@ import { useMoveLine } from '@/hooks/web/useMoveLine'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import CreatDsGroup from './form/CreatDsGroup.vue'
|
||||
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 DeResourceGroupOpt from '@/views/common/DeResourceGroupOpt.vue'
|
||||
import DatasetDetail from './DatasetDetail.vue'
|
||||
@ -352,7 +354,7 @@ const handleClick = (tabName: TabPaneName) => {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const relationChartRef = ref()
|
||||
const operation = (cmd: string, data: BusiTreeNode, nodeType: string) => {
|
||||
if (cmd === 'copy') {
|
||||
if (isDataEaseBi.value) {
|
||||
@ -384,17 +386,65 @@ const operation = (cmd: string, data: BusiTreeNode, nodeType: string) => {
|
||||
delete options.tip
|
||||
}
|
||||
|
||||
ElMessageBox.confirm(
|
||||
nodeType === 'folder'
|
||||
? t('data_set.delete_this_folder')
|
||||
: t('datasource.delete_this_dataset'),
|
||||
options as ElMessageBoxOptions
|
||||
).then(() => {
|
||||
delDatasetTree(data.id).then(() => {
|
||||
getData()
|
||||
ElMessage.success(t('dataset.delete_success'))
|
||||
if (nodeType !== 'folder') {
|
||||
perDelete(data.id).then(res => {
|
||||
if (res === true) {
|
||||
const onClick = () => {
|
||||
relationChartRef.value.getChartData({
|
||||
queryType: 'dataset',
|
||||
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(() => {
|
||||
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 {
|
||||
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" />
|
||||
</template>
|
||||
</div>
|
||||
<relationChart ref="relationChartRef"></relationChart>
|
||||
<de-resource-group-opt
|
||||
:cur-canvas-type="curCanvasType"
|
||||
@finish="resourceOptFinish"
|
||||
|
@ -1,15 +1,23 @@
|
||||
<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 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 ArrowSide from '@/views/common/DeResourceArrow.vue'
|
||||
import relationChart from '@/components/relation-chart/index.vue'
|
||||
import { HandleMore } from '@/components/handle-more'
|
||||
import { Icon } from '@/components/icon-custom'
|
||||
import { fieldType } from '@/utils/attr'
|
||||
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 type { Tree } from '../dataset/form/CreatDsGroup.vue'
|
||||
import { previewData, getById } from '@/api/datasource'
|
||||
@ -738,6 +746,7 @@ const handleDatasourceTree = (cmd: string, data?: Tree) => {
|
||||
creatDsFolder.value.createInit(cmd, data || {})
|
||||
}
|
||||
}
|
||||
const relationChartRef = ref()
|
||||
const operation = (cmd: string, data: Tree, nodeType: string) => {
|
||||
if (cmd === 'copy') {
|
||||
handleCopy(data)
|
||||
@ -758,18 +767,69 @@ const operation = (cmd: string, data: Tree, nodeType: string) => {
|
||||
} else {
|
||||
delete options.tip
|
||||
}
|
||||
ElMessageBox.confirm(
|
||||
nodeType === 'folder' ? '确定删除该文件夹吗' : 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))
|
||||
|
||||
if (nodeType !== 'folder') {
|
||||
perDeleteDatasource(data.id).then(res => {
|
||||
if (res === true) {
|
||||
const onClick = () => {
|
||||
relationChartRef.value.getChartData({
|
||||
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 {
|
||||
creatDsFolder.value.createInit(nodeType, data, cmd)
|
||||
}
|
||||
@ -1661,6 +1721,7 @@ const getMenuList = (val: boolean) => {
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<relationChart ref="relationChartRef"></relationChart>
|
||||
|
||||
<XpackComponent
|
||||
jsname="L2NvbXBvbmVudC9wbHVnaW5zLWhhbmRsZXIvRHNDYXRlZ29yeUhhbmRsZXI="
|
||||
|
Loading…
Reference in New Issue
Block a user