[Core] [Source] [Metadata] Refactor metadata info

This commit is contained in:
qianmoQ 2024-04-18 13:35:42 +08:00
parent e736660fb4
commit f3242cddf4
7 changed files with 252 additions and 305 deletions

View File

@ -21,7 +21,7 @@ public class ReflectionUtils
return true;
}
catch (NoSuchFieldException e) {
log.warn("Has field exception", e);
log.debug("Has field exception", e);
return false;
}
}

View File

@ -216,7 +216,7 @@ const createAdminRouter = (router: any) => {
component: () => import('@/views/pages/admin/source/SourceHome.vue')
},
{
path: 'source/manager/:code',
path: 'source/manager/:source',
component: MetadataContainer,
meta: {
title: 'common.source',
@ -224,7 +224,7 @@ const createAdminRouter = (router: any) => {
},
children: [
{
path: '',
path: 'info/:table',
meta: {
title: 'common.source',
isRoot: false

View File

@ -3,10 +3,13 @@
<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"/>
<MetadataSidebar :code="code" @change="handlerChange"/>
</aside>
<div class="flex-1">
<RouterView/>
<Card v-if="!dataInfo" :body-class="'p-8'" :hidden-title="true">
<Alert :description="$t('source.tip.notSelectedNode')"/>
</Card>
<MetadataContent v-else/>
</div>
</div>
</div>
@ -16,24 +19,37 @@
<script lang="ts">
import { defineComponent } from 'vue'
import MetadataSidebar from '@/views/layouts/metadata/components/MetadataSidebar.vue'
import { useRouter } from 'vue-router'
import DatabaseService from '@/services/database.ts'
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: {
MetadataSidebar
MetadataContent,
MetadataSidebar,
Card,
Alert
},
data()
{
return {
code: null as string | null
code: null as string | null,
dataInfo: null as StructureModel | null
}
},
created()
{
this.code = this.$route.params?.code as string
this.code = this.$route.params?.source as string
},
methods: {
handlerChange(node: StructureModel)
{
this.dataInfo = node
router.push(`/admin/source/manager/${ this.code }/info/${ node.code }`)
}
}
})
</script>

View File

@ -1,11 +1,57 @@
<template>
<Tabs v-model="selectTab" :default-value="selectTab" 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>
<TabsTrigger value="structure" class="cursor-pointer">
<LayoutPanelTop :size="18" class="mr-2"/>
{{ $t('source.common.structure') }}
</TabsTrigger>
<TabsTrigger value="data" class="cursor-pointer">
<Table :size="18" class="mr-2"/>
{{ $t('source.common.tableData') }}
</TabsTrigger>
<TabsTrigger value="statement" class="cursor-pointer">
<SatelliteDish :size="18" class="mr-2"/>
{{ $t('source.common.statement') }}
</TabsTrigger>
<TabsTrigger value="erDiagram" class="cursor-pointer">
<Wind :size="18" class="mr-2"/>
{{ $t('source.common.erDiagram') }}
</TabsTrigger>
</TabsList>
</template>
<TabsContent :value="selectTab">
<div class="h-[695px]">
<RouterView/>
</div>
</TabsContent>
</Card>
</Tabs>
</template>
<script lang="ts">
import { defineComponent } 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'
export default defineComponent({
name: 'MetadataContent',
components: {
Tabs, TabsContent, TabsList, TabsTrigger,
Card,
Info, LayoutPanelTop, Table, SatelliteDish, Wind
},
data()
{
return {
selectTab: 'info'
}
}
})
</script>

View File

@ -265,6 +265,7 @@ export default defineComponent({
return
}
this.selectNode = currentNode
this.$emit('change', this.selectNode)
},
handlerLoadChildData(item: StructureModel, callback: any)
{

View File

@ -1,114 +1,201 @@
<template>
<div class="w-full">
<div class="pl-3 pr-3">
<CircularLoading v-if="loading" :show="loading"/>
<div v-else 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">
<div class="flex-1">
<Card v-if="!applyValue.node" :body-class="'p-8'" :hidden-title="true">
<Alert :description="$t('source.tip.notSelectedNode')"/>
</Card>
<Tabs v-else v-model="applyValue.tabType" :default-value="applyValue.tabType" 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>
<TabsTrigger value="structure" class="cursor-pointer">
<LayoutPanelTop :size="18" class="mr-2"/>
{{ $t('source.common.structure') }}
</TabsTrigger>
<TabsTrigger value="data" class="cursor-pointer">
<Table :size="18" class="mr-2"/>
{{ $t('source.common.tableData') }}
</TabsTrigger>
<TabsTrigger value="statement" class="cursor-pointer">
<SatelliteDish :size="18" class="mr-2"/>
{{ $t('source.common.statement') }}
</TabsTrigger>
<TabsTrigger value="erDiagram" class="cursor-pointer">
<Wind :size="18" class="mr-2"/>
{{ $t('source.common.erDiagram') }}
</TabsTrigger>
</TabsList>
</template>
<TabsContent value="info" class="p-3">
<TableInfo v-if="applyValue.node" :info="applyValue.node"/>
</TabsContent>
<TabsContent value="structure">
<TableStructure v-if="applyValue.node" :info="applyValue.node"/>
</TabsContent>
<TabsContent value="data" class="mt-0">
<TableData v-if="applyValue.node" :info="applyValue.node"/>
</TabsContent>
<TabsContent value="statement">
<TableStatement v-if="applyValue.node" :info="applyValue.node"/>
</TabsContent>
<TabsContent value="erDiagram">
<TableErDiagram v-if="applyValue.node" :info="applyValue.node"/>
</TabsContent>
</Card>
</Tabs>
<div v-else-if="dataInfo">
<div class="grid w-full grid-cols-3 gap-6 pt-2">
<div class="flex items-center">
<Database :size="18" class="mr-2"/>
{{ dataInfo.database?.name }}
</div>
<div class="flex items-center">
<Table :size="18" class="mr-2"/>
{{ dataInfo?.name }}
</div>
<div class="flex items-center">
<Tooltip :content="$t('common.createTime')">
<Clock :size="18" class="mr-2"/>
{{ dataInfo?.inCreateTime === 'null' ? $t('source.common.notSpecified') : dataInfo.inCreateTime }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('common.updateTime')">
<Clock :size="18" class="mr-2"/>
{{ dataInfo?.inUpdateTime === 'null' ? $t('source.common.notUpdated') : dataInfo.inUpdateTime }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.engine')">
<CalendarHeart :size="18" class="mr-2"/>
{{ dataInfo.engine === 'null' ? $t('source.common.notSpecifiedEngine') : dataInfo.engine }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.collation')">
<ArrowUpDown :size="18" class="mr-2"/>
{{ dataInfo.collation === 'null' ? $t('source.common.notSpecifiedCollation') : dataInfo.collation }}
</Tooltip>
</div>
</div>
<Divider class="mt-4 mb-4"/>
<div class="grid w-full grid-cols-3 gap-6 pt-2">
<div class="flex items-center">
<Tooltip :content="$t('source.common.totalRows')">
<TableCellsMerge :size="18" class="mr-2"/>
{{ dataInfo.rows }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.format')">
<RemoveFormatting :size="18" class="mr-2"/>
{{ dataInfo.format === 'null' ? $t('source.common.notSpecifiedFormat') : dataInfo.format }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.avgRowLength')">
<ArrowUp10 :size="18" class="mr-2"/>
{{ dataInfo.avgRowLength === 'null' ? 0 : dataInfo.avgRowLength }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.dataSize')">
<ArrowUpDown :size="18" class="mr-2"/>
{{ dataInfo.dataLength === 'null' ? 0 : dataInfo.dataLength }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.indexSize')">
<Search :size="18" class="mr-2"/>
{{ dataInfo.indexLength === 'null' ? $t('source.common.notSpecifiedIndex') : dataInfo.indexLength }}
</Tooltip>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<Tooltip :content="$t('source.common.autoIncrement')">
<ArrowUpDown :size="18" class="mr-2"/>
{{ dataInfo.autoIncrement === 'null' ? $t('source.common.notSpecifiedPrimaryKey') : dataInfo.autoIncrement }}
</Tooltip>
</div>
<div>
<Popover>
<PopoverTrigger as-child>
<Button size="icon" class="rounded-full w-6 h-6" :disabled="dataInfo.autoIncrement === 'null'">
<Tooltip :content="$t('source.common.resetAutoIncrement')">
<Cog :size="14"/>
</Tooltip>
</Button>
</PopoverTrigger>
<PopoverContent class="w-80">
<div class="grid gap-4">
<div class="space-y-2">
<h4 class="font-medium leading-none">{{ $t('source.common.resetAutoIncrement') }}</h4>
</div>
<div class="grid gap-2">
<div class="grid grid-cols-3 items-center gap-4">
<Label for="autoIncrement">{{ $t('source.common.resetTo') }}</Label>
<Input v-model="dataInfo.autoIncrement" id="autoIncrement" type="number" :default-value="dataInfo.autoIncrement"/>
<Button size="sm" :loading="submitting" :disabled="submitting" @click="handlerApply">
{{ $t('common.apply') }}
</Button>
</div>
</div>
</div>
</PopoverContent>
</Popover>
</div>
</div>
</div>
<Divider class="mt-4 mb-4"/>
<div class="space-y-2">
<Label for="comment">{{ $t('source.common.comment') }}</Label>
<Textarea id="comment" v-model="dataInfo.comment"/>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { defineComponent, watch } from 'vue'
import TableService from '@/services/table'
import CircularLoading from '@/views/components/loading/CircularLoading.vue'
import Card from '@/views/ui/card'
import Alert from '@/views/ui/alert'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { ArrowUpFromLine, Columns, Delete, Info, LayoutPanelTop, Pencil, SatelliteDish, Table, Trash, Wind } from 'lucide-vue-next'
import TableInfo from '@/views/pages/admin/source/components/TableInfo.vue'
import TableCreate from '@/views/pages/admin/source/components/TableCreate.vue'
import ColumnCreate from '@/views/pages/admin/source/components/ColumnCreate.vue'
import TableExport from '@/views/pages/admin/source/components/TableExport.vue'
import TableTruncate from '@/views/pages/admin/source/components/TableTruncate.vue'
import TableDrop from '@/views/pages/admin/source/components/TableDrop.vue'
import TableStructure from '@/views/pages/admin/source/components/TableStructure.vue'
import ColumnChange from '@/views/pages/admin/source/components/ColumnChange.vue'
import ColumnDrop from '@/views/pages/admin/source/components/ColumnDrop.vue'
import TableData from '@/views/pages/admin/source/components/TableData.vue'
import TableStatement from '@/views/pages/admin/source/components/TableStatement.vue'
import TableErDiagram from '@/views/pages/admin/source/components/TableErDiagram.vue'
import { ArrowUp10, ArrowUpDown, CalendarHeart, Clock, Cog, Database, RemoveFormatting, Search, Table, TableCellsMerge } from 'lucide-vue-next'
import Tooltip from '@/views/ui/tooltip'
import { SqlType, TableFilter, TableModel } from '@/model/table'
import { Separator } from '@/components/ui/separator'
import Divider from '@/views/ui/divider'
import Button from '@/views/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Label } from '@/components/ui/label'
import { Input } from '@/components/ui/input'
import { ToastUtils } from '@/utils/toast'
import { Textarea } from '@/components/ui/textarea'
import { toNumber } from 'lodash'
export default defineComponent({
name: 'SourceManagerInfo',
components: {
TableErDiagram,
TableStatement,
TableData,
ColumnDrop,
ColumnChange,
TableStructure,
TableDrop,
TableTruncate,
TableExport,
ColumnCreate,
TableCreate,
TableInfo,
Alert,
Card,
Textarea,
Input,
Label,
Button,
Divider,
Separator,
Tooltip,
CircularLoading,
Tabs, TabsContent, TabsList, TabsTrigger,
Info, Table, Columns, ArrowUpFromLine, Trash, Delete, LayoutPanelTop, Pencil, SatelliteDish, Wind
Database, Table, Clock, CalendarHeart, ArrowUpDown, TableCellsMerge, RemoveFormatting, ArrowUp10, Search, Cog,
Popover, PopoverContent, PopoverTrigger
},
created()
{
this.handlerInitialize()
},
data()
{
return {
loading: false,
applyValue: {
database: undefined,
tabType: 'info'
},
dataTreeLoading: false
submitting: false,
dataInfo: null as TableModel | null
}
},
methods: {}
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)
}
}
)
},
handlerApply()
{
if (this.dataInfo) {
this.submitting = true
const configure: TableFilter = {
type: SqlType.ALTER,
value: this.dataInfo.autoIncrement
}
TableService.getData(toNumber(this.dataInfo.id), configure)
.then(response => {
if (response.status) {
ToastUtils.success(this.$t('source.tip.resetAutoIncrementSuccess').replace('$VALUE', this.dataInfo?.autoIncrement as string))
this.handlerInitialize()
}
else {
ToastUtils.error(response.message)
}
})
.finally(() => this.submitting = false)
}
}
}
})
</script>

View File

@ -1,203 +0,0 @@
<template>
<div>
<CircularLoading v-if="loading" :show="loading"/>
<div v-else-if="dataInfo">
<div class="grid w-full grid-cols-3 gap-6 pt-2">
<div class="flex items-center">
<Database :size="18" class="mr-2"/>
{{ dataInfo.database?.name }}
</div>
<div class="flex items-center">
<Table :size="18" class="mr-2"/>
{{ dataInfo?.name }}
</div>
<div class="flex items-center">
<Tooltip :content="$t('common.createTime')">
<Clock :size="18" class="mr-2"/>
{{ dataInfo?.inCreateTime === 'null' ? $t('source.common.notSpecified') : dataInfo.inCreateTime }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('common.updateTime')">
<Clock :size="18" class="mr-2"/>
{{ dataInfo?.inUpdateTime === 'null' ? $t('source.common.notUpdated') : dataInfo.inUpdateTime }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.engine')">
<CalendarHeart :size="18" class="mr-2"/>
{{ dataInfo.engine === 'null' ? $t('source.common.notSpecifiedEngine') : dataInfo.engine }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.collation')">
<ArrowUpDown :size="18" class="mr-2"/>
{{ dataInfo.collation === 'null' ? $t('source.common.notSpecifiedCollation') : dataInfo.collation }}
</Tooltip>
</div>
</div>
<Divider class="mt-4 mb-4"/>
<div class="grid w-full grid-cols-3 gap-6 pt-2">
<div class="flex items-center">
<Tooltip :content="$t('source.common.totalRows')">
<TableCellsMerge :size="18" class="mr-2"/>
{{ dataInfo.rows }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.format')">
<RemoveFormatting :size="18" class="mr-2"/>
{{ dataInfo.format === 'null' ? $t('source.common.notSpecifiedFormat') : dataInfo.format }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.avgRowLength')">
<ArrowUp10 :size="18" class="mr-2"/>
{{ dataInfo.avgRowLength === 'null' ? 0 : dataInfo.avgRowLength }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.dataSize')">
<ArrowUpDown :size="18" class="mr-2"/>
{{ dataInfo.dataLength === 'null' ? 0 : dataInfo.dataLength }}
</Tooltip>
</div>
<div class="flex items-center">
<Tooltip :content="$t('source.common.indexSize')">
<Search :size="18" class="mr-2"/>
{{ dataInfo.indexLength === 'null' ? $t('source.common.notSpecifiedIndex') : dataInfo.indexLength }}
</Tooltip>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<Tooltip :content="$t('source.common.autoIncrement')">
<ArrowUpDown :size="18" class="mr-2"/>
{{ dataInfo.autoIncrement === 'null' ? $t('source.common.notSpecifiedPrimaryKey') : dataInfo.autoIncrement }}
</Tooltip>
</div>
<div>
<Popover>
<PopoverTrigger as-child>
<Button size="icon" class="rounded-full w-6 h-6" :disabled="dataInfo.autoIncrement === 'null'">
<Tooltip :content="$t('source.common.resetAutoIncrement')">
<Cog :size="14"/>
</Tooltip>
</Button>
</PopoverTrigger>
<PopoverContent class="w-80">
<div class="grid gap-4">
<div class="space-y-2">
<h4 class="font-medium leading-none">{{ $t('source.common.resetAutoIncrement') }}</h4>
</div>
<div class="grid gap-2">
<div class="grid grid-cols-3 items-center gap-4">
<Label for="autoIncrement">{{ $t('source.common.resetTo') }}</Label>
<Input v-model="dataInfo.autoIncrement" id="autoIncrement" type="number" :default-value="dataInfo.autoIncrement"/>
<Button :loading="loading" @click="handlerApply">
{{ $t('common.apply') }}
</Button>
</div>
</div>
</div>
</PopoverContent>
</Popover>
</div>
</div>
</div>
<Divider class="mt-4 mb-4"/>
<div class="space-y-2">
<Label for="comment">{{ $t('source.common.comment') }}</Label>
<Textarea id="comment" v-model="dataInfo.comment"/>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, watch } from 'vue'
import TableService from '@/services/table'
import CircularLoading from '@/views/components/loading/CircularLoading.vue'
import { ArrowUp10, ArrowUpDown, CalendarHeart, Clock, Cog, Database, RemoveFormatting, Search, Table, TableCellsMerge } from 'lucide-vue-next'
import Tooltip from '@/views/ui/tooltip'
import { SqlType, TableFilter, TableModel } from '@/model/table'
import { Separator } from '@/components/ui/separator'
import Divider from '@/views/ui/divider'
import Button from '@/views/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Label } from '@/components/ui/label'
import { Input } from '@/components/ui/input'
import { ToastUtils } from '@/utils/toast'
import { Textarea } from '@/components/ui/textarea'
import { StructureModel } from '@/model/structure'
import { cloneDeep, toNumber } from 'lodash'
export default defineComponent({
name: 'TableInfo',
components: {
Textarea,
Input,
Label,
Button,
Divider,
Separator,
Tooltip,
CircularLoading,
Database, Table, Clock, CalendarHeart, ArrowUpDown, TableCellsMerge, RemoveFormatting, ArrowUp10, Search, Cog,
Popover, PopoverContent, PopoverTrigger
},
props: {
info: {
type: Object as () => StructureModel | null
}
},
created()
{
this.handlerInitialize()
this.watchId()
},
data()
{
return {
loading: false,
dataInfo: null as TableModel | null
}
},
methods: {
handlerInitialize()
{
if (this.info) {
this.dataInfo = cloneDeep(this.info.origin)
}
},
handlerApply()
{
if (this.dataInfo) {
this.loading = true
const configure: TableFilter = {
type: SqlType.ALTER,
value: this.dataInfo.autoIncrement
}
TableService.getData(toNumber(this.dataInfo.id), configure)
.then(response => {
if (response.status) {
ToastUtils.success(this.$t('source.tip.resetAutoIncrementSuccess').replace('$VALUE', this.dataInfo?.autoIncrement as string))
this.handlerInitialize()
}
else {
ToastUtils.error(response.message)
}
})
.finally(() => this.loading = false)
}
},
watchId()
{
watch(
() => this.info,
() => {
this.handlerInitialize()
}
)
}
}
})
</script>