docs: 剔除部分文档目录
This commit is contained in:
		
							parent
							
								
									c79cd2f4c2
								
							
						
					
					
						commit
						898ab51736
					
				| @ -166,7 +166,7 @@ function nav(): DefaultTheme.NavItem[] { | |||||||
|           text: 'y-code-platform', |           text: 'y-code-platform', | ||||||
|           items: [ |           items: [ | ||||||
|             { |             { | ||||||
|               link: 'https://www.vben.pro', |               link: 'https://y-code-platform.shiyuegame.com', | ||||||
|               text: 'Demo Version', |               text: 'Demo Version', | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|  | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -44,12 +44,12 @@ export const shared = defineConfig({ | |||||||
|       }, |       }, | ||||||
|       provider: 'local', |       provider: 'local', | ||||||
|     }, |     }, | ||||||
|     siteTitle: 'y-code-platform', |     siteTitle: '悦码', | ||||||
|     // socialLinks: [
 |     socialLinks: [ | ||||||
|     //   { icon: 'github', link: 'https://github.com/vbenjs/vue-vben-admin' },
 |       { icon: 'github', link: 'https://ptdata-gitlab.shiyue.com/sy3570' }, | ||||||
|     // ],
 |     ], | ||||||
|   }, |   }, | ||||||
|   title: 'y-code-platform', |   title: '悦码', | ||||||
|   vite: { |   vite: { | ||||||
|     build: { |     build: { | ||||||
|       chunkSizeWarningLimit: Infinity, |       chunkSizeWarningLimit: Infinity, | ||||||
| @ -75,20 +75,12 @@ export const shared = defineConfig({ | |||||||
|       GitChangelog({ |       GitChangelog({ | ||||||
|         mapAuthors: [ |         mapAuthors: [ | ||||||
|           { |           { | ||||||
|             mapByNameAliases: ['Vben'], |             mapByNameAliases: ['王雪峰'], | ||||||
|             name: 'vben', |             name: 'wangxuefeng', | ||||||
|             username: 'anncwb', |             username: 'wangxuefeng', | ||||||
|           }, |  | ||||||
|           { |  | ||||||
|             name: 'vince', |  | ||||||
|             username: 'vince292007', |  | ||||||
|           }, |  | ||||||
|           { |  | ||||||
|             name: 'Li Kui', |  | ||||||
|             username: 'likui628', |  | ||||||
|           }, |           }, | ||||||
|         ], |         ], | ||||||
|         repoURL: () => 'https://github.com/vbenjs/vue-vben-admin', |         repoURL: () => 'https://ptdata-gitlab.shiyue.com/workbench/y-code', | ||||||
|       }), |       }), | ||||||
|       GitChangelogMarkdownSection(), |       GitChangelogMarkdownSection(), | ||||||
|       viteArchiverPlugin({ outputDir: '.vitepress' }), |       viteArchiverPlugin({ outputDir: '.vitepress' }), | ||||||
| @ -111,7 +103,7 @@ export const shared = defineConfig({ | |||||||
| 
 | 
 | ||||||
| function head(): HeadConfig[] { | function head(): HeadConfig[] { | ||||||
|   return [ |   return [ | ||||||
|     ['meta', { content: 'Vbenjs Team', name: 'author' }], |     ['meta', { content: 'wangxuefeng', name: 'author' }], | ||||||
|     [ |     [ | ||||||
|       'meta', |       'meta', | ||||||
|       { |       { | ||||||
| @ -144,7 +136,7 @@ function pwa(): PwaOptions { | |||||||
|     includeManifestIcons: false, |     includeManifestIcons: false, | ||||||
|     manifest: { |     manifest: { | ||||||
|       description: |       description: | ||||||
|         'y-code-platform is a modern admin dashboard template based on Vue 3. ', |         'y-code-platform is a low-code management platform based on Vue 3 & vtj.pro ', | ||||||
|       icons: [ |       icons: [ | ||||||
|         { |         { | ||||||
|           sizes: '192x192', |           sizes: '192x192', | ||||||
| @ -159,7 +151,7 @@ function pwa(): PwaOptions { | |||||||
|       ], |       ], | ||||||
|       id: '/', |       id: '/', | ||||||
|       name: 'y-code-platform Doc', |       name: 'y-code-platform Doc', | ||||||
|       short_name: 'vben_admin_doc', |       short_name: 'y-code-platform_doc', | ||||||
|       theme_color: '#ffffff', |       theme_color: '#ffffff', | ||||||
|     }, |     }, | ||||||
|     outDir: resolve(process.cwd(), '.vitepress/dist'), |     outDir: resolve(process.cwd(), '.vitepress/dist'), | ||||||
|  | |||||||
| @ -169,12 +169,7 @@ function nav(): DefaultTheme.NavItem[] { | |||||||
|         { |         { | ||||||
|           activeMatch: '^/guide/', |           activeMatch: '^/guide/', | ||||||
|           link: '/guide/introduction/platform', |           link: '/guide/introduction/platform', | ||||||
|           text: '低代码平台', |           text: '低代码管理平台', | ||||||
|         }, |  | ||||||
|         { |  | ||||||
|           activeMatch: '^/materials/', |  | ||||||
|           link: '/materials/index', |  | ||||||
|           text: '物料', |  | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           activeMatch: '^/renderer/', |           activeMatch: '^/renderer/', | ||||||
| @ -186,6 +181,11 @@ function nav(): DefaultTheme.NavItem[] { | |||||||
|           link: '/designer/index', |           link: '/designer/index', | ||||||
|           text: '设计器', |           text: '设计器', | ||||||
|         }, |         }, | ||||||
|  |         { | ||||||
|  |           activeMatch: '^/materials/', | ||||||
|  |           link: '/materials/index', | ||||||
|  |           text: '物料', | ||||||
|  |         }, | ||||||
|       ], |       ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
| @ -203,7 +203,7 @@ function nav(): DefaultTheme.NavItem[] { | |||||||
|               text: '预发布版本', |               text: '预发布版本', | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|               link: 'https://www.vben.pro', |               link: 'https://y-code-platform.shiyuegame.com', | ||||||
|               text: '演示版本', |               text: '演示版本', | ||||||
|             }, |             }, | ||||||
|           ], |           ], | ||||||
| @ -223,12 +223,12 @@ function nav(): DefaultTheme.NavItem[] { | |||||||
|       text: version, |       text: version, | ||||||
|       items: [ |       items: [ | ||||||
|         { |         { | ||||||
|           link: 'https://github.com/vbenjs/vue-vben-admin/releases', |           link: './changelog', | ||||||
|           text: '更新日志', |           text: '更新日志', | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           link: 'https://doc.weixin.qq.com/smartsheet/s3_Aa0ASwZ0AOEr2TbPuaMRoCvs1yzjA?scode=AOwAYgeoAAkoT6VFa0Aa0ASwZ0AOE&tab=q979lj&viewId=vpDUFs', |           link: 'https://doc.weixin.qq.com/smartsheet/s3_Aa0ASwZ0AOEr2TbPuaMRoCvs1yzjA?scode=AOwAYgeoAAkoT6VFa0Aa0ASwZ0AOE&tab=q979lj&viewId=vpDUFs', | ||||||
|           text: '路线图', |           text: '更新路线图', | ||||||
|         }, |         }, | ||||||
|       ], |       ], | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -1,70 +1,24 @@ | |||||||
| # 基础概念 | # 基础概念 | ||||||
| 
 | 
 | ||||||
| 新版本中,整体工程进行了重构,现在我们将会介绍一些基础概念,以便于你更好的理解整个文档。请务必仔细阅读这一部分。 | ## 低代码引擎 | ||||||
| 
 | 
 | ||||||
| ## 大仓 | 新版本中,悦码整体进行了重构,现在我们将会介绍一些基础概念,以便于你更好的理解悦码是如何工作的。请务必仔细阅读这一部分。 | ||||||
| 
 | 
 | ||||||
| 大仓指的是整个项目的仓库,包含了所有的代码、包、应用、规范、文档、配置等,也就是一整个 `Monorepo` 目录的所有内容。 | ## 悦码中的 DSL (领域特定语言) | ||||||
| 
 | 
 | ||||||
| ## 应用 | > DSL (Domain-Specific Language,领域特定语言) 在低代码平台中是一种专门设计用来描述和定义应用程序特定方面的语言或表达方式。 | ||||||
| 
 | 
 | ||||||
| 应用指的是一个完整的项目,一个项目可以包含多个应用,这些项目可以复用大仓内的代码、包、规范等。应用都被放置在 `apps` 目录下。每个应用都是独立的,可以单独运行、构建、测试、部署,可以引入不同的组件库等等。 | 核心特点: | ||||||
| 
 | 
 | ||||||
| ::: tip | - 专注于特定领域:DSL 专门针对特定问题域设计,如 UI 布局、工作流定义、数据模型等。 | ||||||
|  | - 声明式而非命令式:通常使用声明式语法描述"做什么"而非"怎么做"。 | ||||||
|  | - 抽象层次高:隐藏底层实现细节,让用户专注于业务逻辑。 | ||||||
|  | - 结构化数据格式:通常使用 JSON、YAML 或 XML 等格式表示。 | ||||||
| 
 | 
 | ||||||
| 应用不限于前端应用,也可以是后端应用、移动端应用等,例如 `apps/backend-mock`就是一个后端服务。 | 主要作用: | ||||||
| 
 | 
 | ||||||
| ::: | - 抽象复杂性:将复杂的编程概念转化为领域专家能理解的表达方式。 | ||||||
| 
 | - 提高效率:通过声明式语法快速构建应用,减少编码工作。 | ||||||
| ## 包 | - 标准化:为应用开发提供统一的描述方式,便于团队协作。 | ||||||
| 
 | - 可视化编辑:DSL 通常可以通过可视化编辑器生成和修改,无需直接编写。 | ||||||
| 包指的是一个独立的模块,可以是一个组件、一个工具、一个库等。包可以被多个应用引用,也可以被其他包引用。包都被放置在 `packages` 目录下。 | - 跨平台兼容:同一套 DSL 可以被转译为不同平台的代码。 | ||||||
| 
 |  | ||||||
| 对于这些包,你可以把它看作是一个独立的 `npm` 包,使用方式与 `npm` 包一样。 |  | ||||||
| 
 |  | ||||||
| ### 包引入 |  | ||||||
| 
 |  | ||||||
| 在 `package.json` 中引入包: |  | ||||||
| 
 |  | ||||||
| ```json {3} |  | ||||||
| { |  | ||||||
|   "dependencies": { |  | ||||||
|     "@vben/utils": "workspace:*" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 包使用 |  | ||||||
| 
 |  | ||||||
| 在代码中引入包: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import { isString } from '@vben/utils'; |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## 别名 |  | ||||||
| 
 |  | ||||||
| 在项目中,你可以看到一些 `#` 开头的路径,例如: `#/api`、`#/views`, 这些路径都是别名,用于快速定位到某个目录。它不是通过 `vite` 的 `alias` 实现的,而是通过 `Node.js` 本身的 [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) 原理。只需要在 `package.json` 中配置 `imports` 字段即可。 |  | ||||||
| 
 |  | ||||||
| ```json {3} |  | ||||||
| { |  | ||||||
|   "imports": { |  | ||||||
|     "#/*": "./src/*" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 为了 IDE 能够识别这些别名,我们还需要在`tsconfig.json`内配置: |  | ||||||
| 
 |  | ||||||
| ```json {5} |  | ||||||
| { |  | ||||||
|   "compilerOptions": { |  | ||||||
|     "baseUrl": ".", |  | ||||||
|     "paths": { |  | ||||||
|       "#/*": ["src/*"] |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 这样,你就可以在代码中使用别名了。 |  | ||||||
|  | |||||||
| @ -1,188 +1 @@ | |||||||
| # 本地开发 {#development} | # 本地开发 {#development} | ||||||
| 
 |  | ||||||
| ::: tip 代码获取 |  | ||||||
| 
 |  | ||||||
| 如果你还没有获取代码,可以先从 [快速开始](../introduction/quick-start.md) 处开始阅读文档。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ## 前置准备 |  | ||||||
| 
 |  | ||||||
| 为了更好的开发体验,我们提供了一些工具配置、项目说明,以便于您更好的开发。 |  | ||||||
| 
 |  | ||||||
| ### 需要掌握的基础知识 |  | ||||||
| 
 |  | ||||||
| 本项目需要一定前端基础知识,请确保掌握 Vue 的基础知识,以便能处理一些常见的问题。建议在开发前先学一下以下内容,提前了解和学习这些知识,会对项目理解非常有帮助: |  | ||||||
| 
 |  | ||||||
| - [Vue3](https://vuejs.org/) |  | ||||||
| - [Tailwind CSS](https://tailwindcss.com/) |  | ||||||
| - [TypeScript](https://www.typescriptlang.org/) |  | ||||||
| - [Vue Router](https://router.vuejs.org/) |  | ||||||
| - [Vitejs](https://vitejs.dev/) |  | ||||||
| - [Pnpm](https://pnpm.io/) |  | ||||||
| - [Turbo](https://turbo.build/) |  | ||||||
| 
 |  | ||||||
| ### 工具配置 |  | ||||||
| 
 |  | ||||||
| 如果您使用的 IDE 是[vscode](https://code.visualstudio.com/)(推荐)的话,可以安装以下工具来提高开发效率及代码格式化: |  | ||||||
| 
 |  | ||||||
| - [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) - Vue 官方插件(必备)。 |  | ||||||
| - [Tailwind CSS](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) - Tailwindcss 提示插件。 |  | ||||||
| - [CSS Variable Autocomplete](https://marketplace.visualstudio.com/items?itemName=bradlc.vunguyentuan.vscode-css-variables) - Css 变量提示插件。 |  | ||||||
| - [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) - Iconify 图标插件 |  | ||||||
| - [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) - i18n 插件 |  | ||||||
| - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - 脚本代码检查 |  | ||||||
| - [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - 代码格式化 |  | ||||||
| - [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - css 格式化 |  | ||||||
| - [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - 单词语法检查 |  | ||||||
| - [DotENV](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv) - .env 文件 高亮 |  | ||||||
| 
 |  | ||||||
| ## Npm Scripts |  | ||||||
| 
 |  | ||||||
| npm 脚本是项目常见的配置,用于执行一些常见的任务,比如启动项目、打包项目等。以下的脚本都可以在项目根目录的 `package.json` 文件中找到。 |  | ||||||
| 
 |  | ||||||
| 执行方式为:`pnpm run [script]` 或 `npm run [script]`。 |  | ||||||
| 
 |  | ||||||
| ```json |  | ||||||
| { |  | ||||||
|   "scripts": { |  | ||||||
|     // 构建项目 |  | ||||||
|     "build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build", |  | ||||||
|     // 构建项目并分析 |  | ||||||
|     "build:analyze": "turbo build:analyze", |  | ||||||
|     // 构建本地 docker 镜像 |  | ||||||
|     "build:docker": "./build-local-docker-image.sh", |  | ||||||
|     // 单独构建 web-antd 应用 |  | ||||||
|     "build:antd": "pnpm run build --filter=@vben/web-antd", |  | ||||||
|     // 单独构建文档 |  | ||||||
|     "build:docs": "pnpm run build --filter=@vben/docs", |  | ||||||
|     // 单独构建 web-ele 应用 |  | ||||||
|     "build:ele": "pnpm run build --filter=@vben/web-ele", |  | ||||||
|     // 单独构建 web-naive 应用 |  | ||||||
|     "build:naive": "pnpm run build --filter=@vben/naive", |  | ||||||
|     // 单独构建 playground 应用 |  | ||||||
|     "build:play": "pnpm run build --filter=@vben/playground", |  | ||||||
|     // changeset 版本管理 |  | ||||||
|     "changeset": "pnpm exec changeset", |  | ||||||
|     // 检查项目各种问题 |  | ||||||
|     "check": "pnpm run check:circular && pnpm run check:dep && pnpm run check:type && pnpm check:cspell", |  | ||||||
|     // 检查循环引用 |  | ||||||
|     "check:circular": "vsh check-circular", |  | ||||||
|     // 检查拼写 |  | ||||||
|     "check:cspell": "cspell lint **/*.ts **/README.md .changeset/*.md --no-progress" |  | ||||||
|     // 检查依赖 |  | ||||||
|     "check:dep": "vsh check-dep", |  | ||||||
|     // 检查类型 |  | ||||||
|     "check:type": "turbo run typecheck", |  | ||||||
|     // 清理项目(删除node_modules、dist、.turbo)等目录 |  | ||||||
|     "clean": "node ./scripts/clean.mjs", |  | ||||||
|     // 提交代码 |  | ||||||
|     "commit": "czg", |  | ||||||
|     // 启动项目(默认会运行整个仓库所有包的dev脚本) |  | ||||||
|     "dev": "turbo-run dev", |  | ||||||
|     // 启动web-antd应用 |  | ||||||
|     "dev:antd": "pnpm -F @vben/web-antd run dev", |  | ||||||
|     // 启动文档 |  | ||||||
|     "dev:docs": "pnpm -F @vben/docs run dev", |  | ||||||
|     // 启动web-ele应用 |  | ||||||
|     "dev:ele": "pnpm -F @vben/web-ele run dev", |  | ||||||
|     // 启动web-naive应用 |  | ||||||
|     "dev:naive": "pnpm -F @vben/web-naive run dev", |  | ||||||
|     // 启动演示应用 |  | ||||||
|     "dev:play": "pnpm -F @vben/playground run dev", |  | ||||||
|     // 格式化代码 |  | ||||||
|     "format": "vsh lint --format", |  | ||||||
|     // lint 代码 |  | ||||||
|     "lint": "vsh lint", |  | ||||||
|     // 依赖安装完成之后,执行所有包的stub脚本 |  | ||||||
|     "postinstall": "pnpm -r run stub --if-present", |  | ||||||
|     // 只允许使用pnpm |  | ||||||
|     "preinstall": "npx only-allow pnpm", |  | ||||||
|     // husky的安装 |  | ||||||
|     "prepare": "is-ci || husky", |  | ||||||
|     // 预览应用 |  | ||||||
|     "preview": "turbo-run preview", |  | ||||||
|     // 包规范检查 |  | ||||||
|     "publint": "vsh publint", |  | ||||||
|     // 删除所有的node_modules、yarn.lock、package.lock.json,重新安装依赖 |  | ||||||
|     "reinstall": "pnpm clean --del-lock && pnpm install", |  | ||||||
|     // 运行 vitest 单元测试 |  | ||||||
|     "test:unit": "vitest run --dom", |  | ||||||
|     // 更新项目依赖 |  | ||||||
|     "update:deps": " pnpm update --latest --recursive", |  | ||||||
|     // changeset生成提交集 |  | ||||||
|     "version": "pnpm exec changeset version && pnpm install --no-frozen-lockfile" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## 本地运行项目 |  | ||||||
| 
 |  | ||||||
| 如需本地运行文档,并进行调整,可以执行以下命令,执行该命令,你可以选择需要的应用进行开发: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| pnpm dev |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 如果你想直接运行某个应用,可以执行以下命令: |  | ||||||
| 
 |  | ||||||
| 运行 `web-antd` 应用: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| pnpm dev:antd |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 运行 `web-naive` 应用: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| pnpm dev:naive |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 运行 `web-ele` 应用: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| pnpm dev:ele |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 运行 `docs` 应用: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| pnpm dev:docs |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## 公共静态资源 |  | ||||||
| 
 |  | ||||||
| 项目中需要使用到的公共静态资源,如:图片、静态HTML等,需要在开发中通过 `src="/xxx.png"` 直接引入的。 |  | ||||||
| 
 |  | ||||||
| 需要将资源放在对应项目的 `public/static` 目录下。引入的路径为:`src="/static/xxx.png"`。 |  | ||||||
| 
 |  | ||||||
| ## DevTools |  | ||||||
| 
 |  | ||||||
| 项目内置了 [Vue DevTools](https://github.com/vuejs/devtools-next) 插件,可以在开发过程中使用。默认关闭,可在`.env.development` 内开启,并重新运行项目即可: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| VITE_DEVTOOLS=true |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 开启后,项目运行会在页面底部显示一个 Vue DevTools 的图标,点击即可打开 DevTools。 |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
| 
 |  | ||||||
| ## 本地运行文档 |  | ||||||
| 
 |  | ||||||
| 如需本地运行文档,并进行调整,可以执行以下命令: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| pnpm dev:docs |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## 问题解决 |  | ||||||
| 
 |  | ||||||
| 如果你在使用过程中遇到依赖相关的问题,可以尝试以下重新安装依赖: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| # 请在项目根目录下执行 |  | ||||||
| # 该命令会删除整个仓库所有的 node_modules、yarn.lock、package.lock.json后 |  | ||||||
| # 再进行依赖重新安装(安装速度会明显变慢)。 |  | ||||||
| pnpm reinstall |  | ||||||
| ``` |  | ||||||
|  | |||||||
| @ -1,58 +1 @@ | |||||||
| # 外部模块 | # 外部模块 | ||||||
| 
 |  | ||||||
| 除了项目默认引入的外部模块,有时我们还需要引入其他外部模块。我们以 [ant-design-vue](https://antdv.com/components/overview) 为例: |  | ||||||
| 
 |  | ||||||
| ## 安装依赖 |  | ||||||
| 
 |  | ||||||
| ::: tip 安装依赖到指定包 |  | ||||||
| 
 |  | ||||||
| - 由于项目采用了 [pnpm](https://pnpm.io/) 作为包管理工具,所以我们需要使用 `pnpm` 命令来安装依赖。 |  | ||||||
| - 通过采用了 Monorepo 模块来管理项目,所以我们需要在指定包下安装依赖。安装依赖前请确保已经进入到指定包目录下。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| # cd /path/to/your/package |  | ||||||
| pnpm add ant-design-vue |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## 使用 |  | ||||||
| 
 |  | ||||||
| ### 全局引入 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import { createApp } from 'vue'; |  | ||||||
| import Antd from 'ant-design-vue'; |  | ||||||
| import App from './App'; |  | ||||||
| import 'ant-design-vue/dist/reset.css'; |  | ||||||
| 
 |  | ||||||
| const app = createApp(App); |  | ||||||
| 
 |  | ||||||
| app.use(Antd).mount('#app'); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| #### 使用 |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <template> |  | ||||||
|   <a-button>text</a-button> |  | ||||||
| </template> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 局部引入 |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { Button } from 'ant-design-vue'; |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <template> |  | ||||||
|   <Button>text</Button> |  | ||||||
| </template> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: warning 注意 |  | ||||||
| 
 |  | ||||||
| - 如果组件有依赖样式,则需要再引入样式文件 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
|  | |||||||
| @ -1,78 +1 @@ | |||||||
| # 图标 | # icons | ||||||
| 
 |  | ||||||
| ::: tip 关于图标的管理 |  | ||||||
| 
 |  | ||||||
| - 项目的图标主要由`@vben/icons`包提供,建议统一在该包内部管理,以便于统一管理和维护。 |  | ||||||
| - 如果你使用的是 `Vscode`,推荐安装 [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) 插件,可以方便的查找和使用图标。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| 项目中有以下多种图标使用方式,可以根据实际情况选择使用: |  | ||||||
| 
 |  | ||||||
| ## Iconify 图标 <Badge text="推荐" type="tip"/> |  | ||||||
| 
 |  | ||||||
| 集成了 [iconify](https://github.com/iconify/iconify) 图标库 |  | ||||||
| 
 |  | ||||||
| ### 新增 |  | ||||||
| 
 |  | ||||||
| 可在 `packages/icons/src/iconify` 目录下新增图标: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| // packages/icons/src/iconify/index.ts |  | ||||||
| import { createIconifyIcon } from '@vben-core/icons'; |  | ||||||
| 
 |  | ||||||
| export const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc'); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 使用 |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { MdiKeyboardEsc } from '@vben/icons'; |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <template> |  | ||||||
|   <!-- 一个宽高为20px的图标 --> |  | ||||||
|   <MdiKeyboardEsc class="size-5" /> |  | ||||||
| </template> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## Svg 图标 <Badge text="推荐" type="tip"/> |  | ||||||
| 
 |  | ||||||
| 没有采用 Svg Sprite 的方式,而是直接引入 Svg 图标, |  | ||||||
| 
 |  | ||||||
| ### 新增 |  | ||||||
| 
 |  | ||||||
| 可以在 `packages/icons/src/svg/icons` 目录下新增图标文件`test.svg`, 然后在 `packages/icons/src/svg/index.ts` 中引入: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| // packages/icons/src/svg/index.ts |  | ||||||
| import { createIconifyIcon } from '@vben-core/icons'; |  | ||||||
| 
 |  | ||||||
| const SvgTestIcon = createIconifyIcon('svg:test'); |  | ||||||
| 
 |  | ||||||
| export { SvgTestIcon }; |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 使用 |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { SvgTestIcon } from '@vben/icons'; |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <template> |  | ||||||
|   <!-- 一个宽高为20px的图标 --> |  | ||||||
|   <SvgTestIcon class="size-5" /> |  | ||||||
| </template> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## Tailwind CSS 图标 |  | ||||||
| 
 |  | ||||||
| ### 使用 |  | ||||||
| 
 |  | ||||||
| 直接添加 Tailwind CSS 的图标类名即可使用,图标类名可查看 [iconify](https://github.com/iconify/iconify) : |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <span class="icon-[mdi--ab-testing]"></span> |  | ||||||
| ``` |  | ||||||
|  | |||||||
| @ -1,604 +1 @@ | |||||||
| --- | # route | ||||||
| outline: deep |  | ||||||
| --- |  | ||||||
| 
 |  | ||||||
| # 路由和菜单 |  | ||||||
| 
 |  | ||||||
| 在项目中,框架提供了一套基础的路由系统,并**根据路由文件自动生成对应的菜单结构**。 |  | ||||||
| 
 |  | ||||||
| ## 路由类型 |  | ||||||
| 
 |  | ||||||
| 路由分为核心路由、静态路由和动态路由,核心路由是框架内置的路由,包含了根路由、登录路由、404路由等;静态路由是在项目启动时就已经确定的路由;动态路由一般是在用户登录后,根据用户的权限动态生成的路由。 |  | ||||||
| 
 |  | ||||||
| 静态路由和动态路由都会走权限控制,可以通过配置路由的 `meta` 属性中的 `authority` 字段来控制权限,可以参考[路由权限控制](https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/router/routes/modules/demos.ts)。 |  | ||||||
| 
 |  | ||||||
| ### 核心路由 |  | ||||||
| 
 |  | ||||||
| 核心路由是框架内置的路由,包含了根路由、登录路由、404路由等,核心路由的配置在应用下 `src/router/routes/core` 目录下 |  | ||||||
| 
 |  | ||||||
| ::: tip |  | ||||||
| 
 |  | ||||||
| 核心路由主要用于框架的基础功能,因此不建议将业务相关的路由放在核心路由中,推荐将业务相关的路由放在静态路由或动态路由中。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ### 静态路由 |  | ||||||
| 
 |  | ||||||
| 静态路由的配置在应用下 `src/router/routes/index` 目录下,打开注释的文件内容: |  | ||||||
| 
 |  | ||||||
| ::: tip |  | ||||||
| 
 |  | ||||||
| 权限控制是通过路由的 `meta` 属性中的 `authority` 字段来控制的,如果你的页面项目不需要权限控制,可以不设置 `authority` 字段。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| // 有需要可以自行打开注释,并创建文件夹 |  | ||||||
| // const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true }); // [!code --] |  | ||||||
| const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true }); // [!code ++] |  | ||||||
| /** 动态路由 */ |  | ||||||
| const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles); |  | ||||||
| 
 |  | ||||||
| /** 外部路由列表,访问这些页面可以不需要Layout,可能用于内嵌在别的系统 */ |  | ||||||
| // const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles) // [!code --] |  | ||||||
| const externalRoutes: RouteRecordRaw[] = []; // [!code --] |  | ||||||
| const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles); // [!code ++] |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 动态路由 |  | ||||||
| 
 |  | ||||||
| 动态路由的配置在对应应用 `src/router/routes/modules` 目录下,这个目录下存放了所有的路由文件。每个文件的内容格式如下,与 Vue Router 的路由配置格式一致,以下为二级路由和多级路由的配置。 |  | ||||||
| 
 |  | ||||||
| ## 路由定义 |  | ||||||
| 
 |  | ||||||
| 静态路由与动态路由的配置方式一致,以下为二级路由和多级路由的配置: |  | ||||||
| 
 |  | ||||||
| ### 二级路由 |  | ||||||
| 
 |  | ||||||
| ::: details 二级路由示例代码 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import type { RouteRecordRaw } from 'vue-router'; |  | ||||||
| 
 |  | ||||||
| import { VBEN_LOGO_URL } from '@vben/constants'; |  | ||||||
| 
 |  | ||||||
| import { $t } from '#/locales'; |  | ||||||
| 
 |  | ||||||
| const routes: RouteRecordRaw[] = [ |  | ||||||
|   { |  | ||||||
|     meta: { |  | ||||||
|       badgeType: 'dot', |  | ||||||
|       badgeVariants: 'destructive', |  | ||||||
|       icon: VBEN_LOGO_URL, |  | ||||||
|       order: 9999, |  | ||||||
|       title: $t('page.vben.title'), |  | ||||||
|     }, |  | ||||||
|     name: 'VbenProject', |  | ||||||
|     path: '/vben-admin', |  | ||||||
|     redirect: '/vben-admin/about', |  | ||||||
|     children: [ |  | ||||||
|       { |  | ||||||
|         name: 'VbenAbout', |  | ||||||
|         path: '/vben-admin/about', |  | ||||||
|         component: () => import('#/views/_core/about/index.vue'), |  | ||||||
|         meta: { |  | ||||||
|           badgeType: 'dot', |  | ||||||
|           badgeVariants: 'destructive', |  | ||||||
|           icon: 'lucide:copyright', |  | ||||||
|           title: $t('page.vben.about'), |  | ||||||
|         }, |  | ||||||
|       }, |  | ||||||
|     ], |  | ||||||
|   }, |  | ||||||
| ]; |  | ||||||
| 
 |  | ||||||
| export default routes; |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ### 多级路由 |  | ||||||
| 
 |  | ||||||
| ::: tip |  | ||||||
| 
 |  | ||||||
| - 如果没有特殊情况,父级路由的 `redirect` 属性,不需要指定,默认会指向第一个子路由。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ::: details 多级路由示例代码 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import type { RouteRecordRaw } from 'vue-router'; |  | ||||||
| 
 |  | ||||||
| import { $t } from '#/locales'; |  | ||||||
| 
 |  | ||||||
| const routes: RouteRecordRaw[] = [ |  | ||||||
|   { |  | ||||||
|     meta: { |  | ||||||
|       icon: 'ic:baseline-view-in-ar', |  | ||||||
|       keepAlive: true, |  | ||||||
|       order: 1000, |  | ||||||
|       title: $t('demos.title'), |  | ||||||
|     }, |  | ||||||
|     name: 'Demos', |  | ||||||
|     path: '/demos', |  | ||||||
|     redirect: '/demos/access', |  | ||||||
|     children: [ |  | ||||||
|       // 嵌套菜单 |  | ||||||
|       { |  | ||||||
|         meta: { |  | ||||||
|           icon: 'ic:round-menu', |  | ||||||
|           title: $t('demos.nested.title'), |  | ||||||
|         }, |  | ||||||
|         name: 'NestedDemos', |  | ||||||
|         path: '/demos/nested', |  | ||||||
|         redirect: '/demos/nested/menu1', |  | ||||||
|         children: [ |  | ||||||
|           { |  | ||||||
|             name: 'Menu1Demo', |  | ||||||
|             path: '/demos/nested/menu1', |  | ||||||
|             component: () => import('#/views/demos/nested/menu-1.vue'), |  | ||||||
|             meta: { |  | ||||||
|               icon: 'ic:round-menu', |  | ||||||
|               keepAlive: true, |  | ||||||
|               title: $t('demos.nested.menu1'), |  | ||||||
|             }, |  | ||||||
|           }, |  | ||||||
|           { |  | ||||||
|             name: 'Menu2Demo', |  | ||||||
|             path: '/demos/nested/menu2', |  | ||||||
|             meta: { |  | ||||||
|               icon: 'ic:round-menu', |  | ||||||
|               keepAlive: true, |  | ||||||
|               title: $t('demos.nested.menu2'), |  | ||||||
|             }, |  | ||||||
|             redirect: '/demos/nested/menu2/menu2-1', |  | ||||||
|             children: [ |  | ||||||
|               { |  | ||||||
|                 name: 'Menu21Demo', |  | ||||||
|                 path: '/demos/nested/menu2/menu2-1', |  | ||||||
|                 component: () => import('#/views/demos/nested/menu-2-1.vue'), |  | ||||||
|                 meta: { |  | ||||||
|                   icon: 'ic:round-menu', |  | ||||||
|                   keepAlive: true, |  | ||||||
|                   title: $t('demos.nested.menu2_1'), |  | ||||||
|                 }, |  | ||||||
|               }, |  | ||||||
|             ], |  | ||||||
|           }, |  | ||||||
|           { |  | ||||||
|             name: 'Menu3Demo', |  | ||||||
|             path: '/demos/nested/menu3', |  | ||||||
|             meta: { |  | ||||||
|               icon: 'ic:round-menu', |  | ||||||
|               title: $t('demos.nested.menu3'), |  | ||||||
|             }, |  | ||||||
|             redirect: '/demos/nested/menu3/menu3-1', |  | ||||||
|             children: [ |  | ||||||
|               { |  | ||||||
|                 name: 'Menu31Demo', |  | ||||||
|                 path: 'menu3-1', |  | ||||||
|                 component: () => import('#/views/demos/nested/menu-3-1.vue'), |  | ||||||
|                 meta: { |  | ||||||
|                   icon: 'ic:round-menu', |  | ||||||
|                   keepAlive: true, |  | ||||||
|                   title: $t('demos.nested.menu3_1'), |  | ||||||
|                 }, |  | ||||||
|               }, |  | ||||||
|               { |  | ||||||
|                 name: 'Menu32Demo', |  | ||||||
|                 path: 'menu3-2', |  | ||||||
|                 meta: { |  | ||||||
|                   icon: 'ic:round-menu', |  | ||||||
|                   title: $t('demos.nested.menu3_2'), |  | ||||||
|                 }, |  | ||||||
|                 redirect: '/demos/nested/menu3/menu3-2/menu3-2-1', |  | ||||||
|                 children: [ |  | ||||||
|                   { |  | ||||||
|                     name: 'Menu321Demo', |  | ||||||
|                     path: '/demos/nested/menu3/menu3-2/menu3-2-1', |  | ||||||
|                     component: () => |  | ||||||
|                       import('#/views/demos/nested/menu-3-2-1.vue'), |  | ||||||
|                     meta: { |  | ||||||
|                       icon: 'ic:round-menu', |  | ||||||
|                       keepAlive: true, |  | ||||||
|                       title: $t('demos.nested.menu3_2_1'), |  | ||||||
|                     }, |  | ||||||
|                   }, |  | ||||||
|                 ], |  | ||||||
|               }, |  | ||||||
|             ], |  | ||||||
|           }, |  | ||||||
|         ], |  | ||||||
|       }, |  | ||||||
|     ], |  | ||||||
|   }, |  | ||||||
| ]; |  | ||||||
| 
 |  | ||||||
| export default routes; |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ## 新增页面 |  | ||||||
| 
 |  | ||||||
| 新增一个页面,你只需要添加一个路由及对应的页面组件即可。 |  | ||||||
| 
 |  | ||||||
| ### 添加路由 |  | ||||||
| 
 |  | ||||||
| 在对应的路由文件中添加一个路由对象,如下: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import type { RouteRecordRaw } from 'vue-router'; |  | ||||||
| 
 |  | ||||||
| import { VBEN_LOGO_URL } from '@vben/constants'; |  | ||||||
| 
 |  | ||||||
| import { $t } from '#/locales'; |  | ||||||
| 
 |  | ||||||
| const routes: RouteRecordRaw[] = [ |  | ||||||
|   { |  | ||||||
|     meta: { |  | ||||||
|       icon: 'mdi:home', |  | ||||||
|       title: $t('page.home.title'), |  | ||||||
|     }, |  | ||||||
|     name: 'Home', |  | ||||||
|     path: '/home', |  | ||||||
|     redirect: '/home/index', |  | ||||||
|     children: [ |  | ||||||
|       { |  | ||||||
|         name: 'HomeIndex', |  | ||||||
|         path: '/home/index', |  | ||||||
|         component: () => import('#/views/home/index.vue'), |  | ||||||
|         meta: { |  | ||||||
|           icon: 'mdi:home', |  | ||||||
|           title: $t('page.home.index'), |  | ||||||
|         }, |  | ||||||
|       }, |  | ||||||
|     ], |  | ||||||
|   }, |  | ||||||
| ]; |  | ||||||
| 
 |  | ||||||
| export default routes; |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 添加页面组件 |  | ||||||
| 
 |  | ||||||
| 在`#/views/home/`下,新增一个`index.vue`文件,如下: |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <template> |  | ||||||
|   <div> |  | ||||||
|     <h1>home page</h1> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 验证 |  | ||||||
| 
 |  | ||||||
| 到这里页面已添加完成,访问 `http://localhost:5555/home/index` 出现对应的页面即可。 |  | ||||||
| 
 |  | ||||||
| ## 路由配置 |  | ||||||
| 
 |  | ||||||
| 路由配置项主要在对象路由的 `meta` 属性中,以下为常用的配置项: |  | ||||||
| 
 |  | ||||||
| ```ts {5-8} |  | ||||||
| const routes = [ |  | ||||||
|   { |  | ||||||
|     name: 'HomeIndex', |  | ||||||
|     path: '/home/index', |  | ||||||
|     meta: { |  | ||||||
|       icon: 'mdi:home', |  | ||||||
|       title: $t('page.home.index'), |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
| ]; |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: details 路由Meta配置类型定义 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| interface RouteMeta { |  | ||||||
|   /** |  | ||||||
|    * 激活图标(菜单) |  | ||||||
|    */ |  | ||||||
|   activeIcon?: string; |  | ||||||
|   /** |  | ||||||
|    * 当前激活的菜单,有时候不想激活现有菜单,需要激活父级菜单时使用 |  | ||||||
|    */ |  | ||||||
|   activePath?: string; |  | ||||||
|   /** |  | ||||||
|    * 是否固定标签页 |  | ||||||
|    * @default false |  | ||||||
|    */ |  | ||||||
|   affixTab?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 固定标签页的顺序 |  | ||||||
|    * @default 0 |  | ||||||
|    */ |  | ||||||
|   affixTabOrder?: number; |  | ||||||
|   /** |  | ||||||
|    * 需要特定的角色标识才可以访问 |  | ||||||
|    * @default [] |  | ||||||
|    */ |  | ||||||
|   authority?: string[]; |  | ||||||
|   /** |  | ||||||
|    * 徽标 |  | ||||||
|    */ |  | ||||||
|   badge?: string; |  | ||||||
|   /** |  | ||||||
|    * 徽标类型 |  | ||||||
|    */ |  | ||||||
|   badgeType?: 'dot' | 'normal'; |  | ||||||
|   /** |  | ||||||
|    * 徽标颜色 |  | ||||||
|    */ |  | ||||||
|   badgeVariants?: |  | ||||||
|     | 'default' |  | ||||||
|     | 'destructive' |  | ||||||
|     | 'primary' |  | ||||||
|     | 'success' |  | ||||||
|     | 'warning' |  | ||||||
|     | string; |  | ||||||
|   /** |  | ||||||
|    * 当前路由的子级在菜单中不展现 |  | ||||||
|    * @default false |  | ||||||
|    */ |  | ||||||
|   hideChildrenInMenu?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 当前路由在面包屑中不展现 |  | ||||||
|    * @default false |  | ||||||
|    */ |  | ||||||
|   hideInBreadcrumb?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 当前路由在菜单中不展现 |  | ||||||
|    * @default false |  | ||||||
|    */ |  | ||||||
|   hideInMenu?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 当前路由在标签页不展现 |  | ||||||
|    * @default false |  | ||||||
|    */ |  | ||||||
|   hideInTab?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 图标(菜单/tab) |  | ||||||
|    */ |  | ||||||
|   icon?: string; |  | ||||||
|   /** |  | ||||||
|    * iframe 地址 |  | ||||||
|    */ |  | ||||||
|   iframeSrc?: string; |  | ||||||
|   /** |  | ||||||
|    * 忽略权限,直接可以访问 |  | ||||||
|    * @default false |  | ||||||
|    */ |  | ||||||
|   ignoreAccess?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 开启KeepAlive缓存 |  | ||||||
|    */ |  | ||||||
|   keepAlive?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 外链-跳转路径 |  | ||||||
|    */ |  | ||||||
|   link?: string; |  | ||||||
|   /** |  | ||||||
|    * 路由是否已经加载过 |  | ||||||
|    */ |  | ||||||
|   loaded?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 标签页最大打开数量 |  | ||||||
|    * @default false |  | ||||||
|    */ |  | ||||||
|   maxNumOfOpenTab?: number; |  | ||||||
|   /** |  | ||||||
|    * 菜单可以看到,但是访问会被重定向到403 |  | ||||||
|    */ |  | ||||||
|   menuVisibleWithForbidden?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 当前路由不使用基础布局(仅在顶级生效) |  | ||||||
|    */ |  | ||||||
|   noBasicLayout?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 在新窗口打开 |  | ||||||
|    */ |  | ||||||
|   openInNewWindow?: boolean; |  | ||||||
|   /** |  | ||||||
|    * 用于路由->菜单排序 |  | ||||||
|    */ |  | ||||||
|   order?: number; |  | ||||||
|   /** |  | ||||||
|    * 菜单所携带的参数 |  | ||||||
|    */ |  | ||||||
|   query?: Recordable; |  | ||||||
|   /** |  | ||||||
|    * 标题名称 |  | ||||||
|    */ |  | ||||||
|   title: string; |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ### title |  | ||||||
| 
 |  | ||||||
| - 类型:`string` |  | ||||||
| - 默认值:`''` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的标题,会在菜单和标签页中显示。一般会配合国际化使用。 |  | ||||||
| 
 |  | ||||||
| ### icon |  | ||||||
| 
 |  | ||||||
| - 类型:`string` |  | ||||||
| - 默认值:`''` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的图标,会在菜单和标签页中显示。一般会配合图标库使用,如果是`http`链接,会自动加载图片。 |  | ||||||
| 
 |  | ||||||
| ### activeIcon |  | ||||||
| 
 |  | ||||||
| - 类型:`string` |  | ||||||
| - 默认值:`''` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的激活图标,会在菜单中显示。一般会配合图标库使用,如果是`http`链接,会自动加载图片。 |  | ||||||
| 
 |  | ||||||
| ### keepAlive |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 用于配置页面是否开启缓存,开启后页面会缓存,不会重新加载,仅在标签页启用时有效。 |  | ||||||
| 
 |  | ||||||
| ### hideInMenu |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 用于配置页面是否在菜单中隐藏,隐藏后页面不会在菜单中显示。 |  | ||||||
| 
 |  | ||||||
| ### hideInTab |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 用于配置页面是否在标签页中隐藏,隐藏后页面不会在标签页中显示。 |  | ||||||
| 
 |  | ||||||
| ### hideInBreadcrumb |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 用于配置页面是否在面包屑中隐藏,隐藏后页面不会在面包屑中显示。 |  | ||||||
| 
 |  | ||||||
| ### hideChildrenInMenu |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的子页面是否在菜单中隐藏,隐藏后子页面不会在菜单中显示。 |  | ||||||
| 
 |  | ||||||
| ### authority |  | ||||||
| 
 |  | ||||||
| - 类型:`string[]` |  | ||||||
| - 默认值:`[]` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的权限,只有拥有对应权限的用户才能访问页面,不配置则不需要权限。 |  | ||||||
| 
 |  | ||||||
| ### badge |  | ||||||
| 
 |  | ||||||
| - 类型:`string` |  | ||||||
| - 默认值:`''` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的徽标,会在菜单显示。 |  | ||||||
| 
 |  | ||||||
| ### badgeType |  | ||||||
| 
 |  | ||||||
| - 类型:`'dot' | 'normal'` |  | ||||||
| - 默认值:`'normal'` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的徽标类型,`dot` 为小红点,`normal` 为文本。 |  | ||||||
| 
 |  | ||||||
| ### badgeVariants |  | ||||||
| 
 |  | ||||||
| - 类型:`'default' | 'destructive' | 'primary' | 'success' | 'warning' | string` |  | ||||||
| - 默认值:`'success'` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的徽标颜色。 |  | ||||||
| 
 |  | ||||||
| ### activePath |  | ||||||
| 
 |  | ||||||
| - 类型:`string` |  | ||||||
| - 默认值:`''` |  | ||||||
| 
 |  | ||||||
| 用于配置当前激活的菜单,有时候页面没有显示在菜单内,需要激活父级菜单时使用。 |  | ||||||
| 
 |  | ||||||
| ### affixTab |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 用于配置页面是否固定标签页,固定后页面不可关闭。 |  | ||||||
| 
 |  | ||||||
| ### affixTabOrder |  | ||||||
| 
 |  | ||||||
| - 类型:`number` |  | ||||||
| - 默认值:`0` |  | ||||||
| 
 |  | ||||||
| 用于配置页面固定标签页的排序, 采用升序排序。 |  | ||||||
| 
 |  | ||||||
| ### iframeSrc |  | ||||||
| 
 |  | ||||||
| - 类型:`string` |  | ||||||
| - 默认值:`''` |  | ||||||
| 
 |  | ||||||
| 用于配置内嵌页面的 `iframe` 地址,设置后会在当前页面内嵌对应的页面。 |  | ||||||
| 
 |  | ||||||
| ### ignoreAccess |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 用于配置页面是否忽略权限,直接可以访问。 |  | ||||||
| 
 |  | ||||||
| ### link |  | ||||||
| 
 |  | ||||||
| - 类型:`string` |  | ||||||
| - 默认值:`''` |  | ||||||
| 
 |  | ||||||
| 用于配置外链跳转路径,会在新窗口打开。 |  | ||||||
| 
 |  | ||||||
| ### maxNumOfOpenTab |  | ||||||
| 
 |  | ||||||
| - 类型:`number` |  | ||||||
| - 默认值:`-1` |  | ||||||
| 
 |  | ||||||
| 用于配置标签页最大打开数量,设置后会在打开新标签页时自动关闭最早打开的标签页(仅在打开同名标签页时生效)。 |  | ||||||
| 
 |  | ||||||
| ### menuVisibleWithForbidden |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 用于配置页面在菜单可以看到,但是访问会被重定向到403。 |  | ||||||
| 
 |  | ||||||
| ### openInNewWindow |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 设置为 `true` 时,会在新窗口打开页面。 |  | ||||||
| 
 |  | ||||||
| ### order |  | ||||||
| 
 |  | ||||||
| - 类型:`number` |  | ||||||
| - 默认值:`0` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的排序,用于路由到菜单排序。 |  | ||||||
| 
 |  | ||||||
| _注意:_ 排序仅针对一级菜单有效,二级菜单的排序需要在对应的一级菜单中按代码顺序设置。 |  | ||||||
| 
 |  | ||||||
| ### query |  | ||||||
| 
 |  | ||||||
| - 类型:`Recordable` |  | ||||||
| - 默认值:`{}` |  | ||||||
| 
 |  | ||||||
| 用于配置页面的菜单参数,会在菜单中传递给页面。 |  | ||||||
| 
 |  | ||||||
| ### noBasicLayout |  | ||||||
| 
 |  | ||||||
| - 类型:`boolean` |  | ||||||
| - 默认值:`false` |  | ||||||
| 
 |  | ||||||
| 用于配置当前路由不使用基础布局,仅在顶级时生效。默认情况下,所有的路由都会被包裹在基础布局中(包含顶部以及侧边等导航部件),如果你的页面不需要这些部件,可以设置 `noBasicLayout` 为 `true`。 |  | ||||||
| 
 |  | ||||||
| ## 路由刷新 |  | ||||||
| 
 |  | ||||||
| 路由刷新方式如下: |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { useRefresh } from '@vben/hooks'; |  | ||||||
| 
 |  | ||||||
| const { refresh } = useRefresh(); |  | ||||||
| 
 |  | ||||||
| // 刷新当前路由 |  | ||||||
| refresh(); |  | ||||||
| </script> |  | ||||||
| ``` |  | ||||||
|  | |||||||
| @ -1,357 +1 @@ | |||||||
| # 服务端交互与数据Mock | server | ||||||
| 
 |  | ||||||
| ::: tip 说明 |  | ||||||
| 
 |  | ||||||
| 本文档介绍如何在开发环境下使用 Mock 数据和与服务端进行交互,涉及到的技术有: |  | ||||||
| 
 |  | ||||||
| - [Nitro](https://nitro.unjs.io/) 轻量级后端服务器,可部署在任何地方,项目用作于 Mock 服务器。 |  | ||||||
| - [axios](https://axios-http.com/docs/intro) 用于发送 HTTP 请求与服务端进行交互。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ## 开发环境交互 |  | ||||||
| 
 |  | ||||||
| 如果前端应用和后端接口服务器没有运行在同一个主机上,你需要在开发环境下将接口请求代理到接口服务器。如果是同一个主机,可以直接请求具体的接口地址。 |  | ||||||
| 
 |  | ||||||
| ### 本地开发跨域配置 |  | ||||||
| 
 |  | ||||||
| ::: tip 提示 |  | ||||||
| 
 |  | ||||||
| 本地开发跨域配置项目已经配置好了,如有其他需求,可以自行增加或者调整配置。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| #### 配置本地开发接口地址 |  | ||||||
| 
 |  | ||||||
| 在项目根目录下的 `.env.development` 文件中配置接口地址,这里配置为 `/api`: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| VITE_GLOB_API_URL=/api |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| #### 配置开发服务器代理 |  | ||||||
| 
 |  | ||||||
| 开发环境时候,如果需要处理跨域,接口地址在对应的应用目录下的 `vite.config.mts` 文件中配置: |  | ||||||
| 
 |  | ||||||
| ```ts{8-16} |  | ||||||
| // apps/web-antd/vite.config.mts |  | ||||||
| import { defineConfig } from '@vben/vite-config'; |  | ||||||
| 
 |  | ||||||
| export default defineConfig(async () => { |  | ||||||
|   return { |  | ||||||
|     vite: { |  | ||||||
|       server: { |  | ||||||
|         proxy: {// [!code focus:11] |  | ||||||
|           '/api': { |  | ||||||
|             changeOrigin: true, |  | ||||||
|             rewrite: (path) => path.replace(/^\/api/, ''), |  | ||||||
|             // mock代理目标地址 |  | ||||||
|             target: 'http://localhost:5320/api', |  | ||||||
|             ws: true, |  | ||||||
|           }, |  | ||||||
|         }, |  | ||||||
|       }, |  | ||||||
|     }, |  | ||||||
|   }; |  | ||||||
| }); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| #### 接口请求 |  | ||||||
| 
 |  | ||||||
| 根据上面的配置,我们可以在前端项目中使用 `/api` 作为接口请求的前缀,例如: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import axios from 'axios'; |  | ||||||
| 
 |  | ||||||
| axios.get('/api/user').then((res) => { |  | ||||||
|   console.log(res); |  | ||||||
| }); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 此时,请求会被代理到 `http://localhost:5320/api/user`。 |  | ||||||
| 
 |  | ||||||
| ::: warning 注意 |  | ||||||
| 
 |  | ||||||
| 从浏览器控制台的 Network 看,请求是 `http://localhost:5555/api/user`, 这是因为 proxy 配置不会改变本地请求的 url。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ### 没有跨域时的配置 |  | ||||||
| 
 |  | ||||||
| 如果没有跨域问题,可以直接忽略 [配置开发服务器代理](./server.md#配置开发服务器代理) 配置,直接将接口地址设置在 `VITE_GLOB_API_URL` |  | ||||||
| 
 |  | ||||||
| 在项目根目录下的 `.env.development` 文件中配置接口地址: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| VITE_GLOB_API_URL=https://mock-napi.vben.pro/api |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## 生产环境交互 |  | ||||||
| 
 |  | ||||||
| ### 接口地址配置 |  | ||||||
| 
 |  | ||||||
| 在项目根目录下的 `.env.production` 文件中配置接口地址: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| VITE_GLOB_API_URL=https://mock-napi.vben.pro/api |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: tip 打包如何动态修改接口地址 |  | ||||||
| 
 |  | ||||||
| `.env` 文件内的 `VITE_GLOB_*` 开头的变量会在打包的时候注入 `_app.config.js` 文件内。在 `dist/_app.config.js` 修改相应的接口地址后刷新页面即可,不需要在根据不同环境打包多次,一次打包可以用于多个不同接口环境的部署。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ### 跨域处理 |  | ||||||
| 
 |  | ||||||
| 生产环境如果出现跨域问题,可以使用 `nginx` 代理接口地址 或者后台开启 `cors` 进行处理即可(可参考mock服务)。 |  | ||||||
| 
 |  | ||||||
| ## 接口请求配置 |  | ||||||
| 
 |  | ||||||
| 项目中默认自带了基于 `axios` 封装的基础的请求配置,核心由 `@vben/request` 包提供。项目没有过多的封装,只是简单的封装了一些常用的配置,如有其他需求,可以自行增加或者调整配置。针对不同的app,可能是用到了不同的组件库以及`store`,所以在应用目录下的`src/api/request.ts`文件夹下,有对应的请求配置文件,如`web-antd`项目下的`src/api/request.ts`文件,可以根据自己的需求进行配置。 |  | ||||||
| 
 |  | ||||||
| ### 请求示例 |  | ||||||
| 
 |  | ||||||
| #### GET 请求 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import { requestClient } from '#/api/request'; |  | ||||||
| 
 |  | ||||||
| export async function getUserInfoApi() { |  | ||||||
|   return requestClient.get<UserInfo>('/user/info'); |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| #### POST/PUT 请求 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import { requestClient } from '#/api/request'; |  | ||||||
| 
 |  | ||||||
| export async function saveUserApi(user: UserInfo) { |  | ||||||
|   return requestClient.post<UserInfo>('/user', user); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export async function saveUserApi(user: UserInfo) { |  | ||||||
|   return requestClient.put<UserInfo>('/user', user); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export async function saveUserApi(user: UserInfo) { |  | ||||||
|   const url = user.id ? `/user/${user.id}` : '/user/'; |  | ||||||
|   return requestClient.request<UserInfo>(url, { |  | ||||||
|     data: user, |  | ||||||
|     // 或者 PUT |  | ||||||
|     method: user.id ? 'PUT' : 'POST', |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| #### DELETE 请求 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import { requestClient } from '#/api/request'; |  | ||||||
| 
 |  | ||||||
| export async function deleteUserApi(user: UserInfo) { |  | ||||||
|   return requestClient.delete<boolean>(`/user/${user.id}`, user); |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 请求配置 |  | ||||||
| 
 |  | ||||||
| 应用内的`src/api/request.ts`可以根据自己应用的情况的需求进行配置: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| /** |  | ||||||
|  * 该文件可自行根据业务逻辑进行调整 |  | ||||||
|  */ |  | ||||||
| import type { HttpResponse } from '@vben/request'; |  | ||||||
| 
 |  | ||||||
| import { useAppConfig } from '@vben/hooks'; |  | ||||||
| import { preferences } from '@vben/preferences'; |  | ||||||
| import { |  | ||||||
|   authenticateResponseInterceptor, |  | ||||||
|   errorMessageResponseInterceptor, |  | ||||||
|   RequestClient, |  | ||||||
| } from '@vben/request'; |  | ||||||
| import { useAccessStore } from '@vben/stores'; |  | ||||||
| 
 |  | ||||||
| import { message } from 'ant-design-vue'; |  | ||||||
| 
 |  | ||||||
| import { useAuthStore } from '#/store'; |  | ||||||
| 
 |  | ||||||
| import { refreshTokenApi } from './core'; |  | ||||||
| 
 |  | ||||||
| const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); |  | ||||||
| 
 |  | ||||||
| function createRequestClient(baseURL: string) { |  | ||||||
|   const client = new RequestClient({ |  | ||||||
|     baseURL, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * 重新认证逻辑 |  | ||||||
|    */ |  | ||||||
|   async function doReAuthenticate() { |  | ||||||
|     console.warn('Access token or refresh token is invalid or expired. '); |  | ||||||
|     const accessStore = useAccessStore(); |  | ||||||
|     const authStore = useAuthStore(); |  | ||||||
|     accessStore.setAccessToken(null); |  | ||||||
|     if ( |  | ||||||
|       preferences.app.loginExpiredMode === 'modal' && |  | ||||||
|       accessStore.isAccessChecked |  | ||||||
|     ) { |  | ||||||
|       accessStore.setLoginExpired(true); |  | ||||||
|     } else { |  | ||||||
|       await authStore.logout(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * 刷新token逻辑 |  | ||||||
|    */ |  | ||||||
|   async function doRefreshToken() { |  | ||||||
|     const accessStore = useAccessStore(); |  | ||||||
|     const resp = await refreshTokenApi(); |  | ||||||
|     const newToken = resp.data; |  | ||||||
|     accessStore.setAccessToken(newToken); |  | ||||||
|     return newToken; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   function formatToken(token: null | string) { |  | ||||||
|     return token ? `Bearer ${token}` : null; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // 请求头处理 |  | ||||||
|   client.addRequestInterceptor({ |  | ||||||
|     fulfilled: async (config) => { |  | ||||||
|       const accessStore = useAccessStore(); |  | ||||||
| 
 |  | ||||||
|       config.headers.Authorization = formatToken(accessStore.accessToken); |  | ||||||
|       config.headers['Accept-Language'] = preferences.app.locale; |  | ||||||
|       return config; |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   // 处理返回的响应数据格式。会根据responseReturn指定的类型返回对应的数据 |  | ||||||
|   client.addResponseInterceptor( |  | ||||||
|     defaultResponseInterceptor({ |  | ||||||
|       // 指定接口返回的数据中的 code 字段名 |  | ||||||
|       codeField: 'code', |  | ||||||
|       // 指定接口返回的数据中装载了主要数据的字段名 |  | ||||||
|       dataField: 'data', |  | ||||||
|       // 请求成功的 code 值,如果接口返回的 code 等于 successCode 则会认为是成功的请求 |  | ||||||
|       successCode: 0, |  | ||||||
|     }), |  | ||||||
|   ); |  | ||||||
| 
 |  | ||||||
|   // token过期的处理 |  | ||||||
|   client.addResponseInterceptor( |  | ||||||
|     authenticateResponseInterceptor({ |  | ||||||
|       client, |  | ||||||
|       doReAuthenticate, |  | ||||||
|       doRefreshToken, |  | ||||||
|       enableRefreshToken: preferences.app.enableRefreshToken, |  | ||||||
|       formatToken, |  | ||||||
|     }), |  | ||||||
|   ); |  | ||||||
| 
 |  | ||||||
|   // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里 |  | ||||||
|   client.addResponseInterceptor( |  | ||||||
|     errorMessageResponseInterceptor((msg: string, error) => { |  | ||||||
|       // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg |  | ||||||
|       // 当前mock接口返回的错误字段是 error 或者 message |  | ||||||
|       const responseData = error?.response?.data ?? {}; |  | ||||||
|       const errorMessage = responseData?.error ?? responseData?.message ?? ''; |  | ||||||
|       // 如果没有错误信息,则会根据状态码进行提示 |  | ||||||
|       message.error(errorMessage || msg); |  | ||||||
|     }), |  | ||||||
|   ); |  | ||||||
| 
 |  | ||||||
|   return client; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export const requestClient = createRequestClient(apiURL); |  | ||||||
| 
 |  | ||||||
| export const baseRequestClient = new RequestClient({ baseURL: apiURL }); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 多个接口地址 |  | ||||||
| 
 |  | ||||||
| 只需要创建多个 `requestClient` 即可,如: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| const { apiURL, otherApiURL } = useAppConfig( |  | ||||||
|   import.meta.env, |  | ||||||
|   import.meta.env.PROD, |  | ||||||
| ); |  | ||||||
| 
 |  | ||||||
| export const requestClient = createRequestClient(apiURL); |  | ||||||
| 
 |  | ||||||
| export const otherRequestClient = createRequestClient(otherApiURL); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## 刷新Token |  | ||||||
| 
 |  | ||||||
| 项目中默认提供了刷新 Token 的逻辑,只需要按照下面的配置即可开启: |  | ||||||
| 
 |  | ||||||
| - 确保当前启用了刷新 Token 的配置 |  | ||||||
| 
 |  | ||||||
| 调整对应应用目录下的`preferences.ts`,确保`enableRefreshToken='true'`。 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import { defineOverridesPreferences } from '@vben/preferences'; |  | ||||||
| 
 |  | ||||||
| export const overridesPreferences = defineOverridesPreferences({ |  | ||||||
|   // overrides |  | ||||||
|   app: { |  | ||||||
|     enableRefreshToken: true, |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 在 `src/api/request.ts` 中配置 `doRefreshToken` 方法即可: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| // 这里调整为你的token格式 |  | ||||||
| function formatToken(token: null | string) { |  | ||||||
|   return token ? `Bearer ${token}` : null; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 刷新token逻辑 |  | ||||||
|  */ |  | ||||||
| async function doRefreshToken() { |  | ||||||
|   const accessStore = useAccessStore(); |  | ||||||
|   // 这里调整为你的刷新token接口 |  | ||||||
|   const resp = await refreshTokenApi(); |  | ||||||
|   const newToken = resp.data; |  | ||||||
|   accessStore.setAccessToken(newToken); |  | ||||||
|   return newToken; |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## 数据 Mock |  | ||||||
| 
 |  | ||||||
| ::: tip 生产环境 Mock |  | ||||||
| 
 |  | ||||||
| 新版本不再支持生产环境 mock,请使用真实接口。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| Mock 数据是前端开发过程中必不可少的一环,是分离前后端开发的关键链路。通过预先跟服务器端约定好的接口,模拟请求数据甚至逻辑,能够让前端开发独立自主,不会被服务端的开发进程所阻塞。 |  | ||||||
| 
 |  | ||||||
| 项目使用 [Nitro](https://nitro.unjs.io/) 来进行本地 mock 数据处理。其原理是本地额外启动一个后端服务,是一个真实的后端服务,可以处理请求,返回数据。 |  | ||||||
| 
 |  | ||||||
| ### Nitro 使用 |  | ||||||
| 
 |  | ||||||
| Mock 服务代码位于`apps/backend-mock`目录下,无需手动启动,已经集成在项目中,只需要在项目根目录下运行`pnpm dev`即可,运行成功之后,控制台会打印 `http://localhost:5320/api`, 访问该地址即可查看 mock 服务。 |  | ||||||
| 
 |  | ||||||
| [Nitro](https://nitro.unjs.io/) 语法简单,可以根据自己的需求进行配置及开发,具体配置可以查看 [Nitro 文档](https://nitro.unjs.io/)。 |  | ||||||
| 
 |  | ||||||
| ## 关闭 Mock 服务 |  | ||||||
| 
 |  | ||||||
| mock的本质是一个真实的后端服务,如果不需要 mock 服务,可以在项目根目录下的 `.env.development` 文件中配置 `VITE_NITRO_MOCK=false` 即可关闭 mock 服务。 |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| # .env.development |  | ||||||
| VITE_NITRO_MOCK=false |  | ||||||
| ``` |  | ||||||
|  | |||||||
| @ -1,543 +1 @@ | |||||||
| # 配置 | # settings | ||||||
| 
 |  | ||||||
| ## 环境变量配置 |  | ||||||
| 
 |  | ||||||
| 项目的环境变量配置位于应用目录下的 `.env`、`.env.development`、`.env.production`。 |  | ||||||
| 
 |  | ||||||
| 规则与 [Vite Env Variables and Modes](https://vitejs.dev/guide/env-and-mode.html) 一致。格式如下: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| .env                # 在所有的环境中被载入 |  | ||||||
| .env.local          # 在所有的环境中被载入,但会被 git 忽略 |  | ||||||
| .env.[mode]         # 只在指定的模式中被载入 |  | ||||||
| .env.[mode].local   # 只在指定的模式中被载入,但会被 git 忽略 |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: tip |  | ||||||
| 
 |  | ||||||
| - 只有以 `VITE_` 开头的变量会被嵌入到客户端侧的包中,你可以在项目代码中这样访问它们: |  | ||||||
| 
 |  | ||||||
|   ```ts |  | ||||||
|   console.log(import.meta.env.VITE_PROT); |  | ||||||
|   ``` |  | ||||||
| 
 |  | ||||||
| - 以 `VITE_GLOB_*` 开头的的变量,在打包的时候,会被加入 `_app.config.js`配置文件当中. ::: |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ## 环境配置说明 |  | ||||||
| 
 |  | ||||||
| ::: code-group |  | ||||||
| 
 |  | ||||||
| ```bash [.env] |  | ||||||
| # 应用标题 |  | ||||||
| VITE_APP_TITLE=y-code-platform |  | ||||||
| 
 |  | ||||||
| # 应用命名空间,用于缓存、store等功能的前缀,确保隔离 |  | ||||||
| VITE_APP_NAMESPACE=vben-web-antd |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ```bash [.env.development] |  | ||||||
| # 端口号 |  | ||||||
| VITE_PORT=5555 |  | ||||||
| 
 |  | ||||||
| # 资源公共路径,需要以 / 开头和结尾 |  | ||||||
| VITE_BASE=/ |  | ||||||
| 
 |  | ||||||
| # 接口地址 |  | ||||||
| VITE_GLOB_API_URL=/api |  | ||||||
| 
 |  | ||||||
| # 是否开启 Nitro Mock服务,true 为开启,false 为关闭 |  | ||||||
| VITE_NITRO_MOCK=true |  | ||||||
| 
 |  | ||||||
| # 是否打开 devtools,true 为打开,false 为关闭 |  | ||||||
| VITE_DEVTOOLS=true |  | ||||||
| 
 |  | ||||||
| # 是否注入全局loading |  | ||||||
| VITE_INJECT_APP_LOADING=true |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ```bash [.env.production] |  | ||||||
| # 资源公共路径,需要以 / 开头和结尾 |  | ||||||
| VITE_BASE=/ |  | ||||||
| 
 |  | ||||||
| # 接口地址 |  | ||||||
| VITE_GLOB_API_URL=https://mock-napi.vben.pro/api |  | ||||||
| 
 |  | ||||||
| # 是否开启压缩,可以设置为 none, brotli, gzip |  | ||||||
| VITE_COMPRESS=gzip |  | ||||||
| 
 |  | ||||||
| # 是否开启 PWA |  | ||||||
| VITE_PWA=false |  | ||||||
| 
 |  | ||||||
| # vue-router 的模式 |  | ||||||
| VITE_ROUTER_HISTORY=hash |  | ||||||
| 
 |  | ||||||
| # 是否注入全局loading |  | ||||||
| VITE_INJECT_APP_LOADING=true |  | ||||||
| 
 |  | ||||||
| # 打包后是否生成dist.zip |  | ||||||
| VITE_ARCHIVER=true |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ## 生产环境动态配置 |  | ||||||
| 
 |  | ||||||
| 当在大仓根目录下,执行 `pnpm build`构建项目之后,会自动在对应的应用下生成 `dist/_app.config.js`文件并插入 `index.html`。 |  | ||||||
| 
 |  | ||||||
| `_app.config.js` 是一个动态配置文件,可以在项目构建之后,根据不同的环境动态修改配置。内容如下: |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| window._VBEN_ADMIN_PRO_APP_CONF_ = { |  | ||||||
|   VITE_GLOB_API_URL: 'https://mock-napi.vben.pro/api', |  | ||||||
| }; |  | ||||||
| Object.freeze(window._VBEN_ADMIN_PRO_APP_CONF_); |  | ||||||
| Object.defineProperty(window, '_VBEN_ADMIN_PRO_APP_CONF_', { |  | ||||||
|   configurable: false, |  | ||||||
|   writable: false, |  | ||||||
| }); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 作用 |  | ||||||
| 
 |  | ||||||
| `_app.config.js` 用于项目在打包后,需要动态修改配置的需求,如接口地址。不用重新进行打包,可在打包后修改 /`dist/_app.config.js` 内的变量,刷新即可更新代码内的局部变量。这里使用`js`文件,是为了确保配置文件加载顺序保持在前面。 |  | ||||||
| 
 |  | ||||||
| ### 使用 |  | ||||||
| 
 |  | ||||||
| 想要获取 `_app.config.js` 内的变量,需要使用`@vben/hooks`提供的 `useAppConfig`方法。 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 新增 |  | ||||||
| 
 |  | ||||||
| 新增一个可动态修改的配置项,只需要按照如下步骤即可: |  | ||||||
| 
 |  | ||||||
| - 首先在 `.env` 或者对应的开发环境配置文件内,新增需要可动态配置的变量,需要以 `VITE_GLOB_*` 开头的变量,如: |  | ||||||
| 
 |  | ||||||
|   ```bash |  | ||||||
|   VITE_GLOB_OTHER_API_URL=https://mock-napi.vben.pro/other-api |  | ||||||
|   ``` |  | ||||||
| 
 |  | ||||||
| - 在 `packages/types/global.d.ts`,新增对应的类型定义,如: |  | ||||||
| 
 |  | ||||||
|   ```ts |  | ||||||
|   export interface VbenAdminProAppConfigRaw { |  | ||||||
|     VITE_GLOB_API_URL: string; |  | ||||||
|     VITE_GLOB_OTHER_API_URL: string; // [!code ++] |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   export interface ApplicationConfig { |  | ||||||
|     apiURL: string; |  | ||||||
|     otherApiURL: string; // [!code ++] |  | ||||||
|   } |  | ||||||
|   ``` |  | ||||||
| 
 |  | ||||||
| 到这里,就可以在项目内使用 `useAppConfig`方法获取到新增的配置项了。 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| const { otherApiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: warning 注意 |  | ||||||
| 
 |  | ||||||
| `useAppConfig`方法只能在应用内使用,不要耦合到包内部去使用。这里传入 `import.meta.env`和`import.meta.env.PROD`是为了避免这种情况,一个纯粹的包,应避免使用特定构建工具的变量。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ## 偏好设置 |  | ||||||
| 
 |  | ||||||
| 项目提供了非常丰富的偏好设置,用于动态配置项目的各种功能: |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
| 
 |  | ||||||
| 如果你找不到文档说明,可以尝试自己配置好以后,点击`复制偏好设置`,覆盖项目默认即可。配置文件位于应用目录下的`preferences.ts`,在这里,你可以覆盖框架默认的配置,实现自定义配置。 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| import { useAppConfig } from '@vben/hooks'; |  | ||||||
| import { defineOverridesPreferences } from '@vben/preferences'; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @description 项目配置文件 |  | ||||||
|  * 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置 |  | ||||||
|  * !!! 更改配置后请清空缓存,否则可能不生效 |  | ||||||
|  */ |  | ||||||
| export const overridesPreferences = defineOverridesPreferences({ |  | ||||||
|   // overrides |  | ||||||
| }); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 框架默认配置 |  | ||||||
| 
 |  | ||||||
| ::: details 查看框架默认配置 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| const defaultPreferences: Preferences = { |  | ||||||
|   app: { |  | ||||||
|     accessMode: 'frontend', |  | ||||||
|     authPageLayout: 'panel-right', |  | ||||||
|     checkUpdatesInterval: 1, |  | ||||||
|     colorGrayMode: false, |  | ||||||
|     colorWeakMode: false, |  | ||||||
|     compact: false, |  | ||||||
|     contentCompact: 'wide', |  | ||||||
|     defaultAvatar: |  | ||||||
|       'https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp', |  | ||||||
|     dynamicTitle: true, |  | ||||||
|     enableCheckUpdates: true, |  | ||||||
|     enablePreferences: true, |  | ||||||
|     enableRefreshToken: false, |  | ||||||
|     isMobile: false, |  | ||||||
|     layout: 'sidebar-nav', |  | ||||||
|     locale: 'zh-CN', |  | ||||||
|     loginExpiredMode: 'modal', |  | ||||||
|     name: 'y-code-platform', |  | ||||||
|     preferencesButtonPosition: 'auto', |  | ||||||
|     watermark: false, |  | ||||||
|   }, |  | ||||||
|   breadcrumb: { |  | ||||||
|     enable: true, |  | ||||||
|     hideOnlyOne: false, |  | ||||||
|     showHome: false, |  | ||||||
|     showIcon: true, |  | ||||||
|     styleType: 'normal', |  | ||||||
|   }, |  | ||||||
|   copyright: { |  | ||||||
|     companyName: 'Vben', |  | ||||||
|     companySiteLink: 'https://www.vben.pro', |  | ||||||
|     date: '2024', |  | ||||||
|     enable: true, |  | ||||||
|     icp: '', |  | ||||||
|     icpLink: '', |  | ||||||
|   }, |  | ||||||
|   footer: { |  | ||||||
|     enable: true, |  | ||||||
|     fixed: false, |  | ||||||
|   }, |  | ||||||
|   header: { |  | ||||||
|     enable: true, |  | ||||||
|     hidden: false, |  | ||||||
|     mode: 'fixed', |  | ||||||
|   }, |  | ||||||
|   logo: { |  | ||||||
|     enable: true, |  | ||||||
|     source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp', |  | ||||||
|   }, |  | ||||||
|   navigation: { |  | ||||||
|     accordion: true, |  | ||||||
|     split: true, |  | ||||||
|     styleType: 'rounded', |  | ||||||
|   }, |  | ||||||
|   shortcutKeys: { |  | ||||||
|     enable: true, |  | ||||||
|     globalLockScreen: true, |  | ||||||
|     globalLogout: true, |  | ||||||
|     globalPreferences: true, |  | ||||||
|     globalSearch: true, |  | ||||||
|   }, |  | ||||||
|   sidebar: { |  | ||||||
|     autoActivateChild: false, |  | ||||||
|     collapsed: false, |  | ||||||
|     collapsedShowTitle: false, |  | ||||||
|     enable: true, |  | ||||||
|     expandOnHover: true, |  | ||||||
|     extraCollapse: true, |  | ||||||
|     hidden: false, |  | ||||||
|     width: 230, |  | ||||||
|   }, |  | ||||||
|   tabbar: { |  | ||||||
|     draggable: true, |  | ||||||
|     enable: true, |  | ||||||
|     height: 36, |  | ||||||
|     keepAlive: true, |  | ||||||
|     persist: true, |  | ||||||
|     showIcon: true, |  | ||||||
|     showMaximize: true, |  | ||||||
|     showMore: true, |  | ||||||
|     styleType: 'chrome', |  | ||||||
|   }, |  | ||||||
|   theme: { |  | ||||||
|     builtinType: 'default', |  | ||||||
|     colorDestructive: 'hsl(348 100% 61%)', |  | ||||||
|     colorPrimary: 'hsl(212 100% 45%)', |  | ||||||
|     colorSuccess: 'hsl(144 57% 58%)', |  | ||||||
|     colorWarning: 'hsl(42 84% 61%)', |  | ||||||
|     mode: 'dark', |  | ||||||
|     radius: '0.5', |  | ||||||
|     semiDarkHeader: false, |  | ||||||
|     semiDarkSidebar: true, |  | ||||||
|   }, |  | ||||||
|   transition: { |  | ||||||
|     enable: true, |  | ||||||
|     loading: true, |  | ||||||
|     name: 'fade-slide', |  | ||||||
|     progress: true, |  | ||||||
|   }, |  | ||||||
|   widget: { |  | ||||||
|     fullscreen: true, |  | ||||||
|     globalSearch: true, |  | ||||||
|     languageToggle: true, |  | ||||||
|     lockScreen: true, |  | ||||||
|     notification: true, |  | ||||||
|     refresh: true, |  | ||||||
|     sidebarToggle: true, |  | ||||||
|     themeToggle: true, |  | ||||||
|   }, |  | ||||||
| }; |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ::: details 查看框架默认配置类型 |  | ||||||
| 
 |  | ||||||
| ```ts |  | ||||||
| interface AppPreferences { |  | ||||||
|   /** 权限模式 */ |  | ||||||
|   accessMode: AccessModeType; |  | ||||||
|   /** 登录注册页面布局 */ |  | ||||||
|   authPageLayout: AuthPageLayoutType; |  | ||||||
|   /** 检查更新轮询时间 */ |  | ||||||
|   checkUpdatesInterval: number; |  | ||||||
|   /** 是否开启灰色模式 */ |  | ||||||
|   colorGrayMode: boolean; |  | ||||||
|   /** 是否开启色弱模式 */ |  | ||||||
|   colorWeakMode: boolean; |  | ||||||
|   /** 是否开启紧凑模式 */ |  | ||||||
|   compact: boolean; |  | ||||||
|   /** 是否开启内容紧凑模式 */ |  | ||||||
|   contentCompact: ContentCompactType; |  | ||||||
|   // /** 应用默认头像 */ |  | ||||||
|   defaultAvatar: string; |  | ||||||
|   // /** 开启动态标题 */ |  | ||||||
|   dynamicTitle: boolean; |  | ||||||
|   /** 是否开启检查更新 */ |  | ||||||
|   enableCheckUpdates: boolean; |  | ||||||
|   /** 是否显示偏好设置 */ |  | ||||||
|   enablePreferences: boolean; |  | ||||||
|   /** |  | ||||||
|    * @zh_CN 是否开启refreshToken |  | ||||||
|    */ |  | ||||||
|   enableRefreshToken: boolean; |  | ||||||
|   /** 是否移动端 */ |  | ||||||
|   isMobile: boolean; |  | ||||||
|   /** 布局方式 */ |  | ||||||
|   layout: LayoutType; |  | ||||||
|   /** 支持的语言 */ |  | ||||||
|   locale: SupportedLanguagesType; |  | ||||||
|   /** 登录过期模式 */ |  | ||||||
|   loginExpiredMode: LoginExpiredModeType; |  | ||||||
|   /** 应用名 */ |  | ||||||
|   name: string; |  | ||||||
|   /** 偏好设置按钮位置 */ |  | ||||||
|   preferencesButtonPosition: PreferencesButtonPositionType; |  | ||||||
|   /** |  | ||||||
|    * @zh_CN 是否开启水印 |  | ||||||
|    */ |  | ||||||
|   watermark: boolean; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface BreadcrumbPreferences { |  | ||||||
|   /** 面包屑是否启用 */ |  | ||||||
|   enable: boolean; |  | ||||||
|   /** 面包屑是否只有一个时隐藏 */ |  | ||||||
|   hideOnlyOne: boolean; |  | ||||||
|   /** 面包屑首页图标是否可见 */ |  | ||||||
|   showHome: boolean; |  | ||||||
|   /** 面包屑图标是否可见 */ |  | ||||||
|   showIcon: boolean; |  | ||||||
|   /** 面包屑风格 */ |  | ||||||
|   styleType: BreadcrumbStyleType; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface CopyrightPreferences { |  | ||||||
|   /** 版权公司名 */ |  | ||||||
|   companyName: string; |  | ||||||
|   /** 版权公司名链接 */ |  | ||||||
|   companySiteLink: string; |  | ||||||
|   /** 版权日期 */ |  | ||||||
|   date: string; |  | ||||||
|   /** 版权是否可见 */ |  | ||||||
|   enable: boolean; |  | ||||||
|   /** 备案号 */ |  | ||||||
|   icp: string; |  | ||||||
|   /** 备案号链接 */ |  | ||||||
|   icpLink: string; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface FooterPreferences { |  | ||||||
|   /** 底栏是否可见 */ |  | ||||||
|   enable: boolean; |  | ||||||
|   /** 底栏是否固定 */ |  | ||||||
|   fixed: boolean; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface HeaderPreferences { |  | ||||||
|   /** 顶栏是否启用 */ |  | ||||||
|   enable: boolean; |  | ||||||
|   /** 顶栏是否隐藏,css-隐藏 */ |  | ||||||
|   hidden: boolean; |  | ||||||
|   /** header显示模式 */ |  | ||||||
|   mode: LayoutHeaderModeType; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface LogoPreferences { |  | ||||||
|   /** logo是否可见 */ |  | ||||||
|   enable: boolean; |  | ||||||
|   /** logo地址 */ |  | ||||||
|   source: string; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface NavigationPreferences { |  | ||||||
|   /** 导航菜单手风琴模式 */ |  | ||||||
|   accordion: boolean; |  | ||||||
|   /** 导航菜单是否切割,只在 layout=mixed-nav 生效 */ |  | ||||||
|   split: boolean; |  | ||||||
|   /** 导航菜单风格 */ |  | ||||||
|   styleType: NavigationStyleType; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface SidebarPreferences { |  | ||||||
|   /** 侧边栏是否折叠 */ |  | ||||||
|   collapsed: boolean; |  | ||||||
|   /** 侧边栏折叠时,是否显示title */ |  | ||||||
|   collapsedShowTitle: boolean; |  | ||||||
|   /** 侧边栏是否可见 */ |  | ||||||
|   enable: boolean; |  | ||||||
|   /** 菜单自动展开状态 */ |  | ||||||
|   expandOnHover: boolean; |  | ||||||
|   /** 侧边栏扩展区域是否折叠 */ |  | ||||||
|   extraCollapse: boolean; |  | ||||||
|   /** 侧边栏是否隐藏 - css */ |  | ||||||
|   hidden: boolean; |  | ||||||
|   /** 侧边栏宽度 */ |  | ||||||
|   width: number; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface ShortcutKeyPreferences { |  | ||||||
|   /** 是否启用快捷键-全局 */ |  | ||||||
|   enable: boolean; |  | ||||||
|   /** 是否启用全局锁屏快捷键 */ |  | ||||||
|   globalLockScreen: boolean; |  | ||||||
|   /** 是否启用全局注销快捷键 */ |  | ||||||
|   globalLogout: boolean; |  | ||||||
|   /** 是否启用全局偏好设置快捷键 */ |  | ||||||
|   globalPreferences: boolean; |  | ||||||
|   /** 是否启用全局搜索快捷键 */ |  | ||||||
|   globalSearch: boolean; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface TabbarPreferences { |  | ||||||
|   /** 是否开启多标签页拖拽 */ |  | ||||||
|   draggable: boolean; |  | ||||||
|   /** 是否开启多标签页 */ |  | ||||||
|   enable: boolean; |  | ||||||
|   /** 标签页高度 */ |  | ||||||
|   height: number; |  | ||||||
|   /** 开启标签页缓存功能 */ |  | ||||||
|   keepAlive: boolean; |  | ||||||
|   /** 是否持久化标签 */ |  | ||||||
|   persist: boolean; |  | ||||||
|   /** 是否开启多标签页图标 */ |  | ||||||
|   showIcon: boolean; |  | ||||||
|   /** 显示最大化按钮 */ |  | ||||||
|   showMaximize: boolean; |  | ||||||
|   /** 显示更多按钮 */ |  | ||||||
|   showMore: boolean; |  | ||||||
|   /** 标签页风格 */ |  | ||||||
|   styleType: TabsStyleType; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface ThemePreferences { |  | ||||||
|   /** 内置主题名 */ |  | ||||||
|   builtinType: BuiltinThemeType; |  | ||||||
|   /** 错误色 */ |  | ||||||
|   colorDestructive: string; |  | ||||||
|   /** 主题色 */ |  | ||||||
|   colorPrimary: string; |  | ||||||
|   /** 成功色 */ |  | ||||||
|   colorSuccess: string; |  | ||||||
|   /** 警告色 */ |  | ||||||
|   colorWarning: string; |  | ||||||
|   /** 当前主题 */ |  | ||||||
|   mode: ThemeModeType; |  | ||||||
|   /** 圆角 */ |  | ||||||
|   radius: string; |  | ||||||
|   /** 是否开启半深色header(只在theme='light'时生效) */ |  | ||||||
|   semiDarkHeader: boolean; |  | ||||||
|   /** 是否开启半深色菜单(只在theme='light'时生效) */ |  | ||||||
|   semiDarkSidebar: boolean; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface TransitionPreferences { |  | ||||||
|   /** 页面切换动画是否启用 */ |  | ||||||
|   enable: boolean; |  | ||||||
|   // /** 是否开启页面加载loading */ |  | ||||||
|   loading: boolean; |  | ||||||
|   /** 页面切换动画 */ |  | ||||||
|   name: PageTransitionType | string; |  | ||||||
|   /** 是否开启页面加载进度动画 */ |  | ||||||
|   progress: boolean; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface WidgetPreferences { |  | ||||||
|   /** 是否启用全屏部件 */ |  | ||||||
|   fullscreen: boolean; |  | ||||||
|   /** 是否启用全局搜索部件 */ |  | ||||||
|   globalSearch: boolean; |  | ||||||
|   /** 是否启用语言切换部件 */ |  | ||||||
|   languageToggle: boolean; |  | ||||||
|   /** 是否开启锁屏功能 */ |  | ||||||
|   lockScreen: boolean; |  | ||||||
|   /** 是否显示通知部件 */ |  | ||||||
|   notification: boolean; |  | ||||||
|   /** 显示刷新按钮 */ |  | ||||||
|   refresh: boolean; |  | ||||||
|   /** 是否显示侧边栏显示/隐藏部件 */ |  | ||||||
|   sidebarToggle: boolean; |  | ||||||
|   /** 是否显示主题切换部件 */ |  | ||||||
|   themeToggle: boolean; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface Preferences { |  | ||||||
|   /** 全局配置 */ |  | ||||||
|   app: AppPreferences; |  | ||||||
|   /** 顶栏配置 */ |  | ||||||
|   breadcrumb: BreadcrumbPreferences; |  | ||||||
|   /** 版权配置 */ |  | ||||||
|   copyright: CopyrightPreferences; |  | ||||||
|   /** 底栏配置 */ |  | ||||||
|   footer: FooterPreferences; |  | ||||||
|   /** 面包屑配置 */ |  | ||||||
|   header: HeaderPreferences; |  | ||||||
|   /** logo配置 */ |  | ||||||
|   logo: LogoPreferences; |  | ||||||
|   /** 导航配置 */ |  | ||||||
|   navigation: NavigationPreferences; |  | ||||||
|   /** 快捷键配置 */ |  | ||||||
|   shortcutKeys: ShortcutKeyPreferences; |  | ||||||
|   /** 侧边栏配置 */ |  | ||||||
|   sidebar: SidebarPreferences; |  | ||||||
|   /** 标签页配置 */ |  | ||||||
|   tabbar: TabbarPreferences; |  | ||||||
|   /** 主题配置 */ |  | ||||||
|   theme: ThemePreferences; |  | ||||||
|   /** 动画配置 */ |  | ||||||
|   transition: TransitionPreferences; |  | ||||||
|   /** 功能配置 */ |  | ||||||
|   widget: WidgetPreferences; |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ::: warning 注意 |  | ||||||
| 
 |  | ||||||
| - `overridesPreferences`方法只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置。 |  | ||||||
| - 任何配置项都可以覆盖,只需要在`overridesPreferences`方法内覆盖即可,不要修改默认配置文件。 |  | ||||||
| - 更改配置后请清空缓存,否则可能不生效。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
|  | |||||||
| @ -1,106 +1 @@ | |||||||
| # 样式 | # styles | ||||||
| 
 |  | ||||||
| ::: tip 前言 |  | ||||||
| 
 |  | ||||||
| 对于 vue 项目,[官方文档](https://vuejs.org/api/sfc-css-features.html#deep-selectors) 对语法已经有比较详细的介绍,这里主要是介绍项目中的样式文件结构和使用。 |  | ||||||
| 
 |  | ||||||
| ::: |  | ||||||
| 
 |  | ||||||
| ## 项目结构 |  | ||||||
| 
 |  | ||||||
| 项目中的样式文件存放在 `@vben/styles`,包含一些全局样式,如重置样式、全局变量等,它继承了 `@vben-core/design` 的样式和能力,可以根据项目需求进行覆盖。 |  | ||||||
| 
 |  | ||||||
| ## Scss |  | ||||||
| 
 |  | ||||||
| 项目中使用 `scss` 作为样式预处理器,可以在项目中使用 `scss` 的特性,如变量、函数、混合等。 |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| $font-size: 30px; |  | ||||||
| 
 |  | ||||||
| .box { |  | ||||||
|   .title { |  | ||||||
|     color: green; |  | ||||||
|     font-size: $font-size; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## Postcss |  | ||||||
| 
 |  | ||||||
| 如果你不习惯使用 `scss`,也可以使用 `postcss`,它是一个更加强大的样式处理器,可以使用更多的插件,项目内置了 [postcss-nested](https://github.com/postcss/postcss-nested) 插件,配置 `Css Variables`,完全可以取代 `scss`。 |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <style scoped> |  | ||||||
| .box { |  | ||||||
|   --font-size: 30px; |  | ||||||
|   .title { |  | ||||||
|     color: green; |  | ||||||
|     font-size: var(--font-size); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## Tailwind CSS |  | ||||||
| 
 |  | ||||||
| 项目中集成了 [Tailwind CSS](https://tailwindcss.com/),可以在项目中使用 `tailwindcss` 的类名,快速构建页面。 |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <template> |  | ||||||
|   <div class="bg-white p-4"> |  | ||||||
|     <p class="text-green">hello world</p> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## BEM 规范 |  | ||||||
| 
 |  | ||||||
| 样式冲突的另一种选择,是使用 `BEM` 规范。如果选择 `scss` ,建议使用 `BEM` 命名规范,可以更好的管理样式。项目默认提供了`useNamespace`函数,可以方便的生成命名空间。 |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <script lang="ts" setup> |  | ||||||
| import { useNamespace } from '@vben/hooks'; |  | ||||||
| 
 |  | ||||||
| const { b, e, is } = useNamespace('menu'); |  | ||||||
| </script> |  | ||||||
| <template> |  | ||||||
|   <div :class="[b()]"> |  | ||||||
|     <div :class="[e('item'), is('active', true)]">item1</div> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| // 如果你在应用内使用,这行代码可以省略,已经在所有的应用内全局引入了 |  | ||||||
| @use '@vben/styles/global' as *; |  | ||||||
| @include b('menu') { |  | ||||||
|   color: black; |  | ||||||
| 
 |  | ||||||
|   @include e('item') { |  | ||||||
|     background-color: black; |  | ||||||
| 
 |  | ||||||
|     @include is('active') { |  | ||||||
|       background-color: red; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## CSS Modules |  | ||||||
| 
 |  | ||||||
| 针对样式冲突问题,还有一种方案是使用 `CSS Modules` 模块化方案。使用方式如下。 |  | ||||||
| 
 |  | ||||||
| ```vue |  | ||||||
| <template> |  | ||||||
|   <p :class="$style.red">This should be red</p> |  | ||||||
| </template> |  | ||||||
| 
 |  | ||||||
| <style module> |  | ||||||
| .red { |  | ||||||
|   color: red; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 更多用法可以见 [CSS Modules 官方文档](https://vuejs.org/api/sfc-css-features.html#css-modules)。 |  | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| # 关于悦码 | # 关于悦码 | ||||||
| 
 | 
 | ||||||
| ::: info 你正在阅读的是 [悦码](y-code-platform.shiyuegame.com) `2.0`版本的文档 | ::: info 你正在阅读的是 [悦码](https://yue-code-platform.shiyuegame.com) `2.0`版本的文档 | ||||||
| 
 | 
 | ||||||
| ## 特点 | ## 特点 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -6,29 +6,30 @@ sidebar: false | |||||||
| hero: | hero: | ||||||
|   name: y-code 悦码 |   name: y-code 悦码 | ||||||
|   text: 低代码管理平台 |   text: 低代码管理平台 | ||||||
|   tagline: 全新升级,开箱即用,简单高效 |   tagline: 全新升级,打开即用,简单高效 | ||||||
|   image: |   image: | ||||||
|     src: https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp |     src: https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp | ||||||
|     alt: y-code-platform |     alt: 悦码 | ||||||
|   actions: |   actions: | ||||||
|     - theme: brand |     - theme: brand | ||||||
|       text: 快速开始 -> |       text: 快速开始 -> | ||||||
|       link: /guide/introduction/platform |       link: /guide/introduction/platform | ||||||
|     - theme: alt |     - theme: alt | ||||||
|       text: 在线预览 |       text: 立即体验 -> | ||||||
|       link: https://www.vben.pro |       link: https://y-code-platform.shiyuegame.com | ||||||
| 
 | 
 | ||||||
| features: | features: | ||||||
|   - icon: 🚀 |   - icon: 🚀 | ||||||
|     title: 最新技术栈 |     title: 最新技术栈 | ||||||
|     details: 基于 Vue3、Pinia、Vue Router、TypeScript、等最新技术栈。 |     details: 基于 Vue3、Pinia、Vue Router、TypeScript、等最新技术栈。 | ||||||
|     link: /guide/introduction/quick-start |     link: /guide/essentials/concept | ||||||
|     linkText: 快速开始 |     linkText: 基础概念 | ||||||
|   # - icon: 🦄 |   - icon: 📚 | ||||||
|   #   title: 丰富的配置 |     title: 低学习成本 | ||||||
|   #   details: 企业级中后台前端解决方案,提供丰富的组件和模板以及 N 种偏好设置组合方案。 |     details: 专为前端开发者设计,无需改变您熟悉的前端开发流程和编码习惯。只需了解Vue,即可轻松上手,实现无缝对接,真正做到零学习成本。 | ||||||
|   #   link: /guide/essentials/settings |   - icon: 🛠️ | ||||||
|   #   linkText: 配置文档 |     title: 自由个性化 | ||||||
|  |     details: 悦码设计器支持源码级别的自定义,可轻松适配个性化需求,理论上写代码开发能实现的在设计器上都能完成。 | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| <!-- <script setup> | <!-- <script setup> | ||||||
| @ -39,17 +40,6 @@ import { | |||||||
|   VPTeamPageSection |   VPTeamPageSection | ||||||
| } from 'vitepress/theme'; | } from 'vitepress/theme'; | ||||||
| 
 | 
 | ||||||
| const members = [ |  | ||||||
|   { |  | ||||||
|     avatar: 'https://avatars.githubusercontent.com/u/28132598?v=4', |  | ||||||
|     name: 'Vben', |  | ||||||
|     title: '创建者', |  | ||||||
|     desc: 'Vben Admin以及相关生态的作者,负责项目的整体开发。', |  | ||||||
|     links: [ |  | ||||||
|       { icon: 'github', link: 'https://github.com/anncwb' }, |  | ||||||
|     ] |  | ||||||
|   }, |  | ||||||
| ] |  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <VPTeamPage> | <VPTeamPage> | ||||||
| @ -58,9 +48,6 @@ const members = [ | |||||||
|       核心成员介绍 |       核心成员介绍 | ||||||
|     </template> |     </template> | ||||||
|   </VPTeamPageTitle> |   </VPTeamPageTitle> | ||||||
|   <VPTeamMembers |  | ||||||
|     :members="members" |  | ||||||
|   /> |  | ||||||
| </VPTeamPage> --> | </VPTeamPage> --> | ||||||
| 
 | 
 | ||||||
| <!-- <VbenContributors /> --> | <!-- <VbenContributors /> --> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 wangxuefeng
						wangxuefeng