添加获取当前数据表列信息

This commit is contained in:
bunny 2025-07-02 19:29:44 +08:00
parent 395ec89666
commit 7f55cecb7a
2 changed files with 221 additions and 155 deletions

View File

@ -31,6 +31,6 @@ public class TableMetaData {
private String className; private String className;
@Schema(name = "columns", description = "列名称") @Schema(name = "columns", description = "列名称")
private List<ColumnMetaData> columns; private List<ColumnMetaData> columns = List.of();
} }

View File

@ -1,138 +1,197 @@
const DatabaseTable = defineComponent({ const DatabaseTable = defineComponent({
name: "MainTable", name: "MainTable",
template: ` template: `
<div class="card mt-2 shadow-sm"> <div class="card mt-2 shadow-sm">
<!-- 表格标题和选择选项 --> <!-- 表格标题和选择选项 -->
<div class="d-flex justify-content-between card-header bg-primary bg-opacity-10"> <div class="d-flex justify-content-between card-header bg-primary bg-opacity-10">
<h5 class="card-title mb-0"> <h5 class="card-title mb-0">
<i class="bi bi-table me-2"></i> <i class="bi bi-table me-2"></i>
</h5> </h5>
<div> <div>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="form-check-input" name="TableSelectRadios" type="radio" id="radioSelectAll" <input class="form-check-input" name="TableSelectRadios" type="radio" id="radioSelectAll" value="all"
value="all" v-model="selectedOption"> v-model="selectedOption">
<label class="form-check-label" for="radioSelectAll">选择全部</label> <label class="form-check-label" for="radioSelectAll">选择全部</label>
</div> </div>
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="form-check-input" name="TableSelectRadios" type="radio" id="radioSelectCurrentPage" <input class="form-check-input" name="TableSelectRadios" type="radio" id="radioSelectCurrentPage"
value="current" v-model="selectedOption"> value="current" v-model="selectedOption">
<label class="form-check-label" for="radioSelectCurrentPage">选择当前页</label> <label class="form-check-label" for="radioSelectCurrentPage">选择当前页</label>
</div> </div>
</div>
</div>
<!-- 表格内容区域 -->
<div class="card-body p-0">
<div class="table-responsive">
<!-- 加载状态 -->
<div class="p-5 text-center" v-if="loading">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div> </div>
</div> </div>
<!-- 空状态提示 --> <!-- 表格内容区域 -->
<div class="p-5 text-center" v-else-if="tableList.length === 0"> <div class="card-body p-0">
<i class="bi bi-exclamation-circle fs-1 text-muted"></i> <div class="table-responsive">
<p class="mt-2 text-muted">没有找到数据表</p> <!-- 加载状态 -->
<div class="p-5 text-center" v-if="loading">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<!-- 空状态提示 -->
<div class="p-5 text-center" v-else-if="tableList.length === 0">
<i class="bi bi-exclamation-circle fs-1 text-muted"></i>
<p class="mt-2 text-muted">没有找到数据表</p>
</div>
<!-- 数据表格 -->
<table class="table table-striped table-bordered table-hover mb-0" v-else>
<thead class="table-light">
<tr>
<th scope="col" width="2%">
<input class="form-check-input border-secondary" type="checkbox"
v-model="tableSelectAllChecked" @change="onSelectAllTable">
</th>
<th scope="col" width="3%">#</th>
<th scope="col" width="25%">表名</th>
<th scope="col" width="25%">注释</th>
<th scope="col" width="15%">所属数据库</th>
<th class="text-center" scope="col" width="15%">操作</th>
</tr>
</thead>
<tbody>
<template v-for="(table, index) in paginatedTableList" :key="table.tableName">
<tr>
<td>
<input class="form-check-input border-secondary" type="checkbox" v-model="table.checked"
@change="onSelectTable($event.target.checked, table)">
</td>
<td>{{ (currentPage - 1) * itemsPerPage + index + 1 }}</td>
<td>
<a class="text-decoration-none" href="#" @click.prevent="toggleTableDetails(table)">
{{ table.tableName }}
<i class="bi"
:class="{'bi-chevron-down': !table.showDetails, 'bi-chevron-up': table.showDetails}"></i>
</a>
</td>
<td>{{ table.comment || '无注释' }}</td>
<td>{{ table.tableCat }}</td>
<td class="d-flex justify-content-around">
<button class="btn btn-sm btn-outline-primary"
@click="onSelectTable(!table.checked, table)">
<i class="bi bi-database-check"></i>
</button>
<button class="btn btn-sm btn-outline-primary" @click="toggleTableDetails(table)">
<i class="bi bi-gear"></i>
</button>
</td>
</tr>
<!-- 表详情展开行 -->
<tr v-if="table.showDetails">
<td colspan="6" class="p-0">
<div class="p-3 bg-light">
<h6 class="mb-3">表信息</h6>
<div class="row mb-4">
<div class="col-md-3">
<p class="mb-1"><strong>表名:</strong> {{table.tableName}}</p>
</div>
<div class="col-md-3">
<p class="mb-1"><strong>类型:</strong> {{table.tableType}}</p>
</div>
<div class="col-md-6">
<p class="mb-1"><strong>注释:</strong> {{table.comment || ''}}</p>
</div>
</div>
<h6 class="mb-3">列信息</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead>
<tr>
<th>列名</th>
<th>数据库类型</th>
<th>Java类型</th>
<th>JS类型</th>
<th>主键</th>
<th>注释</th>
</tr>
</thead>
<tbody>
<tr v-for="column in table.columns" :key="column.columnName">
<td>{{column.columnName}}</td>
<td>{{column.jdbcType}}</td>
<td>{{column.javaType}}</td>
<td>{{column.javascriptType}}</td>
<td>
<span class="badge bg-success"
v-if="column.isPrimaryKey"></span>
<span class="badge bg-secondary" v-else></span>
</td>
<td>{{column.comment || '无'}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div> </div>
<!-- 数据表格 --> <!-- 分页控件 -->
<table class="table table-striped table-bordered table-hover mb-0" v-else> <div class="card-footer bg-light" v-if="tableList.length > 0">
<thead class="table-light"> <div class="d-flex justify-content-between align-items-center">
<tr> <div class="form-text">
<th scope="col" width="2%"> 显示 {{ (currentPage - 1) * itemsPerPage + 1 }}~{{ Math.min(currentPage * itemsPerPage,
<input class="form-check-input border-secondary" type="checkbox" rawTableList.length) }} {{ rawTableList.length }}
v-model="tableSelectAllChecked" @change="onSelectAllTable"> </div>
</th>
<th scope="col" width="3%">#</th> <nav aria-label="Page navigation">
<th scope="col" width="30%">表名</th> <ul class="pagination mb-0">
<th scope="col" width="35%">注释</th> <li :class="{ disabled: currentPage === 1 }" class="page-item">
<th scope="col" width="20%">所属数据库</th> <a @click.prevent="goToPage(1)" class="page-link" href="#">
<th class="text-center" scope="col" width="10%">操作</th> <i class="bi bi-chevron-double-left"></i>
</tr> </a>
</thead> </li>
<tbody> <li :class="{ disabled: currentPage === 1 }" class="page-item">
<tr :key="table.tableName" v-for="(table, index) in paginatedTableList"> <a @click.prevent="goToPage(currentPage - 1)" class="page-link" href="#">
<td> <i class="bi bi-chevron-left"></i>
<input class="form-check-input border-secondary" type="checkbox" </a>
v-model="table.checked" @change="onSelectTable($event.target.checked, table)"> </li>
</td>
<td>{{ (currentPage - 1) * itemsPerPage + index + 1 }}</td> <!-- 显示页码 -->
<td> <li v-for="page in visiblePages" :key="page" :class="{ active: currentPage === page }"
<a class="text-decoration-none" href="#" @click.prevent="onSelectTable(!table.checked, table)"> class="page-item">
{{ table.tableName }} <a @click.prevent="goToPage(page)" class="page-link" href="#">{{ page }}</a>
</a> </li>
</td>
<td>{{ table.comment || '无注释' }}</td> <li :class="{ disabled: currentPage === totalPages }" class="page-item">
<td>{{ table.tableCat }}</td> <a @click.prevent="goToPage(currentPage + 1)" class="page-link" href="#">
<td class="text-center"> <i class="bi bi-chevron-right"></i>
<button class="btn btn-sm btn-outline-primary" @click="onSelectTable(!table.checked, table)"> </a>
<i class="bi bi-gear"></i> </li>
<li :class="{ disabled: currentPage === totalPages }" class="page-item">
<a @click.prevent="goToPage(totalPages)" class="page-link" href="#">
<i class="bi bi-chevron-double-right"></i>
</a>
</li>
</ul>
</nav>
<div class="dropdown">
<button aria-expanded="false" class="btn btn-outline-secondary dropdown-toggle"
data-bs-toggle="dropdown" id="itemsPerPageDropdown" type="button">
每页 {{ itemsPerPage }}
</button> </button>
</td> <ul aria-labelledby="itemsPerPageDropdown" class="dropdown-menu">
</tr> <li v-for="option in tablePageOptions" :key="option">
</tbody> <a @click.prevent="changeItemsPerPage(option)" class="dropdown-item" href="#">
</table> {{ option }} /
</div> </a>
</div> </li>
</ul>
<!-- 分页控件 --> </div>
<div class="card-footer bg-light" v-if="tableList.length > 0"> </div>
<div class="d-flex justify-content-between align-items-center">
<div class="form-text">
显示 {{ (currentPage - 1) * itemsPerPage + 1 }}~{{ Math.min(currentPage * itemsPerPage, rawTableList.length) }} {{ rawTableList.length }}
</div>
<nav aria-label="Page navigation">
<ul class="pagination mb-0">
<li :class="{ disabled: currentPage === 1 }" class="page-item">
<a @click.prevent="goToPage(1)" class="page-link" href="#">
<i class="bi bi-chevron-double-left"></i>
</a>
</li>
<li :class="{ disabled: currentPage === 1 }" class="page-item">
<a @click.prevent="goToPage(currentPage - 1)" class="page-link" href="#">
<i class="bi bi-chevron-left"></i>
</a>
</li>
<!-- 显示页码 -->
<li v-for="page in visiblePages" :key="page"
:class="{ active: currentPage === page }" class="page-item">
<a @click.prevent="goToPage(page)" class="page-link" href="#">{{ page }}</a>
</li>
<li :class="{ disabled: currentPage === totalPages }" class="page-item">
<a @click.prevent="goToPage(currentPage + 1)" class="page-link" href="#">
<i class="bi bi-chevron-right"></i>
</a>
</li>
<li :class="{ disabled: currentPage === totalPages }" class="page-item">
<a @click.prevent="goToPage(totalPages)" class="page-link" href="#">
<i class="bi bi-chevron-double-right"></i>
</a>
</li>
</ul>
</nav>
<div class="dropdown">
<button aria-expanded="false" class="btn btn-outline-secondary dropdown-toggle"
data-bs-toggle="dropdown" id="itemsPerPageDropdown" type="button">
每页 {{ itemsPerPage }}
</button>
<ul aria-labelledby="itemsPerPageDropdown" class="dropdown-menu">
<li v-for="option in tablePageOptions" :key="option">
<a @click.prevent="changeItemsPerPage(option)" class="dropdown-item" href="#">
{{ option }} /
</a>
</li>
</ul>
</div> </div>
</div> </div>
</div>
</div>
`, `,
props: { props: {
// 加载状态 // 加载状态
@ -264,6 +323,32 @@ const DatabaseTable = defineComponent({
} }
}, },
/**
* 切换表格详情展开/收起状态
* 如果是首次展开且没有列数据则请求获取列信息
* @param {Object} table - 表格对象
* @returns {Promise<void>}
*/
async toggleTableDetails(table) {
// 如果是展开操作且没有列数据,则请求获取列信息
if (!table.showDetails && !table.columns) {
// 发送请求获取列信息
const {data, code, message} = await axiosInstance({
url: "/table/tableColumnInfo",
params: {tableName: table.tableName}
});
// 请求成功时保存列数据
if (code === 200) {
table.columns = data;
antd.message.success(message);
}
}
// 切换展开/收起状态
table.showDetails = !table.showDetails;
},
/* 更新表单中选中的表名 */ /* 更新表单中选中的表名 */
updateFormSelectedTables() { updateFormSelectedTables() {
const payload = { const payload = {
@ -279,39 +364,20 @@ const DatabaseTable = defineComponent({
* 如果要同时更新会变得很复杂所以在这里讲逻辑定义为 * 如果要同时更新会变得很复杂所以在这里讲逻辑定义为
* 选型变化时直接取消全部之后重新选择 * 选型变化时直接取消全部之后重新选择
*/ */
restForm() { resetForm() {
this.tableSelectAllChecked = false; this.tableSelectAllChecked = false;
this.tableList.forEach(table => table.checked = false); this.tableList.forEach(table => table.checked = false);
this.updateFormSelectedTables(); this.updateFormSelectedTables();
} }
}, },
watch: { watch: {
/** /* 监听选择模式变化 */
* 监听选择模式变化 selectedOption: 'resetForm',
*/ /* 监听当前页变化 */
selectedOption() { currentPage: 'resetForm',
this.restForm(); /* 监听每页条数变化 */
}, itemsPerPage: 'resetForm',
/* 数据库选择发生变化也重置表单 */
/** dbSelect: 'resetForm',
* 监听当前页变化
*/
currentPage() {
this.restForm();
},
/**
* 监听每页条数变化
*/
itemsPerPage() {
this.restForm();
},
/**
* 数据库选择发生变化也重置表单
*/
dbSelect() {
this.restForm();
}
} }
}); });