feat: 重构页面布局为独立磨砂卡片样式并修改数据库文件名

优化说明:
1. 调整多个页面布局,将内容区拆分为独立的磨砂卡片,统一样式规范
2. 修改全局磨砂玻璃面板的透明度,避免阴影叠加导致的灰色遮罩
3. 新增扁平磨砂卡片样式,移除不必要的阴影
4. 将数据库文件名从 reader.db 改为 frpilot.db
5. 更新相关文档说明,同步 UI 修改内容
This commit is contained in:
Yuhang Wu
2026-10-13 14:27:38 +08:00
parent 5fea53aff1
commit 30ddf583e5
9 changed files with 66 additions and 27 deletions
+12 -2
View File
@@ -28,7 +28,7 @@
### 2. 设置页面外观设置 ### 2. 设置页面外观设置
#### 窗口背景设置开发 #### 2.1 窗口背景设置开发
- 我新加了一个设置页面Setting.vue和一个外观设置Appearance.vue文件,帮我在路由表里面增加设置页路由,以及外观设置子路由 - 我新加了一个设置页面Setting.vue和一个外观设置Appearance.vue文件,帮我在路由表里面增加设置页路由,以及外观设置子路由
- 设置页面左侧为菜单栏,先增加第一项菜单-外观设置,设置项为主题模式切换(明/暗)、背景图片切换 - 设置页面左侧为菜单栏,先增加第一项菜单-外观设置,设置项为主题模式切换(明/暗)、背景图片切换
@@ -37,6 +37,14 @@
开发过程中使用到的组件尽可能全部使用Antdv库里面的,另外我引入的有tailwindcss原子化组件,开发之前尽可能先阅读一下package.json,看一下有哪些依赖可以简化代码开发 开发过程中使用到的组件尽可能全部使用Antdv库里面的,另外我引入的有tailwindcss原子化组件,开发之前尽可能先阅读一下package.json,看一下有哪些依赖可以简化代码开发
#### 2.2 UI修改
Layout布局content区域的磨砂玻璃卡片圆角样式我要改动一下:
- 不是在整个main区域设置成glass-panel样式
- 而是在每一个页面单独设置,现在先以服务器配置页面为例,按照我图片中红色框选部分作为区域分割
- 左侧菜单栏已经是glass-panel样式,现在需要在main区域设置成圆角卡片磨砂玻璃效果
### 3. 功能开发 ### 3. 功能开发
#### 3.1 开发服务器配置功能 #### 3.1 开发服务器配置功能
@@ -46,4 +54,6 @@
- 页面展示已经配置的服务器列表,列表服务器以卡片形式展示,卡片有开关可以直接操作是否置顶和是否启用,是否启用选项只能启用一个,另外还需要有编辑和删除,新增和编辑使用同一个表单 - 页面展示已经配置的服务器列表,列表服务器以卡片形式展示,卡片有开关可以直接操作是否置顶和是否启用,是否启用选项只能启用一个,另外还需要有编辑和删除,新增和编辑使用同一个表单
- 服务器信息在Rust端使用SQLite存储,Rust已经加入相关的sqlx依赖等,后端操作返回前端务必使用ApiResponse统一返回格式,前端也需要做好对应的类型匹配 - 服务器信息在Rust端使用SQLite存储,Rust已经加入相关的sqlx依赖等,后端操作返回前端务必使用ApiResponse统一返回格式,前端也需要做好对应的类型匹配
开发过程中使用到的组件尽可能全部使用Antdv库里面的,另外我引入的有tailwindcss原子化组件、auto-import和components依赖可以简化引入,开发之前尽可能先阅读一下package.json,看一下有哪些依赖可以简化代码开发 开发过程中使用到的组件尽可能全部使用Antdv库里面的,另外我引入的有tailwindcss原子化组件、auto-import和components依赖可以简化引入,开发之前尽可能先阅读一下package.json,看一下有哪些依赖可以简化代码开发
3.2 开发隧道
+1 -1
View File
@@ -5,7 +5,7 @@ pub async fn init_pool(app: &AppHandle) -> Result<SqlitePool, sqlx::Error> {
// 数据库文件路径 // 数据库文件路径
let app_dir = app.path().app_data_dir().expect("无法获取APP数据目录"); let app_dir = app.path().app_data_dir().expect("无法获取APP数据目录");
std::fs::create_dir_all(&app_dir).unwrap(); std::fs::create_dir_all(&app_dir).unwrap();
let db_path = app_dir.join("reader.db"); let db_path = app_dir.join("frpilot.db");
// 初始化数据库连接池 // 初始化数据库连接池
let options = SqliteConnectOptions::new() let options = SqliteConnectOptions::new()
.filename(&db_path) .filename(&db_path)
+7 -1
View File
@@ -56,6 +56,12 @@ body {
justify-content: center; justify-content: center;
} }
/* 主内容区卡片:去掉投影,避免上下卡片之间的阴影透过半透明背景叠加成灰色遮罩 */
.glass-panel.glass-panel-flat,
.dark .glass-panel.glass-panel-flat {
box-shadow: none;
}
/* 窗口圆角固定 8px,与 Windows 11 系统默认圆角保持一致 */ /* 窗口圆角固定 8px,与 Windows 11 系统默认圆角保持一致 */
#app { #app {
border-radius: 8px; border-radius: 8px;
@@ -66,7 +72,7 @@ body {
.glass-panel { .glass-panel {
border-radius: 16px; border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.55); border: 1px solid rgba(255, 255, 255, 0.55);
background: rgba(255, 255, 255, 0.55); background: rgba(255, 255, 255, 0.35);
backdrop-filter: blur(18px) saturate(160%); backdrop-filter: blur(18px) saturate(160%);
-webkit-backdrop-filter: blur(18px) saturate(160%); -webkit-backdrop-filter: blur(18px) saturate(160%);
box-shadow: 0 8px 32px rgba(15, 23, 42, 0.12); box-shadow: 0 8px 32px rgba(15, 23, 42, 0.12);
+1 -1
View File
@@ -8,7 +8,7 @@
<div class="flex min-h-0 flex-1 gap-3 px-3 pb-3"> <div class="flex min-h-0 flex-1 gap-3 px-3 pb-3">
<Aside /> <Aside />
<main class="glass-panel min-w-0 flex-1 overflow-y-auto"> <main class="min-w-0 flex-1 overflow-hidden">
<router-view /> <router-view />
</main> </main>
</div> </div>
+10 -3
View File
@@ -1,7 +1,14 @@
<template> <template>
<div class="flex h-full flex-col p-6"> <div class="flex h-full flex-col gap-3">
<h2 class="mb-4 text-lg font-semibold">{{ t("menu.dashboard") }}</h2> <!-- 顶部操作栏(独立磨砂卡片) -->
<a-result status="info" :sub-title="t('common.developing')" /> <div class="glass-panel glass-panel-flat flex shrink-0 items-center justify-between gap-3 px-5 py-3">
<h2 class="text-lg font-semibold">{{ t("menu.dashboard") }}</h2>
</div>
<!-- 内容区(独立磨砂卡片) -->
<div class="glass-panel glass-panel-flat min-h-0 flex-1 overflow-y-auto p-5">
<a-result status="info" :sub-title="t('common.developing')" />
</div>
</div> </div>
</template> </template>
+10 -3
View File
@@ -1,7 +1,14 @@
<template> <template>
<div class="flex h-full flex-col p-6"> <div class="flex h-full flex-col gap-3">
<h2 class="mb-4 text-lg font-semibold">{{ t("menu.download") }}</h2> <!-- 顶部操作栏(独立磨砂卡片) -->
<a-result status="info" :sub-title="t('common.developing')" /> <div class="glass-panel glass-panel-flat flex shrink-0 items-center justify-between gap-3 px-5 py-3">
<h2 class="text-lg font-semibold">{{ t("menu.download") }}</h2>
</div>
<!-- 内容区(独立磨砂卡片) -->
<div class="glass-panel glass-panel-flat min-h-0 flex-1 overflow-y-auto p-5">
<a-result status="info" :sub-title="t('common.developing')" />
</div>
</div> </div>
</template> </template>
+14 -12
View File
@@ -1,7 +1,7 @@
<template> <template>
<div class="flex h-full flex-col gap-4 p-6"> <div class="flex h-full flex-col gap-3">
<!-- 顶部:标题 + 操作按钮 --> <!-- 顶部操作栏(独立磨砂卡片) -->
<div class="flex items-center justify-between gap-3"> <div class="glass-panel glass-panel-flat flex shrink-0 items-center justify-between gap-3 px-5 py-3">
<h2 class="text-lg font-semibold">{{ t("menu.servers") }}</h2> <h2 class="text-lg font-semibold">{{ t("menu.servers") }}</h2>
<a-space> <a-space>
<a-button :loading="loading" :icon="h(ReloadOutlined)" @click="refresh()"> <a-button :loading="loading" :icon="h(ReloadOutlined)" @click="refresh()">
@@ -13,16 +13,18 @@
</a-space> </a-space>
</div> </div>
<!-- 服务器列表 --> <!-- 内容区(独立磨砂卡片,内部滚动) -->
<a-spin :spinning="loading" class="min-h-0 flex-1"> <div class="glass-panel glass-panel-flat min-h-0 flex-1 overflow-y-auto p-5">
<a-empty v-if="!servers.length" class="mt-20" :description="t('server.empty')" /> <a-spin :spinning="loading">
<a-empty v-if="!servers.length" class="mt-20" :description="t('server.empty')" />
<div v-else class="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3"> <div v-else class="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
<ServerCard v-for="item in servers" :key="item.id" :server="item" @edit="openEdit(item)" <ServerCard v-for="item in servers" :key="item.id" :server="item" @edit="openEdit(item)"
@delete="onDelete(item)" @toggle-enabled="(value) => onToggleEnabled(item, value)" @delete="onDelete(item)" @toggle-enabled="(value) => onToggleEnabled(item, value)"
@toggle-pinned="(value) => onTogglePinned(item, value)" /> @toggle-pinned="(value) => onTogglePinned(item, value)" />
</div> </div>
</a-spin> </a-spin>
</div>
<!-- 新增 / 编辑弹窗 --> <!-- 新增 / 编辑弹窗 -->
<ServerFormModal v-model:open="modalOpen" :server="editing" @saved="onSaved" /> <ServerFormModal v-model:open="modalOpen" :server="editing" @saved="onSaved" />
+1 -1
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="flex h-full min-h-0"> <div class="glass-panel flex h-full min-h-0">
<!-- 左侧:设置菜单 --> <!-- 左侧:设置菜单 -->
<aside class="w-44 shrink-0 border-r border-slate-200/70 p-2 dark:border-white/10"> <aside class="w-44 shrink-0 border-r border-slate-200/70 p-2 dark:border-white/10">
<a-menu <a-menu
+10 -3
View File
@@ -1,7 +1,14 @@
<template> <template>
<div class="flex h-full flex-col p-6"> <div class="flex h-full flex-col gap-3">
<h2 class="mb-4 text-lg font-semibold">{{ t("menu.tunnels") }}</h2> <!-- 顶部操作栏(独立磨砂卡片) -->
<a-result status="info" :sub-title="t('common.developing')" /> <div class="glass-panel glass-panel-flat flex shrink-0 items-center justify-between gap-3 px-5 py-3">
<h2 class="text-lg font-semibold">{{ t("menu.tunnels") }}</h2>
</div>
<!-- 内容区(独立磨砂卡片) -->
<div class="glass-panel glass-panel-flat min-h-0 flex-1 overflow-y-auto p-5">
<a-result status="info" :sub-title="t('common.developing')" />
</div>
</div> </div>
</template> </template>