Commit 6ebccc30 authored by nick zheng's avatar nick zheng

Merge branch 'beta' into 'master'

feat: 数据库表内容展示

See merge request !232
parents 50622da7 242aaa28
......@@ -66,3 +66,11 @@ export function fetchGetDBTableList<T>(id: string) {
export function fetchGetDataListByIds<T>(ids: number[]) {
return request.post<T>(`/databaseRest/getByIds.json?ids=${ids}`)
}
/**
* @params id 数据库Id table 数据表名称
* @returns 查询数据库表数据
*/
export function fetchGetDBTableDataList<T>(payload: object) {
return request.post<T>('/databaseRest/getTableData.json', payload)
}
......@@ -660,6 +660,9 @@ personal_space_module:
connect_test_must_pass_to_create: 'Requires successful database connection to create'
connect_test_must_pass_to_update: 'Requires successful database connection to update'
add_database: 'Add database'
table_name: 'Table name'
table_desc: 'Table description'
table_data_volume: 'Table data volume'
share_agent_module:
please: 'Please first'
......
......@@ -658,6 +658,9 @@ personal_space_module:
connect_test_must_pass_to_create: '数据库连接成功才能创建'
connect_test_must_pass_to_update: '数据库连接成功才能更新'
add_database: '添加数据库'
table_name: '数据表名称'
table_desc: '数据表描述'
table_data_volume: '数据量'
share_agent_module:
please: '请先'
......
......@@ -658,6 +658,9 @@ personal_space_module:
connect_test_must_pass_to_create: '數據庫連接成功才能創建'
connect_test_must_pass_to_update: '數據庫連接成功才能更新'
add_database: '添加數據庫'
table_name: '數據表名稱'
table_desc: '數據表描述'
table_data_volume: '數據量'
share_agent_module:
please: '請先'
......
......@@ -67,6 +67,16 @@ export default [
},
component: () => import('@/views/personal-space/personal-db-table/personal-db-table.vue'),
},
{
path: '/personal-space/database/table/detail/:databaseId?/:tableName?',
name: 'PersonalSpaceDBTableDetail',
meta: {
rank: 1001,
title: 'router_title_module.personal',
belong: 'PersonalSpace',
},
component: () => import('@/views/personal-space/personal-db-table/personal-db-table-detail.vue'),
},
{
path: '/knowledge/document/:id',
......
import { type ComposerTranslation } from 'vue-i18n'
import { DBTableItemInterface } from './type'
// import { formatDateTime } from '@/utils/date-formatter'
import { DBTableDataItemInterface, DBTableItemInterface } from './type'
import i18n from '@/locales'
import { formatDateTime } from '@/utils/date-formatter'
export function createDatabaseColumn(_config: { t?: ComposerTranslation } = {}) {
const t = i18n.global.t
export function createDatabaseColumn(handleDatabaseTableAction: (actionType: string, tableName: string) => void) {
return [
{
title: () => <span>数据表名称</span>,
title: () => <span>{t('personal_space_module.database_module.table_name')}</span>,
key: 'name',
align: 'left',
ellipsis: {
......@@ -30,7 +32,7 @@ export function createDatabaseColumn(_config: { t?: ComposerTranslation } = {})
// },
// },
{
title: () => <span>数据表描述</span>,
title: () => <span>{t('personal_space_module.database_module.table_desc')}</span>,
key: 'docs',
align: 'left',
ellipsis: {
......@@ -66,7 +68,7 @@ export function createDatabaseColumn(_config: { t?: ComposerTranslation } = {})
// },
// },
{
title: () => <span>数据量</span>,
title: () => <span>{t('personal_space_module.database_module.table_data_volume')}</span>,
key: 'dataSize',
align: 'left',
ellipsis: {
......@@ -77,39 +79,58 @@ export function createDatabaseColumn(_config: { t?: ComposerTranslation } = {})
return row.dataSize || '--'
},
},
// {
// title: () => <span>{t('common_module.data_table_module.action')}</span>,
// key: 'action',
// align: 'left',
// ellipsis: {
// tooltip: true,
// },
// width: 190,
// fixed: 'right',
// render(row: DatabaseItemInterface) {
// return (
// <div>
// <span
// className='text-theme-color mr-5 cursor-pointer hover:opacity-80'
// onClick={() => handleDatabaseTableAction('view', row.id)}
// >
// {t('common_module.data_table_module.view')}
// </span>
// <span
// className='text-theme-color mr-5 cursor-pointer hover:opacity-80'
// onClick={() => handleDatabaseTableAction('edit', row.id)}
// >
// {t('common_module.data_table_module.edit')}
// </span>
// <span
// className='text-error-font-color mr-5 cursor-pointer hover:opacity-80'
// onClick={() => handleDatabaseTableAction('delete', row.id)}
// >
// {t('common_module.data_table_module.delete')}
// </span>
// </div>
// )
// },
// },
{
title: () => <span>{t('common_module.data_table_module.action')}</span>,
key: 'action',
align: 'left',
ellipsis: {
tooltip: true,
},
width: 100,
fixed: 'right',
render(row: DBTableItemInterface) {
return (
<div>
<span
className='text-theme-color mr-5 cursor-pointer hover:opacity-80'
onClick={() => {
handleDatabaseTableAction('view', row.name)
}}
>
{t('common_module.data_table_module.view')}
</span>
</div>
)
},
},
]
}
export function createDatabaseTableDetailColumns(columns: string[] = []) {
return [
...columns.map((column, index) => {
return {
title: column,
key: column,
align: 'left',
ellipsis: {
tooltip: {
contentClass: 'max-w-[340px]',
},
},
width: 170,
render(row: DBTableDataItemInterface[]) {
if (!row?.[index] || row[index].value === null || row[index].value === undefined) {
return '--'
}
if (row[index]?.type === 'data' && row[index]?.value) {
return formatDateTime(row?.[index]?.value)
}
return `${row[index]?.value}` || '--'
},
}
}),
]
}
<script lang="ts" setup>
import { computed, onMounted, ref, useTemplateRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import { DataTableInst } from 'naive-ui'
import { createDatabaseTableDetailColumns } from './columns'
import CustomPagination from '@/components/custom-pagination/custom-pagination.vue'
import { type DefaultPaginationData, usePagination } from '@/composables/usePagination'
import useTableScrollY from '@/composables/useTableScrollY'
import { DBTableDataItemInterface } from './type'
import { fetchGetDBTableDataList } from '@/apis/database'
const route = useRoute()
const router = useRouter()
const { t } = useI18n()
const dbTableDataRef = useTemplateRef<DataTableInst>('dbTableDataRef')
const { pageContentWrapRef, tableContentY } = useTableScrollY(37 + 44 + 48 + 44)
const { paginationData, handlePageNoChange, handlePageSizeChange } = usePagination()
const dbTableName = ref('')
const dbTableDataListLoading = ref(false)
const tableColumns = ref<string[]>([])
const dbTableDataList = ref<DBTableDataItemInterface[][]>([])
const dbTableColumns = computed(() => {
return createDatabaseTableDetailColumns(tableColumns.value)
})
const dbTableScrollX = computed(() => {
return tableColumns.value.length * 170
})
watch([() => paginationData.pageNo, () => paginationData.pageSize], () => {
getDBTableDataList()
dbTableDataRef.value?.scrollTo({ top: 0, behavior: 'smooth' })
})
onMounted(() => {
dbTableName.value = (route.params.tableName as string) || ''
getDBTableDataList()
})
async function getDBTableDataList() {
const payload = {
id: route.params.databaseId as string,
table: route.params.tableName as string,
pagingInfo: paginationData,
}
dbTableDataListLoading.value = true
const res = await fetchGetDBTableDataList<{
column: string[]
tableDatas: { type: string; value: any }[][]
pageInfo: DefaultPaginationData
}>(payload).finally(() => {
dbTableDataListLoading.value = false
})
if (res.code === 0) {
tableColumns.value = res.data.column
dbTableDataList.value = res.data.tableDatas.map((tableDataItem) => {
return tableDataItem.map((item, index) => {
return { ...item, key: tableColumns.value?.[index] }
})
})
paginationData.totalPages = res.data?.pageInfo?.totalPages || 0
paginationData.totalRows = res.data?.pageInfo?.totalRows || 0
}
}
function handleNavBack() {
router.replace({
name: 'PersonalSpaceDBTable',
params: { id: route.params.databaseId as string },
})
}
</script>
<template>
<div ref="pageContentWrapRef" class="flex h-full w-full flex-col overflow-hidden">
<div class="mb-4">
<span class="cursor-pointer select-none text-[14px] hover:opacity-80" @click="handleNavBack">
<i class="iconfont icon-left mr-[6px] text-[12px]"></i>
<span>{{ dbTableName || '返回数据表列表' }}</span>
</span>
</div>
<div class="flex h-full w-full flex-1 flex-col overflow-hidden rounded-[10px] bg-white p-[22px]">
<div class="h-full w-full flex-1">
<n-data-table
ref="dbTableDataRef"
:loading="dbTableDataListLoading"
:columns="dbTableColumns"
:data="dbTableDataList"
:bordered="true"
:bottom-bordered="true"
:max-height="tableContentY"
:scroll-x="dbTableScrollX"
>
<template #empty>
<div :style="{ height: tableContentY + 'px' }" class="flex items-center justify-center">
<div class="flex flex-col items-center justify-center">
<div class="bg-px-empty_list-png mb-5 h-[68px] w-[68px]" />
<p class="text-gray-font-color select-none">{{ t('common_module.empty_data') }}</p>
</div>
</div>
</template>
</n-data-table>
</div>
<footer class="mt-4 flex justify-end">
<CustomPagination
:paging-info="paginationData"
@update-page-no="handlePageNoChange"
@update-page-size="handlePageSizeChange"
/>
</footer>
</div>
</div>
</template>
......@@ -14,7 +14,7 @@ const { t } = useI18n()
const route = useRoute()
const router = useRouter()
const { pageContentWrapRef, tableContentY } = useTableScrollY(46 + 48 + 33)
const { pageContentWrapRef, tableContentY } = useTableScrollY(46 + 48 + 37)
// const { paginationData, handlePageNoChange, handlePageSizeChange } = usePagination()
// const searchDBTableInputValue = ref('')
......@@ -23,7 +23,7 @@ const dbTableList = ref<DBTableItemInterface[]>([])
const dbTableListLoading = ref(true)
const dbTitle = ref('')
const dbTableColumns = createDatabaseColumn({ t })
const dbTableColumns = createDatabaseColumn(handleDatabaseTableAction)
const emptyTableDataText = computed(() => {
return isSearchEmptyList.value ? t('common_module.search_empty_data') : t('common_module.empty_data')
......@@ -63,6 +63,24 @@ function getDBTableList() {
})
}
function handleDatabaseTableAction(actionType: string, tableName: string) {
switch (actionType) {
case 'view':
handleViewDatabaseTable(tableName)
break
}
}
function handleViewDatabaseTable(tableName: string) {
router.push({
name: 'PersonalSpaceDBTableDetail',
params: {
databaseId: route.params.id as string,
tableName,
},
})
}
function handleNavBack() {
router.replace({
name: 'PersonalSpaceDatabase',
......@@ -71,7 +89,7 @@ function handleNavBack() {
</script>
<template>
<div ref="pageContentWrapRef" class="h-full w-full">
<div ref="pageContentWrapRef" class="flex h-full w-full flex-col overflow-hidden">
<!-- <div class="mb-[18px] flex justify-end">
<n-input v-model:value="searchDBTableInputValue" :placeholder="t('common_module.search')" class="w-[256px]!">
<template #suffix>
......@@ -79,14 +97,14 @@ function handleNavBack() {
</template>
</n-input>
</div> -->
<div class="mb-[12px]">
<div class="mb-4">
<span class="cursor-pointer select-none text-[14px]" @click="handleNavBack">
<i class="iconfont icon-left mr-[6px] text-[12px]"></i>
<span>{{ dbTitle || '返回数据库列表' }}</span>
</span>
</div>
<div class="rounded-[10px] bg-white p-[23px]">
<div class="flex-1 rounded-[10px] bg-white p-[23px]">
<n-data-table
:loading="dbTableListLoading"
:bordered="true"
......
......@@ -6,3 +6,9 @@ export interface DBTableItemInterface {
// updatedTime: Data
dataSize: string
}
export interface DBTableDataItemInterface {
key: string
type: string
value: any
}
......@@ -668,6 +668,9 @@ declare namespace I18n {
connect_test_fail: string
connect_test_must_pass_to_create: string
connect_test_must_pass_to_update: string
table_name: string
table_desc: string
table_data_volume: string
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment