From bcc8c03ca296868365af11567b82034378247920 Mon Sep 17 00:00:00 2001 From: Guo Tiantian <1431335589@qq.com> Date: Thu, 28 Aug 2025 23:17:41 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E5=A4=96?= =?UTF-8?q?=E9=93=BE=E6=A0=87=E7=AD=BE=E6=A0=B7=E5=BC=8F=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=B3=BB=E7=BB=9F=E4=B8=BB=E9=A2=98=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/CHANGELOG.md | 386 --- frontend/PROJECT_GUIDE.md | 3053 +++++++++++++++++ .../src/layouts/components/TagsView/index.vue | 1 - .../views/dashboard/components/QuickStart.vue | 10 +- 4 files changed, 3062 insertions(+), 388 deletions(-) delete mode 100644 frontend/CHANGELOG.md create mode 100644 frontend/PROJECT_GUIDE.md diff --git a/frontend/CHANGELOG.md b/frontend/CHANGELOG.md deleted file mode 100644 index aef3f6da..00000000 --- a/frontend/CHANGELOG.md +++ /dev/null @@ -1,386 +0,0 @@ - -# 2.11.5 (2024/6/18) - -## ✨ feat - -- 支持后端文件导入([#142](https://github.com/youlaitech/vue3-element-admin/pull/142)) [@cshaptx4869](https://github.com/cshaptx4869) - - -## 🐛 fix -- vue-dev-tools 插件导致菜单路由切换卡死,暂时关闭 ([28349e](https://github.com/youlaitech/vue3-element-admin/commit/28349efe147afab36531ba148eaac3a448fe6c71)) [@haoxianrui](https://github.com/haoxianrui) - - - -# 2.11.4 (2024/6/16) - -## ✨ feat - -- 操作栏增加render配置参数([#138](https://github.com/youlaitech/vue3-element-admin/pull/140)) [@cshaptx4869](https://github.com/cshaptx4869) -- 左侧工具栏增加type配置参数([#141](https://github.com/youlaitech/vue3-element-admin/pull/141)) [@diamont1001](https://github.com/diamont1001) - -## ♻️ refactor -- 更换权限分配弹窗类型为 drawer 并添加父子联动开关([2d9193](https://github.com/youlaitech/vue3-element-admin/commit/2d9193c47fd224f01f82b9c0b2bbeb5e7cb33584)) [@haoxianrui](https://github.com/haoxianrui) - - - -# 2.11.3 (2024/6/11) - -## ✨ feat - -- 支持默认工具栏的导入([#138](https://github.com/youlaitech/vue3-element-admin/pull/138)) [@cshaptx4869](https://github.com/cshaptx4869) -- 添加CURD导入示例([19e7bb](https://github.com/youlaitech/vue3-element-admin/commit/eab91effd6a01d5a3d9257249c8d06aa252b3bf8)) [@cshaptx4869](https://github.com/cshaptx4869) - -## ♻️ refactor -- 修改导出全量数据选项文本([904fec](https://github.com/youlaitech/vue3-element-admin/commit/904fecad65217650482fcdbb10ffb7f3d27eb9ea)) [@cshaptx4869](https://github.com/cshaptx4869) - -## 🐛 fix -- 菜单列表未适配el-icon导致图标不显示问题修复([e72b68](https://github.com/youlaitech/vue3-element-admin/commit/e72b68337562b5a7ea24ad55bbe00023e1266b40)) [@haoxianrui](https://github.com/haoxianrui) - -# 2.11.2 (2024/6/8) - -## ✨ feat - -- 支持表格远程筛选([#131](https://github.com/youlaitech/vue3-element-admin/pull/131)) [@cshaptx4869](https://github.com/cshaptx4869) -- 支持标签输入框([#132](https://github.com/youlaitech/vue3-element-admin/pull/132)) [@cshaptx4869](https://github.com/cshaptx4869) -- 表单项支持tips配置([#133](https://github.com/youlaitech/vue3-element-admin/pull/133)) [@cshaptx4869](https://github.com/cshaptx4869) -- 前端导出支持全量数据([#134](https://github.com/youlaitech/vue3-element-admin/pull/134)) [@cshaptx4869](https://github.com/cshaptx4869) -- 支持选中数据导出([#135](https://github.com/youlaitech/vue3-element-admin/pull/135)) [@cshaptx4869](https://github.com/cshaptx4869) -- 表格默认工具栏的导出、搜索按钮增加权限点控制([883128](https://github.com/youlaitech/vue3-element-admin/commit/8831289b655f2cc086ecdababaa89f8d8a087c42)) [@cshaptx4869](https://github.com/cshaptx4869) -- 页签title支持动态设置([23876a](https://github.com/youlaitech/vue3-element-admin/commit/23876aa396143bf77cb5c86af8d6023d9ff6555a)) [@haoxianrui](https://github.com/haoxianrui) - -## ♻️ refactor -- 默认工具栏支持自定义([#136](https://github.com/youlaitech/vue3-element-admin/pull/136)) [@cshaptx4869](https://github.com/cshaptx4869) -- 未配置全量导出接口时选项隐藏([eab91ef](https://github.com/youlaitech/vue3-element-admin/commit/eab91effd6a01d5a3d9257249c8d06aa252b3bf8)) [@cshaptx4869](https://github.com/cshaptx4869) - -## 🐛 fix -- 修复注销登出后redirect跳转路由参数丢失([5626017](https://github.com/youlaitech/vue3-element-admin/commit/562601736731afd20bb1a5140d856f6515720159)) [@haoxianrui](https://github.com/haoxianrui) - -# 2.11.1 (2024/6/6) - -## ✨ feat - -- 增加pagination、request、parseData配置参数([#119](https://github.com/youlaitech/vue3-element-admin/pull/119)) [@cshaptx4869](https://github.com/cshaptx4869) -- 增加返回顶部功能([#120](https://github.com/youlaitech/vue3-element-admin/pull/120)) [@cshaptx4869](https://github.com/cshaptx4869) -- 支持前端导出([#126](https://github.com/youlaitech/vue3-element-admin/pull/126)) [@cshaptx4869](https://github.com/cshaptx4869) - -## ♻️ refactor -- 重构布局样式(解决页面抖动问题)([#116](https://github.com/youlaitech/vue3-element-admin/pull/116)) [@cshaptx4869](https://github.com/cshaptx4869) -- 修改CURD示例编辑弹窗尺寸([#121](https://github.com/youlaitech/vue3-element-admin/pull/121)) [@cshaptx4869](https://github.com/cshaptx4869) -- 统一注册vue插件([#122](https://github.com/youlaitech/vue3-element-admin/pull/122)) [@cshaptx4869](https://github.com/cshaptx4869) -- 默认主题跟随系统([#128](https://github.com/youlaitech/vue3-element-admin/pull/128)) [@cshaptx4869](https://github.com/cshaptx4869) -- 增加"scss.lint.unknownAtRules": "ignore"代码,解决style中使用@apply提示unknow at rules@apply提示问题([Gitee#22](https://gitee.com/youlaiorg/vue3-element-admin/pulls/22)) [@zjsy521](https://gitee.com/zjsy521) - -## 🐛 fix -- 修复左侧布局移动端菜单弹出样式 ([#117](https://github.com/youlaitech/vue3-element-admin/pull/117)) [@cshaptx4869](https://github.com/cshaptx4869) - -- 修复编辑后未清空id再新增菜单覆盖的问题([0e78eeb](https://github.com/youlaitech/vue3-element-admin/commit/0e78eeb75008fa8e9732b1b4e7d7a1ea345c7a1b)) [@haoxianrui](https://github.com/haoxianrui) -- 修复水印层级问题([#123](https://github.com/youlaitech/vue3-element-admin/pull/123)) [@cshaptx4869](https://github.com/cshaptx4869) -- 修复混合布局样式问题([#124](https://github.com/youlaitech/vue3-element-admin/pull/124)) [@cshaptx4869](https://github.com/cshaptx4869) -- 修复关闭弹窗时没有clearValidate问题([#125](https://github.com/youlaitech/vue3-element-admin/pull/125)) [@andm31](https://github.com/andm31) - - - -# 2.11.0 (2024/5/27) - -## ✨ feat -- 菜单添加路由参数设置(author by [haoxianrui](https://github.com/haoxianrui)) -- 增加列表选择组件(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 增加列表选择组件使用示例(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 增加defaultToolbar配置参数(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 表单弹窗支持drawer模式(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 表单项增加computed和watchEffect配置(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 支持switch属性修改(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 表单项增加文本类型支持(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 列表列增加show配置项(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 支持搜索表单显隐控制(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 支持input属性修改(author by [cshaptx4869](https://github.com/cshaptx4869)) -- search配置新增函数能力拓展(author by [xiudaozhe](https://github.com/xiudaozhe)) -- 表格新增列设置控制(author by [haoxianrui](https://github.com/haoxianrui)) -- 搜索添加展开和收缩(author by [haoxianrui](https://github.com/haoxianrui)) -- watch函数增加配置项参数返回(author by [cshaptx4869](https://github.com/cshaptx4869)) - -## ♻️ refactor -- 重构图标选择组件(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 重构列表选择组件默认样式 (author by [cshaptx4869](https://github.com/cshaptx4869)) -- 加强对话框表单组件和列表选择组件(author by [cshaptx4869](https://github.com/cshaptx4869)) -- routeMeta增加alwaysShow字段声明(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 分页组件增加溢出滚动效果(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 修正登录表单的Ref类型(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 点击表格刷新按钮不重置页码(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 筛选列超出一定高度滚动(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 优化加强initFn函数,表单项增加initFn函数(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 重构watch、computed、watchEffect调用(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 修改操作成功提示(author by [cshaptx4869](https://github.com/cshaptx4869)) -- PageSearch 改用card作为容器,样式改用unocss写法(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 优化首页 loading 动画效果author by [haoxianrui](https://github.com/haoxianrui)) - - -## 🐛 fix -- 路由是否始终显示不限制只有顶级目录才有的配置,开放至菜单 (author by [haoxianrui](https://github.com/haoxianrui)) -- sockjs-client 报错 global is not defined 导致开发环境无法打开 WebSocket 页面问题修复 (author by [haoxianrui](https://github.com/haoxianrui)) -- 发送用户重启密码功能,最少为6位字符(小于6位登陆时不允许的问题) (author by [dreamnyj](https://gitee.com/dreamnyj)) -- 修复系统设置面板滚动条问题(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 修复表单插槽失效问题(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 修改tagsview刷新丢失query问题(author by [xiudaozhe](https://github.com/xiudaozhe)) - -## 📦️ build -- 升级 NPM 包版本至最新 (author by [haoxianrui](https://github.com/haoxianrui)) - -## ⚙️ ci -- 规整脚本执行命令(author by [cshaptx4869](https://github.com/cshaptx4869)) - - -# 2.10.1 (2024/5/4) - -## ♻️ refactor -- 抽离CURD的使用部分代码为Hooks实现(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 修改CURD导入权限点标识名(author by [cshaptx4869](https://github.com/cshaptx4869)) -- cURD表单字段支持watch监听(author by [cshaptx4869](https://github.com/cshaptx4869)) -- cURD表单input支持number修饰(author by [cshaptx4869](https://github.com/cshaptx4869)) -- cURD表单组件支持checkbox多选框(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 优化axios响应数据TS类型提示(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 修改CURD表单组件自定义类型的attrs传值(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 同步重置密码按钮权限标识重命名(author by [haoxianrui](https://github.com/haoxianrui)) -- 重构API为静态方法实现模块化管理,并将types.ts重命名为model.ts用于存放接口模型定义(author by [haoxianrui](https://github.com/haoxianrui)) - - -## 🐛 fix -- sockjs-client 报错 global is not defined 导致开发环境无法打开 WebSocket 页面问题修复 (author by [haoxianrui](https://github.com/haoxianrui)) -- 主题颜色设置覆盖暗黑模式下el-table行激活的背景色问题修复 (author by [haoxianrui](https://github.com/haoxianrui)) -- 修复因API接口调整而影响的调用页面的问题 (author by [haoxianrui](https://github.com/haoxianrui)) - -## 📦️ build -- 升级 NPM 包版本至最新 (author by [haoxianrui](https://github.com/haoxianrui)) - - -# 2.10.0 (2024/4/26) -## ✨ feat -- 封装增删改查组件(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 集成 vite-plugin-vue-devtools 插件(author by [Tricker39](https://github.com/Tricker39)) -- 增加CURD配置化实现(author by [cshaptx4869](https://github.com/cshaptx4869)) - - -# 2.9.3 (2024/04/14) -## ✨ feat -- 增加vue文件代码片段(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 菜单 hover 背景色添加值全局SCSS变量进行控制(author by [haoxianrui](https://github.com/haoxianrui)) - -## ♻️ refactor -- 加强基础国际化(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 增加语言和布局大小枚举类型(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 增加侧边栏状态枚举类型(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 使用布局枚举替换字面量(author by [haoxianrui](https://github.com/haoxianrui)) -- 控制台使用静态数据循环渲染(author by [april](mailto:april@zen-game.cn)) -- 本地缓存的 token 变量重命名(author by [haoxianrui](https://github.com/haoxianrui)) -- 完善 Vite 环境变量类型声明(author by [haoxianrui](https://github.com/haoxianrui)) - -## 🐛 fix -- 修复构建时提示iconComponent.name可能为undefined的报错 (author by [wangji1042](https://github.com/wangji1042)) -- 修复浏览器密码自动填充时可能存在的报错 (author by [cshaptx4869](https://github.com/cshaptx4869)) -- 修复eslint报错(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 移动端下点击左侧菜单节点后关闭侧边栏(author by [haoxianrui](https://github.com/haoxianrui)) -- 添加 size 类型断言修复类型报错(author by [haoxianrui](https://github.com/haoxianrui)) - -## 📦️ build -- husky9.x版本适配 (author by [cshaptx4869](https://github.com/cshaptx4869)) -- 升级 npm 包版本至最新(author by [haoxianrui](https://github.com/haoxianrui)) - -# 2.9.2 (2024/03/05) -## ✨ feat -- vscode开发扩展推荐(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 完善基础增删改查Mock接口(author by [haoxianrui](https://github.com/haoxianrui)) - -## ♻️ refactor -- 修改login密码框功能实现(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 弱化页面进入动画效果(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 取消推荐TypeScript Vue Plugin (author by [cshaptx4869](https://github.com/cshaptx4869)) -- 网站加载动画替换 (author by [haoxianrui](https://github.com/haoxianrui)) -- 优化主题和主题色监听,避免多个页面重复初始化 (author by [haoxianrui](https://github.com/haoxianrui)) - -## 🐛 fix -- AppMain 高度在非固定头部不正确导致出现滚动条问题修复 (author by [haoxianrui](https://github.com/haoxianrui)) -- 修复混合模式开启固定Head时的样式问题 (author by [cshaptx4869](https://github.com/cshaptx4869)) -- 设置面板统一字体大小 (author by [cshaptx4869](https://github.com/cshaptx4869)) - -## 📦️build -- 通过env配置控制mock服务 (author by [cshaptx4869](https://github.com/cshaptx4869)) -- 升级依赖包至最新版本 (author by [haoxianrui](https://github.com/haoxianrui)) -- 定义vite全局常量替换项目标题和版本 (author by [cshaptx4869](https://github.com/cshaptx4869)) - -# 2.9.1 (2024/02/28) -## ♻️ refactor -- 项目配置按钮移入navbar(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 优化user数据定义(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 统一设置栏的 SVG 图标风格 - -## 🐛 fix -- 规整一些开发依赖(author by [cshaptx4869](https://github.com/cshaptx4869)) -- 修复登录页主题切换问题 (author by [cshaptx4869](https://github.com/cshaptx4869)) - -## 🚀 pref - -- 压缩图片资源 (author by [cshaptx4869](https://github.com/cshaptx4869)) - - -# 2.9.0 (2024/02/25) - -## ✨ feat -- 引入 animate.css 动画库 -- 新增水印和配置 -- 动态路由菜单支持 element plus 的图标 - -## ♻️ refactor -- Layout 布局重构和相关问题修复 -- sass 使用 @use 替代 @import 引入外部文件指令 - -## 🐛 fix -- 修复管理页面部分弹窗无法打开问题 -- 主题颜色设置按钮 hover 等未变化问题修复 - - -# 2.8.1 (2024/01/10) - -## ✨ feat -- 替换 Mock 解决方案 vite-plugin-mock 为 vite-plugin-mock-dev-server 适配 Vite5 - -# 2.8.0 (2023/12/27) - -## ⬆️ chore -- 升级 Vite4 至 Vite5 - -# 2.7.1 (2023/12/12) - -## ♻️ refactor -- 将打包后的文件进行分类 (author by [ityangzhiwen](https://gitee.com/ityangzhiwen)) - -# 2.7.0 (2023/11/19) - -## ♻️ refactor -- 代码重构优化 -- 修改自动导入组件类型声明文件路径 -- 完善 typescript 类型 - -## 🐛 fix -- 修复管理页面部分弹窗无法打开问题 - - -# 2.7.0 (2023/11/19) - -## ♻️ refactor -- 代码重构 -- 修改自动导入组件类型声明文件路径 -- 完善 typescript 类型 - -## 🐛 fix -- 修复管理页面部分弹窗无法打开问题 - - -# 2.6.3 (2023/10/22) - -## ✨ feat -- 菜单管理新增目录只有一级子路由是否始终显示(alwaysShow)和路由页面是否缓存(keepAlive)的配置 -- 接口文档新增 swagger、knife4j -- 引入和支持 tsx - -## ♻️ refactor -- 代码瘦身,整理并删除未使用的 svg -- 控制台样式优化 - -## 🐛 fix -- 菜单栏折叠和展开的图标暗黑模式显示问题修复 - - -# 2.6.2 (2023/10/11) - -## 🐛 fix -- 主题设置未持久化问题 -- UnoCSS 插件无智能提示 - -## ♻️ refactor -- WebSocket 演示样式和代码优化 -- 用户管理代码重构 - -# 2.6.1 (2023/9/4) - -## 🐛 fix -- 导航顶部模式、混合模式样式在固定 Header 出现的样式问题修复 -- 固定 Header 没有持久化问题修复 -- 字典回显兼容 String 和 Number 类型 - -# 2.6.0 (2023/8/24)💥💥💥 - -## ✨ feat -- 导航顶部模式、混合模式支持(author by [april-tong](https://april-tong.com/)) -- 平台文档(内嵌)(author by [april-tong](https://april-tong.com/)) - -# 2.5.0 (2023/8/8) - -## ✨ feat -- 新增 Mock(author by [ygcaicn](https://github.com/ygcaicn)) -- 图标 DEMO(author by [ygcaicn](https://github.com/ygcaicn)) - -## 🐛 fix -- 字典支持 Number 类型 - -# 2.4.1 (2023/7/20) - -## ✨ feat -- 整合 vite-plugin-compression 插件打包优化(3.66MB → 1.58MB) (author by [april-tong](https://april-tong.com/)) -- 字典组件封装(author by [haoxr](https://juejin.cn/user/4187394044331261/posts)) - -## 🐛 fix -- 分页组件hidden无效 -- 签名无法保存至后端 -- Git 提交 stylelint 校验部分机器报错 - -# 2.4.0 (2023/6/17) - -## ✨ feat -- 新增组件标签输入框(author by [april-tong](https://april-tong.com/)) -- 新增组件签名(author by [april-tong](https://april-tong.com/)) -- 新增组件表格(author by [april-tong](https://april-tong.com/)) -- Echarts 图表添加下载功能 author by [april-tong](https://april-tong.com/)) - -## ♻️ refactor -- 限制包管理器为 pnpm 和 node 版本16+ -- 自定义组件自动导入配置 -- 搜索框样式写法优化 - -## 🐛 fix -- 用户导入的部门回显成数字问题修复 - -## ⬆️ chore -- element-plus 版本升级 2.3.5 → 2.3.6 - -# 2.3.1 (2023/5/21) - -## 🔄 refactor -- 组件示例文件名称优化 - -# 2.2.2 (2023/5/11) - -## ✨ feat -- 组件封装示例添加源码地址 -- 角色、菜单、部门、字段按钮添加权限控制 - - -# 2.3.0 (2023/5/12) - -## ⬆️ chore -- vue 版本升级 3.2.45 → 3.3.1 ([CHANGELOG](https://github.com/vuejs/core/blob/main/CHANGELOG.md)) -- vite 版本升级 4.3.1 → 4.3.5 - -## ♻️ refactor -- 使用 vue 3.3 版本新特性 `defineOptions` 在 `setup` 定义组件名称,移除重复的 `script` 标签 - -# 2.2.2 (2023/5/11) - -## ✨ feat -- 用户新增提交添加 `vueUse` 的 `useDebounceFn` 函数实现按钮防抖节流 - - -# 2.2.1 (2023/4/25) - -## 🐛 fix -- 图标选择器组件使用 `onClickOutside` 未排除下拉弹出框元素导致无法输入搜索。 - diff --git a/frontend/PROJECT_GUIDE.md b/frontend/PROJECT_GUIDE.md new file mode 100644 index 00000000..254f19d1 --- /dev/null +++ b/frontend/PROJECT_GUIDE.md @@ -0,0 +1,3053 @@ +# FastAPI Vue3 Admin 前端项目 + +## 📖 项目介绍 + +### 项目概述 + +**FastAPI Vue3 Admin** 是一个基于 Vue3 + Vite + TypeScript + Element-Plus 构建的现代化后台管理系统前端模板。 + +- 🎨 **现代化技术栈**:Vue 3 + TypeScript + Vite + Element Plus +- 🚀 **高性能**:Vite 构建,快速热重载 +- 📱 **响应式设计**:适配桌面和移动端 +- 🌙 **主题切换**:支持明暗主题 +- 🌍 **国际化**:多语言支持 +- 🔧 **开箱即用**:完整的后台管理功能 +- 🎯 **TypeScript**:完整的类型支持 +- 📦 **组件化**:高度模块化的架构 + +### 核心特性 + +#### 🎨 界面功能 +- ✅ 响应式布局(桌面端、平板、手机) +- ✅ 暗色主题/亮色主题切换 +- ✅ 多种布局模式(左侧、顶部、混合) +- ✅ 动态面包屑导航 +- ✅ 标签页导航(TagsView) +- ✅ 快捷开始功能 + +#### 🔐 权限管理 +- ✅ 基于角色的权限控制 +- ✅ 动态路由生成 +- ✅ 菜单权限控制 +- ✅ 按钮级别的权限控制 + +#### 📊 数据管理 +- ✅ 统一的API接口管理 +- ✅ 状态管理(Pinia) +- ✅ 本地存储管理 +- ✅ 请求拦截和响应处理 + +#### 🛠️ 开发体验 +- ✅ TypeScript 支持 +- ✅ 自动导入(Auto Import) +- ✅ 组件自动注册 +- ✅ UnoCSS 原子化CSS +- ✅ ESLint + Prettier 代码规范 +- ✅ Husky Git 提交规范 + +## 🏗️ 技术栈 + +### 核心框架 +- **Vue 3** - 渐进式前端框架 +- **TypeScript** - 类型安全的JavaScript +- **Vite** - 下一代前端构建工具 +- **Element Plus** - Vue3 UI组件库 + +### 状态管理 +- **Pinia** - Vue3 官方状态管理库 + +### 构建工具 +- **Vite** - 快速的构建工具 +- **UnoCSS** - 原子化CSS引擎 +- **ESLint** - 代码检查工具 +- **Prettier** - 代码格式化工具 + +### HTTP 客户端 +- **Axios** - HTTP请求库 + +### 路由管理 +- **Vue Router 4** - Vue3 路由管理 + +### 国际化 +- **Vue I18n** - Vue 国际化插件 + +### 图表库 +- **ECharts** - 百度开源图表库 + +### 富文本编辑器 +- **WangEditor** - 轻量级富文本编辑器 + +## ⚙️ 环境配置 + +### 环境变量说明 + +项目支持多种环境配置: + +#### 开发环境 (.env.development) +```bash +# 应用配置 +VITE_APP_TITLE=FastAPI Vue3 Admin +VITE_APP_ENV=development + +# API 配置 +VITE_APP_API_BASE_URL=http://localhost:8000 +VITE_APP_API_TIMEOUT=10000 + +# 其他配置 +VITE_APP_ROUTER_HISTORY=hash +VITE_APP_PUBLIC_PATH=/ +``` + +#### 生产环境 (.env.production) +```bash +# 应用配置 +VITE_APP_TITLE=FastAPI Vue3 Admin +VITE_APP_ENV=production + +# API 配置 +VITE_APP_API_BASE_URL=https://api.yourdomain.com +VITE_APP_API_TIMEOUT=15000 + +# 其他配置 +VITE_APP_ROUTER_HISTORY=history +VITE_APP_PUBLIC_PATH=/ +``` + +#### 测试环境 (.env.test) +```bash +# 应用配置 +VITE_APP_TITLE=FastAPI Vue3 Admin Test +VITE_APP_ENV=test + +# API 配置 +VITE_APP_API_BASE_URL=https://test-api.yourdomain.com +VITE_APP_API_TIMEOUT=15000 +``` + +### 环境变量使用 + +在代码中使用环境变量: + +```typescript +// src/config/index.ts +export const config = { + title: import.meta.env.VITE_APP_TITLE, + env: import.meta.env.VITE_APP_ENV, + api: { + baseURL: import.meta.env.VITE_APP_API_BASE_URL, + timeout: Number(import.meta.env.VITE_APP_API_TIMEOUT) + } +} +``` + +## 📁 项目结构详解 + +### 完整目录结构 + +``` +fastapi_vue3_admin/frontend/ +├── 📁 .husky/ # Git Hooks 配置 +│ ├── pre-commit # 提交前钩子 +│ ├── commit-msg # 提交信息钩子 +│ └── ... # 其他 Git 钩子 +├── 📁 node_modules/ # 依赖包目录 +├── 📁 public/ # 静态资源目录 +│ ├── background.svg # 背景图片 +│ ├── favicon.png # 网站图标 +│ └── logo.png # 网站Logo +├── 📁 src/ # 源代码目录 +│ ├── 📁 api/ # API 接口层 +│ │ ├── codegen.api.ts # 代码生成接口 +│ │ ├── 📁 demo/ # 示例接口 +│ │ │ └── example.ts # 示例 API +│ │ ├── 📁 monitor/ # 监控相关接口 +│ │ │ ├── cache.ts # 缓存监控 +│ │ │ ├── job.ts # 定时任务 +│ │ │ ├── online.ts # 在线用户 +│ │ │ └── server.ts # 服务器监控 +│ │ └── 📁 system/ # 系统相关接口 +│ │ ├── auth.ts # 认证接口 +│ │ ├── config.ts # 系统配置 +│ │ ├── dept.ts # 部门管理 +│ │ ├── dict.ts # 字典管理 +│ │ ├── log.ts # 日志管理 +│ │ ├── menu.ts # 菜单管理 +│ │ ├── notice.ts # 通知公告 +│ │ ├── position.ts # 职位管理 +│ │ ├── role.ts # 角色管理 +│ │ └── user.ts # 用户管理 +│ ├── 📁 assets/ # 静态资源 +│ │ ├── 📁 icons/ # 图标资源 +│ │ │ ├── api.svg # API 图标 +│ │ │ ├── user.svg # 用户图标 +│ │ │ ├── menu.svg # 菜单图标 +│ │ │ └── ... # 其他图标 (70+ 个图标) +│ │ └── 📁 images/ # 图片资源 +│ │ ├── 401.svg # 401 错误图片 +│ │ ├── 404.svg # 404 错误图片 +│ │ └── 500.svg # 500 错误图片 +│ ├── 📁 components/ # 全局组件库 +│ │ ├── 📁 AppLink/ # 应用链接组件 +│ │ ├── 📁 Breadcrumb/ # 面包屑导航 +│ │ ├── 📁 CommonWrapper/ # 通用包装器 +│ │ ├── 📁 CURD/ # CRUD 通用组件 +│ │ │ ├── PageContent.vue # 页面内容组件 +│ │ │ ├── PageModal.vue # 页面弹窗组件 +│ │ │ ├── PageSearch.vue # 页面搜索组件 +│ │ │ ├── types.ts # 类型定义 +│ │ │ └── usePage.ts # 页面逻辑组合 +│ │ ├── 📁 DarkModeSwitch/ # 暗色模式切换 +│ │ ├── 📁 DatePicker/ # 日期选择器 +│ │ ├── 📁 ECharts/ # 图表组件 +│ │ ├── 📁 Frame/ # 框架组件 +│ │ ├── 📁 Fullscreen/ # 全屏组件 +│ │ ├── 📁 GithubCorner/ # GitHub 角标 +│ │ ├── 📁 Guide/ # 引导组件 +│ │ ├── 📁 Hamburger/ # 汉堡菜单 +│ │ ├── 📁 IconSelect/ # 图标选择器 +│ │ ├── 📁 InputTag/ # 标签输入 +│ │ ├── 📁 IntervalTab/ # 间隔标签页 +│ │ ├── 📁 LangSelect/ # 语言选择器 +│ │ ├── 📁 MenuSearch/ # 菜单搜索 +│ │ ├── 📁 Notification/ # 通知组件 +│ │ ├── 📁 OperationColumn/ # 操作列组件 +│ │ ├── 📁 Pagination/ # 分页组件 +│ │ ├── 📁 SizeSelect/ # 尺寸选择器 +│ │ ├── 📁 TableSelect/ # 表格选择器 +│ │ ├── 📁 TextScroll/ # 文字滚动 +│ │ ├── 📁 Upload/ # 上传组件 +│ │ │ ├── ImportModal.vue # 导入弹窗 +│ │ │ └── SingleImageUpload.vue # 单图上传 +│ │ └── 📁 WangEditor/ # 富文本编辑器 +│ ├── 📁 constants/ # 常量定义 +│ │ ├── index.ts # 常量导出 +│ │ └── storage-keys.ts # 存储键常量 +│ ├── 📁 enums/ # 枚举定义 +│ │ ├── index.ts # 枚举导出 +│ │ ├── 📁 api/ # API 相关枚举 +│ │ │ └── result.enum.ts # API 结果枚举 +│ │ ├── 📁 codegen/ # 代码生成枚举 +│ │ │ ├── form.enum.ts # 表单枚举 +│ │ │ └── query.enum.ts # 查询枚举 +│ │ ├── 📁 settings/ # 设置相关枚举 +│ │ │ ├── device.enum.ts # 设备枚举 +│ │ │ ├── layout.enum.ts # 布局枚举 +│ │ │ ├── locale.enum.ts # 语言枚举 +│ │ │ └── theme.enum.ts # 主题枚举 +│ │ └── 📁 system/ # 系统相关枚举 +│ │ └── menu.enum.ts # 菜单枚举 +│ ├── 📁 lang/ # 国际化配置 +│ │ ├── index.ts # 国际化入口 +│ │ └── 📁 package/ # 语言包 +│ │ ├── zh-cn.ts # 中文语言包 +│ │ └── en.ts # 英文语言包 +│ ├── 📁 layouts/ # 布局系统 +│ │ ├── index.vue # 主布局组件 +│ │ ├── 📁 components/ # 布局子组件 +│ │ │ ├── 📁 AppLogo/ # 应用Logo +│ │ │ ├── 📁 AppMain/ # 主内容区域 +│ │ │ ├── 📁 Menu/ # 菜单组件 (4个文件) +│ │ │ ├── 📁 NavBar/ # 导航栏 (4个文件) +│ │ │ ├── 📁 Settings/ # 设置面板 +│ │ │ └── 📁 TagsView/ # 标签页视图 +│ │ ├── 📁 composables/ # 布局逻辑组合 +│ │ │ ├── useLayout.ts # 布局逻辑 +│ │ │ ├── useLayoutMenu.ts # 菜单逻辑 +│ │ │ └── useLayoutResponsive.ts # 响应式逻辑 +│ │ └── 📁 views/ # 布局视图 +│ │ ├── BaseLayout.vue # 基础布局 +│ │ ├── LeftLayout.vue # 左侧布局 +│ │ ├── MixLayout.vue # 混合布局 +│ │ └── TopLayout.vue # 顶部布局 +│ ├── 📁 plugins/ # 插件配置 +│ │ ├── icons.ts # 图标插件 +│ │ ├── index.ts # 插件入口 +│ │ └── permission.ts # 权限插件 +│ ├── 📁 router/ # 路由配置 +│ │ └── index.ts # 路由入口文件 +│ ├── 📁 store/ # 状态管理 +│ │ ├── index.ts # 状态管理入口 +│ │ └── 📁 modules/ # 状态模块 +│ │ ├── app.store.ts # 应用状态 +│ │ ├── config.store.ts # 配置状态 +│ │ ├── dict.store.ts # 字典状态 +│ │ ├── lock.store.ts # 锁屏状态 +│ │ ├── notice.store.ts # 通知状态 +│ │ ├── permission.store.ts # 权限状态 +│ │ ├── settings.store.ts # 设置状态 +│ │ ├── tags-view.store.ts # 标签页状态 +│ │ └── user.store.ts # 用户状态 +│ ├── 📁 styles/ # 样式系统 +│ │ ├── index.scss # 全局样式入口 +│ │ ├── reset.scss # 样式重置 +│ │ ├── variables.scss # CSS 变量 +│ │ ├── variables.module.scss # 模块化变量 +│ │ ├── element-plus.scss # Element Plus 样式覆盖 +│ │ ├── vxe-table.scss # VxeTable 样式 +│ │ ├── vxe-table.css # VxeTable 样式 +│ │ ├── 📁 dark/ # 暗色主题 +│ │ │ └── css-vars.css # 暗色主题变量 +│ ├── 📁 types/ # TypeScript 类型定义 +│ │ ├── auto-imports.d.ts # 自动导入类型 +│ │ ├── components.d.ts # 组件类型 +│ │ ├── env.d.ts # 环境类型 +│ │ ├── global.d.ts # 全局类型 +│ │ ├── router.d.ts # 路由类型 +│ │ ├── shims-vue.d.ts # Vue 声明文件 +│ │ └── vue3-cron-plus.d.ts # Cron 组件类型 +│ ├── 📁 utils/ # 工具函数库 +│ │ ├── index.ts # 工具导出 +│ │ ├── auth.ts # 认证工具 +│ │ ├── common.ts # 通用工具 +│ │ ├── dateUtil.ts # 日期工具 +│ │ ├── i18n.ts # 国际化工具 +│ │ ├── nprogress.ts # 进度条工具 +│ │ ├── quickStartManager.ts # 快速开始管理器 +│ │ ├── request.ts # HTTP 请求封装 +│ │ ├── storage.ts # 本地存储工具 +│ │ └── theme.ts # 主题工具 +│ ├── 📁 views/ # 页面视图 +│ │ ├── 📁 codegen/ # 代码生成页面 +│ │ │ └── index.html # 代码生成器页面 +│ │ ├── 📁 common/ # 公共页面 +│ │ │ ├── 📁 docs/ # 文档页面 +│ │ │ └── 📁 redoc/ # ReDoc API 文档 +│ │ ├── 📁 current/ # 当前用户页面 +│ │ │ └── profile.vue # 用户资料页 +│ │ ├── 📁 dashboard/ # 仪表板页面 +│ │ │ ├── analysis.vue # 数据分析页 +│ │ │ ├── workplace.vue # 工作台页面 +│ │ │ └── 📁 components/ # 仪表板组件 +│ │ ├── 📁 demo/ # 示例页面 +│ │ │ └── 📁 example/ # 示例页面 +│ │ ├── 📁 error/ # 错误页面 +│ │ │ ├── 401.vue # 401 未授权 +│ │ │ ├── 404.vue # 404 未找到 +│ │ │ └── 500.vue # 500 服务器错误 +│ │ ├── 📁 monitor/ # 监控页面 +│ │ │ ├── 📁 cache/ # 缓存监控 +│ │ │ ├── 📁 job/ # 定时任务 +│ │ │ ├── 📁 online/ # 在线用户 +│ │ │ └── 📁 server/ # 服务器监控 +│ │ ├── 📁 redirect/ # 重定向页面 +│ │ │ └── index.vue # 重定向入口 +│ │ └── 📁 system/ # 系统管理页面 +│ │ ├── 📁 auth/ # 权限管理 (4个文件) +│ │ ├── 📁 config/ # 系统配置 (2个文件) +│ │ ├── 📁 dept/ # 部门管理 (1个文件) +│ │ ├── 📁 dict/ # 字典管理 (2个文件) +│ │ ├── 📁 log/ # 日志管理 (1个文件) +│ │ ├── 📁 menu/ # 菜单管理 (1个文件) +│ │ ├── 📁 notice/ # 通知公告 (1个文件) +│ │ ├── 📁 position/ # 职位管理 (1个文件) +│ │ ├── 📁 role/ # 角色管理 (2个文件) +│ │ └── 📁 user/ # 用户管理 (2个文件) +│ ├── App.vue # Vue 根组件 +│ ├── main.ts # 应用入口文件 +│ └── settings.ts # 应用配置 +├── 📁 .vscode/ # VS Code 配置 (可选) +├── 📁 scripts/ # 构建和工具脚本 +├── 📄 .editorconfig # 编辑器配置 +├── 📄 .env.development # 开发环境变量 +├── 📄 .env.production # 生产环境变量 +├── 📄 .eslintignore # ESLint 忽略配置 +├── 📄 .eslintrc-auto-import.json # ESLint 自动导入配置 +├── 📄 .gitignore # Git 忽略文件 +├── 📄 .prettierignore # Prettier 忽略配置 +├── 📄 .prettierrc.yaml # Prettier 配置 +├── 📄 .stylelintignore # Stylelint 忽略配置 +├── 📄 .stylelintrc.cjs # Stylelint 配置 +├── 📄 CHANGELOG.md # 更新日志 +├── 📄 commitlint.config.cjs # Commitlint 配置 +├── 📄 eslint.config.ts # ESLint 配置 +├── 📄 index.html # HTML 入口文件 +├── 📄 package.json # 项目依赖配置 +├── 📄 pnpm-lock.yaml # pnpm 锁定文件 +├── 📄 PROJECT_GUIDE.md # 项目指南 (本文档) +├── 📄 README.md # 项目说明 +├── 📄 tsconfig.json # TypeScript 配置 +├── 📄 uno.config.ts # UnoCSS 配置 +└── 📄 vite.config.ts # Vite 构建配置 +``` + +### 核心文件说明 + +#### 🔧 构建配置 + +| 文件 | 说明 | +|------|------| +| `vite.config.ts` | Vite 构建工具主配置,包含插件、代理、构建优化等 | +| `tsconfig.json` | TypeScript 编译配置,定义编译选项和路径映射 | +| `uno.config.ts` | UnoCSS 原子化CSS配置,定义样式规则和主题 | +| `eslint.config.ts` | ESLint 代码检查配置,确保代码质量和规范 | +| `package.json` | 项目依赖管理和脚本配置 | + +#### ⚡ 应用入口 + +| 文件 | 说明 | +|------|------| +| `index.html` | HTML 入口文件,包含基础的页面结构 | +| `src/main.ts` | 应用入口文件,初始化 Vue 应用和各项配置 | +| `src/App.vue` | Vue 根组件,应用的主要布局结构 | +| `src/settings.ts` | 应用基础配置,包含主题、语言等设置 | + +#### 🗂️ 核心目录详解 + +##### 1. API 接口层 (`src/api/`) + +负责前后端数据交互,采用分层架构: + +- **system/**: 系统管理相关接口(用户、角色、菜单、权限等) +- **monitor/**: 系统监控相关接口(缓存、任务、服务器状态等) +- **codegen/**: 代码生成相关接口 +- **demo/**: 示例接口(用于测试和演示) + +每个接口模块都包含完整的 CRUD 操作和类型定义。 + +##### 2. 组件库 (`src/components/`) + +高度复用的组件集合: + +- **CURD/**: 通用CRUD组件,支持列表、搜索、编辑、删除等操作 +- **Upload/**: 文件上传组件,支持单图、多图、批量导入 +- **布局相关**: 菜单、导航栏、面包屑等布局组件 +- **业务组件**: 针对具体业务场景的专用组件 + +##### 3. 状态管理 (`src/store/`) + +基于 Pinia 的状态管理: + +- **modules/**: 按功能划分的状态模块 +- **持久化**: 支持状态持久化存储 +- **类型安全**: 完整的 TypeScript 类型支持 + +##### 4. 样式系统 (`src/styles/`) + +统一的样式管理: + +- **主题系统**: 支持亮色/暗色主题切换 +- **变量管理**: CSS 变量集中管理 +- **组件样式**: 各组件的专用样式 +- **UnoCSS**: 原子化CSS框架,提升开发效率 + +##### 5. 工具函数 (`src/utils/`) + +通用工具函数库: + +- **request.ts**: HTTP 请求封装,包含拦截器、错误处理 +- **auth.ts**: 认证相关工具 +- **storage.ts**: 本地存储封装 +- **dateUtil.ts**: 日期时间处理工具 +- **theme.ts**: 主题切换工具 + +##### 6. 页面视图 (`src/views/`) + +具体的页面组件: + +- **system/**: 系统管理页面(用户、角色、菜单等) +- **monitor/**: 系统监控页面 +- **dashboard/**: 数据仪表板 +- **error/**: 错误页面 +- **current/**: 当前用户相关页面 + +### 架构设计原则 + +1. **模块化**: 每个功能模块独立,便于维护和扩展 +2. **类型安全**: 全面的 TypeScript 支持,减少运行时错误 +3. **组件复用**: 抽象通用组件,提高开发效率 +4. **配置化**: 通过配置而非硬编码实现功能 +5. **规范化**: 统一的代码规范和开发流程 + +### 文件组织规范 + +1. **命名规范**: + - 文件夹:kebab-case (短横线分隔) + - 组件文件:PascalCase (大驼峰) + - 工具文件:camelCase (小驼峰) + +2. **目录结构**: + - 相关文件放在同一目录下 + - 按功能划分子目录 + - 保持目录层级清晰 + +3. **导入导出**: + - 使用相对路径导入 + - 统一使用 index.ts 导出 + - 按类型分组导入 + +### 关键配置文件详解 + +#### 📄 package.json + +项目依赖和脚本配置: + +```json +{ + "name": "fastapi-vue3-admin", + "version": "2.0.0", + "scripts": { + "dev": "vite", // 开发服务器 + "build": "vite build", // 生产构建 + "build:pro": "vite build --mode pro", // 生产环境构建 + "build:dev": "vite build --mode dev", // 开发环境构建 + "build:test": "vite build --mode test", // 测试环境构建 + "preview": "vite preview", // 预览构建结果 + "lint": "eslint ...", // 代码检查 + "type-check": "vue-tsc --noEmit" // 类型检查 + }, + "dependencies": { + "vue": "^3.5.17", // Vue 3 核心 + "element-plus": "^2.10.4", // UI 组件库 + "pinia": "^3.0.3", // 状态管理 + "vue-router": "^4.5.1", // 路由管理 + "axios": "^1.10.0", // HTTP 客户端 + "vue-i18n": "^11.1.10" // 国际化 + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.2.4", // Vue 插件 + "typescript": "^5.8.3", // TypeScript + "unocss": "66.2.3", // 原子化CSS + "vite": "^6.3.5" // 构建工具 + } +} +``` + +#### ⚙️ vite.config.ts + +Vite 构建配置: + +```typescript +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import { resolve } from 'path' + +export default defineConfig({ + plugins: [vue()], + resolve: { + alias: { + '@': resolve(__dirname, 'src') // 路径别名 + } + }, + server: { + port: 5173, + proxy: { + '/api': { + target: 'http://localhost:8000', // 后端API地址 + changeOrigin: true + } + } + }, + build: { + outDir: 'dist', + sourcemap: false, + rollupOptions: { + output: { + chunkFileNames: 'js/[name]-[hash].js', + entryFileNames: 'js/[name]-[hash].js', + assetFileNames: '[ext]/[name]-[hash].[ext]' + } + } + } +}) +``` + +#### 🔷 uno.config.ts + +UnoCSS 原子化CSS配置: + +```typescript +import { defineConfig } from 'unocss' +import { presetUno, presetAttributify } from 'unocss' + +export default defineConfig({ + presets: [ + presetUno(), // UnoCSS 预设 + presetAttributify() // 属性化模式 + ], + theme: { + colors: { + primary: 'var(--el-color-primary)', + success: 'var(--el-color-success)', + warning: 'var(--el-color-warning)', + danger: 'var(--el-color-danger)' + } + }, + shortcuts: { + 'flex-center': 'flex items-center justify-center', + 'flex-between': 'flex items-center justify-between' + } +}) +``` + +#### 📝 tsconfig.json + +TypeScript 配置: + +```json +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] // 路径映射 + } + }, + "include": [ + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.tsx", + "src/**/*.vue" + ], + "exclude": ["node_modules"] +} +``` + +### 核心模块功能详解 + +#### 🎯 应用入口 (`src/main.ts`) + +应用初始化和配置: + +```typescript +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import ElementPlus from 'element-plus' +import router from './router' +import i18n from './lang' +import App from './App.vue' + +// 创建应用实例 +const app = createApp(App) + +// 安装插件 +app.use(createPinia()) +app.use(router) +app.use(ElementPlus) +app.use(i18n) + +// 挂载应用 +app.mount('#app') +``` + +#### 🏗️ 应用配置 (`src/settings.ts`) + +应用基础配置: + +```typescript +export const settings = { + // 应用信息 + title: 'FastAPI Vue3 Admin', + version: '2.0.0', + + // 显示配置 + showSettings: true, + showTagsView: true, + showSidebarLogo: true, + + // 功能开关 + enableErrorLog: true, + enableWatermark: false, + + // 主题配置 + theme: 'light', + primaryColor: '#409EFF', + + // 布局配置 + layout: 'left', + fixedHeader: true, + + // 其他配置 + defaultLanguage: 'zh-cn', + whiteList: ['/login', '/404', '/401'] +} +``` + +#### 🧩 组件系统架构 + +##### CURD 通用组件 + +```typescript +// src/components/CURD/usePage.ts +export const usePage = (config: PageConfig) => { + const loading = ref(false) + const data = ref([]) + const pagination = ref({ + current: 1, + size: 20, + total: 0 + }) + + // 分页查询 + const fetchData = async () => { + loading.value = true + try { + const result = await config.api.list({ + page: pagination.value.current, + size: pagination.value.size, + ...config.queryParams + }) + data.value = result.records + pagination.value.total = result.total + } finally { + loading.value = false + } + } + + // 新增 + const handleCreate = () => { + config.onCreate?.() + } + + // 编辑 + const handleUpdate = (record: any) => { + config.onUpdate?.(record) + } + + // 删除 + const handleDelete = async (id: string) => { + await config.api.delete(id) + await fetchData() + } + + return { + loading, + data, + pagination, + fetchData, + handleCreate, + handleUpdate, + handleDelete + } +} +``` + +#### 🔄 状态管理架构 + +##### 用户状态管理 + +```typescript +// src/store/modules/user.store.ts +export const useUserStore = defineStore('user', () => { + // 状态 + const userInfo = ref(null) + const token = ref('') + const permissions = ref([]) + const roles = ref([]) + + // 计算属性 + const isLogin = computed(() => !!token.value) + const userId = computed(() => userInfo.value?.id) + + // 动作 + const login = async (loginForm: LoginForm) => { + const { data } = await loginApi(loginForm) + token.value = data.token + await getUserInfo() + } + + const getUserInfo = async () => { + const { data } = await getUserInfoApi() + userInfo.value = data.user + permissions.value = data.permissions + roles.value = data.roles + } + + const logout = () => { + userInfo.value = null + token.value = '' + permissions.value = [] + roles.value = [] + } + + return { + userInfo, + token, + permissions, + roles, + isLogin, + userId, + login, + getUserInfo, + logout + } +}, { + persist: true // 持久化存储 +}) +``` + +#### 🎨 样式系统架构 + +##### 主题系统 + +```scss +// src/styles/variables.scss +:root { + // 亮色主题 + --primary-color: #409EFF; + --success-color: #67C23A; + --warning-color: #E6A23C; + --danger-color: #F56C6C; + + // 布局变量 + --header-height: 60px; + --sidebar-width: 260px; + --sidebar-collapse-width: 64px; + + // 间距变量 + --spacing-xs: 4px; + --spacing-sm: 8px; + --spacing-md: 16px; + --spacing-lg: 24px; + --spacing-xl: 32px; +} + +// 暗色主题 +.dark { + --primary-color: #66D9EF; + --success-color: #A6E22E; + --warning-color: #FD971F; + --danger-color: #F92672; + + --bg-color: #1E1E1E; + --text-color: #D4D4D4; + --border-color: #3E3E3E; +} +``` + +##### UnoCSS 工具类 + +```vue + +``` + +#### 🔧 工具函数库 + +##### HTTP 请求封装 + +```typescript +// src/utils/request.ts +import axios, { AxiosInstance, AxiosResponse } from 'axios' + +class Request { + private instance: AxiosInstance + + constructor() { + this.instance = axios.create({ + baseURL: import.meta.env.VITE_APP_API_BASE_URL, + timeout: 10000, + headers: { + 'Content-Type': 'application/json' + } + }) + + this.setupInterceptors() + } + + private setupInterceptors() { + // 请求拦截器 + this.instance.interceptors.request.use( + (config) => { + const token = localStorage.getItem('token') + if (token) { + config.headers.Authorization = `Bearer ${token}` + } + return config + }, + (error) => Promise.reject(error) + ) + + // 响应拦截器 + this.instance.interceptors.response.use( + (response: AxiosResponse) => { + const { data } = response + if (data.code === 200) { + return data + } + return Promise.reject(new Error(data.message)) + }, + (error) => { + if (error.response?.status === 401) { + // 处理未授权 + router.push('/login') + } + return Promise.reject(error) + } + ) + } + + public get(url: string, config?: any): Promise { + return this.instance.get(url, config) + } + + public post(url: string, data?: any, config?: any): Promise { + return this.instance.post(url, data, config) + } + + public put(url: string, data?: any, config?: any): Promise { + return this.instance.put(url, data, config) + } + + public delete(url: string, config?: any): Promise { + return this.instance.delete(url, config) + } +} + +export const request = new Request() +export default request +``` + +##### 日期时间工具 + +```typescript +// src/utils/dateUtil.ts +import dayjs from 'dayjs' + +export const formatDate = (date: string | Date, format = 'YYYY-MM-DD HH:mm:ss') => { + return dayjs(date).format(format) +} + +export const formatDateTime = (date: string | Date) => { + return formatDate(date, 'YYYY-MM-DD HH:mm:ss') +} + +export const formatDateOnly = (date: string | Date) => { + return formatDate(date, 'YYYY-MM-DD') +} + +export const formatTimeOnly = (date: string | Date) => { + return formatDate(date, 'HH:mm:ss') +} + +export const getRelativeTime = (date: string | Date) => { + return dayjs(date).fromNow() +} + +export const isToday = (date: string | Date) => { + return dayjs(date).isSame(dayjs(), 'day') +} + +export const isYesterday = (date: string | Date) => { + return dayjs(date).isSame(dayjs().subtract(1, 'day'), 'day') +} + +export const getDateRange = (days: number) => { + const end = dayjs() + const start = dayjs().subtract(days, 'day') + return [start.format('YYYY-MM-DD'), end.format('YYYY-MM-DD')] +} +``` + +### 项目文件统计 + +| 类别 | 文件数量 | 主要文件类型 | +|------|----------|--------------| +| **Vue 组件** | 50+ | .vue (页面组件、业务组件) | +| **TypeScript** | 80+ | .ts (工具函数、类型定义、配置) | +| **样式文件** | 15+ | .scss, .css (样式表、主题) | +| **配置文件** | 20+ | .json, .ts, .js (构建、工具配置) | +| **静态资源** | 70+ | .svg, .png (图标、图片) | +| **文档文件** | 3 | .md (说明文档) | + +### 技术栈依赖关系 + +``` +Vue 3 (核心框架) +├── Vue Router 4 (路由管理) +├── Pinia (状态管理) +├── Element Plus (UI组件) +├── Vue I18n (国际化) +├── Axios (HTTP客户端) +└── UnoCSS (原子化CSS) + +Vite (构建工具) +├── TypeScript (类型系统) +├── ESLint (代码检查) +├── Prettier (代码格式化) +└── PostCSS (CSS处理) +``` + +这个项目结构体现了现代前端项目的标准架构,具有良好的可维护性、可扩展性和开发体验。 + +## 🔗 API 接口管理 + +### 接口层架构 + +项目采用分层的API接口管理架构: + +``` +src/api/ +├── 📁 system/ # 系统相关接口 +│ ├── auth.ts # 认证接口 +│ ├── user.ts # 用户管理接口 +│ ├── menu.ts # 菜单管理接口 +│ └── config.ts # 系统配置接口 +├── 📁 monitor/ # 监控相关接口 +│ ├── cache.ts # 缓存监控 +│ ├── job.ts # 定时任务 +│ ├── online.ts # 在线用户 +│ └── server.ts # 服务器监控 +└── 📁 codegen/ # 代码生成接口 +``` + +### 请求封装 + +项目使用统一的HTTP请求封装: + +```typescript +// src/utils/request.ts +import axios from 'axios' +import type { AxiosResponse } from 'axios' + +const request = axios.create({ + baseURL: import.meta.env.VITE_APP_API_BASE_URL, + timeout: 10000, + headers: { + 'Content-Type': 'application/json' + } +}) + +// 请求拦截器 +request.interceptors.request.use( + (config) => { + // 添加认证token + const token = localStorage.getItem('token') + if (token) { + config.headers.Authorization = `Bearer ${token}` + } + return config + }, + (error) => Promise.reject(error) +) + +// 响应拦截器 +request.interceptors.response.use( + (response: AxiosResponse) => { + const { data } = response + if (data.code === 200) { + return data + } else { + ElMessage.error(data.message || '请求失败') + return Promise.reject(new Error(data.message || '请求失败')) + } + }, + (error) => { + if (error.response?.status === 401) { + // 处理未授权 + router.push('/login') + } else { + ElMessage.error(error.message || '网络错误') + } + return Promise.reject(error) + } +) + +export default request +``` + +### 接口定义示例 + +```typescript +// src/api/system/user.ts +import request from '@/utils/request' + +export interface UserInfo { + id: number + username: string + email: string + avatar?: string + roles: string[] + status: 'active' | 'inactive' +} + +export interface UserQuery { + page?: number + size?: number + username?: string + status?: string +} + +// 获取用户列表 +export const getUserList = (params?: UserQuery) => { + return request.get('/system/user/list', { params }) +} + +// 获取用户信息 +export const getUserInfo = (id: number) => { + return request.get(`/system/user/${id}`) +} + +// 创建用户 +export const createUser = (data: Omit) => { + return request.post('/system/user', data) +} + +// 更新用户 +export const updateUser = (id: number, data: Partial) => { + return request.put(`/system/user/${id}`, data) +} + +// 删除用户 +export const deleteUser = (id: number) => { + return request.delete(`/system/user/${id}`) +} + +// 批量删除用户 +export const batchDeleteUsers = (ids: number[]) => { + return request.delete('/system/user/batch', { data: { ids } }) +} +``` + +### 接口错误处理 + +```typescript +// src/hooks/useApi.ts +import { ref } from 'vue' +import { ElMessage } from 'element-plus' + +export const useApi = (apiFn: (...args: any[]) => Promise) => { + const loading = ref(false) + const error = ref(null) + const data = ref(null) + + const execute = async (...args: any[]) => { + loading.value = true + error.value = null + + try { + const result = await apiFn(...args) + data.value = result + return result + } catch (err: any) { + error.value = err.message || '请求失败' + ElMessage.error(error.value) + throw err + } finally { + loading.value = false + } + } + + return { + loading: readonly(loading), + error: readonly(error), + data: readonly(data), + execute + } +} +``` + +### 接口使用示例 + +```vue + +``` + +## 🚀 快速开始 + +### 环境要求 + +- **Node.js**: >= 16.0.0 +- **pnpm**: >= 7.0.0 (推荐) +- **Git**: >= 2.0.0 + +### 安装依赖 + +```bash +# 进入项目目录 +cd frontend + +# 安装依赖(推荐使用 pnpm) +pnpm install +``` + +### 开发环境 + +```bash +# 启动开发服务器 +pnpm run dev + +# 构建生产版本 +pnpm run build + +# 预览构建结果 +pnpm run preview +``` + +### 其他命令 + +```bash +# 代码检查 +pnpm run lint + +# 类型检查 +pnpm run type-check + +# 格式化代码 +pnpm run lint:format + +# 清理缓存 +pnpm run clean:cache +``` + +## 🔧 二次开发指南 + +## 🎯 动态菜单系统介绍 + +### 系统特性 + +**FastAPI Vue3 Admin** 采用 **动态路由 + 动态菜单** 的设计模式,具有以下优势: + +#### ✅ 优势特点 +- **运行时动态配置**:无需重新编译前端代码 +- **权限控制灵活**:基于角色的菜单权限管理 +- **组件动态加载**:按需加载页面组件 +- **菜单结构自由**:支持多级菜单、目录、按钮、外链 +- **热更新生效**:添加菜单后立即生效 + +#### 🔄 工作原理 + +```mermaid +graph TD + A[用户登录] --> B[获取用户权限] + B --> C[后端返回菜单数据] + C --> D[前端解析菜单] + D --> E[动态生成路由] + E --> F[注册到Vue Router] + F --> G[渲染菜单和页面] +``` + +### 动态路由流程详解 + +1. **后端数据结构**: + ```typescript + interface MenuTable { + id: number + name: string // 菜单名称(显示在菜单栏) + title: string // 菜单标题(显示在标签页) + route_path: string // 路由路径 + route_name: string // 路由名称 + component_path: string // 组件路径 + icon: string // 菜单图标 + type: 'CATALOG' | 'MENU' | 'BUTTON' | 'EXTLINK' + parent_id?: number // 父级菜单ID + order: number // 排序 + keep_alive: boolean // 是否缓存 + hidden: boolean // 是否隐藏 + always_show: boolean // 只有一个子路由时是否始终显示 + params: Array<{key: string, value: string}> // 路由参数 + status: boolean // 状态 + } + ``` + +2. **前端转换逻辑**: + ```typescript + // src/store/modules/permission.store.ts + const generator = (routers: MenuTable[]): RouteVO[] => { + return routers.map((item) => { + const currentRouter: RouteVO = { + path: item.route_path, + name: item.route_name, + component: item.component_path, // 动态组件路径 + meta: { + title: item.title, + icon: item.icon, + keepAlive: item.keep_alive, + hidden: item.hidden, + } + }; + // 递归处理子菜单 + if (item.children) { + currentRouter.children = generator(item.children); + } + return currentRouter; + }); + }; + ``` + +3. **组件动态解析**: + ```typescript + // 动态导入组件 + const modules = import.meta.glob("../../views/**/**.vue"); + normalizedRoute.component = + !normalizedRoute.component + ? Layout // 目录使用Layout组件 + : modules[`../../views/${normalizedRoute.component}.vue`] || // 动态导入页面组件 + modules["../../views/error/404.vue"]; // 404页面兜底 + ``` + +## 🚀 运行时动态添加页面 + +### 方法一:通过菜单管理界面添加 + +#### 步骤1:访问菜单管理 + +1. 登录系统后,进入 **系统管理 → 菜单管理** +2. 点击 **新增** 按钮 + +#### 步骤2:创建目录菜单 + +如果需要先创建父级目录: + +```json +{ + "菜单名称": "示例模块", + "菜单标题": "示例模块", + "菜单类型": "目录", + "路由路径": "/example", + "路由名称": "Example", + "图标": "Document", + "排序": 10, + "状态": "启用" +} +``` + +#### 步骤3:创建页面菜单 + +```json +{ + "父级菜单": "示例模块", + "菜单名称": "用户列表", + "菜单标题": "用户管理", + "菜单类型": "菜单", + "路由路径": "/example/user-list", + "路由名称": "ExampleUserList", + "组件路径": "example/user-list/index", + "图标": "User", + "是否缓存": true, + "排序": 1, + "状态": "启用" +} +``` + +#### 步骤4:创建页面组件 + +在 `src/views/example/user-list/index.vue` 创建组件: + +```vue + + + + + +``` + +#### 步骤5:刷新页面 + +添加菜单后: +1. 刷新浏览器页面 +2. 系统会重新加载用户权限和菜单数据 +3. 新菜单立即出现在侧边栏 +4. 点击新菜单可访问新页面 + +### 方法二:批量导入菜单 + +可以通过后端API批量创建菜单,然后前端自动识别: + +```typescript +// 后端批量创建菜单的示例数据 +const batchMenus = [ + { + name: "数据统计", + title: "数据统计", + type: "CATALOG", + route_path: "/statistics", + route_name: "Statistics", + icon: "TrendCharts", + order: 5, + children: [ + { + name: "用户统计", + title: "用户统计", + type: "MENU", + route_path: "/statistics/user", + route_name: "StatisticsUser", + component_path: "statistics/user/index", + icon: "User", + keep_alive: true, + order: 1 + }, + { + name: "订单统计", + title: "订单统计", + type: "MENU", + route_path: "/statistics/order", + route_name: "StatisticsOrder", + component_path: "statistics/order/index", + icon: "Document", + keep_alive: true, + order: 2 + } + ] + } +] +``` + +## 📝 菜单配置字段详解 + +### 核心字段说明 + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| `name` | string | ✅ | 菜单显示名称 | +| `title` | string | ✅ | 页面标题(标签页显示) | +| `type` | enum | ✅ | 菜单类型:CATALOG/MENU/BUTTON/EXTLINK | +| `route_path` | string | ✅ | 路由路径,如 `/system/user` | +| `route_name` | string | ✅ | 路由名称,用于keep-alive缓存 | +| `component_path` | string | 菜单必填 | 组件路径,相对于 `src/views/` | +| `parent_id` | number | ❌ | 父级菜单ID | +| `icon` | string | ❌ | 菜单图标,支持 Element Plus 图标 | +| `order` | number | ❌ | 排序号,越小越靠前 | +| `keep_alive` | boolean | ❌ | 是否开启页面缓存 | +| `hidden` | boolean | ❌ | 是否在菜单中隐藏 | +| `always_show` | boolean | ❌ | 只有一个子路由时是否始终显示 | +| `params` | array | ❌ | 路由参数数组 | +| `status` | boolean | ❌ | 菜单状态:true-启用,false-禁用 | + +### 菜单类型详解 + +#### 1. 目录 (CATALOG) +```json +{ + "type": "CATALOG", + "route_path": "/system", + "route_name": "System", + "component_path": null, + "children": [...] // 子菜单数组 +} +``` + +#### 2. 菜单 (MENU) +```json +{ + "type": "MENU", + "route_path": "/system/user", + "route_name": "SystemUser", + "component_path": "system/user/index", + "keep_alive": true +} +``` + +#### 3. 按钮 (BUTTON) +```json +{ + "type": "BUTTON", + "name": "用户新增", + "route_path": null, + "route_name": null, + "component_path": null +} +``` + +#### 4. 外链 (EXTLINK) +```json +{ + "type": "EXTLINK", + "route_path": "https://example.com", + "route_name": "ExternalLink" +} +``` + +### 图标配置 + +支持的图标格式: +- Element Plus 图标:`el-icon-User`、`el-icon-Setting` +- 自定义SVG图标:`icon-user`、`icon-setting` +- 空值:不显示图标 + +## 🔄 动态更新的机制 + +### 路由热更新 + +当菜单数据发生变化时,系统会: + +1. **检测变化**:监听用户权限和菜单数据变化 +2. **重新生成路由**:调用 `generateRoutes()` 方法 +3. **更新路由表**:动态注册新的路由到 Vue Router +4. **刷新菜单**:更新侧边栏菜单显示 +5. **清理缓存**:移除旧的路由缓存 + +```typescript +// src/store/modules/permission.store.ts +async function generateRoutes() { + const userStore = useUserStore(); + if (!userStore.hasGetRoute) { + await userStore.getUserInfo(); + } + + const routersTree = listToTree(userStore.routeList); + const routerMap = generator(routersTree); + const dynamicRoutes = parseDynamicRoutes(routerMap); + + routes.value = [...constantRoutes, ...dynamicRoutes]; + routesLoaded.value = true; + + return dynamicRoutes; +} +``` + +### 组件动态加载 + +系统使用 Vite 的 `import.meta.glob` 实现组件动态加载: + +```typescript +// 预加载所有页面组件 +const modules = import.meta.glob("../../views/**/**.vue"); + +// 动态解析组件 +normalizedRoute.component = + !normalizedRoute.component + ? Layout // 目录使用Layout组件 + : modules[`../../views/${normalizedRoute.component}.vue`] || + modules["../../views/error/404.vue"]; // 404兜底 +``` + +## 🎯 最佳实践 + +### 1. 菜单规划 + +#### 合理的菜单层级 +``` +📁 系统管理 (CATALOG) +├── 👤 用户管理 (MENU) +├── 🔐 角色管理 (MENU) +├── 📋 菜单管理 (MENU) +└── 📝 操作日志 (MENU) +``` + +#### 菜单命名规范 +- **目录**:使用名词,如 "系统管理"、"内容管理" +- **菜单**:使用功能描述,如 "用户列表"、"角色配置" +- **按钮**:使用操作描述,如 "用户新增"、"数据导出" + +### 2. 路由设计 + +#### 路由路径规范 +```typescript +// ✅ 推荐格式 +/system/user // 用户管理 +/system/role // 角色管理 +/content/article // 文章管理 +/statistics/dashboard // 数据统计 + +// ❌ 避免格式 +/user-management // 太长 +/usr-mgmt // 缩写不易懂 +``` + +#### 组件路径规范 +```typescript +// ✅ 推荐格式 +"system/user/index" // 用户管理主页面 +"system/user/detail" // 用户详情页面 +"content/article/editor" // 文章编辑器 + +// ❌ 避免格式 +"UserManagement" // PascalCase +"system/UserList.vue" // 包含扩展名 +``` + +### 3. 权限控制 + +#### 菜单权限 +```typescript +// 后端控制菜单显示 +{ + "name": "用户管理", + "roles": ["admin", "user_manager"], + "status": true +} +``` + +#### 页面权限 +```vue + +``` + +### 4. 缓存策略 + +#### 页面缓存配置 +```vue + +``` + +#### 缓存控制 +```json +{ + "keep_alive": true, // 启用缓存 + "route_name": "UserList" // 必须与组件name一致 +} +``` + +## 🔧 故障排除 + +### 常见问题 + +#### 1. 菜单不显示 +**问题**:添加菜单后在侧边栏不显示 +**解决**: +- 检查菜单状态是否为启用 +- 检查父级菜单是否存在且启用 +- 刷新页面重新加载菜单数据 + +#### 2. 页面404 +**问题**:点击菜单显示404页面 +**解决**: +- 检查组件路径是否正确 +- 确认组件文件是否存在 +- 检查路由路径格式 + +#### 3. 权限不足 +**问题**:菜单显示但无法访问 +**解决**: +- 检查用户角色权限 +- 确认菜单权限配置 +- 验证后端权限接口 + +#### 4. 图标不显示 +**问题**:菜单图标无法正常显示 +**解决**: +- 检查图标名称格式 +- 确认图标是否存在 +- 使用正确的图标命名规范 + +### 调试技巧 + +#### 1. 查看路由信息 +```typescript +// 在浏览器控制台查看当前路由 +console.log(router.currentRoute.value) + +// 查看所有路由 +console.log(router.getRoutes()) +``` + +#### 2. 查看权限数据 +```typescript +// 查看用户权限 +const userStore = useUserStore() +console.log(userStore.permissions) + +// 查看菜单数据 +console.log(userStore.routeList) +``` + +#### 3. 查看组件加载 +```typescript +// 查看动态导入的组件 +console.log(modules) +``` + +## 🚀 高级功能 + +### 自定义组件加载器 + +可以扩展动态组件加载逻辑: + +```typescript +// src/utils/componentLoader.ts +export const loadComponent = (componentPath: string) => { + // 自定义组件加载逻辑 + if (componentPath.startsWith('http')) { + // 远程组件加载 + return () => import(/* @vite-ignore */ componentPath) + } + + // 本地组件加载 + const modules = import.meta.glob("../../views/**/**.vue"); + return modules[`../../views/${componentPath}.vue`] || + modules["../../views/error/404.vue"]; +}; +``` + +### 菜单数据缓存 + +```typescript +// src/store/modules/menu.store.ts +export const useMenuStore = defineStore('menu', () => { + const menuCache = ref>(new Map()) + + const getMenuByRole = (role: string) => { + if (menuCache.value.has(role)) { + return menuCache.value.get(role) + } + // 从后端获取并缓存 + // ... + } + + return { + menuCache, + getMenuByRole + } +}) +``` + +## 🔧 传统开发方式(代码层面) + +### 1. 添加新页面 + +#### 步骤1:创建页面组件 + +在 `src/views/` 下创建新的页面组件: + +```vue + + + + + + +``` + +#### 步骤2:添加路由配置 + +在 `src/router/index.ts` 中添加路由: + +```typescript +import NewPage from '@/views/example/new-page.vue' + +const routes: RouteRecordRaw[] = [ + // ... 其他路由 + { + path: '/example/new-page', + name: 'NewPage', + component: NewPage, + meta: { + title: '新页面', + icon: 'Document', + keepAlive: true, + roles: ['admin'] + } + } +] +``` + +#### 步骤3:添加菜单配置 + +如果需要菜单显示,需要在后端菜单配置中添加对应的菜单项。 + +#### 步骤4:添加国际化 + +在语言包中添加翻译: + +```typescript +// src/lang/package/zh-cn.ts +export default { + example: { + newPage: '新页面' + } +} + +// src/lang/package/en.ts +export default { + example: { + newPage: 'New Page' + } +} +``` + +### 2. 添加新组件 + +#### 创建全局组件 + +```vue + + + + +``` + +#### 导出组件 + +在 `src/components/index.ts` 中导出: + +```typescript +export { default as CustomButton } from './CustomButton/index.vue' +``` + +### 3. 添加API接口 + +#### 创建API模块 + +```typescript +// src/api/example.ts +import request from '@/utils/request' + +export interface ExampleData { + id: number + name: string + status: string +} + +export const getExampleList = (params?: any) => { + return request.get('/example/list', { params }) +} + +export const createExample = (data: Omit) => { + return request.post('/example', data) +} + +export const updateExample = (id: number, data: Partial) => { + return request.put(`/example/${id}`, data) +} + +export const deleteExample = (id: number) => { + return request.delete(`/example/${id}`) +} +``` + +### 4. 添加状态管理 + +#### 创建Store模块 + +```typescript +// src/store/modules/example.store.ts +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { ExampleData } from '@/api/example' + +export const useExampleStore = defineStore('example', () => { + // 状态 + const exampleList = ref([]) + const loading = ref(false) + + // 计算属性 + const activeExamples = computed(() => + exampleList.value.filter(item => item.status === 'active') + ) + + // 动作 + const fetchExampleList = async () => { + loading.value = true + try { + const { data } = await getExampleList() + exampleList.value = data + } catch (error) { + console.error('获取示例列表失败:', error) + } finally { + loading.value = false + } + } + + const addExample = async (data: Omit) => { + await createExample(data) + await fetchExampleList() + } + + const updateExample = async (id: number, data: Partial) => { + await updateExample(id, data) + await fetchExampleList() + } + + const removeExample = async (id: number) => { + await deleteExample(id) + await fetchExampleList() + } + + return { + // 状态 + exampleList, + loading, + + // 计算属性 + activeExamples, + + // 动作 + fetchExampleList, + addExample, + updateExample, + removeExample + } +}) +``` + +### 5. 添加工具函数 + +```typescript +// src/utils/example.ts +/** + * 格式化示例数据 + */ +export const formatExampleData = (data: any): ExampleData => { + return { + id: data.id, + name: data.name || '', + status: data.status || 'inactive' + } +} + +/** + * 验证示例数据 + */ +export const validateExampleData = (data: Partial): string[] => { + const errors: string[] = [] + + if (!data.name?.trim()) { + errors.push('名称不能为空') + } + + if (!data.status) { + errors.push('状态不能为空') + } + + return errors +} +``` + +### 6. 添加类型定义 + +```typescript +// src/types/example.d.ts +export interface ExampleData { + id: number + name: string + status: 'active' | 'inactive' + createdAt: string + updatedAt: string +} + +export interface ExampleForm { + name: string + status: 'active' | 'inactive' +} + +export interface ExampleQuery { + page?: number + size?: number + name?: string + status?: 'active' | 'inactive' +} +``` + +### 7. 添加常量和枚举 + +```typescript +// src/constants/example.ts +export const EXAMPLE_STATUS = { + ACTIVE: 'active', + INACTIVE: 'inactive' +} as const + +export const EXAMPLE_STATUS_TEXT = { + [EXAMPLE_STATUS.ACTIVE]: '启用', + [EXAMPLE_STATUS.INACTIVE]: '禁用' +} as const + +export const EXAMPLE_PAGE_SIZE = 20 +``` + +### 8. 使用 UnoCSS + +项目使用 UnoCSS 进行原子化CSS开发: + +```vue + +``` + +常用 UnoCSS 类名: +- **布局**: `flex`, `grid`, `block`, `inline-block` +- **定位**: `relative`, `absolute`, `fixed` +- **间距**: `p-4`, `m-2`, `mt-4`, `mb-4`, `ml-4`, `mr-4` +- **颜色**: `text-red-500`, `bg-blue-500`, `border-gray-300` +- **尺寸**: `w-4`, `h-8`, `min-w-20`, `max-h-100` +- **边框**: `border`, `border-t`, `border-solid`, `rounded`, `rounded-lg` +- **阴影**: `shadow`, `shadow-lg`, `shadow-xl` +- **文字**: `text-sm`, `text-lg`, `font-bold`, `text-center` + +## 🎨 主题和样式 + +### 主题配置 + +项目支持明暗主题切换,主题变量定义在: + +```scss +// src/styles/variables.scss +:root { + // 亮色主题 + --el-color-primary: #409eff; + --el-color-success: #67c23a; + --el-color-warning: #e6a23c; + --el-color-danger: #f56c6c; + --el-color-info: #909399; +} + +// 暗色主题 +.dark { + --el-color-primary: #66d9ef; + --el-color-success: #a6e22e; + --el-color-warning: #fd971f; + --el-color-danger: #f92672; + --el-color-info: #75715e; +} +``` + +### 自定义样式 + +#### 全局样式 + +在 `src/styles/index.scss` 中添加全局样式: + +```scss +// 自定义全局样式 +.custom-class { + // 自定义样式 +} +``` + +#### 组件样式 + +使用 scoped 样式: + +```vue + +``` + +## 🔧 开发规范 + +### 代码规范 + +项目使用 ESLint + Prettier 进行代码规范检查: + +```bash +# 检查代码 +pnpm run lint + +# 修复代码 +pnpm run lint:fix +``` + +### Git 提交规范 + +项目使用 Husky + commitizen 进行 Git 提交规范: + +```bash +# 交互式提交 +pnpm run commit + +# 或直接提交 +git commit -m "feat: 添加新功能" +``` + +提交类型: +- `feat`: 新功能 +- `fix`: 修复bug +- `docs`: 文档更新 +- `style`: 代码格式调整 +- `refactor`: 代码重构 +- `test`: 测试相关 +- `chore`: 构建过程或工具配置更新 + +### 文件命名规范 + +- **组件文件**: PascalCase (`UserCard.vue`) +- **工具函数**: camelCase (`formatDate.ts`) +- **类型定义**: PascalCase (`UserType.ts`) +- **常量文件**: kebab-case (`user-constants.ts`) +- **页面文件**: kebab-case (`user-list.vue`) + +## 🚀 部署指南 + +### 构建生产版本 + +```bash +# 构建生产版本 +pnpm run build + +# 构建特定环境 +pnpm run build:pro # 生产环境 +pnpm run build:dev # 开发环境 +pnpm run build:test # 测试环境 +``` + +### Nginx 配置 + +```nginx +server { + listen 80; + server_name your-domain.com; + + location / { + root /path/to/dist; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + # API 代理 + location /api/ { + proxy_pass http://backend-server:8000/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +### Docker 部署 + +```dockerfile +# Dockerfile +FROM nginx:alpine + +COPY dist/ /usr/share/nginx/html/ +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] +``` + +## 🌍 国际化配置 + +### 国际化架构 + +项目使用 Vue I18n 进行国际化管理: + +``` +src/lang/ +├── 📁 package/ # 语言包 +│ ├── zh-cn.ts # 中文语言包 +│ └── en.ts # 英文语言包 +└── index.ts # 国际化配置 +``` + +### 语言包配置 + +```typescript +// src/lang/package/zh-cn.ts +export default { + common: { + confirm: '确定', + cancel: '取消', + save: '保存', + delete: '删除', + edit: '编辑', + add: '新增', + search: '搜索', + reset: '重置', + export: '导出', + import: '导入' + }, + menu: { + dashboard: '仪表板', + system: '系统管理', + user: '用户管理', + role: '角色管理', + menu: '菜单管理' + }, + message: { + success: '操作成功', + error: '操作失败', + confirmDelete: '确定要删除这条记录吗?', + noPermission: '没有权限访问' + } +} +``` + +### 在组件中使用 + +```vue + + + +``` + +## 🛡️ 错误处理机制 + +### 全局错误处理 + +```typescript +// src/utils/errorHandler.ts +import { ElMessage } from 'element-plus' + +export const setupErrorHandler = (app: App) => { + // Vue 错误处理 + app.config.errorHandler = (err: Error, instance, info) => { + console.error('Vue Error:', err, info) + handleError(err) + } + + // 全局错误处理函数 + const handleError = (error: any) => { + if (error.code === 'NETWORK_ERROR') { + ElMessage.error('网络连接失败') + } else if (error.code === 401) { + ElMessage.error('登录已过期,请重新登录') + router.push('/login') + } else if (error.code === 403) { + ElMessage.error('没有权限访问') + } else { + ElMessage.error(error.message || '发生未知错误') + } + } +} +``` + +### 错误边界组件 + +```vue + + + + +``` + +## 🚀 性能优化 + +### 代码分割和懒加载 + +```typescript +// 路由懒加载 +const routes = [ + { + path: '/dashboard', + component: () => import('@/views/dashboard/index.vue') + }, + { + path: '/system/user', + component: () => import('@/views/system/user/index.vue') + } +] +``` + +### 组件懒加载 + +```vue + +``` + +### 图片懒加载 + +```vue + + + + +``` + +## 🔒 安全性 + +### XSS 防护 + +```typescript +// src/utils/sanitize.ts +export const sanitizeHtml = (html: string): string => { + return html.replace(/[<>]/g, '') +} +``` + +### 权限验证 + +```typescript +// src/composables/usePermission.ts +export const usePermission = () => { + const hasPermission = (permission: string): boolean => { + const userStore = useUserStore() + return userStore.permissions.includes(permission) + } + + const hasRole = (role: string): boolean => { + const userStore = useUserStore() + return userStore.roles.includes(role) + } + + return { hasPermission, hasRole } +} +``` + +## 🧪 单元测试 + +### 测试配置 + +```typescript +// vitest.config.ts +export default defineConfig({ + test: { + globals: true, + environment: 'jsdom' + } +}) +``` + +### 组件测试 + +```typescript +// src/components/__tests__/Button.test.ts +import { mount } from '@vue/test-utils' + +describe('Button', () => { + it('renders correctly', () => { + const wrapper = mount(Button, { + props: { type: 'primary' } + }) + expect(wrapper.classes()).toContain('el-button--primary') + }) +}) +``` + +### API 测试 + +```typescript +// src/api/__tests__/user.test.ts +import { vi, describe, it, expect } from 'vitest' + +vi.mock('@/utils/request') + +describe('User API', () => { + it('fetches user list', async () => { + const mockUsers = [{ id: 1, name: 'John' }] + mockRequest.get.mockResolvedValue({ data: mockUsers }) + + const result = await getUserList() + expect(result).toEqual(mockUsers) + }) +}) +``` + +### 运行测试 + +```bash +# 运行测试 +pnpm test + +# 生成覆盖率 +pnpm test:coverage +``` + +## 🔄 CI/CD 集成 + +### GitHub Actions 配置 + +```yaml +# .github/workflows/ci.yml +name: CI/CD + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install + + - name: Run linter + run: pnpm run lint + + - name: Run tests + run: pnpm test + + - name: Build + run: pnpm run build + + deploy: + needs: test + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + + steps: + - name: Deploy to production + run: | + echo "Deploy to production server" + # Add your deployment commands here +``` + +### Jenkins 配置 + +```groovy +// Jenkinsfile +pipeline { + agent any + + stages { + stage('Checkout') { + steps { + git branch: 'main', url: 'https://github.com/your-repo.git' + } + } + + stage('Install') { + steps { + sh 'pnpm install' + } + } + + stage('Test') { + steps { + sh 'pnpm test' + } + } + + stage('Build') { + steps { + sh 'pnpm run build' + } + } + + stage('Deploy') { + steps { + sh 'scp -r dist/* user@server:/path/to/web/root/' + } + } + } + + post { + success { + echo 'Pipeline succeeded!' + } + failure { + echo 'Pipeline failed!' + } + } +} +``` + +## ❓ 常见问题解答 + +### 项目配置问题 + +**Q: 如何修改项目的标题和Logo?** + +A: 在 `src/settings.ts` 中修改应用配置: + +```typescript +export const settings = { + title: '你的应用名称', + logo: '/path/to/your/logo.png' +} +``` + +**Q: 如何修改主题色?** + +A: 在 `src/styles/variables.scss` 中修改CSS变量: + +```scss +:root { + --el-color-primary: #your-color; +} +``` + +**Q: 如何添加新的环境变量?** + +A: 在对应的 `.env` 文件中添加变量,然后在代码中使用: + +```bash +# .env.development +VITE_APP_NEW_VAR=value +``` + +```typescript +// 在代码中使用 +const newVar = import.meta.env.VITE_APP_NEW_VAR +``` + +### 开发问题 + +**Q: 组件样式不生效怎么办?** + +A: 检查以下几点: +1. 是否使用了 `scoped` 样式 +2. CSS 类名是否正确 +3. 是否使用了正确的 UnoCSS 类名 +4. 样式优先级是否正确 + +**Q: API请求失败怎么办?** + +A: 检查以下几点: +1. 后端服务是否启动 +2. API地址是否正确 +3. 请求头是否包含认证信息 +4. 网络连接是否正常 + +**Q: 路由跳转失败怎么办?** + +A: 检查以下几点: +1. 路由路径是否正确 +2. 路由组件是否存在 +3. 路由权限是否正确 +4. 路由参数是否正确传递 + +### 性能问题 + +**Q: 页面加载慢怎么办?** + +A: 尝试以下优化: +1. 启用代码分割和懒加载 +2. 优化图片资源 +3. 启用压缩和缓存 +4. 使用CDN加速 + +**Q: 内存泄漏怎么办?** + +A: 注意以下几点: +1. 及时清理定时器和事件监听器 +2. 正确使用 Vue 的生命周期 +3. 避免在组件中保存大量数据 +4. 使用内存分析工具检查 + +### 部署问题 + +**Q: 部署后页面空白怎么办?** + +A: 检查以下几点: +1. 构建是否成功 +2. 静态资源路径是否正确 +3. 服务器配置是否正确 +4. 路由模式是否匹配服务器配置 + +**Q: API请求跨域怎么办?** + +A: 配置代理或修改服务器CORS设置: + +```typescript +// vite.config.ts +export default defineConfig({ + server: { + proxy: { + '/api': { + target: 'http://localhost:8000', + changeOrigin: true + } + } + } +}) +``` + +## 📊 监控和日志 + +### 错误监控 + +```typescript +// src/utils/monitor.ts +import * as Sentry from '@sentry/vue' + +export const initSentry = (app: App) => { + Sentry.init({ + app, + dsn: import.meta.env.VITE_SENTRY_DSN, + integrations: [ + new Sentry.BrowserTracing({ + routingInstrumentation: Sentry.vueRouterInstrumentation(router) + }) + ], + tracesSampleRate: 1.0 + }) +} +``` + +### 性能监控 + +```typescript +// src/utils/performance.ts +export const reportWebVitals = (metric: any) => { + // 发送性能指标到监控服务 + console.log('Web Vitals:', metric) + + // 可以发送到自己的监控服务 + // fetch('/api/metrics', { + // method: 'POST', + // body: JSON.stringify(metric) + // }) +} + +// 使用 Web Vitals 库 +import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals' + +getCLS(reportWebVitals) +getFID(reportWebVitals) +getFCP(reportWebVitals) +getLCP(reportWebVitals) +getTTFB(reportWebVitals) +``` + +### 用户行为分析 + +```typescript +// src/utils/analytics.ts +export const trackEvent = (eventName: string, properties?: Record) => { + // 发送事件到分析服务 + console.log('Track Event:', eventName, properties) + + // 可以集成 Google Analytics、百度统计等 + // gtag('event', eventName, properties) +} +``` + +## 🎯 最佳实践 + +### 代码组织 + +1. **组件设计** + - 单一职责原则 + - 可复用性 + - 清晰的API设计 + +2. **状态管理** + - 合理划分状态范围 + - 使用组合式函数 + - 避免状态冗余 + +3. **类型安全** + - 使用TypeScript + - 定义清晰的接口 + - 充分利用类型推导 + +### 性能优化 + +1. **打包优化** + - 代码分割 + - 资源压缩 + - 缓存策略 + +2. **运行时优化** + - 虚拟滚动 + - 图片懒加载 + - 防抖节流 + +3. **网络优化** + - 请求缓存 + - 预加载 + - CDN加速 + +### 安全性 + +1. **输入验证** + - XSS防护 + - CSRF防护 + - SQL注入防护 + +2. **权限控制** + - 角色权限 + - 菜单权限 + - 按钮权限 + +3. **数据保护** + - 敏感信息加密 + - HTTPS传输 + - 本地存储安全 + +## 📚 常用资源 + +### 官方文档 +- [Vue 3](https://cn.vuejs.org/) +- [TypeScript](https://www.typescriptlang.org/) +- [Vite](https://cn.vitejs.dev/) +- [Element Plus](https://element-plus.org/) +- [Pinia](https://pinia.vuejs.org/) +- [UnoCSS](https://unocss.dev/) + +### 推荐工具 +- [Vue DevTools](https://devtools.vuejs.org/) +- [Vite DevTools](https://github.com/vadxq/vite-devtools) +- [Element Plus DevTools](https://github.com/element-plus/element-plus-devtools) + +### 学习资源 +- [Vue 3 官方教程](https://cn.vuejs.org/tutorial/) +- [TypeScript 入门](https://www.typescriptlang.org/docs/) +- [现代前端开发指南](https://modern-frontend.guide/) + +## 🤝 贡献指南 + +1. Fork 项目 +2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) +3. 提交更改 (`git commit -m 'feat: Add some AmazingFeature'`) +4. 推送到分支 (`git push origin feature/AmazingFeature`) +5. 打开 Pull Request + +## 📝 更新日志 + +### v1.0.0 (2024-01-XX) + +#### ✨ 新增功能 +- 🎨 支持明暗主题切换 +- 🌍 完整的国际化支持 +- 🔐 基于角色的权限管理系统 +- 📊 动态菜单系统 +- 🧪 完整的单元测试配置 +- 📊 性能监控和错误监控 +- 🔄 CI/CD 集成配置 +- 🚀 代码分割和懒加载优化 + +#### 🛠️ 技术栈升级 +- Vue 3 + TypeScript +- Vite 4.x 构建工具 +- Element Plus UI 组件库 +- Pinia 状态管理 +- UnoCSS 原子化CSS +- Vue I18n 国际化 + +#### 📚 文档完善 +- 详细的项目结构说明 +- 完整的二次开发指南 +- API 接口管理文档 +- 最佳实践和性能优化指南 +- 常见问题解答 + +## 🔄 版本管理 + +项目采用语义化版本控制: + +- **MAJOR.MINOR.PATCH** (主版本.次版本.补丁版本) +- 主版本:破坏性变更 +- 次版本:新增功能,向后兼容 +- 补丁版本:修复bug,向后兼容 + +### 分支管理 + +``` +main # 主分支,生产环境代码 +develop # 开发分支,集成新功能 +feature/* # 功能分支,新功能开发 +hotfix/* # 热修复分支,紧急bug修复 +release/* # 发布分支,准备发布版本 +``` + +### 发布流程 + +1. **开发阶段** + ```bash + git checkout develop + git checkout -b feature/new-feature + # 开发新功能 + git commit -m "feat: add new feature" + ``` + +2. **代码审查** + ```bash + git push origin feature/new-feature + # 创建 Pull Request + ``` + +3. **合并到开发分支** + ```bash + git checkout develop + git merge feature/new-feature + ``` + +4. **发布准备** + ```bash + git checkout -b release/v1.1.0 + # 测试和修复 + ``` + +5. **发布到生产** + ```bash + git checkout main + git merge release/v1.1.0 + git tag v1.1.0 + git push origin main --tags + ``` + +## 📄 许可证 + +本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情 + +## 📞 联系我们 + +如有问题或建议,请: + +1. 查看 [项目文档](PROJECT_GUIDE.md) +2. 提交 [Issue](https://github.com/your-repo/issues) +3. 发送邮件至:contact@example.com + +## 🙏 致谢 + +感谢以下开源项目的贡献: + +- **Vue.js** - 渐进式前端框架 +- **Element Plus** - Vue3 UI组件库 +- **Vite** - 下一代前端构建工具 +- **TypeScript** - 类型安全的JavaScript +- **UnoCSS** - 原子化CSS引擎 +- **Pinia** - Vue3官方状态管理库 + +--- + +## 🎯 项目总结 + +**FastAPI Vue3 Admin** 是一个功能完整、架构清晰、易于维护的现代化后台管理系统前端模板,具有以下特点: + +### ✅ 核心优势 + +1. **现代化技术栈** - Vue3 + TypeScript + Vite + Element Plus +2. **完整的功能体系** - 从开发到部署的全流程解决方案 +3. **高度可定制** - 支持主题切换、国际化、动态菜单等 +4. **优秀的开发体验** - 热重载、类型检查、代码规范等 +5. **生产就绪** - 包含测试、监控、部署等完整配置 + +### 🎨 设计理念 + +- **组件化** - 一切皆组件,提高复用性 +- **配置化** - 通过配置而非硬编码实现功能 +- **规范化** - 统一的代码规范和开发流程 +- **可扩展** - 插件化架构,易于扩展新功能 + +### 🚀 快速开始 + +```bash +# 1. 克隆项目 +git clone https://github.com/your-repo.git + +# 2. 安装依赖 +cd frontend && pnpm install + +# 3. 启动开发服务器 +pnpm run dev + +# 4. 开始开发 +# 访问 http://localhost:5173 +``` + +### 📚 学习路径 + +1. **新手入门** - 阅读快速开始和项目结构 +2. **功能开发** - 学习动态菜单系统和API接口管理 +3. **高级特性** - 掌握性能优化和安全性配置 +4. **生产部署** - 了解CI/CD和监控配置 + +--- + +**🎉 祝您开发愉快!使用这个模板构建出色的后台管理系统!** diff --git a/frontend/src/layouts/components/TagsView/index.vue b/frontend/src/layouts/components/TagsView/index.vue index 858eb862..c13f2f1b 100644 --- a/frontend/src/layouts/components/TagsView/index.vue +++ b/frontend/src/layouts/components/TagsView/index.vue @@ -236,7 +236,6 @@ const extractAffixTags = (routes: RouteRecordRaw[], basePath = "/"): TagView[] = fullPath, name: String(route.name || ""), title: route.meta.title || "no-name", - icon: (route as any).icon || route.meta?.icon, affix: true, keepAlive: route.meta.keepAlive || false, }); diff --git a/frontend/src/views/dashboard/components/QuickStart.vue b/frontend/src/views/dashboard/components/QuickStart.vue index 8e8cf7f9..05e43656 100644 --- a/frontend/src/views/dashboard/components/QuickStart.vue +++ b/frontend/src/views/dashboard/components/QuickStart.vue @@ -261,10 +261,18 @@ onUnmounted(() => { .external-link-badge { font-size: 10px; font-weight: 400; - background-color: #409EFF; + background-color: var(--el-color-primary); + color: #ffffff; padding: 1px 4px; border-radius: 2px; line-height: 1.2; + transition: all 0.3s ease; + } + + // 暗色主题适配 - 使用项目标准的暗色主题选择器 + html.dark .external-link-badge { + background-color: var(--el-color-primary-dark-2); + color: var(--el-text-color-primary); } } } From 39c2389d2e20c6ce554e054f88bf90edeef4699c Mon Sep 17 00:00:00 2001 From: Guo Tiantian <1431335589@qq.com> Date: Thu, 28 Aug 2025 23:19:45 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E5=A4=96?= =?UTF-8?q?=E9=93=BE=E6=A0=87=E7=AD=BE=E6=A0=B7=E5=BC=8F=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=B3=BB=E7=BB=9F=E4=B8=BB=E9=A2=98=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/CHANGELOG.md | 386 +++++ frontend/PROJECT_GUIDE.md | 3053 ------------------------------------- 2 files changed, 386 insertions(+), 3053 deletions(-) create mode 100644 frontend/CHANGELOG.md delete mode 100644 frontend/PROJECT_GUIDE.md diff --git a/frontend/CHANGELOG.md b/frontend/CHANGELOG.md new file mode 100644 index 00000000..aef3f6da --- /dev/null +++ b/frontend/CHANGELOG.md @@ -0,0 +1,386 @@ + +# 2.11.5 (2024/6/18) + +## ✨ feat + +- 支持后端文件导入([#142](https://github.com/youlaitech/vue3-element-admin/pull/142)) [@cshaptx4869](https://github.com/cshaptx4869) + + +## 🐛 fix +- vue-dev-tools 插件导致菜单路由切换卡死,暂时关闭 ([28349e](https://github.com/youlaitech/vue3-element-admin/commit/28349efe147afab36531ba148eaac3a448fe6c71)) [@haoxianrui](https://github.com/haoxianrui) + + + +# 2.11.4 (2024/6/16) + +## ✨ feat + +- 操作栏增加render配置参数([#138](https://github.com/youlaitech/vue3-element-admin/pull/140)) [@cshaptx4869](https://github.com/cshaptx4869) +- 左侧工具栏增加type配置参数([#141](https://github.com/youlaitech/vue3-element-admin/pull/141)) [@diamont1001](https://github.com/diamont1001) + +## ♻️ refactor +- 更换权限分配弹窗类型为 drawer 并添加父子联动开关([2d9193](https://github.com/youlaitech/vue3-element-admin/commit/2d9193c47fd224f01f82b9c0b2bbeb5e7cb33584)) [@haoxianrui](https://github.com/haoxianrui) + + + +# 2.11.3 (2024/6/11) + +## ✨ feat + +- 支持默认工具栏的导入([#138](https://github.com/youlaitech/vue3-element-admin/pull/138)) [@cshaptx4869](https://github.com/cshaptx4869) +- 添加CURD导入示例([19e7bb](https://github.com/youlaitech/vue3-element-admin/commit/eab91effd6a01d5a3d9257249c8d06aa252b3bf8)) [@cshaptx4869](https://github.com/cshaptx4869) + +## ♻️ refactor +- 修改导出全量数据选项文本([904fec](https://github.com/youlaitech/vue3-element-admin/commit/904fecad65217650482fcdbb10ffb7f3d27eb9ea)) [@cshaptx4869](https://github.com/cshaptx4869) + +## 🐛 fix +- 菜单列表未适配el-icon导致图标不显示问题修复([e72b68](https://github.com/youlaitech/vue3-element-admin/commit/e72b68337562b5a7ea24ad55bbe00023e1266b40)) [@haoxianrui](https://github.com/haoxianrui) + +# 2.11.2 (2024/6/8) + +## ✨ feat + +- 支持表格远程筛选([#131](https://github.com/youlaitech/vue3-element-admin/pull/131)) [@cshaptx4869](https://github.com/cshaptx4869) +- 支持标签输入框([#132](https://github.com/youlaitech/vue3-element-admin/pull/132)) [@cshaptx4869](https://github.com/cshaptx4869) +- 表单项支持tips配置([#133](https://github.com/youlaitech/vue3-element-admin/pull/133)) [@cshaptx4869](https://github.com/cshaptx4869) +- 前端导出支持全量数据([#134](https://github.com/youlaitech/vue3-element-admin/pull/134)) [@cshaptx4869](https://github.com/cshaptx4869) +- 支持选中数据导出([#135](https://github.com/youlaitech/vue3-element-admin/pull/135)) [@cshaptx4869](https://github.com/cshaptx4869) +- 表格默认工具栏的导出、搜索按钮增加权限点控制([883128](https://github.com/youlaitech/vue3-element-admin/commit/8831289b655f2cc086ecdababaa89f8d8a087c42)) [@cshaptx4869](https://github.com/cshaptx4869) +- 页签title支持动态设置([23876a](https://github.com/youlaitech/vue3-element-admin/commit/23876aa396143bf77cb5c86af8d6023d9ff6555a)) [@haoxianrui](https://github.com/haoxianrui) + +## ♻️ refactor +- 默认工具栏支持自定义([#136](https://github.com/youlaitech/vue3-element-admin/pull/136)) [@cshaptx4869](https://github.com/cshaptx4869) +- 未配置全量导出接口时选项隐藏([eab91ef](https://github.com/youlaitech/vue3-element-admin/commit/eab91effd6a01d5a3d9257249c8d06aa252b3bf8)) [@cshaptx4869](https://github.com/cshaptx4869) + +## 🐛 fix +- 修复注销登出后redirect跳转路由参数丢失([5626017](https://github.com/youlaitech/vue3-element-admin/commit/562601736731afd20bb1a5140d856f6515720159)) [@haoxianrui](https://github.com/haoxianrui) + +# 2.11.1 (2024/6/6) + +## ✨ feat + +- 增加pagination、request、parseData配置参数([#119](https://github.com/youlaitech/vue3-element-admin/pull/119)) [@cshaptx4869](https://github.com/cshaptx4869) +- 增加返回顶部功能([#120](https://github.com/youlaitech/vue3-element-admin/pull/120)) [@cshaptx4869](https://github.com/cshaptx4869) +- 支持前端导出([#126](https://github.com/youlaitech/vue3-element-admin/pull/126)) [@cshaptx4869](https://github.com/cshaptx4869) + +## ♻️ refactor +- 重构布局样式(解决页面抖动问题)([#116](https://github.com/youlaitech/vue3-element-admin/pull/116)) [@cshaptx4869](https://github.com/cshaptx4869) +- 修改CURD示例编辑弹窗尺寸([#121](https://github.com/youlaitech/vue3-element-admin/pull/121)) [@cshaptx4869](https://github.com/cshaptx4869) +- 统一注册vue插件([#122](https://github.com/youlaitech/vue3-element-admin/pull/122)) [@cshaptx4869](https://github.com/cshaptx4869) +- 默认主题跟随系统([#128](https://github.com/youlaitech/vue3-element-admin/pull/128)) [@cshaptx4869](https://github.com/cshaptx4869) +- 增加"scss.lint.unknownAtRules": "ignore"代码,解决style中使用@apply提示unknow at rules@apply提示问题([Gitee#22](https://gitee.com/youlaiorg/vue3-element-admin/pulls/22)) [@zjsy521](https://gitee.com/zjsy521) + +## 🐛 fix +- 修复左侧布局移动端菜单弹出样式 ([#117](https://github.com/youlaitech/vue3-element-admin/pull/117)) [@cshaptx4869](https://github.com/cshaptx4869) + +- 修复编辑后未清空id再新增菜单覆盖的问题([0e78eeb](https://github.com/youlaitech/vue3-element-admin/commit/0e78eeb75008fa8e9732b1b4e7d7a1ea345c7a1b)) [@haoxianrui](https://github.com/haoxianrui) +- 修复水印层级问题([#123](https://github.com/youlaitech/vue3-element-admin/pull/123)) [@cshaptx4869](https://github.com/cshaptx4869) +- 修复混合布局样式问题([#124](https://github.com/youlaitech/vue3-element-admin/pull/124)) [@cshaptx4869](https://github.com/cshaptx4869) +- 修复关闭弹窗时没有clearValidate问题([#125](https://github.com/youlaitech/vue3-element-admin/pull/125)) [@andm31](https://github.com/andm31) + + + +# 2.11.0 (2024/5/27) + +## ✨ feat +- 菜单添加路由参数设置(author by [haoxianrui](https://github.com/haoxianrui)) +- 增加列表选择组件(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 增加列表选择组件使用示例(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 增加defaultToolbar配置参数(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 表单弹窗支持drawer模式(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 表单项增加computed和watchEffect配置(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 支持switch属性修改(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 表单项增加文本类型支持(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 列表列增加show配置项(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 支持搜索表单显隐控制(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 支持input属性修改(author by [cshaptx4869](https://github.com/cshaptx4869)) +- search配置新增函数能力拓展(author by [xiudaozhe](https://github.com/xiudaozhe)) +- 表格新增列设置控制(author by [haoxianrui](https://github.com/haoxianrui)) +- 搜索添加展开和收缩(author by [haoxianrui](https://github.com/haoxianrui)) +- watch函数增加配置项参数返回(author by [cshaptx4869](https://github.com/cshaptx4869)) + +## ♻️ refactor +- 重构图标选择组件(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 重构列表选择组件默认样式 (author by [cshaptx4869](https://github.com/cshaptx4869)) +- 加强对话框表单组件和列表选择组件(author by [cshaptx4869](https://github.com/cshaptx4869)) +- routeMeta增加alwaysShow字段声明(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 分页组件增加溢出滚动效果(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 修正登录表单的Ref类型(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 点击表格刷新按钮不重置页码(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 筛选列超出一定高度滚动(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 优化加强initFn函数,表单项增加initFn函数(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 重构watch、computed、watchEffect调用(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 修改操作成功提示(author by [cshaptx4869](https://github.com/cshaptx4869)) +- PageSearch 改用card作为容器,样式改用unocss写法(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 优化首页 loading 动画效果author by [haoxianrui](https://github.com/haoxianrui)) + + +## 🐛 fix +- 路由是否始终显示不限制只有顶级目录才有的配置,开放至菜单 (author by [haoxianrui](https://github.com/haoxianrui)) +- sockjs-client 报错 global is not defined 导致开发环境无法打开 WebSocket 页面问题修复 (author by [haoxianrui](https://github.com/haoxianrui)) +- 发送用户重启密码功能,最少为6位字符(小于6位登陆时不允许的问题) (author by [dreamnyj](https://gitee.com/dreamnyj)) +- 修复系统设置面板滚动条问题(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 修复表单插槽失效问题(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 修改tagsview刷新丢失query问题(author by [xiudaozhe](https://github.com/xiudaozhe)) + +## 📦️ build +- 升级 NPM 包版本至最新 (author by [haoxianrui](https://github.com/haoxianrui)) + +## ⚙️ ci +- 规整脚本执行命令(author by [cshaptx4869](https://github.com/cshaptx4869)) + + +# 2.10.1 (2024/5/4) + +## ♻️ refactor +- 抽离CURD的使用部分代码为Hooks实现(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 修改CURD导入权限点标识名(author by [cshaptx4869](https://github.com/cshaptx4869)) +- cURD表单字段支持watch监听(author by [cshaptx4869](https://github.com/cshaptx4869)) +- cURD表单input支持number修饰(author by [cshaptx4869](https://github.com/cshaptx4869)) +- cURD表单组件支持checkbox多选框(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 优化axios响应数据TS类型提示(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 修改CURD表单组件自定义类型的attrs传值(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 同步重置密码按钮权限标识重命名(author by [haoxianrui](https://github.com/haoxianrui)) +- 重构API为静态方法实现模块化管理,并将types.ts重命名为model.ts用于存放接口模型定义(author by [haoxianrui](https://github.com/haoxianrui)) + + +## 🐛 fix +- sockjs-client 报错 global is not defined 导致开发环境无法打开 WebSocket 页面问题修复 (author by [haoxianrui](https://github.com/haoxianrui)) +- 主题颜色设置覆盖暗黑模式下el-table行激活的背景色问题修复 (author by [haoxianrui](https://github.com/haoxianrui)) +- 修复因API接口调整而影响的调用页面的问题 (author by [haoxianrui](https://github.com/haoxianrui)) + +## 📦️ build +- 升级 NPM 包版本至最新 (author by [haoxianrui](https://github.com/haoxianrui)) + + +# 2.10.0 (2024/4/26) +## ✨ feat +- 封装增删改查组件(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 集成 vite-plugin-vue-devtools 插件(author by [Tricker39](https://github.com/Tricker39)) +- 增加CURD配置化实现(author by [cshaptx4869](https://github.com/cshaptx4869)) + + +# 2.9.3 (2024/04/14) +## ✨ feat +- 增加vue文件代码片段(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 菜单 hover 背景色添加值全局SCSS变量进行控制(author by [haoxianrui](https://github.com/haoxianrui)) + +## ♻️ refactor +- 加强基础国际化(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 增加语言和布局大小枚举类型(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 增加侧边栏状态枚举类型(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 使用布局枚举替换字面量(author by [haoxianrui](https://github.com/haoxianrui)) +- 控制台使用静态数据循环渲染(author by [april](mailto:april@zen-game.cn)) +- 本地缓存的 token 变量重命名(author by [haoxianrui](https://github.com/haoxianrui)) +- 完善 Vite 环境变量类型声明(author by [haoxianrui](https://github.com/haoxianrui)) + +## 🐛 fix +- 修复构建时提示iconComponent.name可能为undefined的报错 (author by [wangji1042](https://github.com/wangji1042)) +- 修复浏览器密码自动填充时可能存在的报错 (author by [cshaptx4869](https://github.com/cshaptx4869)) +- 修复eslint报错(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 移动端下点击左侧菜单节点后关闭侧边栏(author by [haoxianrui](https://github.com/haoxianrui)) +- 添加 size 类型断言修复类型报错(author by [haoxianrui](https://github.com/haoxianrui)) + +## 📦️ build +- husky9.x版本适配 (author by [cshaptx4869](https://github.com/cshaptx4869)) +- 升级 npm 包版本至最新(author by [haoxianrui](https://github.com/haoxianrui)) + +# 2.9.2 (2024/03/05) +## ✨ feat +- vscode开发扩展推荐(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 完善基础增删改查Mock接口(author by [haoxianrui](https://github.com/haoxianrui)) + +## ♻️ refactor +- 修改login密码框功能实现(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 弱化页面进入动画效果(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 取消推荐TypeScript Vue Plugin (author by [cshaptx4869](https://github.com/cshaptx4869)) +- 网站加载动画替换 (author by [haoxianrui](https://github.com/haoxianrui)) +- 优化主题和主题色监听,避免多个页面重复初始化 (author by [haoxianrui](https://github.com/haoxianrui)) + +## 🐛 fix +- AppMain 高度在非固定头部不正确导致出现滚动条问题修复 (author by [haoxianrui](https://github.com/haoxianrui)) +- 修复混合模式开启固定Head时的样式问题 (author by [cshaptx4869](https://github.com/cshaptx4869)) +- 设置面板统一字体大小 (author by [cshaptx4869](https://github.com/cshaptx4869)) + +## 📦️build +- 通过env配置控制mock服务 (author by [cshaptx4869](https://github.com/cshaptx4869)) +- 升级依赖包至最新版本 (author by [haoxianrui](https://github.com/haoxianrui)) +- 定义vite全局常量替换项目标题和版本 (author by [cshaptx4869](https://github.com/cshaptx4869)) + +# 2.9.1 (2024/02/28) +## ♻️ refactor +- 项目配置按钮移入navbar(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 优化user数据定义(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 统一设置栏的 SVG 图标风格 + +## 🐛 fix +- 规整一些开发依赖(author by [cshaptx4869](https://github.com/cshaptx4869)) +- 修复登录页主题切换问题 (author by [cshaptx4869](https://github.com/cshaptx4869)) + +## 🚀 pref + +- 压缩图片资源 (author by [cshaptx4869](https://github.com/cshaptx4869)) + + +# 2.9.0 (2024/02/25) + +## ✨ feat +- 引入 animate.css 动画库 +- 新增水印和配置 +- 动态路由菜单支持 element plus 的图标 + +## ♻️ refactor +- Layout 布局重构和相关问题修复 +- sass 使用 @use 替代 @import 引入外部文件指令 + +## 🐛 fix +- 修复管理页面部分弹窗无法打开问题 +- 主题颜色设置按钮 hover 等未变化问题修复 + + +# 2.8.1 (2024/01/10) + +## ✨ feat +- 替换 Mock 解决方案 vite-plugin-mock 为 vite-plugin-mock-dev-server 适配 Vite5 + +# 2.8.0 (2023/12/27) + +## ⬆️ chore +- 升级 Vite4 至 Vite5 + +# 2.7.1 (2023/12/12) + +## ♻️ refactor +- 将打包后的文件进行分类 (author by [ityangzhiwen](https://gitee.com/ityangzhiwen)) + +# 2.7.0 (2023/11/19) + +## ♻️ refactor +- 代码重构优化 +- 修改自动导入组件类型声明文件路径 +- 完善 typescript 类型 + +## 🐛 fix +- 修复管理页面部分弹窗无法打开问题 + + +# 2.7.0 (2023/11/19) + +## ♻️ refactor +- 代码重构 +- 修改自动导入组件类型声明文件路径 +- 完善 typescript 类型 + +## 🐛 fix +- 修复管理页面部分弹窗无法打开问题 + + +# 2.6.3 (2023/10/22) + +## ✨ feat +- 菜单管理新增目录只有一级子路由是否始终显示(alwaysShow)和路由页面是否缓存(keepAlive)的配置 +- 接口文档新增 swagger、knife4j +- 引入和支持 tsx + +## ♻️ refactor +- 代码瘦身,整理并删除未使用的 svg +- 控制台样式优化 + +## 🐛 fix +- 菜单栏折叠和展开的图标暗黑模式显示问题修复 + + +# 2.6.2 (2023/10/11) + +## 🐛 fix +- 主题设置未持久化问题 +- UnoCSS 插件无智能提示 + +## ♻️ refactor +- WebSocket 演示样式和代码优化 +- 用户管理代码重构 + +# 2.6.1 (2023/9/4) + +## 🐛 fix +- 导航顶部模式、混合模式样式在固定 Header 出现的样式问题修复 +- 固定 Header 没有持久化问题修复 +- 字典回显兼容 String 和 Number 类型 + +# 2.6.0 (2023/8/24)💥💥💥 + +## ✨ feat +- 导航顶部模式、混合模式支持(author by [april-tong](https://april-tong.com/)) +- 平台文档(内嵌)(author by [april-tong](https://april-tong.com/)) + +# 2.5.0 (2023/8/8) + +## ✨ feat +- 新增 Mock(author by [ygcaicn](https://github.com/ygcaicn)) +- 图标 DEMO(author by [ygcaicn](https://github.com/ygcaicn)) + +## 🐛 fix +- 字典支持 Number 类型 + +# 2.4.1 (2023/7/20) + +## ✨ feat +- 整合 vite-plugin-compression 插件打包优化(3.66MB → 1.58MB) (author by [april-tong](https://april-tong.com/)) +- 字典组件封装(author by [haoxr](https://juejin.cn/user/4187394044331261/posts)) + +## 🐛 fix +- 分页组件hidden无效 +- 签名无法保存至后端 +- Git 提交 stylelint 校验部分机器报错 + +# 2.4.0 (2023/6/17) + +## ✨ feat +- 新增组件标签输入框(author by [april-tong](https://april-tong.com/)) +- 新增组件签名(author by [april-tong](https://april-tong.com/)) +- 新增组件表格(author by [april-tong](https://april-tong.com/)) +- Echarts 图表添加下载功能 author by [april-tong](https://april-tong.com/)) + +## ♻️ refactor +- 限制包管理器为 pnpm 和 node 版本16+ +- 自定义组件自动导入配置 +- 搜索框样式写法优化 + +## 🐛 fix +- 用户导入的部门回显成数字问题修复 + +## ⬆️ chore +- element-plus 版本升级 2.3.5 → 2.3.6 + +# 2.3.1 (2023/5/21) + +## 🔄 refactor +- 组件示例文件名称优化 + +# 2.2.2 (2023/5/11) + +## ✨ feat +- 组件封装示例添加源码地址 +- 角色、菜单、部门、字段按钮添加权限控制 + + +# 2.3.0 (2023/5/12) + +## ⬆️ chore +- vue 版本升级 3.2.45 → 3.3.1 ([CHANGELOG](https://github.com/vuejs/core/blob/main/CHANGELOG.md)) +- vite 版本升级 4.3.1 → 4.3.5 + +## ♻️ refactor +- 使用 vue 3.3 版本新特性 `defineOptions` 在 `setup` 定义组件名称,移除重复的 `script` 标签 + +# 2.2.2 (2023/5/11) + +## ✨ feat +- 用户新增提交添加 `vueUse` 的 `useDebounceFn` 函数实现按钮防抖节流 + + +# 2.2.1 (2023/4/25) + +## 🐛 fix +- 图标选择器组件使用 `onClickOutside` 未排除下拉弹出框元素导致无法输入搜索。 + diff --git a/frontend/PROJECT_GUIDE.md b/frontend/PROJECT_GUIDE.md deleted file mode 100644 index 254f19d1..00000000 --- a/frontend/PROJECT_GUIDE.md +++ /dev/null @@ -1,3053 +0,0 @@ -# FastAPI Vue3 Admin 前端项目 - -## 📖 项目介绍 - -### 项目概述 - -**FastAPI Vue3 Admin** 是一个基于 Vue3 + Vite + TypeScript + Element-Plus 构建的现代化后台管理系统前端模板。 - -- 🎨 **现代化技术栈**:Vue 3 + TypeScript + Vite + Element Plus -- 🚀 **高性能**:Vite 构建,快速热重载 -- 📱 **响应式设计**:适配桌面和移动端 -- 🌙 **主题切换**:支持明暗主题 -- 🌍 **国际化**:多语言支持 -- 🔧 **开箱即用**:完整的后台管理功能 -- 🎯 **TypeScript**:完整的类型支持 -- 📦 **组件化**:高度模块化的架构 - -### 核心特性 - -#### 🎨 界面功能 -- ✅ 响应式布局(桌面端、平板、手机) -- ✅ 暗色主题/亮色主题切换 -- ✅ 多种布局模式(左侧、顶部、混合) -- ✅ 动态面包屑导航 -- ✅ 标签页导航(TagsView) -- ✅ 快捷开始功能 - -#### 🔐 权限管理 -- ✅ 基于角色的权限控制 -- ✅ 动态路由生成 -- ✅ 菜单权限控制 -- ✅ 按钮级别的权限控制 - -#### 📊 数据管理 -- ✅ 统一的API接口管理 -- ✅ 状态管理(Pinia) -- ✅ 本地存储管理 -- ✅ 请求拦截和响应处理 - -#### 🛠️ 开发体验 -- ✅ TypeScript 支持 -- ✅ 自动导入(Auto Import) -- ✅ 组件自动注册 -- ✅ UnoCSS 原子化CSS -- ✅ ESLint + Prettier 代码规范 -- ✅ Husky Git 提交规范 - -## 🏗️ 技术栈 - -### 核心框架 -- **Vue 3** - 渐进式前端框架 -- **TypeScript** - 类型安全的JavaScript -- **Vite** - 下一代前端构建工具 -- **Element Plus** - Vue3 UI组件库 - -### 状态管理 -- **Pinia** - Vue3 官方状态管理库 - -### 构建工具 -- **Vite** - 快速的构建工具 -- **UnoCSS** - 原子化CSS引擎 -- **ESLint** - 代码检查工具 -- **Prettier** - 代码格式化工具 - -### HTTP 客户端 -- **Axios** - HTTP请求库 - -### 路由管理 -- **Vue Router 4** - Vue3 路由管理 - -### 国际化 -- **Vue I18n** - Vue 国际化插件 - -### 图表库 -- **ECharts** - 百度开源图表库 - -### 富文本编辑器 -- **WangEditor** - 轻量级富文本编辑器 - -## ⚙️ 环境配置 - -### 环境变量说明 - -项目支持多种环境配置: - -#### 开发环境 (.env.development) -```bash -# 应用配置 -VITE_APP_TITLE=FastAPI Vue3 Admin -VITE_APP_ENV=development - -# API 配置 -VITE_APP_API_BASE_URL=http://localhost:8000 -VITE_APP_API_TIMEOUT=10000 - -# 其他配置 -VITE_APP_ROUTER_HISTORY=hash -VITE_APP_PUBLIC_PATH=/ -``` - -#### 生产环境 (.env.production) -```bash -# 应用配置 -VITE_APP_TITLE=FastAPI Vue3 Admin -VITE_APP_ENV=production - -# API 配置 -VITE_APP_API_BASE_URL=https://api.yourdomain.com -VITE_APP_API_TIMEOUT=15000 - -# 其他配置 -VITE_APP_ROUTER_HISTORY=history -VITE_APP_PUBLIC_PATH=/ -``` - -#### 测试环境 (.env.test) -```bash -# 应用配置 -VITE_APP_TITLE=FastAPI Vue3 Admin Test -VITE_APP_ENV=test - -# API 配置 -VITE_APP_API_BASE_URL=https://test-api.yourdomain.com -VITE_APP_API_TIMEOUT=15000 -``` - -### 环境变量使用 - -在代码中使用环境变量: - -```typescript -// src/config/index.ts -export const config = { - title: import.meta.env.VITE_APP_TITLE, - env: import.meta.env.VITE_APP_ENV, - api: { - baseURL: import.meta.env.VITE_APP_API_BASE_URL, - timeout: Number(import.meta.env.VITE_APP_API_TIMEOUT) - } -} -``` - -## 📁 项目结构详解 - -### 完整目录结构 - -``` -fastapi_vue3_admin/frontend/ -├── 📁 .husky/ # Git Hooks 配置 -│ ├── pre-commit # 提交前钩子 -│ ├── commit-msg # 提交信息钩子 -│ └── ... # 其他 Git 钩子 -├── 📁 node_modules/ # 依赖包目录 -├── 📁 public/ # 静态资源目录 -│ ├── background.svg # 背景图片 -│ ├── favicon.png # 网站图标 -│ └── logo.png # 网站Logo -├── 📁 src/ # 源代码目录 -│ ├── 📁 api/ # API 接口层 -│ │ ├── codegen.api.ts # 代码生成接口 -│ │ ├── 📁 demo/ # 示例接口 -│ │ │ └── example.ts # 示例 API -│ │ ├── 📁 monitor/ # 监控相关接口 -│ │ │ ├── cache.ts # 缓存监控 -│ │ │ ├── job.ts # 定时任务 -│ │ │ ├── online.ts # 在线用户 -│ │ │ └── server.ts # 服务器监控 -│ │ └── 📁 system/ # 系统相关接口 -│ │ ├── auth.ts # 认证接口 -│ │ ├── config.ts # 系统配置 -│ │ ├── dept.ts # 部门管理 -│ │ ├── dict.ts # 字典管理 -│ │ ├── log.ts # 日志管理 -│ │ ├── menu.ts # 菜单管理 -│ │ ├── notice.ts # 通知公告 -│ │ ├── position.ts # 职位管理 -│ │ ├── role.ts # 角色管理 -│ │ └── user.ts # 用户管理 -│ ├── 📁 assets/ # 静态资源 -│ │ ├── 📁 icons/ # 图标资源 -│ │ │ ├── api.svg # API 图标 -│ │ │ ├── user.svg # 用户图标 -│ │ │ ├── menu.svg # 菜单图标 -│ │ │ └── ... # 其他图标 (70+ 个图标) -│ │ └── 📁 images/ # 图片资源 -│ │ ├── 401.svg # 401 错误图片 -│ │ ├── 404.svg # 404 错误图片 -│ │ └── 500.svg # 500 错误图片 -│ ├── 📁 components/ # 全局组件库 -│ │ ├── 📁 AppLink/ # 应用链接组件 -│ │ ├── 📁 Breadcrumb/ # 面包屑导航 -│ │ ├── 📁 CommonWrapper/ # 通用包装器 -│ │ ├── 📁 CURD/ # CRUD 通用组件 -│ │ │ ├── PageContent.vue # 页面内容组件 -│ │ │ ├── PageModal.vue # 页面弹窗组件 -│ │ │ ├── PageSearch.vue # 页面搜索组件 -│ │ │ ├── types.ts # 类型定义 -│ │ │ └── usePage.ts # 页面逻辑组合 -│ │ ├── 📁 DarkModeSwitch/ # 暗色模式切换 -│ │ ├── 📁 DatePicker/ # 日期选择器 -│ │ ├── 📁 ECharts/ # 图表组件 -│ │ ├── 📁 Frame/ # 框架组件 -│ │ ├── 📁 Fullscreen/ # 全屏组件 -│ │ ├── 📁 GithubCorner/ # GitHub 角标 -│ │ ├── 📁 Guide/ # 引导组件 -│ │ ├── 📁 Hamburger/ # 汉堡菜单 -│ │ ├── 📁 IconSelect/ # 图标选择器 -│ │ ├── 📁 InputTag/ # 标签输入 -│ │ ├── 📁 IntervalTab/ # 间隔标签页 -│ │ ├── 📁 LangSelect/ # 语言选择器 -│ │ ├── 📁 MenuSearch/ # 菜单搜索 -│ │ ├── 📁 Notification/ # 通知组件 -│ │ ├── 📁 OperationColumn/ # 操作列组件 -│ │ ├── 📁 Pagination/ # 分页组件 -│ │ ├── 📁 SizeSelect/ # 尺寸选择器 -│ │ ├── 📁 TableSelect/ # 表格选择器 -│ │ ├── 📁 TextScroll/ # 文字滚动 -│ │ ├── 📁 Upload/ # 上传组件 -│ │ │ ├── ImportModal.vue # 导入弹窗 -│ │ │ └── SingleImageUpload.vue # 单图上传 -│ │ └── 📁 WangEditor/ # 富文本编辑器 -│ ├── 📁 constants/ # 常量定义 -│ │ ├── index.ts # 常量导出 -│ │ └── storage-keys.ts # 存储键常量 -│ ├── 📁 enums/ # 枚举定义 -│ │ ├── index.ts # 枚举导出 -│ │ ├── 📁 api/ # API 相关枚举 -│ │ │ └── result.enum.ts # API 结果枚举 -│ │ ├── 📁 codegen/ # 代码生成枚举 -│ │ │ ├── form.enum.ts # 表单枚举 -│ │ │ └── query.enum.ts # 查询枚举 -│ │ ├── 📁 settings/ # 设置相关枚举 -│ │ │ ├── device.enum.ts # 设备枚举 -│ │ │ ├── layout.enum.ts # 布局枚举 -│ │ │ ├── locale.enum.ts # 语言枚举 -│ │ │ └── theme.enum.ts # 主题枚举 -│ │ └── 📁 system/ # 系统相关枚举 -│ │ └── menu.enum.ts # 菜单枚举 -│ ├── 📁 lang/ # 国际化配置 -│ │ ├── index.ts # 国际化入口 -│ │ └── 📁 package/ # 语言包 -│ │ ├── zh-cn.ts # 中文语言包 -│ │ └── en.ts # 英文语言包 -│ ├── 📁 layouts/ # 布局系统 -│ │ ├── index.vue # 主布局组件 -│ │ ├── 📁 components/ # 布局子组件 -│ │ │ ├── 📁 AppLogo/ # 应用Logo -│ │ │ ├── 📁 AppMain/ # 主内容区域 -│ │ │ ├── 📁 Menu/ # 菜单组件 (4个文件) -│ │ │ ├── 📁 NavBar/ # 导航栏 (4个文件) -│ │ │ ├── 📁 Settings/ # 设置面板 -│ │ │ └── 📁 TagsView/ # 标签页视图 -│ │ ├── 📁 composables/ # 布局逻辑组合 -│ │ │ ├── useLayout.ts # 布局逻辑 -│ │ │ ├── useLayoutMenu.ts # 菜单逻辑 -│ │ │ └── useLayoutResponsive.ts # 响应式逻辑 -│ │ └── 📁 views/ # 布局视图 -│ │ ├── BaseLayout.vue # 基础布局 -│ │ ├── LeftLayout.vue # 左侧布局 -│ │ ├── MixLayout.vue # 混合布局 -│ │ └── TopLayout.vue # 顶部布局 -│ ├── 📁 plugins/ # 插件配置 -│ │ ├── icons.ts # 图标插件 -│ │ ├── index.ts # 插件入口 -│ │ └── permission.ts # 权限插件 -│ ├── 📁 router/ # 路由配置 -│ │ └── index.ts # 路由入口文件 -│ ├── 📁 store/ # 状态管理 -│ │ ├── index.ts # 状态管理入口 -│ │ └── 📁 modules/ # 状态模块 -│ │ ├── app.store.ts # 应用状态 -│ │ ├── config.store.ts # 配置状态 -│ │ ├── dict.store.ts # 字典状态 -│ │ ├── lock.store.ts # 锁屏状态 -│ │ ├── notice.store.ts # 通知状态 -│ │ ├── permission.store.ts # 权限状态 -│ │ ├── settings.store.ts # 设置状态 -│ │ ├── tags-view.store.ts # 标签页状态 -│ │ └── user.store.ts # 用户状态 -│ ├── 📁 styles/ # 样式系统 -│ │ ├── index.scss # 全局样式入口 -│ │ ├── reset.scss # 样式重置 -│ │ ├── variables.scss # CSS 变量 -│ │ ├── variables.module.scss # 模块化变量 -│ │ ├── element-plus.scss # Element Plus 样式覆盖 -│ │ ├── vxe-table.scss # VxeTable 样式 -│ │ ├── vxe-table.css # VxeTable 样式 -│ │ ├── 📁 dark/ # 暗色主题 -│ │ │ └── css-vars.css # 暗色主题变量 -│ ├── 📁 types/ # TypeScript 类型定义 -│ │ ├── auto-imports.d.ts # 自动导入类型 -│ │ ├── components.d.ts # 组件类型 -│ │ ├── env.d.ts # 环境类型 -│ │ ├── global.d.ts # 全局类型 -│ │ ├── router.d.ts # 路由类型 -│ │ ├── shims-vue.d.ts # Vue 声明文件 -│ │ └── vue3-cron-plus.d.ts # Cron 组件类型 -│ ├── 📁 utils/ # 工具函数库 -│ │ ├── index.ts # 工具导出 -│ │ ├── auth.ts # 认证工具 -│ │ ├── common.ts # 通用工具 -│ │ ├── dateUtil.ts # 日期工具 -│ │ ├── i18n.ts # 国际化工具 -│ │ ├── nprogress.ts # 进度条工具 -│ │ ├── quickStartManager.ts # 快速开始管理器 -│ │ ├── request.ts # HTTP 请求封装 -│ │ ├── storage.ts # 本地存储工具 -│ │ └── theme.ts # 主题工具 -│ ├── 📁 views/ # 页面视图 -│ │ ├── 📁 codegen/ # 代码生成页面 -│ │ │ └── index.html # 代码生成器页面 -│ │ ├── 📁 common/ # 公共页面 -│ │ │ ├── 📁 docs/ # 文档页面 -│ │ │ └── 📁 redoc/ # ReDoc API 文档 -│ │ ├── 📁 current/ # 当前用户页面 -│ │ │ └── profile.vue # 用户资料页 -│ │ ├── 📁 dashboard/ # 仪表板页面 -│ │ │ ├── analysis.vue # 数据分析页 -│ │ │ ├── workplace.vue # 工作台页面 -│ │ │ └── 📁 components/ # 仪表板组件 -│ │ ├── 📁 demo/ # 示例页面 -│ │ │ └── 📁 example/ # 示例页面 -│ │ ├── 📁 error/ # 错误页面 -│ │ │ ├── 401.vue # 401 未授权 -│ │ │ ├── 404.vue # 404 未找到 -│ │ │ └── 500.vue # 500 服务器错误 -│ │ ├── 📁 monitor/ # 监控页面 -│ │ │ ├── 📁 cache/ # 缓存监控 -│ │ │ ├── 📁 job/ # 定时任务 -│ │ │ ├── 📁 online/ # 在线用户 -│ │ │ └── 📁 server/ # 服务器监控 -│ │ ├── 📁 redirect/ # 重定向页面 -│ │ │ └── index.vue # 重定向入口 -│ │ └── 📁 system/ # 系统管理页面 -│ │ ├── 📁 auth/ # 权限管理 (4个文件) -│ │ ├── 📁 config/ # 系统配置 (2个文件) -│ │ ├── 📁 dept/ # 部门管理 (1个文件) -│ │ ├── 📁 dict/ # 字典管理 (2个文件) -│ │ ├── 📁 log/ # 日志管理 (1个文件) -│ │ ├── 📁 menu/ # 菜单管理 (1个文件) -│ │ ├── 📁 notice/ # 通知公告 (1个文件) -│ │ ├── 📁 position/ # 职位管理 (1个文件) -│ │ ├── 📁 role/ # 角色管理 (2个文件) -│ │ └── 📁 user/ # 用户管理 (2个文件) -│ ├── App.vue # Vue 根组件 -│ ├── main.ts # 应用入口文件 -│ └── settings.ts # 应用配置 -├── 📁 .vscode/ # VS Code 配置 (可选) -├── 📁 scripts/ # 构建和工具脚本 -├── 📄 .editorconfig # 编辑器配置 -├── 📄 .env.development # 开发环境变量 -├── 📄 .env.production # 生产环境变量 -├── 📄 .eslintignore # ESLint 忽略配置 -├── 📄 .eslintrc-auto-import.json # ESLint 自动导入配置 -├── 📄 .gitignore # Git 忽略文件 -├── 📄 .prettierignore # Prettier 忽略配置 -├── 📄 .prettierrc.yaml # Prettier 配置 -├── 📄 .stylelintignore # Stylelint 忽略配置 -├── 📄 .stylelintrc.cjs # Stylelint 配置 -├── 📄 CHANGELOG.md # 更新日志 -├── 📄 commitlint.config.cjs # Commitlint 配置 -├── 📄 eslint.config.ts # ESLint 配置 -├── 📄 index.html # HTML 入口文件 -├── 📄 package.json # 项目依赖配置 -├── 📄 pnpm-lock.yaml # pnpm 锁定文件 -├── 📄 PROJECT_GUIDE.md # 项目指南 (本文档) -├── 📄 README.md # 项目说明 -├── 📄 tsconfig.json # TypeScript 配置 -├── 📄 uno.config.ts # UnoCSS 配置 -└── 📄 vite.config.ts # Vite 构建配置 -``` - -### 核心文件说明 - -#### 🔧 构建配置 - -| 文件 | 说明 | -|------|------| -| `vite.config.ts` | Vite 构建工具主配置,包含插件、代理、构建优化等 | -| `tsconfig.json` | TypeScript 编译配置,定义编译选项和路径映射 | -| `uno.config.ts` | UnoCSS 原子化CSS配置,定义样式规则和主题 | -| `eslint.config.ts` | ESLint 代码检查配置,确保代码质量和规范 | -| `package.json` | 项目依赖管理和脚本配置 | - -#### ⚡ 应用入口 - -| 文件 | 说明 | -|------|------| -| `index.html` | HTML 入口文件,包含基础的页面结构 | -| `src/main.ts` | 应用入口文件,初始化 Vue 应用和各项配置 | -| `src/App.vue` | Vue 根组件,应用的主要布局结构 | -| `src/settings.ts` | 应用基础配置,包含主题、语言等设置 | - -#### 🗂️ 核心目录详解 - -##### 1. API 接口层 (`src/api/`) - -负责前后端数据交互,采用分层架构: - -- **system/**: 系统管理相关接口(用户、角色、菜单、权限等) -- **monitor/**: 系统监控相关接口(缓存、任务、服务器状态等) -- **codegen/**: 代码生成相关接口 -- **demo/**: 示例接口(用于测试和演示) - -每个接口模块都包含完整的 CRUD 操作和类型定义。 - -##### 2. 组件库 (`src/components/`) - -高度复用的组件集合: - -- **CURD/**: 通用CRUD组件,支持列表、搜索、编辑、删除等操作 -- **Upload/**: 文件上传组件,支持单图、多图、批量导入 -- **布局相关**: 菜单、导航栏、面包屑等布局组件 -- **业务组件**: 针对具体业务场景的专用组件 - -##### 3. 状态管理 (`src/store/`) - -基于 Pinia 的状态管理: - -- **modules/**: 按功能划分的状态模块 -- **持久化**: 支持状态持久化存储 -- **类型安全**: 完整的 TypeScript 类型支持 - -##### 4. 样式系统 (`src/styles/`) - -统一的样式管理: - -- **主题系统**: 支持亮色/暗色主题切换 -- **变量管理**: CSS 变量集中管理 -- **组件样式**: 各组件的专用样式 -- **UnoCSS**: 原子化CSS框架,提升开发效率 - -##### 5. 工具函数 (`src/utils/`) - -通用工具函数库: - -- **request.ts**: HTTP 请求封装,包含拦截器、错误处理 -- **auth.ts**: 认证相关工具 -- **storage.ts**: 本地存储封装 -- **dateUtil.ts**: 日期时间处理工具 -- **theme.ts**: 主题切换工具 - -##### 6. 页面视图 (`src/views/`) - -具体的页面组件: - -- **system/**: 系统管理页面(用户、角色、菜单等) -- **monitor/**: 系统监控页面 -- **dashboard/**: 数据仪表板 -- **error/**: 错误页面 -- **current/**: 当前用户相关页面 - -### 架构设计原则 - -1. **模块化**: 每个功能模块独立,便于维护和扩展 -2. **类型安全**: 全面的 TypeScript 支持,减少运行时错误 -3. **组件复用**: 抽象通用组件,提高开发效率 -4. **配置化**: 通过配置而非硬编码实现功能 -5. **规范化**: 统一的代码规范和开发流程 - -### 文件组织规范 - -1. **命名规范**: - - 文件夹:kebab-case (短横线分隔) - - 组件文件:PascalCase (大驼峰) - - 工具文件:camelCase (小驼峰) - -2. **目录结构**: - - 相关文件放在同一目录下 - - 按功能划分子目录 - - 保持目录层级清晰 - -3. **导入导出**: - - 使用相对路径导入 - - 统一使用 index.ts 导出 - - 按类型分组导入 - -### 关键配置文件详解 - -#### 📄 package.json - -项目依赖和脚本配置: - -```json -{ - "name": "fastapi-vue3-admin", - "version": "2.0.0", - "scripts": { - "dev": "vite", // 开发服务器 - "build": "vite build", // 生产构建 - "build:pro": "vite build --mode pro", // 生产环境构建 - "build:dev": "vite build --mode dev", // 开发环境构建 - "build:test": "vite build --mode test", // 测试环境构建 - "preview": "vite preview", // 预览构建结果 - "lint": "eslint ...", // 代码检查 - "type-check": "vue-tsc --noEmit" // 类型检查 - }, - "dependencies": { - "vue": "^3.5.17", // Vue 3 核心 - "element-plus": "^2.10.4", // UI 组件库 - "pinia": "^3.0.3", // 状态管理 - "vue-router": "^4.5.1", // 路由管理 - "axios": "^1.10.0", // HTTP 客户端 - "vue-i18n": "^11.1.10" // 国际化 - }, - "devDependencies": { - "@vitejs/plugin-vue": "^5.2.4", // Vue 插件 - "typescript": "^5.8.3", // TypeScript - "unocss": "66.2.3", // 原子化CSS - "vite": "^6.3.5" // 构建工具 - } -} -``` - -#### ⚙️ vite.config.ts - -Vite 构建配置: - -```typescript -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import { resolve } from 'path' - -export default defineConfig({ - plugins: [vue()], - resolve: { - alias: { - '@': resolve(__dirname, 'src') // 路径别名 - } - }, - server: { - port: 5173, - proxy: { - '/api': { - target: 'http://localhost:8000', // 后端API地址 - changeOrigin: true - } - } - }, - build: { - outDir: 'dist', - sourcemap: false, - rollupOptions: { - output: { - chunkFileNames: 'js/[name]-[hash].js', - entryFileNames: 'js/[name]-[hash].js', - assetFileNames: '[ext]/[name]-[hash].[ext]' - } - } - } -}) -``` - -#### 🔷 uno.config.ts - -UnoCSS 原子化CSS配置: - -```typescript -import { defineConfig } from 'unocss' -import { presetUno, presetAttributify } from 'unocss' - -export default defineConfig({ - presets: [ - presetUno(), // UnoCSS 预设 - presetAttributify() // 属性化模式 - ], - theme: { - colors: { - primary: 'var(--el-color-primary)', - success: 'var(--el-color-success)', - warning: 'var(--el-color-warning)', - danger: 'var(--el-color-danger)' - } - }, - shortcuts: { - 'flex-center': 'flex items-center justify-center', - 'flex-between': 'flex items-center justify-between' - } -}) -``` - -#### 📝 tsconfig.json - -TypeScript 配置: - -```json -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "preserve", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "baseUrl": ".", - "paths": { - "@/*": ["src/*"] // 路径映射 - } - }, - "include": [ - "src/**/*.ts", - "src/**/*.d.ts", - "src/**/*.tsx", - "src/**/*.vue" - ], - "exclude": ["node_modules"] -} -``` - -### 核心模块功能详解 - -#### 🎯 应用入口 (`src/main.ts`) - -应用初始化和配置: - -```typescript -import { createApp } from 'vue' -import { createPinia } from 'pinia' -import ElementPlus from 'element-plus' -import router from './router' -import i18n from './lang' -import App from './App.vue' - -// 创建应用实例 -const app = createApp(App) - -// 安装插件 -app.use(createPinia()) -app.use(router) -app.use(ElementPlus) -app.use(i18n) - -// 挂载应用 -app.mount('#app') -``` - -#### 🏗️ 应用配置 (`src/settings.ts`) - -应用基础配置: - -```typescript -export const settings = { - // 应用信息 - title: 'FastAPI Vue3 Admin', - version: '2.0.0', - - // 显示配置 - showSettings: true, - showTagsView: true, - showSidebarLogo: true, - - // 功能开关 - enableErrorLog: true, - enableWatermark: false, - - // 主题配置 - theme: 'light', - primaryColor: '#409EFF', - - // 布局配置 - layout: 'left', - fixedHeader: true, - - // 其他配置 - defaultLanguage: 'zh-cn', - whiteList: ['/login', '/404', '/401'] -} -``` - -#### 🧩 组件系统架构 - -##### CURD 通用组件 - -```typescript -// src/components/CURD/usePage.ts -export const usePage = (config: PageConfig) => { - const loading = ref(false) - const data = ref([]) - const pagination = ref({ - current: 1, - size: 20, - total: 0 - }) - - // 分页查询 - const fetchData = async () => { - loading.value = true - try { - const result = await config.api.list({ - page: pagination.value.current, - size: pagination.value.size, - ...config.queryParams - }) - data.value = result.records - pagination.value.total = result.total - } finally { - loading.value = false - } - } - - // 新增 - const handleCreate = () => { - config.onCreate?.() - } - - // 编辑 - const handleUpdate = (record: any) => { - config.onUpdate?.(record) - } - - // 删除 - const handleDelete = async (id: string) => { - await config.api.delete(id) - await fetchData() - } - - return { - loading, - data, - pagination, - fetchData, - handleCreate, - handleUpdate, - handleDelete - } -} -``` - -#### 🔄 状态管理架构 - -##### 用户状态管理 - -```typescript -// src/store/modules/user.store.ts -export const useUserStore = defineStore('user', () => { - // 状态 - const userInfo = ref(null) - const token = ref('') - const permissions = ref([]) - const roles = ref([]) - - // 计算属性 - const isLogin = computed(() => !!token.value) - const userId = computed(() => userInfo.value?.id) - - // 动作 - const login = async (loginForm: LoginForm) => { - const { data } = await loginApi(loginForm) - token.value = data.token - await getUserInfo() - } - - const getUserInfo = async () => { - const { data } = await getUserInfoApi() - userInfo.value = data.user - permissions.value = data.permissions - roles.value = data.roles - } - - const logout = () => { - userInfo.value = null - token.value = '' - permissions.value = [] - roles.value = [] - } - - return { - userInfo, - token, - permissions, - roles, - isLogin, - userId, - login, - getUserInfo, - logout - } -}, { - persist: true // 持久化存储 -}) -``` - -#### 🎨 样式系统架构 - -##### 主题系统 - -```scss -// src/styles/variables.scss -:root { - // 亮色主题 - --primary-color: #409EFF; - --success-color: #67C23A; - --warning-color: #E6A23C; - --danger-color: #F56C6C; - - // 布局变量 - --header-height: 60px; - --sidebar-width: 260px; - --sidebar-collapse-width: 64px; - - // 间距变量 - --spacing-xs: 4px; - --spacing-sm: 8px; - --spacing-md: 16px; - --spacing-lg: 24px; - --spacing-xl: 32px; -} - -// 暗色主题 -.dark { - --primary-color: #66D9EF; - --success-color: #A6E22E; - --warning-color: #FD971F; - --danger-color: #F92672; - - --bg-color: #1E1E1E; - --text-color: #D4D4D4; - --border-color: #3E3E3E; -} -``` - -##### UnoCSS 工具类 - -```vue - -``` - -#### 🔧 工具函数库 - -##### HTTP 请求封装 - -```typescript -// src/utils/request.ts -import axios, { AxiosInstance, AxiosResponse } from 'axios' - -class Request { - private instance: AxiosInstance - - constructor() { - this.instance = axios.create({ - baseURL: import.meta.env.VITE_APP_API_BASE_URL, - timeout: 10000, - headers: { - 'Content-Type': 'application/json' - } - }) - - this.setupInterceptors() - } - - private setupInterceptors() { - // 请求拦截器 - this.instance.interceptors.request.use( - (config) => { - const token = localStorage.getItem('token') - if (token) { - config.headers.Authorization = `Bearer ${token}` - } - return config - }, - (error) => Promise.reject(error) - ) - - // 响应拦截器 - this.instance.interceptors.response.use( - (response: AxiosResponse) => { - const { data } = response - if (data.code === 200) { - return data - } - return Promise.reject(new Error(data.message)) - }, - (error) => { - if (error.response?.status === 401) { - // 处理未授权 - router.push('/login') - } - return Promise.reject(error) - } - ) - } - - public get(url: string, config?: any): Promise { - return this.instance.get(url, config) - } - - public post(url: string, data?: any, config?: any): Promise { - return this.instance.post(url, data, config) - } - - public put(url: string, data?: any, config?: any): Promise { - return this.instance.put(url, data, config) - } - - public delete(url: string, config?: any): Promise { - return this.instance.delete(url, config) - } -} - -export const request = new Request() -export default request -``` - -##### 日期时间工具 - -```typescript -// src/utils/dateUtil.ts -import dayjs from 'dayjs' - -export const formatDate = (date: string | Date, format = 'YYYY-MM-DD HH:mm:ss') => { - return dayjs(date).format(format) -} - -export const formatDateTime = (date: string | Date) => { - return formatDate(date, 'YYYY-MM-DD HH:mm:ss') -} - -export const formatDateOnly = (date: string | Date) => { - return formatDate(date, 'YYYY-MM-DD') -} - -export const formatTimeOnly = (date: string | Date) => { - return formatDate(date, 'HH:mm:ss') -} - -export const getRelativeTime = (date: string | Date) => { - return dayjs(date).fromNow() -} - -export const isToday = (date: string | Date) => { - return dayjs(date).isSame(dayjs(), 'day') -} - -export const isYesterday = (date: string | Date) => { - return dayjs(date).isSame(dayjs().subtract(1, 'day'), 'day') -} - -export const getDateRange = (days: number) => { - const end = dayjs() - const start = dayjs().subtract(days, 'day') - return [start.format('YYYY-MM-DD'), end.format('YYYY-MM-DD')] -} -``` - -### 项目文件统计 - -| 类别 | 文件数量 | 主要文件类型 | -|------|----------|--------------| -| **Vue 组件** | 50+ | .vue (页面组件、业务组件) | -| **TypeScript** | 80+ | .ts (工具函数、类型定义、配置) | -| **样式文件** | 15+ | .scss, .css (样式表、主题) | -| **配置文件** | 20+ | .json, .ts, .js (构建、工具配置) | -| **静态资源** | 70+ | .svg, .png (图标、图片) | -| **文档文件** | 3 | .md (说明文档) | - -### 技术栈依赖关系 - -``` -Vue 3 (核心框架) -├── Vue Router 4 (路由管理) -├── Pinia (状态管理) -├── Element Plus (UI组件) -├── Vue I18n (国际化) -├── Axios (HTTP客户端) -└── UnoCSS (原子化CSS) - -Vite (构建工具) -├── TypeScript (类型系统) -├── ESLint (代码检查) -├── Prettier (代码格式化) -└── PostCSS (CSS处理) -``` - -这个项目结构体现了现代前端项目的标准架构,具有良好的可维护性、可扩展性和开发体验。 - -## 🔗 API 接口管理 - -### 接口层架构 - -项目采用分层的API接口管理架构: - -``` -src/api/ -├── 📁 system/ # 系统相关接口 -│ ├── auth.ts # 认证接口 -│ ├── user.ts # 用户管理接口 -│ ├── menu.ts # 菜单管理接口 -│ └── config.ts # 系统配置接口 -├── 📁 monitor/ # 监控相关接口 -│ ├── cache.ts # 缓存监控 -│ ├── job.ts # 定时任务 -│ ├── online.ts # 在线用户 -│ └── server.ts # 服务器监控 -└── 📁 codegen/ # 代码生成接口 -``` - -### 请求封装 - -项目使用统一的HTTP请求封装: - -```typescript -// src/utils/request.ts -import axios from 'axios' -import type { AxiosResponse } from 'axios' - -const request = axios.create({ - baseURL: import.meta.env.VITE_APP_API_BASE_URL, - timeout: 10000, - headers: { - 'Content-Type': 'application/json' - } -}) - -// 请求拦截器 -request.interceptors.request.use( - (config) => { - // 添加认证token - const token = localStorage.getItem('token') - if (token) { - config.headers.Authorization = `Bearer ${token}` - } - return config - }, - (error) => Promise.reject(error) -) - -// 响应拦截器 -request.interceptors.response.use( - (response: AxiosResponse) => { - const { data } = response - if (data.code === 200) { - return data - } else { - ElMessage.error(data.message || '请求失败') - return Promise.reject(new Error(data.message || '请求失败')) - } - }, - (error) => { - if (error.response?.status === 401) { - // 处理未授权 - router.push('/login') - } else { - ElMessage.error(error.message || '网络错误') - } - return Promise.reject(error) - } -) - -export default request -``` - -### 接口定义示例 - -```typescript -// src/api/system/user.ts -import request from '@/utils/request' - -export interface UserInfo { - id: number - username: string - email: string - avatar?: string - roles: string[] - status: 'active' | 'inactive' -} - -export interface UserQuery { - page?: number - size?: number - username?: string - status?: string -} - -// 获取用户列表 -export const getUserList = (params?: UserQuery) => { - return request.get('/system/user/list', { params }) -} - -// 获取用户信息 -export const getUserInfo = (id: number) => { - return request.get(`/system/user/${id}`) -} - -// 创建用户 -export const createUser = (data: Omit) => { - return request.post('/system/user', data) -} - -// 更新用户 -export const updateUser = (id: number, data: Partial) => { - return request.put(`/system/user/${id}`, data) -} - -// 删除用户 -export const deleteUser = (id: number) => { - return request.delete(`/system/user/${id}`) -} - -// 批量删除用户 -export const batchDeleteUsers = (ids: number[]) => { - return request.delete('/system/user/batch', { data: { ids } }) -} -``` - -### 接口错误处理 - -```typescript -// src/hooks/useApi.ts -import { ref } from 'vue' -import { ElMessage } from 'element-plus' - -export const useApi = (apiFn: (...args: any[]) => Promise) => { - const loading = ref(false) - const error = ref(null) - const data = ref(null) - - const execute = async (...args: any[]) => { - loading.value = true - error.value = null - - try { - const result = await apiFn(...args) - data.value = result - return result - } catch (err: any) { - error.value = err.message || '请求失败' - ElMessage.error(error.value) - throw err - } finally { - loading.value = false - } - } - - return { - loading: readonly(loading), - error: readonly(error), - data: readonly(data), - execute - } -} -``` - -### 接口使用示例 - -```vue - -``` - -## 🚀 快速开始 - -### 环境要求 - -- **Node.js**: >= 16.0.0 -- **pnpm**: >= 7.0.0 (推荐) -- **Git**: >= 2.0.0 - -### 安装依赖 - -```bash -# 进入项目目录 -cd frontend - -# 安装依赖(推荐使用 pnpm) -pnpm install -``` - -### 开发环境 - -```bash -# 启动开发服务器 -pnpm run dev - -# 构建生产版本 -pnpm run build - -# 预览构建结果 -pnpm run preview -``` - -### 其他命令 - -```bash -# 代码检查 -pnpm run lint - -# 类型检查 -pnpm run type-check - -# 格式化代码 -pnpm run lint:format - -# 清理缓存 -pnpm run clean:cache -``` - -## 🔧 二次开发指南 - -## 🎯 动态菜单系统介绍 - -### 系统特性 - -**FastAPI Vue3 Admin** 采用 **动态路由 + 动态菜单** 的设计模式,具有以下优势: - -#### ✅ 优势特点 -- **运行时动态配置**:无需重新编译前端代码 -- **权限控制灵活**:基于角色的菜单权限管理 -- **组件动态加载**:按需加载页面组件 -- **菜单结构自由**:支持多级菜单、目录、按钮、外链 -- **热更新生效**:添加菜单后立即生效 - -#### 🔄 工作原理 - -```mermaid -graph TD - A[用户登录] --> B[获取用户权限] - B --> C[后端返回菜单数据] - C --> D[前端解析菜单] - D --> E[动态生成路由] - E --> F[注册到Vue Router] - F --> G[渲染菜单和页面] -``` - -### 动态路由流程详解 - -1. **后端数据结构**: - ```typescript - interface MenuTable { - id: number - name: string // 菜单名称(显示在菜单栏) - title: string // 菜单标题(显示在标签页) - route_path: string // 路由路径 - route_name: string // 路由名称 - component_path: string // 组件路径 - icon: string // 菜单图标 - type: 'CATALOG' | 'MENU' | 'BUTTON' | 'EXTLINK' - parent_id?: number // 父级菜单ID - order: number // 排序 - keep_alive: boolean // 是否缓存 - hidden: boolean // 是否隐藏 - always_show: boolean // 只有一个子路由时是否始终显示 - params: Array<{key: string, value: string}> // 路由参数 - status: boolean // 状态 - } - ``` - -2. **前端转换逻辑**: - ```typescript - // src/store/modules/permission.store.ts - const generator = (routers: MenuTable[]): RouteVO[] => { - return routers.map((item) => { - const currentRouter: RouteVO = { - path: item.route_path, - name: item.route_name, - component: item.component_path, // 动态组件路径 - meta: { - title: item.title, - icon: item.icon, - keepAlive: item.keep_alive, - hidden: item.hidden, - } - }; - // 递归处理子菜单 - if (item.children) { - currentRouter.children = generator(item.children); - } - return currentRouter; - }); - }; - ``` - -3. **组件动态解析**: - ```typescript - // 动态导入组件 - const modules = import.meta.glob("../../views/**/**.vue"); - normalizedRoute.component = - !normalizedRoute.component - ? Layout // 目录使用Layout组件 - : modules[`../../views/${normalizedRoute.component}.vue`] || // 动态导入页面组件 - modules["../../views/error/404.vue"]; // 404页面兜底 - ``` - -## 🚀 运行时动态添加页面 - -### 方法一:通过菜单管理界面添加 - -#### 步骤1:访问菜单管理 - -1. 登录系统后,进入 **系统管理 → 菜单管理** -2. 点击 **新增** 按钮 - -#### 步骤2:创建目录菜单 - -如果需要先创建父级目录: - -```json -{ - "菜单名称": "示例模块", - "菜单标题": "示例模块", - "菜单类型": "目录", - "路由路径": "/example", - "路由名称": "Example", - "图标": "Document", - "排序": 10, - "状态": "启用" -} -``` - -#### 步骤3:创建页面菜单 - -```json -{ - "父级菜单": "示例模块", - "菜单名称": "用户列表", - "菜单标题": "用户管理", - "菜单类型": "菜单", - "路由路径": "/example/user-list", - "路由名称": "ExampleUserList", - "组件路径": "example/user-list/index", - "图标": "User", - "是否缓存": true, - "排序": 1, - "状态": "启用" -} -``` - -#### 步骤4:创建页面组件 - -在 `src/views/example/user-list/index.vue` 创建组件: - -```vue - - - - - -``` - -#### 步骤5:刷新页面 - -添加菜单后: -1. 刷新浏览器页面 -2. 系统会重新加载用户权限和菜单数据 -3. 新菜单立即出现在侧边栏 -4. 点击新菜单可访问新页面 - -### 方法二:批量导入菜单 - -可以通过后端API批量创建菜单,然后前端自动识别: - -```typescript -// 后端批量创建菜单的示例数据 -const batchMenus = [ - { - name: "数据统计", - title: "数据统计", - type: "CATALOG", - route_path: "/statistics", - route_name: "Statistics", - icon: "TrendCharts", - order: 5, - children: [ - { - name: "用户统计", - title: "用户统计", - type: "MENU", - route_path: "/statistics/user", - route_name: "StatisticsUser", - component_path: "statistics/user/index", - icon: "User", - keep_alive: true, - order: 1 - }, - { - name: "订单统计", - title: "订单统计", - type: "MENU", - route_path: "/statistics/order", - route_name: "StatisticsOrder", - component_path: "statistics/order/index", - icon: "Document", - keep_alive: true, - order: 2 - } - ] - } -] -``` - -## 📝 菜单配置字段详解 - -### 核心字段说明 - -| 字段名 | 类型 | 必填 | 说明 | -|--------|------|------|------| -| `name` | string | ✅ | 菜单显示名称 | -| `title` | string | ✅ | 页面标题(标签页显示) | -| `type` | enum | ✅ | 菜单类型:CATALOG/MENU/BUTTON/EXTLINK | -| `route_path` | string | ✅ | 路由路径,如 `/system/user` | -| `route_name` | string | ✅ | 路由名称,用于keep-alive缓存 | -| `component_path` | string | 菜单必填 | 组件路径,相对于 `src/views/` | -| `parent_id` | number | ❌ | 父级菜单ID | -| `icon` | string | ❌ | 菜单图标,支持 Element Plus 图标 | -| `order` | number | ❌ | 排序号,越小越靠前 | -| `keep_alive` | boolean | ❌ | 是否开启页面缓存 | -| `hidden` | boolean | ❌ | 是否在菜单中隐藏 | -| `always_show` | boolean | ❌ | 只有一个子路由时是否始终显示 | -| `params` | array | ❌ | 路由参数数组 | -| `status` | boolean | ❌ | 菜单状态:true-启用,false-禁用 | - -### 菜单类型详解 - -#### 1. 目录 (CATALOG) -```json -{ - "type": "CATALOG", - "route_path": "/system", - "route_name": "System", - "component_path": null, - "children": [...] // 子菜单数组 -} -``` - -#### 2. 菜单 (MENU) -```json -{ - "type": "MENU", - "route_path": "/system/user", - "route_name": "SystemUser", - "component_path": "system/user/index", - "keep_alive": true -} -``` - -#### 3. 按钮 (BUTTON) -```json -{ - "type": "BUTTON", - "name": "用户新增", - "route_path": null, - "route_name": null, - "component_path": null -} -``` - -#### 4. 外链 (EXTLINK) -```json -{ - "type": "EXTLINK", - "route_path": "https://example.com", - "route_name": "ExternalLink" -} -``` - -### 图标配置 - -支持的图标格式: -- Element Plus 图标:`el-icon-User`、`el-icon-Setting` -- 自定义SVG图标:`icon-user`、`icon-setting` -- 空值:不显示图标 - -## 🔄 动态更新的机制 - -### 路由热更新 - -当菜单数据发生变化时,系统会: - -1. **检测变化**:监听用户权限和菜单数据变化 -2. **重新生成路由**:调用 `generateRoutes()` 方法 -3. **更新路由表**:动态注册新的路由到 Vue Router -4. **刷新菜单**:更新侧边栏菜单显示 -5. **清理缓存**:移除旧的路由缓存 - -```typescript -// src/store/modules/permission.store.ts -async function generateRoutes() { - const userStore = useUserStore(); - if (!userStore.hasGetRoute) { - await userStore.getUserInfo(); - } - - const routersTree = listToTree(userStore.routeList); - const routerMap = generator(routersTree); - const dynamicRoutes = parseDynamicRoutes(routerMap); - - routes.value = [...constantRoutes, ...dynamicRoutes]; - routesLoaded.value = true; - - return dynamicRoutes; -} -``` - -### 组件动态加载 - -系统使用 Vite 的 `import.meta.glob` 实现组件动态加载: - -```typescript -// 预加载所有页面组件 -const modules = import.meta.glob("../../views/**/**.vue"); - -// 动态解析组件 -normalizedRoute.component = - !normalizedRoute.component - ? Layout // 目录使用Layout组件 - : modules[`../../views/${normalizedRoute.component}.vue`] || - modules["../../views/error/404.vue"]; // 404兜底 -``` - -## 🎯 最佳实践 - -### 1. 菜单规划 - -#### 合理的菜单层级 -``` -📁 系统管理 (CATALOG) -├── 👤 用户管理 (MENU) -├── 🔐 角色管理 (MENU) -├── 📋 菜单管理 (MENU) -└── 📝 操作日志 (MENU) -``` - -#### 菜单命名规范 -- **目录**:使用名词,如 "系统管理"、"内容管理" -- **菜单**:使用功能描述,如 "用户列表"、"角色配置" -- **按钮**:使用操作描述,如 "用户新增"、"数据导出" - -### 2. 路由设计 - -#### 路由路径规范 -```typescript -// ✅ 推荐格式 -/system/user // 用户管理 -/system/role // 角色管理 -/content/article // 文章管理 -/statistics/dashboard // 数据统计 - -// ❌ 避免格式 -/user-management // 太长 -/usr-mgmt // 缩写不易懂 -``` - -#### 组件路径规范 -```typescript -// ✅ 推荐格式 -"system/user/index" // 用户管理主页面 -"system/user/detail" // 用户详情页面 -"content/article/editor" // 文章编辑器 - -// ❌ 避免格式 -"UserManagement" // PascalCase -"system/UserList.vue" // 包含扩展名 -``` - -### 3. 权限控制 - -#### 菜单权限 -```typescript -// 后端控制菜单显示 -{ - "name": "用户管理", - "roles": ["admin", "user_manager"], - "status": true -} -``` - -#### 页面权限 -```vue - -``` - -### 4. 缓存策略 - -#### 页面缓存配置 -```vue - -``` - -#### 缓存控制 -```json -{ - "keep_alive": true, // 启用缓存 - "route_name": "UserList" // 必须与组件name一致 -} -``` - -## 🔧 故障排除 - -### 常见问题 - -#### 1. 菜单不显示 -**问题**:添加菜单后在侧边栏不显示 -**解决**: -- 检查菜单状态是否为启用 -- 检查父级菜单是否存在且启用 -- 刷新页面重新加载菜单数据 - -#### 2. 页面404 -**问题**:点击菜单显示404页面 -**解决**: -- 检查组件路径是否正确 -- 确认组件文件是否存在 -- 检查路由路径格式 - -#### 3. 权限不足 -**问题**:菜单显示但无法访问 -**解决**: -- 检查用户角色权限 -- 确认菜单权限配置 -- 验证后端权限接口 - -#### 4. 图标不显示 -**问题**:菜单图标无法正常显示 -**解决**: -- 检查图标名称格式 -- 确认图标是否存在 -- 使用正确的图标命名规范 - -### 调试技巧 - -#### 1. 查看路由信息 -```typescript -// 在浏览器控制台查看当前路由 -console.log(router.currentRoute.value) - -// 查看所有路由 -console.log(router.getRoutes()) -``` - -#### 2. 查看权限数据 -```typescript -// 查看用户权限 -const userStore = useUserStore() -console.log(userStore.permissions) - -// 查看菜单数据 -console.log(userStore.routeList) -``` - -#### 3. 查看组件加载 -```typescript -// 查看动态导入的组件 -console.log(modules) -``` - -## 🚀 高级功能 - -### 自定义组件加载器 - -可以扩展动态组件加载逻辑: - -```typescript -// src/utils/componentLoader.ts -export const loadComponent = (componentPath: string) => { - // 自定义组件加载逻辑 - if (componentPath.startsWith('http')) { - // 远程组件加载 - return () => import(/* @vite-ignore */ componentPath) - } - - // 本地组件加载 - const modules = import.meta.glob("../../views/**/**.vue"); - return modules[`../../views/${componentPath}.vue`] || - modules["../../views/error/404.vue"]; -}; -``` - -### 菜单数据缓存 - -```typescript -// src/store/modules/menu.store.ts -export const useMenuStore = defineStore('menu', () => { - const menuCache = ref>(new Map()) - - const getMenuByRole = (role: string) => { - if (menuCache.value.has(role)) { - return menuCache.value.get(role) - } - // 从后端获取并缓存 - // ... - } - - return { - menuCache, - getMenuByRole - } -}) -``` - -## 🔧 传统开发方式(代码层面) - -### 1. 添加新页面 - -#### 步骤1:创建页面组件 - -在 `src/views/` 下创建新的页面组件: - -```vue - - - - - - -``` - -#### 步骤2:添加路由配置 - -在 `src/router/index.ts` 中添加路由: - -```typescript -import NewPage from '@/views/example/new-page.vue' - -const routes: RouteRecordRaw[] = [ - // ... 其他路由 - { - path: '/example/new-page', - name: 'NewPage', - component: NewPage, - meta: { - title: '新页面', - icon: 'Document', - keepAlive: true, - roles: ['admin'] - } - } -] -``` - -#### 步骤3:添加菜单配置 - -如果需要菜单显示,需要在后端菜单配置中添加对应的菜单项。 - -#### 步骤4:添加国际化 - -在语言包中添加翻译: - -```typescript -// src/lang/package/zh-cn.ts -export default { - example: { - newPage: '新页面' - } -} - -// src/lang/package/en.ts -export default { - example: { - newPage: 'New Page' - } -} -``` - -### 2. 添加新组件 - -#### 创建全局组件 - -```vue - - - - -``` - -#### 导出组件 - -在 `src/components/index.ts` 中导出: - -```typescript -export { default as CustomButton } from './CustomButton/index.vue' -``` - -### 3. 添加API接口 - -#### 创建API模块 - -```typescript -// src/api/example.ts -import request from '@/utils/request' - -export interface ExampleData { - id: number - name: string - status: string -} - -export const getExampleList = (params?: any) => { - return request.get('/example/list', { params }) -} - -export const createExample = (data: Omit) => { - return request.post('/example', data) -} - -export const updateExample = (id: number, data: Partial) => { - return request.put(`/example/${id}`, data) -} - -export const deleteExample = (id: number) => { - return request.delete(`/example/${id}`) -} -``` - -### 4. 添加状态管理 - -#### 创建Store模块 - -```typescript -// src/store/modules/example.store.ts -import { defineStore } from 'pinia' -import { ref, computed } from 'vue' -import type { ExampleData } from '@/api/example' - -export const useExampleStore = defineStore('example', () => { - // 状态 - const exampleList = ref([]) - const loading = ref(false) - - // 计算属性 - const activeExamples = computed(() => - exampleList.value.filter(item => item.status === 'active') - ) - - // 动作 - const fetchExampleList = async () => { - loading.value = true - try { - const { data } = await getExampleList() - exampleList.value = data - } catch (error) { - console.error('获取示例列表失败:', error) - } finally { - loading.value = false - } - } - - const addExample = async (data: Omit) => { - await createExample(data) - await fetchExampleList() - } - - const updateExample = async (id: number, data: Partial) => { - await updateExample(id, data) - await fetchExampleList() - } - - const removeExample = async (id: number) => { - await deleteExample(id) - await fetchExampleList() - } - - return { - // 状态 - exampleList, - loading, - - // 计算属性 - activeExamples, - - // 动作 - fetchExampleList, - addExample, - updateExample, - removeExample - } -}) -``` - -### 5. 添加工具函数 - -```typescript -// src/utils/example.ts -/** - * 格式化示例数据 - */ -export const formatExampleData = (data: any): ExampleData => { - return { - id: data.id, - name: data.name || '', - status: data.status || 'inactive' - } -} - -/** - * 验证示例数据 - */ -export const validateExampleData = (data: Partial): string[] => { - const errors: string[] = [] - - if (!data.name?.trim()) { - errors.push('名称不能为空') - } - - if (!data.status) { - errors.push('状态不能为空') - } - - return errors -} -``` - -### 6. 添加类型定义 - -```typescript -// src/types/example.d.ts -export interface ExampleData { - id: number - name: string - status: 'active' | 'inactive' - createdAt: string - updatedAt: string -} - -export interface ExampleForm { - name: string - status: 'active' | 'inactive' -} - -export interface ExampleQuery { - page?: number - size?: number - name?: string - status?: 'active' | 'inactive' -} -``` - -### 7. 添加常量和枚举 - -```typescript -// src/constants/example.ts -export const EXAMPLE_STATUS = { - ACTIVE: 'active', - INACTIVE: 'inactive' -} as const - -export const EXAMPLE_STATUS_TEXT = { - [EXAMPLE_STATUS.ACTIVE]: '启用', - [EXAMPLE_STATUS.INACTIVE]: '禁用' -} as const - -export const EXAMPLE_PAGE_SIZE = 20 -``` - -### 8. 使用 UnoCSS - -项目使用 UnoCSS 进行原子化CSS开发: - -```vue - -``` - -常用 UnoCSS 类名: -- **布局**: `flex`, `grid`, `block`, `inline-block` -- **定位**: `relative`, `absolute`, `fixed` -- **间距**: `p-4`, `m-2`, `mt-4`, `mb-4`, `ml-4`, `mr-4` -- **颜色**: `text-red-500`, `bg-blue-500`, `border-gray-300` -- **尺寸**: `w-4`, `h-8`, `min-w-20`, `max-h-100` -- **边框**: `border`, `border-t`, `border-solid`, `rounded`, `rounded-lg` -- **阴影**: `shadow`, `shadow-lg`, `shadow-xl` -- **文字**: `text-sm`, `text-lg`, `font-bold`, `text-center` - -## 🎨 主题和样式 - -### 主题配置 - -项目支持明暗主题切换,主题变量定义在: - -```scss -// src/styles/variables.scss -:root { - // 亮色主题 - --el-color-primary: #409eff; - --el-color-success: #67c23a; - --el-color-warning: #e6a23c; - --el-color-danger: #f56c6c; - --el-color-info: #909399; -} - -// 暗色主题 -.dark { - --el-color-primary: #66d9ef; - --el-color-success: #a6e22e; - --el-color-warning: #fd971f; - --el-color-danger: #f92672; - --el-color-info: #75715e; -} -``` - -### 自定义样式 - -#### 全局样式 - -在 `src/styles/index.scss` 中添加全局样式: - -```scss -// 自定义全局样式 -.custom-class { - // 自定义样式 -} -``` - -#### 组件样式 - -使用 scoped 样式: - -```vue - -``` - -## 🔧 开发规范 - -### 代码规范 - -项目使用 ESLint + Prettier 进行代码规范检查: - -```bash -# 检查代码 -pnpm run lint - -# 修复代码 -pnpm run lint:fix -``` - -### Git 提交规范 - -项目使用 Husky + commitizen 进行 Git 提交规范: - -```bash -# 交互式提交 -pnpm run commit - -# 或直接提交 -git commit -m "feat: 添加新功能" -``` - -提交类型: -- `feat`: 新功能 -- `fix`: 修复bug -- `docs`: 文档更新 -- `style`: 代码格式调整 -- `refactor`: 代码重构 -- `test`: 测试相关 -- `chore`: 构建过程或工具配置更新 - -### 文件命名规范 - -- **组件文件**: PascalCase (`UserCard.vue`) -- **工具函数**: camelCase (`formatDate.ts`) -- **类型定义**: PascalCase (`UserType.ts`) -- **常量文件**: kebab-case (`user-constants.ts`) -- **页面文件**: kebab-case (`user-list.vue`) - -## 🚀 部署指南 - -### 构建生产版本 - -```bash -# 构建生产版本 -pnpm run build - -# 构建特定环境 -pnpm run build:pro # 生产环境 -pnpm run build:dev # 开发环境 -pnpm run build:test # 测试环境 -``` - -### Nginx 配置 - -```nginx -server { - listen 80; - server_name your-domain.com; - - location / { - root /path/to/dist; - index index.html index.htm; - try_files $uri $uri/ /index.html; - } - - # API 代理 - location /api/ { - proxy_pass http://backend-server:8000/; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } -} -``` - -### Docker 部署 - -```dockerfile -# Dockerfile -FROM nginx:alpine - -COPY dist/ /usr/share/nginx/html/ -COPY nginx.conf /etc/nginx/conf.d/default.conf - -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] -``` - -## 🌍 国际化配置 - -### 国际化架构 - -项目使用 Vue I18n 进行国际化管理: - -``` -src/lang/ -├── 📁 package/ # 语言包 -│ ├── zh-cn.ts # 中文语言包 -│ └── en.ts # 英文语言包 -└── index.ts # 国际化配置 -``` - -### 语言包配置 - -```typescript -// src/lang/package/zh-cn.ts -export default { - common: { - confirm: '确定', - cancel: '取消', - save: '保存', - delete: '删除', - edit: '编辑', - add: '新增', - search: '搜索', - reset: '重置', - export: '导出', - import: '导入' - }, - menu: { - dashboard: '仪表板', - system: '系统管理', - user: '用户管理', - role: '角色管理', - menu: '菜单管理' - }, - message: { - success: '操作成功', - error: '操作失败', - confirmDelete: '确定要删除这条记录吗?', - noPermission: '没有权限访问' - } -} -``` - -### 在组件中使用 - -```vue - - - -``` - -## 🛡️ 错误处理机制 - -### 全局错误处理 - -```typescript -// src/utils/errorHandler.ts -import { ElMessage } from 'element-plus' - -export const setupErrorHandler = (app: App) => { - // Vue 错误处理 - app.config.errorHandler = (err: Error, instance, info) => { - console.error('Vue Error:', err, info) - handleError(err) - } - - // 全局错误处理函数 - const handleError = (error: any) => { - if (error.code === 'NETWORK_ERROR') { - ElMessage.error('网络连接失败') - } else if (error.code === 401) { - ElMessage.error('登录已过期,请重新登录') - router.push('/login') - } else if (error.code === 403) { - ElMessage.error('没有权限访问') - } else { - ElMessage.error(error.message || '发生未知错误') - } - } -} -``` - -### 错误边界组件 - -```vue - - - - -``` - -## 🚀 性能优化 - -### 代码分割和懒加载 - -```typescript -// 路由懒加载 -const routes = [ - { - path: '/dashboard', - component: () => import('@/views/dashboard/index.vue') - }, - { - path: '/system/user', - component: () => import('@/views/system/user/index.vue') - } -] -``` - -### 组件懒加载 - -```vue - -``` - -### 图片懒加载 - -```vue - - - - -``` - -## 🔒 安全性 - -### XSS 防护 - -```typescript -// src/utils/sanitize.ts -export const sanitizeHtml = (html: string): string => { - return html.replace(/[<>]/g, '') -} -``` - -### 权限验证 - -```typescript -// src/composables/usePermission.ts -export const usePermission = () => { - const hasPermission = (permission: string): boolean => { - const userStore = useUserStore() - return userStore.permissions.includes(permission) - } - - const hasRole = (role: string): boolean => { - const userStore = useUserStore() - return userStore.roles.includes(role) - } - - return { hasPermission, hasRole } -} -``` - -## 🧪 单元测试 - -### 测试配置 - -```typescript -// vitest.config.ts -export default defineConfig({ - test: { - globals: true, - environment: 'jsdom' - } -}) -``` - -### 组件测试 - -```typescript -// src/components/__tests__/Button.test.ts -import { mount } from '@vue/test-utils' - -describe('Button', () => { - it('renders correctly', () => { - const wrapper = mount(Button, { - props: { type: 'primary' } - }) - expect(wrapper.classes()).toContain('el-button--primary') - }) -}) -``` - -### API 测试 - -```typescript -// src/api/__tests__/user.test.ts -import { vi, describe, it, expect } from 'vitest' - -vi.mock('@/utils/request') - -describe('User API', () => { - it('fetches user list', async () => { - const mockUsers = [{ id: 1, name: 'John' }] - mockRequest.get.mockResolvedValue({ data: mockUsers }) - - const result = await getUserList() - expect(result).toEqual(mockUsers) - }) -}) -``` - -### 运行测试 - -```bash -# 运行测试 -pnpm test - -# 生成覆盖率 -pnpm test:coverage -``` - -## 🔄 CI/CD 集成 - -### GitHub Actions 配置 - -```yaml -# .github/workflows/ci.yml -name: CI/CD - -on: - push: - branches: [ main, develop ] - pull_request: - branches: [ main ] - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '18' - cache: 'pnpm' - - - name: Install dependencies - run: pnpm install - - - name: Run linter - run: pnpm run lint - - - name: Run tests - run: pnpm test - - - name: Build - run: pnpm run build - - deploy: - needs: test - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' - - steps: - - name: Deploy to production - run: | - echo "Deploy to production server" - # Add your deployment commands here -``` - -### Jenkins 配置 - -```groovy -// Jenkinsfile -pipeline { - agent any - - stages { - stage('Checkout') { - steps { - git branch: 'main', url: 'https://github.com/your-repo.git' - } - } - - stage('Install') { - steps { - sh 'pnpm install' - } - } - - stage('Test') { - steps { - sh 'pnpm test' - } - } - - stage('Build') { - steps { - sh 'pnpm run build' - } - } - - stage('Deploy') { - steps { - sh 'scp -r dist/* user@server:/path/to/web/root/' - } - } - } - - post { - success { - echo 'Pipeline succeeded!' - } - failure { - echo 'Pipeline failed!' - } - } -} -``` - -## ❓ 常见问题解答 - -### 项目配置问题 - -**Q: 如何修改项目的标题和Logo?** - -A: 在 `src/settings.ts` 中修改应用配置: - -```typescript -export const settings = { - title: '你的应用名称', - logo: '/path/to/your/logo.png' -} -``` - -**Q: 如何修改主题色?** - -A: 在 `src/styles/variables.scss` 中修改CSS变量: - -```scss -:root { - --el-color-primary: #your-color; -} -``` - -**Q: 如何添加新的环境变量?** - -A: 在对应的 `.env` 文件中添加变量,然后在代码中使用: - -```bash -# .env.development -VITE_APP_NEW_VAR=value -``` - -```typescript -// 在代码中使用 -const newVar = import.meta.env.VITE_APP_NEW_VAR -``` - -### 开发问题 - -**Q: 组件样式不生效怎么办?** - -A: 检查以下几点: -1. 是否使用了 `scoped` 样式 -2. CSS 类名是否正确 -3. 是否使用了正确的 UnoCSS 类名 -4. 样式优先级是否正确 - -**Q: API请求失败怎么办?** - -A: 检查以下几点: -1. 后端服务是否启动 -2. API地址是否正确 -3. 请求头是否包含认证信息 -4. 网络连接是否正常 - -**Q: 路由跳转失败怎么办?** - -A: 检查以下几点: -1. 路由路径是否正确 -2. 路由组件是否存在 -3. 路由权限是否正确 -4. 路由参数是否正确传递 - -### 性能问题 - -**Q: 页面加载慢怎么办?** - -A: 尝试以下优化: -1. 启用代码分割和懒加载 -2. 优化图片资源 -3. 启用压缩和缓存 -4. 使用CDN加速 - -**Q: 内存泄漏怎么办?** - -A: 注意以下几点: -1. 及时清理定时器和事件监听器 -2. 正确使用 Vue 的生命周期 -3. 避免在组件中保存大量数据 -4. 使用内存分析工具检查 - -### 部署问题 - -**Q: 部署后页面空白怎么办?** - -A: 检查以下几点: -1. 构建是否成功 -2. 静态资源路径是否正确 -3. 服务器配置是否正确 -4. 路由模式是否匹配服务器配置 - -**Q: API请求跨域怎么办?** - -A: 配置代理或修改服务器CORS设置: - -```typescript -// vite.config.ts -export default defineConfig({ - server: { - proxy: { - '/api': { - target: 'http://localhost:8000', - changeOrigin: true - } - } - } -}) -``` - -## 📊 监控和日志 - -### 错误监控 - -```typescript -// src/utils/monitor.ts -import * as Sentry from '@sentry/vue' - -export const initSentry = (app: App) => { - Sentry.init({ - app, - dsn: import.meta.env.VITE_SENTRY_DSN, - integrations: [ - new Sentry.BrowserTracing({ - routingInstrumentation: Sentry.vueRouterInstrumentation(router) - }) - ], - tracesSampleRate: 1.0 - }) -} -``` - -### 性能监控 - -```typescript -// src/utils/performance.ts -export const reportWebVitals = (metric: any) => { - // 发送性能指标到监控服务 - console.log('Web Vitals:', metric) - - // 可以发送到自己的监控服务 - // fetch('/api/metrics', { - // method: 'POST', - // body: JSON.stringify(metric) - // }) -} - -// 使用 Web Vitals 库 -import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals' - -getCLS(reportWebVitals) -getFID(reportWebVitals) -getFCP(reportWebVitals) -getLCP(reportWebVitals) -getTTFB(reportWebVitals) -``` - -### 用户行为分析 - -```typescript -// src/utils/analytics.ts -export const trackEvent = (eventName: string, properties?: Record) => { - // 发送事件到分析服务 - console.log('Track Event:', eventName, properties) - - // 可以集成 Google Analytics、百度统计等 - // gtag('event', eventName, properties) -} -``` - -## 🎯 最佳实践 - -### 代码组织 - -1. **组件设计** - - 单一职责原则 - - 可复用性 - - 清晰的API设计 - -2. **状态管理** - - 合理划分状态范围 - - 使用组合式函数 - - 避免状态冗余 - -3. **类型安全** - - 使用TypeScript - - 定义清晰的接口 - - 充分利用类型推导 - -### 性能优化 - -1. **打包优化** - - 代码分割 - - 资源压缩 - - 缓存策略 - -2. **运行时优化** - - 虚拟滚动 - - 图片懒加载 - - 防抖节流 - -3. **网络优化** - - 请求缓存 - - 预加载 - - CDN加速 - -### 安全性 - -1. **输入验证** - - XSS防护 - - CSRF防护 - - SQL注入防护 - -2. **权限控制** - - 角色权限 - - 菜单权限 - - 按钮权限 - -3. **数据保护** - - 敏感信息加密 - - HTTPS传输 - - 本地存储安全 - -## 📚 常用资源 - -### 官方文档 -- [Vue 3](https://cn.vuejs.org/) -- [TypeScript](https://www.typescriptlang.org/) -- [Vite](https://cn.vitejs.dev/) -- [Element Plus](https://element-plus.org/) -- [Pinia](https://pinia.vuejs.org/) -- [UnoCSS](https://unocss.dev/) - -### 推荐工具 -- [Vue DevTools](https://devtools.vuejs.org/) -- [Vite DevTools](https://github.com/vadxq/vite-devtools) -- [Element Plus DevTools](https://github.com/element-plus/element-plus-devtools) - -### 学习资源 -- [Vue 3 官方教程](https://cn.vuejs.org/tutorial/) -- [TypeScript 入门](https://www.typescriptlang.org/docs/) -- [现代前端开发指南](https://modern-frontend.guide/) - -## 🤝 贡献指南 - -1. Fork 项目 -2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) -3. 提交更改 (`git commit -m 'feat: Add some AmazingFeature'`) -4. 推送到分支 (`git push origin feature/AmazingFeature`) -5. 打开 Pull Request - -## 📝 更新日志 - -### v1.0.0 (2024-01-XX) - -#### ✨ 新增功能 -- 🎨 支持明暗主题切换 -- 🌍 完整的国际化支持 -- 🔐 基于角色的权限管理系统 -- 📊 动态菜单系统 -- 🧪 完整的单元测试配置 -- 📊 性能监控和错误监控 -- 🔄 CI/CD 集成配置 -- 🚀 代码分割和懒加载优化 - -#### 🛠️ 技术栈升级 -- Vue 3 + TypeScript -- Vite 4.x 构建工具 -- Element Plus UI 组件库 -- Pinia 状态管理 -- UnoCSS 原子化CSS -- Vue I18n 国际化 - -#### 📚 文档完善 -- 详细的项目结构说明 -- 完整的二次开发指南 -- API 接口管理文档 -- 最佳实践和性能优化指南 -- 常见问题解答 - -## 🔄 版本管理 - -项目采用语义化版本控制: - -- **MAJOR.MINOR.PATCH** (主版本.次版本.补丁版本) -- 主版本:破坏性变更 -- 次版本:新增功能,向后兼容 -- 补丁版本:修复bug,向后兼容 - -### 分支管理 - -``` -main # 主分支,生产环境代码 -develop # 开发分支,集成新功能 -feature/* # 功能分支,新功能开发 -hotfix/* # 热修复分支,紧急bug修复 -release/* # 发布分支,准备发布版本 -``` - -### 发布流程 - -1. **开发阶段** - ```bash - git checkout develop - git checkout -b feature/new-feature - # 开发新功能 - git commit -m "feat: add new feature" - ``` - -2. **代码审查** - ```bash - git push origin feature/new-feature - # 创建 Pull Request - ``` - -3. **合并到开发分支** - ```bash - git checkout develop - git merge feature/new-feature - ``` - -4. **发布准备** - ```bash - git checkout -b release/v1.1.0 - # 测试和修复 - ``` - -5. **发布到生产** - ```bash - git checkout main - git merge release/v1.1.0 - git tag v1.1.0 - git push origin main --tags - ``` - -## 📄 许可证 - -本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情 - -## 📞 联系我们 - -如有问题或建议,请: - -1. 查看 [项目文档](PROJECT_GUIDE.md) -2. 提交 [Issue](https://github.com/your-repo/issues) -3. 发送邮件至:contact@example.com - -## 🙏 致谢 - -感谢以下开源项目的贡献: - -- **Vue.js** - 渐进式前端框架 -- **Element Plus** - Vue3 UI组件库 -- **Vite** - 下一代前端构建工具 -- **TypeScript** - 类型安全的JavaScript -- **UnoCSS** - 原子化CSS引擎 -- **Pinia** - Vue3官方状态管理库 - ---- - -## 🎯 项目总结 - -**FastAPI Vue3 Admin** 是一个功能完整、架构清晰、易于维护的现代化后台管理系统前端模板,具有以下特点: - -### ✅ 核心优势 - -1. **现代化技术栈** - Vue3 + TypeScript + Vite + Element Plus -2. **完整的功能体系** - 从开发到部署的全流程解决方案 -3. **高度可定制** - 支持主题切换、国际化、动态菜单等 -4. **优秀的开发体验** - 热重载、类型检查、代码规范等 -5. **生产就绪** - 包含测试、监控、部署等完整配置 - -### 🎨 设计理念 - -- **组件化** - 一切皆组件,提高复用性 -- **配置化** - 通过配置而非硬编码实现功能 -- **规范化** - 统一的代码规范和开发流程 -- **可扩展** - 插件化架构,易于扩展新功能 - -### 🚀 快速开始 - -```bash -# 1. 克隆项目 -git clone https://github.com/your-repo.git - -# 2. 安装依赖 -cd frontend && pnpm install - -# 3. 启动开发服务器 -pnpm run dev - -# 4. 开始开发 -# 访问 http://localhost:5173 -``` - -### 📚 学习路径 - -1. **新手入门** - 阅读快速开始和项目结构 -2. **功能开发** - 学习动态菜单系统和API接口管理 -3. **高级特性** - 掌握性能优化和安全性配置 -4. **生产部署** - 了解CI/CD和监控配置 - ---- - -**🎉 祝您开发愉快!使用这个模板构建出色的后台管理系统!** From 0687205052b18f230f99e9b30cf8580514693400 Mon Sep 17 00:00:00 2001 From: Guo Tiantian <1431335589@qq.com> Date: Fri, 29 Aug 2025 00:09:13 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix=EF=BC=9A=E6=9A=B4=E9=9C=B2=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E9=85=8D=E7=BD=AE=E6=A0=B7=E5=BC=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/lang/package/en.ts | 1 + frontend/src/lang/package/zh-cn.ts | 1 + .../src/layouts/components/Settings/index.vue | 11 +++- frontend/src/settings.ts | 50 ++++++++++++++++--- frontend/src/types/auto-imports.d.ts | 1 + .../views/dashboard/components/QuickStart.vue | 23 +++++---- 6 files changed, 68 insertions(+), 19 deletions(-) diff --git a/frontend/src/lang/package/en.ts b/frontend/src/lang/package/en.ts index b3301b0c..2b3df172 100644 --- a/frontend/src/lang/package/en.ts +++ b/frontend/src/lang/package/en.ts @@ -172,6 +172,7 @@ export default { interface: "Interface", navigation: "Navigation", themeColor: "Theme Color", + customColor: "Custom Color", showTagsView: "Show Tags View", showAppLogo: "Show App Logo", sidebarColorScheme: "Sidebar Color Scheme", diff --git a/frontend/src/lang/package/zh-cn.ts b/frontend/src/lang/package/zh-cn.ts index 6c3ce54a..30894cce 100644 --- a/frontend/src/lang/package/zh-cn.ts +++ b/frontend/src/lang/package/zh-cn.ts @@ -174,6 +174,7 @@ export default { navigation: "导航主题", themeColor: "主题颜色", themeColorTip: "主题颜色", + customColor: "自定义颜色", darkMode: "暗黑模式", layoutSetting: "布局设置", sidebarColorScheme: "侧边栏配色", diff --git a/frontend/src/layouts/components/Settings/index.vue b/frontend/src/layouts/components/Settings/index.vue index 846ce964..bcb18abb 100644 --- a/frontend/src/layouts/components/Settings/index.vue +++ b/frontend/src/layouts/components/Settings/index.vue @@ -350,10 +350,15 @@ const handleCloseDrawer = () => { min-height: 0; /* 确保内容区域可以收缩 */ } + /* 底部操作区域样式 */ .action-footer { - flex-shrink: 0; - margin-top: auto; /* 将底部操作区域推到最下方 */ + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 10; + padding: 0; background: var(--el-bg-color); border-top: 1px solid var(--el-border-color-light); @@ -361,6 +366,8 @@ const handleCloseDrawer = () => { display: none; /* 移除重复的分割线 */ } + + .action-card { padding: 16px 20px; margin: 0; diff --git a/frontend/src/settings.ts b/frontend/src/settings.ts index ab84d461..87b6b9c1 100644 --- a/frontend/src/settings.ts +++ b/frontend/src/settings.ts @@ -37,17 +37,55 @@ export const defaultSettings: AppSettings = { guideVisible: false, }; -// 主题色预设 - 经典配色方案 +// 主题色预设 - 现代化配色方案 // 注意:修改默认主题色时,需要同步修改 src/styles/variables.scss 中的 primary.base 值 export const themeColorPresets = [ + // === 蓝色系 - 科技与专业 === "#4080FF", // Arco Design 蓝 - 现代感强 "#1890FF", // Ant Design 蓝 - 经典商务 "#409EFF", // Element Plus 蓝 - 清新自然 - "#FA8C16", // 活力橙 - 温暖友好 - "#722ED1", // 优雅紫 - 高端大气 - "#13C2C2", // 青色 - 科技感 - "#52C41A", // 成功绿 - 活力清新 - "#F5222D", // 警示红 - 醒目强烈 "#2F54EB", // 深蓝 - 稳重专业 + "#1E40AF", // 深蓝色 - 商务精英 + "#1D4ED8", // 皇家蓝 - 高端商务 + + // === 绿色系 - 自然与活力 === + "#52C41A", // 成功绿 - 活力清新 + "#10B981", // 翠绿色 - 清新自然 + "#059669", // 森林绿 - 生态环保 + "#16A34A", // 草绿色 - 健康活力 + "#15803D", // 深绿色 - 稳重大气 + + // === 紫色系 - 创意与优雅 === + "#722ED1", // 优雅紫 - 高端大气 + "#7C3AED", // 紫罗兰 - 创意无限 + "#8B5CF6", // 浅紫色 - 时尚现代 + "#6D28D9", // 深紫色 - 神秘高端 + "#5B21B6", // 皇家紫 - 王者风范 + + // === 橙色系 - 温暖与活力 === + "#FA8C16", // 活力橙 - 温暖友好 + "#F97316", // 火橙色 - 热情奔放 + "#EA580C", // 深橙色 - 阳光活力 + "#DC2626", // 珊瑚红 - 温暖亲切 + + // === 青色系 - 科技与清新 === + "#13C2C2", // 青色 - 科技感 + "#0891B2", // 天蓝色 - 清新自然 + "#0E7490", // 深青色 - 专业科技 + "#06B6D4", // 青蓝色 - 海洋清新 + + // === 红色系 - 激情与警示 === + "#F5222D", // 警示红 - 醒目强烈 + "#DC2626", // 猩红色 - 激情四射 + "#B91C1C", // 深红色 - 庄重严肃 + + // === 粉色系 - 温柔与时尚 === "#EB2F96", // 品红 - 时尚个性 + "#EC4899", // 玫瑰粉 - 浪漫温馨 + "#F472B6", // 浅粉色 - 柔美可爱 + + // === 灰色系 - 简约与现代 === + "#6B7280", // 经典灰 - 简约现代 + "#4B5563", // 深灰色 - 商务专业 + "#374151", // 石板灰 - 高端商务 ]; diff --git a/frontend/src/types/auto-imports.d.ts b/frontend/src/types/auto-imports.d.ts index 96afad15..d800967e 100644 --- a/frontend/src/types/auto-imports.d.ts +++ b/frontend/src/types/auto-imports.d.ts @@ -587,6 +587,7 @@ declare module 'vue' { readonly useThrottleFn: UnwrapRef readonly useThrottledRefHistory: UnwrapRef readonly useTimeAgo: UnwrapRef + readonly useTimeAgoIntl: UnwrapRef readonly useTimeout: UnwrapRef readonly useTimeoutFn: UnwrapRef readonly useTimeoutPoll: UnwrapRef diff --git a/frontend/src/views/dashboard/components/QuickStart.vue b/frontend/src/views/dashboard/components/QuickStart.vue index 05e43656..3f299f68 100644 --- a/frontend/src/views/dashboard/components/QuickStart.vue +++ b/frontend/src/views/dashboard/components/QuickStart.vue @@ -197,28 +197,29 @@ onUnmounted(() => { From 78083325ec51652e303b316d3b19d6cb5265b2bf Mon Sep 17 00:00:00 2001 From: zhangtao <9480807882@qq.com> Date: Fri, 29 Aug 2025 00:35:46 +0800 Subject: [PATCH 4/5] =?UTF-8?q?style(Settings):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=9D=A2=E6=9D=BF=E7=9A=84=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除不必要的flex布局,改用固定高度计算方式 清理未使用的useTimeAgoIntl类型声明 --- frontend/src/layouts/components/Settings/index.vue | 8 +------- frontend/src/types/auto-imports.d.ts | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/frontend/src/layouts/components/Settings/index.vue b/frontend/src/layouts/components/Settings/index.vue index bcb18abb..5ec90a7d 100644 --- a/frontend/src/layouts/components/Settings/index.vue +++ b/frontend/src/layouts/components/Settings/index.vue @@ -336,21 +336,17 @@ const handleCloseDrawer = () => { height: 100%; padding: 0; overflow: hidden; - display: flex; - flex-direction: column; } } /* 设置内容区域 */ .settings-content { - flex: 1; + height: calc(100vh - 120px); /* 减去头部和底部按钮的高度 */ padding: 20px; padding-bottom: 20px; overflow-y: auto; - min-height: 0; /* 确保内容区域可以收缩 */ } - /* 底部操作区域样式 */ .action-footer { position: absolute; @@ -366,8 +362,6 @@ const handleCloseDrawer = () => { display: none; /* 移除重复的分割线 */ } - - .action-card { padding: 16px 20px; margin: 0; diff --git a/frontend/src/types/auto-imports.d.ts b/frontend/src/types/auto-imports.d.ts index d800967e..96afad15 100644 --- a/frontend/src/types/auto-imports.d.ts +++ b/frontend/src/types/auto-imports.d.ts @@ -587,7 +587,6 @@ declare module 'vue' { readonly useThrottleFn: UnwrapRef readonly useThrottledRefHistory: UnwrapRef readonly useTimeAgo: UnwrapRef - readonly useTimeAgoIntl: UnwrapRef readonly useTimeout: UnwrapRef readonly useTimeoutFn: UnwrapRef readonly useTimeoutPoll: UnwrapRef From 2bb32df0e838f1278f02bb13361f1a751f3e7d28 Mon Sep 17 00:00:00 2001 From: Guo Tiantian <1431335589@qq.com> Date: Fri, 29 Aug 2025 17:29:36 +0800 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E5=AF=BC=E8=88=AA=E4=BA=A4=E4=BA=92=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/layouts/components/TagsView/index.vue | 130 ++++++++++++++---- frontend/src/types/auto-imports.d.ts | 1 + frontend/src/utils/quickStartManager.ts | 2 - 3 files changed, 103 insertions(+), 30 deletions(-) diff --git a/frontend/src/layouts/components/TagsView/index.vue b/frontend/src/layouts/components/TagsView/index.vue index c13f2f1b..c4c06ca6 100644 --- a/frontend/src/layouts/components/TagsView/index.vue +++ b/frontend/src/layouts/components/TagsView/index.vue @@ -13,6 +13,7 @@ (null); // 滚动条引用 const scrollbarRef = ref(); +// 标签切换来源跟踪 +const tagSwitchSource = ref<'menu' | 'tab' | null>(null); + // 路由映射缓存,提升查找性能 const routePathMap = computed(() => { const map = new Map(); @@ -271,20 +275,21 @@ const initAffixTags = () => { const addCurrentTag = () => { if (!route.meta?.title) return; - // 检查标签是否已存在 const existingTag = visitedViews.value.find(tag => tag.path === route.path); - + if (existingTag) { - // 如果标签已存在,将其移动到最新位置(除非是固定标签) + // 如果标签已存在,根据来源决定是否移动位置 if (!existingTag.affix) { - // 从当前位置移除 - const index = visitedViews.value.findIndex(tag => tag.path === route.path); - if (index !== -1) { - const tag = visitedViews.value.splice(index, 1)[0]; - // 添加到末尾 - visitedViews.value.push(tag); + if (tagSwitchSource.value === 'menu') { + // 通过菜单点击:移动到最新位置 + const index = visitedViews.value.findIndex(tag => tag.path === route.path); + if (index !== -1) { + const tag = visitedViews.value.splice(index, 1)[0]; + visitedViews.value.push(tag); + } } + // 通过标签容器点击:不移动位置,只激活 } } else { // 添加新标签 @@ -300,11 +305,17 @@ const addCurrentTag = () => { }); } + // 根据来源决定是否滚动 + if (tagSwitchSource.value === 'menu') { + // 通过菜单点击:滚动到最新标签 + nextTick(() => { + autoScrollToLatestTag(); + }); + } + // 通过标签容器点击:不滚动,保持当前位置 - // 检查是否需要自动滚动到最新标签 - nextTick(() => { - autoScrollToLatestTag(); - }); + // 重置来源状态 + tagSwitchSource.value = null; }; /** @@ -329,6 +340,14 @@ const updateCurrentTag = () => { }); }; +/** + * 处理标签点击 + */ +const handleTabClick = (tag: TagView) => { + // 设置标签切换来源为标签容器点击 + tagSwitchSource.value = 'tab'; +}; + /** * 处理中键点击 */ @@ -389,6 +408,10 @@ const closeSelectedTag = (tag: TagView | null) => { if (tagsViewStore.isActive(currentTag)) { tagsViewStore.toLastView(result.visitedViews, currentTag); } + // 关闭标签后重置滚动状态,以便下次可以重新判断是否需要滚动 + nextTick(() => { + resetScrollState(); + }); }); }; @@ -404,6 +427,10 @@ const closeLeftTags = () => { if (!hasCurrentRoute) { tagsViewStore.toLastView(result.visitedViews); } + // 关闭标签后重置滚动状态 + nextTick(() => { + resetScrollState(); + }); }); }; @@ -419,6 +446,10 @@ const closeRightTags = () => { if (!hasCurrentRoute) { tagsViewStore.toLastView(result.visitedViews); } + // 关闭标签后重置滚动状态 + nextTick(() => { + resetScrollState(); + }); }); }; @@ -431,6 +462,10 @@ const closeOtherTags = () => { router.push(selectedTag.value); tagsViewStore.delOtherViews(selectedTag.value).then(() => { updateCurrentTag(); + // 关闭标签后重置滚动状态 + nextTick(() => { + resetScrollState(); + }); }); }; @@ -440,6 +475,10 @@ const closeOtherTags = () => { const closeAllTags = (tag: TagView | null) => { tagsViewStore.delAllViews().then((result: any) => { tagsViewStore.toLastView(result.visitedViews, tag || undefined); + // 关闭所有标签后重置滚动状态 + nextTick(() => { + resetScrollState(); + }); }); }; @@ -544,8 +583,27 @@ const scrollRight = () => { const maxScrollLeft = scrollWrapper.scrollWidth - scrollWrapper.clientWidth const newScrollLeft = Math.min(maxScrollLeft, scrollWrapper.scrollLeft + 200) scrollbarRef.value.setScrollLeft(newScrollLeft) + + // 如果滚动到最右边,重置滚动状态以允许下次自动滚动 + if (newScrollLeft >= maxScrollLeft - 1) { + scrollState.value.hasScrolledToLatest = false + } } +/** + * 重置滚动状态 + */ +const resetScrollState = () => { + scrollState.value.hasScrolledToLatest = false + scrollState.value.isContainerFull = false +} + +// 滚动状态跟踪 +const scrollState = ref({ + hasScrolledToLatest: false, // 是否已经滚动到最新标签 + isContainerFull: false // 容器是否已满 +}) + /** * 自动滚动到最新标签 */ @@ -557,21 +615,34 @@ const autoScrollToLatestTag = () => { const containerWidth = scrollWrapper.clientWidth const contentWidth = scrollWrapper.scrollWidth - // 如果内容宽度超过容器宽度,需要滚动 - if (contentWidth > containerWidth) { + // 判断容器是否已满(内容宽度是否超过容器宽度) + const isContainerFull = contentWidth > containerWidth + + // 如果容器已满且还没有滚动到最新标签,则滚动到最右边 + if (isContainerFull && !scrollState.value.hasScrolledToLatest) { // 计算需要滚动到的位置,确保最新标签在右侧可见 const maxScrollLeft = contentWidth - containerWidth scrollbarRef.value.setScrollLeft(maxScrollLeft) - } else { + scrollState.value.hasScrolledToLatest = true + scrollState.value.isContainerFull = true + } else if (!isContainerFull) { // 如果内容宽度不超过容器宽度,滚动到最左边 scrollbarRef.value.setScrollLeft(0) + // 重置滚动状态 + scrollState.value.hasScrolledToLatest = false + scrollState.value.isContainerFull = false } + // 如果容器已满且已经滚动过,则保持当前位置 } // 监听路由变化 watch( route, () => { + // 如果没有设置来源,则默认为菜单点击 + if (tagSwitchSource.value === null) { + tagSwitchSource.value = 'menu'; + } addCurrentTag(); updateCurrentTag(); }, @@ -581,25 +652,28 @@ watch( // 监听容器大小变化 let resizeObserver: ResizeObserver | null = null; -// 监听标签数量变化,自动滚动到最新标签 +// 监听标签数量变化,自动滚动到最新标签(新标签添加时) watch( () => visitedViews.value.length, () => { - nextTick(() => { - autoScrollToLatestTag(); - }); + // 只有在通过菜单添加新标签时才滚动 + if (tagSwitchSource.value === 'menu') { + nextTick(() => { + autoScrollToLatestTag(); + }); + } } ); // 监听当前路由变化,确保点击隐藏标签时滚动到最新位置 -watch( - () => route.path, - () => { - nextTick(() => { - autoScrollToLatestTag(); - }); - } -); +// watch( +// () => route.path, +// () => { +// nextTick(() => { +// autoScrollToLatestTag(); +// }); +// } +// ); // 初始化 onMounted(() => { diff --git a/frontend/src/types/auto-imports.d.ts b/frontend/src/types/auto-imports.d.ts index 96afad15..d800967e 100644 --- a/frontend/src/types/auto-imports.d.ts +++ b/frontend/src/types/auto-imports.d.ts @@ -587,6 +587,7 @@ declare module 'vue' { readonly useThrottleFn: UnwrapRef readonly useThrottledRefHistory: UnwrapRef readonly useTimeAgo: UnwrapRef + readonly useTimeAgoIntl: UnwrapRef readonly useTimeout: UnwrapRef readonly useTimeoutFn: UnwrapRef readonly useTimeoutPoll: UnwrapRef diff --git a/frontend/src/utils/quickStartManager.ts b/frontend/src/utils/quickStartManager.ts index 3a66c740..85c1ce86 100644 --- a/frontend/src/utils/quickStartManager.ts +++ b/frontend/src/utils/quickStartManager.ts @@ -118,8 +118,6 @@ class QuickStartManager { routeIcon = routeIcon.charAt(0).toUpperCase() + routeIcon.slice(1); } - console.log("routeIcon",routeIcon) - // 确定最终使用的标题 - 优先使用route.title const finalTitle = customTitle || route.title || route.name || '未命名页面';