mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-12-02 20:17:45 +08:00
[Core] [Source] [Metadata] Refactor metadata structure
This commit is contained in:
parent
f3242cddf4
commit
dec9f83dae
@ -576,7 +576,9 @@ public class SourceServiceImpl
|
||||
databaseTableCache.put(key, this.tableHandler.findSimpleAllByDatabase(item));
|
||||
});
|
||||
// Delete invalid data that no longer exists
|
||||
List<DatabaseEntity> deleteEntities = origin.stream().filter(node -> entities.stream().noneMatch(item -> node.getName().equals(item.getName()))).collect(Collectors.toList());
|
||||
List<DatabaseEntity> deleteEntities = origin.stream()
|
||||
.filter(node -> entities.stream().noneMatch(item -> node.getName().equals(item.getName())))
|
||||
.collect(Collectors.toList());
|
||||
log.info("Removed database size [ {} ] from source [ {} ]", deleteEntities.size(), entity.getName());
|
||||
databaseHandler.deleteAll(deleteEntities);
|
||||
databaseRemovedCount.addAndGet(deleteEntities.size());
|
||||
|
@ -216,7 +216,7 @@ const createAdminRouter = (router: any) => {
|
||||
component: () => import('@/views/pages/admin/source/SourceHome.vue')
|
||||
},
|
||||
{
|
||||
path: 'source/manager/:source',
|
||||
path: 'source/:source',
|
||||
component: MetadataContainer,
|
||||
meta: {
|
||||
title: 'common.source',
|
||||
@ -224,12 +224,30 @@ const createAdminRouter = (router: any) => {
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'info/:table',
|
||||
path: 'd/:database/',
|
||||
meta: {
|
||||
title: 'common.source',
|
||||
isRoot: false
|
||||
},
|
||||
component: () => import('@/views/pages/admin/source/SourceManagerInfo.vue')
|
||||
component: () => import('@/views/pages/admin/source/SourceDatabase.vue')
|
||||
},
|
||||
{
|
||||
path: 'd/:database/t/info/:table',
|
||||
meta: {
|
||||
title: 'common.source',
|
||||
isRoot: false,
|
||||
type: 'info'
|
||||
},
|
||||
component: () => import('@/views/pages/admin/source/SourceTableInfo.vue')
|
||||
},
|
||||
{
|
||||
path: 'd/:database/t/structure/:table',
|
||||
meta: {
|
||||
title: 'common.source',
|
||||
isRoot: false,
|
||||
type: 'structure'
|
||||
},
|
||||
component: () => import('@/views/pages/admin/source/SourceTableStructure.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -16,12 +16,12 @@ class TableService
|
||||
/**
|
||||
* Retrieves all data from the database by the specified ID.
|
||||
*
|
||||
* @param {number} id - The ID of the database.
|
||||
* @param {number} code - The code of the database.
|
||||
* @return {Promise<ResponseModel>} A promise that resolves to a ResponseModel object.
|
||||
*/
|
||||
getAllByDatabase(id: number): Promise<ResponseModel>
|
||||
getAllByDatabase(code: string): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpUtils().post(`${ DEFAULT_PATH }/database/${ id }`)
|
||||
return new HttpUtils().post(`${ DEFAULT_PATH }/database/${ code }`)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,13 +3,10 @@
|
||||
<div class="hidden space-y-6 w-full md:block">
|
||||
<div class="flex flex-col space-y-8 lg:flex-row lg:space-x-6 lg:space-y-0">
|
||||
<aside class="-mx-4 w-[200px]">
|
||||
<MetadataSidebar :code="code" @change="handlerChange"/>
|
||||
<MetadataSidebar/>
|
||||
</aside>
|
||||
<div class="flex-1">
|
||||
<Card v-if="!dataInfo" :body-class="'p-8'" :hidden-title="true">
|
||||
<Alert :description="$t('source.tip.notSelectedNode')"/>
|
||||
</Card>
|
||||
<MetadataContent v-else/>
|
||||
<MetadataContent/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -22,33 +19,19 @@ import MetadataSidebar from '@/views/layouts/metadata/components/MetadataSidebar
|
||||
import MetadataContent from '@/views/layouts/metadata/components/MetadataContent.vue'
|
||||
import { StructureModel } from '@/model/structure.ts'
|
||||
import router from '@/router'
|
||||
import Card from '@/views/ui/card'
|
||||
import Alert from '@/views/ui/alert'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MetadataContainer',
|
||||
components: {
|
||||
MetadataContent,
|
||||
MetadataSidebar,
|
||||
Card,
|
||||
Alert
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
code: null as string | null,
|
||||
dataInfo: null as StructureModel | null
|
||||
}
|
||||
},
|
||||
created()
|
||||
{
|
||||
this.code = this.$route.params?.source as string
|
||||
MetadataSidebar
|
||||
},
|
||||
methods: {
|
||||
handlerChange(node: StructureModel)
|
||||
{
|
||||
this.dataInfo = node
|
||||
router.push(`/admin/source/manager/${ this.code }/info/${ node.code }`)
|
||||
console.log(node)
|
||||
router.push(`/admin/source/manager/${ this.code }/d/${ node.code }`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,15 +1,19 @@
|
||||
<template>
|
||||
<Tabs v-model="selectTab" :default-value="selectTab" class="w-full">
|
||||
<Tabs v-model="selectTab as string" :default-value="selectTab as string" class="w-full">
|
||||
<Card :title-class="'p-0'" :body-class="'p-0'">
|
||||
<template #title>
|
||||
<TabsList>
|
||||
<TabsTrigger value="info" class="cursor-pointer">
|
||||
<Info :size="18" class="mr-2"/>
|
||||
{{ $t('source.common.info') }}
|
||||
<TabsTrigger value="info" class="cursor-pointer" @click="handlerChange">
|
||||
<div class="flex space-x-2">
|
||||
<Info :size="18"/>
|
||||
<span>{{ $t('source.common.info') }}</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="structure" class="cursor-pointer">
|
||||
<LayoutPanelTop :size="18" class="mr-2"/>
|
||||
{{ $t('source.common.structure') }}
|
||||
<TabsTrigger value="structure" class="cursor-pointer" @click="handlerChange">
|
||||
<div class="flex space-x-2">
|
||||
<LayoutPanelTop :size="18"/>
|
||||
<span>{{ $t('source.common.structure') }}</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="data" class="cursor-pointer">
|
||||
<Table :size="18" class="mr-2"/>
|
||||
@ -25,7 +29,7 @@
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</template>
|
||||
<TabsContent :value="selectTab">
|
||||
<TabsContent :value="selectTab as string">
|
||||
<div class="h-[695px]">
|
||||
<RouterView/>
|
||||
</div>
|
||||
@ -35,7 +39,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import Card from '@/views/ui/card'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Info, LayoutPanelTop, SatelliteDish, Table, Wind } from 'lucide-vue-next'
|
||||
@ -50,7 +54,44 @@ export default defineComponent({
|
||||
data()
|
||||
{
|
||||
return {
|
||||
selectTab: 'info'
|
||||
selectTab: null as string | null,
|
||||
originalSource: null as string | null,
|
||||
originalDatabase: null as string | null,
|
||||
originalTable: null as string | null
|
||||
}
|
||||
},
|
||||
created()
|
||||
{
|
||||
this.handlerInitialize()
|
||||
this.watchChange()
|
||||
},
|
||||
methods: {
|
||||
handlerInitialize()
|
||||
{
|
||||
const source = this.$route.params?.source as string
|
||||
const database = this.$route.params?.database as string
|
||||
const table = this.$route.params?.table as string
|
||||
const type = this.$route.meta.type as string
|
||||
this.originalSource = source
|
||||
this.originalDatabase = database
|
||||
this.originalTable = table
|
||||
this.selectTab = type
|
||||
},
|
||||
handlerChange()
|
||||
{
|
||||
if (this.selectTab === 'info') {
|
||||
this.$router.push(`/admin/source/${ this.originalSource }/d/${ this.originalDatabase }/t/info/${ this.originalTable }`)
|
||||
}
|
||||
if (this.selectTab === 'structure') {
|
||||
this.$router.push(`/admin/source/${ this.originalSource }/d/${ this.originalDatabase }/t/structure/${ this.originalTable }`)
|
||||
}
|
||||
},
|
||||
watchChange()
|
||||
{
|
||||
watch(
|
||||
() => this.$route?.params.table,
|
||||
() => this.handlerInitialize()
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<Card :title-class="'p-0'" :body-class="'p-0'">
|
||||
<template #title>
|
||||
<Select v-model="selectDatabase" @update:modelValue="handlerChangeDatabase">
|
||||
<Select v-model="selectDatabase" :default-value="originalDatabase ? originalDatabase : selectDatabase" @update:modelValue="handlerChangeDatabase">
|
||||
<SelectTrigger class="border-0 w-[200px]">
|
||||
<SelectValue :placeholder="$t('source.tip.selectDatabase')"/>
|
||||
</SelectTrigger>
|
||||
@ -123,6 +123,7 @@ import ColumnChange from '@/views/pages/admin/source/components/ColumnChange.vue
|
||||
import TableTruncate from '@/views/pages/admin/source/components/TableTruncate.vue'
|
||||
import TableDrop from '@/views/pages/admin/source/components/TableDrop.vue'
|
||||
import TableCreate from '@/views/pages/admin/source/components/TableCreate.vue'
|
||||
import { ToastUtils } from '@/utils/toast.ts'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MetadataSidebar',
|
||||
@ -146,11 +147,6 @@ export default defineComponent({
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger
|
||||
},
|
||||
props: {
|
||||
code: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
StructureEnum()
|
||||
{
|
||||
@ -162,6 +158,9 @@ export default defineComponent({
|
||||
return {
|
||||
loading: false,
|
||||
selectDatabase: undefined,
|
||||
originalSource: null as string | null,
|
||||
originalDatabase: null as string | null,
|
||||
originalTable: null as string | null,
|
||||
selectNode: null as StructureModel | null,
|
||||
databaseArray: Array<StructureModel>(),
|
||||
dataTreeArray: Array<StructureModel>(),
|
||||
@ -182,19 +181,31 @@ export default defineComponent({
|
||||
methods: {
|
||||
handlerInitialize()
|
||||
{
|
||||
if (this.code) {
|
||||
const source = this.$route.params?.source as string
|
||||
const database = this.$route.params?.database as string
|
||||
if (source) {
|
||||
this.originalSource = source
|
||||
this.loading = true
|
||||
DatabaseService.getAllBySource(this.code as string)
|
||||
DatabaseService.getAllBySource(source)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
response.data.forEach((item: { name: null; catalog: null; code: null }) => {
|
||||
const structure: StructureModel = {
|
||||
title: item.name,
|
||||
catalog: item.catalog,
|
||||
code: item.code
|
||||
}
|
||||
this.databaseArray.push(structure)
|
||||
})
|
||||
response.data
|
||||
.forEach((item: { name: null; catalog: null; code: undefined }) => {
|
||||
const structure: StructureModel = {
|
||||
title: item.name,
|
||||
catalog: item.catalog,
|
||||
code: item.code
|
||||
}
|
||||
this.databaseArray.push(structure)
|
||||
})
|
||||
if (database) {
|
||||
this.originalDatabase = database
|
||||
this.selectDatabase = database as any
|
||||
this.handlerChangeDatabase()
|
||||
}
|
||||
}
|
||||
else {
|
||||
ToastUtils.error(response.message)
|
||||
}
|
||||
})
|
||||
.finally(() => this.loading = false)
|
||||
@ -204,50 +215,67 @@ export default defineComponent({
|
||||
{
|
||||
this.loading = true
|
||||
this.dataTreeArray = []
|
||||
TableService.getAllByDatabase(this.selectDatabase as string)
|
||||
TableService.getAllByDatabase(this.selectDatabase as any)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
response.data.forEach((item: {
|
||||
name: null;
|
||||
title: null;
|
||||
catalog: null;
|
||||
code: null;
|
||||
type: null;
|
||||
engine: null;
|
||||
comment: null;
|
||||
database: { name: null, id: string };
|
||||
}) => {
|
||||
const structure: StructureModel = {
|
||||
title: item.name,
|
||||
database: item.database.name,
|
||||
databaseId: item.database.id,
|
||||
catalog: item.catalog,
|
||||
code: item.code,
|
||||
type: item.type,
|
||||
level: StructureEnum.TABLE,
|
||||
engine: item.engine,
|
||||
comment: item.comment,
|
||||
origin: item,
|
||||
loading: false,
|
||||
contextmenu: true,
|
||||
children: [] as StructureModel[],
|
||||
render: (h: any, { data }: { data: StructureModel }) => {
|
||||
return h('div', [
|
||||
h('span', [
|
||||
h(resolveComponent('FontAwesomeIcon'), {
|
||||
icon: 'table',
|
||||
style: { marginRight: '6px' }
|
||||
}),
|
||||
this.resolveTableComponent(h, data)
|
||||
])
|
||||
])
|
||||
}
|
||||
}
|
||||
this.dataTreeArray.push(structure)
|
||||
})
|
||||
response.data
|
||||
.forEach((item: {
|
||||
name: null;
|
||||
title: null;
|
||||
catalog: null;
|
||||
code: undefined;
|
||||
type: null;
|
||||
engine: null;
|
||||
comment: null;
|
||||
database: { name: null, id: string };
|
||||
}) => {
|
||||
const structure: StructureModel = {
|
||||
title: item.name,
|
||||
database: item.database.name,
|
||||
databaseId: item.database.id,
|
||||
catalog: item.catalog,
|
||||
code: item.code,
|
||||
type: item.type,
|
||||
level: StructureEnum.TABLE,
|
||||
engine: item.engine,
|
||||
comment: item.comment,
|
||||
origin: item,
|
||||
loading: false,
|
||||
contextmenu: true,
|
||||
children: [] as StructureModel[],
|
||||
render: (h: any, { data }: { data: StructureModel }) => {
|
||||
return h('div', [
|
||||
h('span', [
|
||||
h(resolveComponent('FontAwesomeIcon'), {
|
||||
icon: 'table',
|
||||
style: { marginRight: '6px' }
|
||||
}),
|
||||
this.resolveTableComponent(h, data)
|
||||
])
|
||||
])
|
||||
}
|
||||
}
|
||||
this.dataTreeArray.push(structure)
|
||||
})
|
||||
}
|
||||
else {
|
||||
ToastUtils.error(response.message)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
const table = this.$route.params?.table as string
|
||||
if (table) {
|
||||
const node = this.dataTreeArray.find(item => item.code === table)
|
||||
if (node) {
|
||||
node.selected = true
|
||||
this.handlerSelectNode([node])
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.$router.push(`/admin/source/${ this.originalSource }/d/${ this.selectDatabase }`)
|
||||
}
|
||||
})
|
||||
.finally(() => this.loading = false)
|
||||
},
|
||||
handlerSelectNode(node: Array<StructureModel>)
|
||||
{
|
||||
@ -265,7 +293,7 @@ export default defineComponent({
|
||||
return
|
||||
}
|
||||
this.selectNode = currentNode
|
||||
this.$emit('change', this.selectNode)
|
||||
this.$router.push(`/admin/source/${ this.originalSource }/d/${ this.selectDatabase }/t/info/${ currentNode.code }`)
|
||||
},
|
||||
handlerLoadChildData(item: StructureModel, callback: any)
|
||||
{
|
||||
@ -274,14 +302,14 @@ export default defineComponent({
|
||||
callback(dataChildArray)
|
||||
return
|
||||
}
|
||||
ColumnService.getAllByTable(item.code)
|
||||
ColumnService.getAllByTable(item.code as string)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
response.data.forEach((item: {
|
||||
name: null;
|
||||
title: null;
|
||||
catalog: null;
|
||||
code: null;
|
||||
code: undefined;
|
||||
type: null;
|
||||
dataType: null;
|
||||
extra: null;
|
||||
|
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<Card :body-class="'p-8'" :hidden-title="true">
|
||||
<Alert :description="$t('source.tip.notSelectedNode')"/>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import Card from '@/views/ui/card'
|
||||
import Alert from '@/views/ui/alert'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SourceDatabase',
|
||||
components: {
|
||||
Card,
|
||||
Alert
|
||||
}
|
||||
})
|
||||
</script>
|
@ -42,7 +42,7 @@
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem :disabled="(loginUserId !== row.user.id) || !row.available" class="cursor-pointer">
|
||||
<RouterLink :to="`/admin/source/manager/${row?.code}`" target="_blank" class="flex items-center">
|
||||
<RouterLink :to="`/admin/source/${row?.code}`" target="_blank" class="flex items-center">
|
||||
<Cog class="mr-2 h-4 w-4"/>
|
||||
<span>{{ $t('source.common.manager') }}</span>
|
||||
</RouterLink>
|
||||
|
@ -130,7 +130,7 @@ import { Textarea } from '@/components/ui/textarea'
|
||||
import { toNumber } from 'lodash'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SourceManagerInfo',
|
||||
name: 'SourceTableInfo',
|
||||
components: {
|
||||
Textarea,
|
||||
Input,
|
||||
@ -146,6 +146,7 @@ export default defineComponent({
|
||||
created()
|
||||
{
|
||||
this.handlerInitialize()
|
||||
this.watchChange()
|
||||
},
|
||||
data()
|
||||
{
|
||||
@ -158,22 +159,20 @@ export default defineComponent({
|
||||
methods: {
|
||||
handlerInitialize()
|
||||
{
|
||||
watch(
|
||||
() => this.$route?.params.table,
|
||||
() => {
|
||||
const code = this.$route?.params.table as string
|
||||
if (code) {
|
||||
this.loading = true
|
||||
TableService.getByCode(code)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
this.dataInfo = response.data
|
||||
}
|
||||
})
|
||||
.finally(() => this.loading = false)
|
||||
}
|
||||
}
|
||||
)
|
||||
const code = this.$route?.params.table as string
|
||||
if (code) {
|
||||
this.loading = true
|
||||
TableService.getByCode(code)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
this.dataInfo = response.data
|
||||
}
|
||||
else {
|
||||
ToastUtils.error(response.message)
|
||||
}
|
||||
})
|
||||
.finally(() => this.loading = false)
|
||||
}
|
||||
},
|
||||
handlerApply()
|
||||
{
|
||||
@ -195,6 +194,13 @@ export default defineComponent({
|
||||
})
|
||||
.finally(() => this.submitting = false)
|
||||
}
|
||||
},
|
||||
watchChange()
|
||||
{
|
||||
watch(
|
||||
() => this.$route?.params.table,
|
||||
() => this.handlerInitialize()
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
@ -8,27 +8,19 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import { StructureModel } from '@/model/structure'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { createHeaders } from '@/views/pages/admin/source/components/TableUtils'
|
||||
import { createHeaders } from '@/views/pages/admin/source/components/TableUtils.ts'
|
||||
import TableCommon from '@/views/components/table/TableCommon.vue'
|
||||
import ColumnService from '@/services/column'
|
||||
import { cloneDeep, toNumber } from 'lodash'
|
||||
import { TableModel } from '@/model/table'
|
||||
import { ColumnModel } from '@/model/column'
|
||||
import ColumnService from '@/services/column.ts'
|
||||
import { ColumnModel } from '@/model/column.ts'
|
||||
import Switch from '@/views/ui/switch'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TableStructure',
|
||||
name: 'SourceTableStructure',
|
||||
components: {
|
||||
TableCommon,
|
||||
Switch
|
||||
},
|
||||
props: {
|
||||
info: {
|
||||
type: Object as () => StructureModel | null
|
||||
}
|
||||
},
|
||||
setup()
|
||||
{
|
||||
const headers = createHeaders(useI18n())
|
||||
@ -41,22 +33,21 @@ export default defineComponent({
|
||||
{
|
||||
return {
|
||||
loading: false,
|
||||
dataInfo: null as TableModel | null,
|
||||
data: Array<ColumnModel>
|
||||
}
|
||||
},
|
||||
created()
|
||||
{
|
||||
this.handlerInitialize()
|
||||
this.watchId()
|
||||
this.watchChange()
|
||||
},
|
||||
methods: {
|
||||
handlerInitialize()
|
||||
{
|
||||
if (this.info) {
|
||||
this.dataInfo = cloneDeep(this.info.origin)
|
||||
const code = this.$route?.params.table as string
|
||||
if (code) {
|
||||
this.loading = true
|
||||
ColumnService.getAllByTable(toNumber(this.dataInfo?.id))
|
||||
ColumnService.getAllByTable(code)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
this.data = response.data
|
||||
@ -65,10 +56,10 @@ export default defineComponent({
|
||||
.finally(() => this.loading = false)
|
||||
}
|
||||
},
|
||||
watchId()
|
||||
watchChange()
|
||||
{
|
||||
watch(
|
||||
() => this.info,
|
||||
() => this.$route?.params.table,
|
||||
() => {
|
||||
this.handlerInitialize()
|
||||
}
|
Loading…
Reference in New Issue
Block a user