💄 主页面组件

This commit is contained in:
bunny 2025-06-25 21:48:12 +08:00
parent 0cd9129efa
commit 7633593bfc
1 changed files with 15 additions and 292 deletions

View File

@ -21,304 +21,41 @@
<div id="app"> <div id="app">
<div class="container my-4"> <div class="container my-4">
<!-- 主标题 --> <!-- 主标题 -->
<div class="text-center mb-4"> <app-header></app-header>
<h2 class="text-primary fw-bold">
<i class="bi bi-code-square me-2"></i>
代码生成器
</h2>
<p class="text-muted">快速生成数据库表对应的代码</p>
</div>
<!-- 主卡片 --> <!-- 主卡片 -->
<div class="card shadow-sm"> <main-card :raw-table-list="rawTableList"
<!-- 卡片头部 --> @get-database-table-list="getDatabaseTableList"
<div class="card-header bg-primary bg-opacity-10 border-bottom"> v-model:db-select="dbSelect" v-model:table-select="tableSelect"></main-card>
<div class="d-flex justify-content-between align-items-center">
<div>
<h5 class="card-title mb-0">
<i class="bi bi-info-circle-fill text-primary me-2"></i>使用提示
</h5>
</div>
<div>
<span class="badge bg-primary rounded-pill me-2">
<i class="bi bi-database me-1"></i>
数据库: <span class="fw-normal">{{databaseList.length}}</span>
</span>
<span class="badge bg-primary rounded-pill">
<i class="bi bi-table me-1"></i>
数据库表: <span class="fw-normal">{{rawTableList.length}}</span>
</span>
</div>
</div>
<p class="card-subtitle mt-2 text-muted">
<i class="bi bi-mouse me-1"></i>
点击 <code class="bg-primary bg-opacity-10">表名</code>
<code class="bg-primary bg-opacity-10">生成</code> 进行跳转
</p>
</div>
<!-- 卡片主体 -->
<div class="card-body">
<div class="d-flex flex-wrap align-items-center gap-3">
<!-- GitHub 链接 -->
<a class="btn btn-outline-dark d-flex align-items-center gap-2"
href="https://github.com/BunnyMaster/generator-code-server" target="_blank">
<svg class="feather feather-github" fill="none" height="20" stroke="currentColor"
stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg">
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
</svg>
GitHub 仓库
</a>
<!-- Gitee 链接 -->
<a class="btn btn-outline-danger d-flex align-items-center gap-2"
href="https://gitee.com/BunnyBoss/generator-code-server" target="_blank">
<svg height="20" viewBox="0 0 24 24" width="20" xmlns="http://www.w3.org/2000/svg">
<path d="M11.984 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12a12 12 0 0 0 12-12A12 12 0 0 0 12 0zm6.09 5.333c.328 0 .593.266.592.593v1.482a.594.594 0 0 1-.593.592H9.777c-.982 0-1.778.796-1.778 1.778v5.63c0 .327.266.592.593.592h5.63c.982 0 1.778-.796 1.778-1.778v-.296a.593.593 0 0 0-.592-.593h-4.15a.59.59 0 0 1-.592-.592v-1.482a.593.593 0 0 1 .593-.592h6.815c.327 0 .593.265.593.592v3.408a4 4 0 0 1-4 4H5.926a.593.593 0 0 1-.593-.593V9.778a4.444 4.444 0 0 1 4.445-4.444h8.296Z"
fill="currentColor"/>
</svg>
Gitee 仓库
</a>
</div>
</div>
<!-- 卡片底部 - 数据库选择 -->
<div class="card-footer bg-light">
<div class="row g-3 align-items-end">
<div class="col-md-5">
<label class="form-label fw-semibold" for="databaseSelect">
<i class="bi bi-database me-1"></i>数据库选择
</label>
<select class="form-select shadow-sm" id="databaseSelect" v-model="dbSelect">
<option disabled selected>请选择数据库...</option>
<option :key="index" :title="db.comment" :value="db.tableCat"
v-for="(db,index) in databaseList">
{{db.tableCat}}
</option>
</select>
</div>
<div class="col-md-5">
<label class="form-label fw-semibold" for="tableSelect">
<i class="bi bi-table me-1"></i>
数据库表选择
</label>
<input class="form-control shadow-sm" id="tableSelect" placeholder="输入表名或表注释"
v-model="tableSelect"/>
</div>
<div class="col-md-2 d-grid">
<button class="btn btn-primary shadow-sm" disabled type="button"
v-if="dbLoading">
<span aria-hidden="true" class="spinner-grow spinner-grow-sm"></span>
<span role="status">Loading...</span>
</button>
<button @click="getDatabaseInfoMetaData" class="btn btn-primary shadow-sm" v-else>
<i class="bi bi-search me-1"></i>
查询
</button>
</div>
</div>
<div class="pt-1 bg-light">
<a class="d-flex align-items-center text-decoration-none" data-bs-toggle="collapse"
href="#dbInfoCollapse">
<i class="bi bi-database me-2"></i>
<span>数据库连接详情</span>
<i class="bi bi-chevron-down ms-auto"></i>
</a>
<div class="collapse mt-2" id="dbInfoCollapse">
<div class="card card-body bg-white">
<ul class="list-unstyled mb-0">
<li class="mb-2">
<strong>数据库:</strong> {{databaseInfo.databaseProductName}}
{{databaseInfo.databaseProductVersion}}
</li>
<li class="mb-2">
<strong>驱动:</strong> {{databaseInfo.driverName}}
({{databaseInfo.driverVersion}})
</li>
<li class="mb-2"><strong>URL:</strong>
<code class="d-block text-break">{{databaseInfo.url}}</code>
</li>
<li class="mb-2"><strong>用户:</strong> {{databaseInfo.username}}</li>
<li><strong>当前库:</strong> {{databaseInfo.currentDatabase}}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- 表格显示 --> <!-- 表格显示 -->
<div class="card mt-4 shadow-sm"> <main-table :loading="loading" :raw-table-list="rawTableList" :table-list="tableList"></main-table>
<div class="card-header bg-primary bg-opacity-10">
<h5 class="card-title mb-0">
<i class="bi bi-table me-2"></i>数据表列表
</h5>
</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>
<!-- 展示当前数据库所有的表 -->
<table class="table table-striped table-bordered table-hover mb-0" v-else>
<thead class="table-light">
<tr>
<th scope="col" width="5%">#</th>
<th scope="col" width="30%">表名</th>
<th scope="col" width="35%">注释</th>
<th scope="col" width="20%">所属数据库</th>
<th class="text-center" scope="col" width="10%">操作</th>
</tr>
</thead>
<tbody>
<tr :key="index" v-for="(table,index) in paginatedTableList">
<th scope="row">{{index + 1}}</th>
<td><a class="text-decoration-none" href="#">{{ table.tableName}}</a></td>
<td>{{ table.comment }}</td>
<td>{{ table.tableCat }}</td>
<td class="text-center">
<button class="btn btn-sm btn-outline-primary">
<i class="bi bi-gear"></i> 生成
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 在表格显示卡片底部添加分页 -->
<div class="card-footer bg-light">
<div class="d-flex justify-content-between align-items-center">
<div class="form-text">共 {{ totalItems }} 条</div>
<nav aria-label="Page navigation">
<ul class="pagination mb-0">
<li :class="{ disabled: currentPage === 1 }" class="page-item">
<a @click.prevent="currentPage = 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="currentPage--" class="page-link" href="#">
<i class="bi bi-chevron-left"></i>
</a>
</li>
<!-- 显示页码 -->
<li :class="{ active: currentPage === page }" :key="page" class="page-item"
v-for="page in visiblePages">
<a @click.prevent="currentPage = page" class="page-link" href="#">{{ page }}</a>
</li>
<li :class="{ disabled: currentPage === totalPages }" class="page-item">
<a @click.prevent="currentPage++" class="page-link" href="#">
<i class="bi bi-chevron-right"></i>
</a>
</li>
<li :class="{ disabled: currentPage === totalPages }" class="page-item">
<a @click.prevent="currentPage = 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 :key="index" v-for="(table,index) in tablePageOptions">
<a @click.prevent="itemsPerPage = table" class="dropdown-item" href="JavaScript:">
{{table}} 条/页
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</body> </body>
<script th:src="@{/lib/vue/index/AppHeader.js}"></script>
<script th:src="@{/lib/vue/index/MainCard.js}"></script>
<script th:src="@{/lib/vue/index/MainTable.js}"></script>
<script> <script>
const {createApp, ref} = Vue const {createApp, ref} = Vue
createApp({ const app = createApp({
setup() { setup() {
return { return {
// 数据库选择 // 数据库选择
dbSelect: ref(""), dbSelect: ref(""),
// 数据库表过滤 // 数据库表过滤
tableSelect: ref(""), tableSelect: ref(""),
// 所有数据库列表
databaseList: ref([]),
// 数据库信息
databaseInfo: ref({}),
// 数据库表列表 // 数据库表列表
tableList: ref([]), tableList: ref([]),
// 原始数据库列表 // 原始数据库列表
rawTableList: ref([]), rawTableList: ref([]),
// 查询数据库加载
dbLoading: ref(false),
// 是否加载 // 是否加载
loading: ref(false), loading: ref(false),
// 分页相关数据
currentPage: ref(1),
// 每页数
itemsPerPage: ref(10),
// 总的数据条数
totalItems: ref(0),
// 表格选项
tablePageOptions: [5, 10, 20, 50, 100, 150, 200]
}; };
}, },
computed: {
// 计算总页数
totalPages() {
return Math.ceil(this.totalItems / this.itemsPerPage);
},
// 分页后的数据
paginatedTableList() {
const start = (this.currentPage - 1) * this.itemsPerPage;
const end = start + this.itemsPerPage;
return this.tableList.slice(start, end);
}
},
methods: { methods: {
/* 当前连接的数据库信息 */
async getDatabaseInfoMetaData() {
this.dbLoading = true;
const response = await axios.get("/table/databaseInfoMetaData");
const {data, code} = response.data;
if (code !== 200) return;
this.databaseInfo = data
// 设置返回的所有的数据库列表
this.databaseList = data.databaseList;
// 设置当前的数据库
this.dbSelect = data.currentDatabase;
this.dbLoading = false;
},
/* 获取[当前/所有]数据库表 */ /* 获取[当前/所有]数据库表 */
async getDatabaseTableList() { async getDatabaseTableList() {
this.loading = true; this.loading = true;
@ -339,24 +76,6 @@
this.loading = false; this.loading = false;
}, },
/* 计算可见的页码范围 */
visiblePages() {
// 显示当前页前后各2页
const range = 2;
const start = Math.max(1, this.currentPage - range);
const end = Math.min(this.totalPages, this.currentPage + range);
const pages = [];
for (let i = start; i <= end; i++) {
pages.push(i);
}
return pages;
}
},
mounted() {
// 当前连接的数据库信息
this.getDatabaseInfoMetaData();
}, },
watch: { watch: {
/* 数据表选择 */ /* 数据表选择 */
@ -370,13 +89,17 @@
tableSelect: { tableSelect: {
handler(val) { handler(val) {
this.tableList = this.rawTableList; this.tableList = this.rawTableList;
// 根据表名进行过滤筛选或者根据注释内容进行筛选 // 根据表名进行过滤筛选或者根据注释内容进行筛选
this.tableList = this.tableList.filter(table => table.tableName.includes(val) || table.comment.includes(val)); this.tableList = this.tableList.filter(table => table.tableName.includes(val) || table.comment.includes(val));
} }
} }
} }
}).mount('#app'); });
app.component('AppHeader', AppHeader);
app.component('MainCard', MainCard);
app.component('MainTable', MainTable);
app.mount('#app');
</script> </script>
</html> </html>