chore: 文档更新
This commit is contained in:
parent
bbc19319ee
commit
3fd26fd1e6
@ -76,7 +76,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
|
||||
},
|
||||
{
|
||||
text: '深入',
|
||||
items: [{ link: 'in-depth/features', text: '常用功能' }],
|
||||
items: [{ link: 'in-depth/materials', text: '物料' }],
|
||||
},
|
||||
{
|
||||
text: '其他',
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@sy/y-code-docs",
|
||||
"version": "1.0.0-alpha.1",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
@ -1,311 +0,0 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# 权限
|
||||
|
||||
框架内置了两种权限控制方式:
|
||||
|
||||
- 通过用户角色来判断菜单或者按钮是否可以访问
|
||||
- 通过接口来判断菜单或者按钮是否可以访问
|
||||
|
||||
## 前端访问控制
|
||||
|
||||
**实现原理**: 在前端固定写死路由的权限,指定路由有哪些权限可以查看。只初始化通用的路由,需要权限才能访问的路由没有被加入路由表内。在登录后或者其他方式获取用户角色后,通过角色去遍历路由表,获取该角色可以访问的路由表,生成路由表,再通过 `router.addRoute` 添加到路由实例,实现权限的过滤。
|
||||
|
||||
**缺点**: 权限相对不自由,如果后台改动角色,前台也需要跟着改动。适合角色较固定的系统
|
||||
|
||||
### 步骤
|
||||
|
||||
- 确保当前模式为前端访问控制模式
|
||||
|
||||
调整对应应用目录下的`preferences.ts`,确保`accessMode='frontend'`。
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
// 默认值,可不填
|
||||
accessMode: 'frontend',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
- 配置路由权限
|
||||
|
||||
**如果不配置,默认可见**
|
||||
|
||||
```ts {3}
|
||||
{
|
||||
meta: {
|
||||
authority: ['super'],
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
- 确保接口返回的角色和路由表的权限匹配
|
||||
|
||||
可查看应用下的 `src/store/auth`,找到下面代码,
|
||||
|
||||
```ts
|
||||
// 设置登录用户信息,需要确保 userInfo.roles 是一个数组,且包含路由表中的权限
|
||||
// 例如:userInfo.roles=['super', 'admin']
|
||||
authStore.setUserInfo(userInfo);
|
||||
```
|
||||
|
||||
到这里,就已经配置完成,你需要确保登录后,接口返回的角色和路由表的权限匹配,否则无法访问。
|
||||
|
||||
### 菜单可见,但禁止访问
|
||||
|
||||
有时候,我们需要菜单可见,但是禁止访问,可以通过下面的方式实现,设置 `menuVisibleWithForbidden` 为 `true`,此时菜单可见,但是禁止访问,会跳转403页面。
|
||||
|
||||
```ts
|
||||
{
|
||||
meta: {
|
||||
menuVisibleWithForbidden: true,
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
## 后端访问控制
|
||||
|
||||
**实现原理**: 是通过接口动态生成路由表,且遵循一定的数据结构返回。前端根据需要处理该数据为可识别的结构,再通过 `router.addRoute` 添加到路由实例,实现权限的动态生成。
|
||||
|
||||
**缺点**: 后端需要提供符合规范的数据结构,前端需要处理数据结构,适合权限较为复杂的系统。
|
||||
|
||||
### 步骤
|
||||
|
||||
- 确保当前模式为后端访问控制模式
|
||||
|
||||
调整对应应用目录下的`preferences.ts`,确保`accessMode='backend'`。
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
accessMode: 'backend',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
- 确保接口返回的菜单数据结构正确
|
||||
|
||||
可查看应用下的 `src/router/access.ts`,找到下面代码,
|
||||
|
||||
```ts {5}
|
||||
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
||||
return await generateAccessible(preferences.app.accessMode, {
|
||||
fetchMenuListAsync: async () => {
|
||||
// 这个接口为后端返回的菜单数据
|
||||
return await getAllMenus();
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
- 接口返回菜单数据,可看注释说明
|
||||
|
||||
::: details 接口返回菜单数据示例
|
||||
|
||||
```ts
|
||||
const dashboardMenus = [
|
||||
{
|
||||
// 这里固定写死 BasicLayout,不可更改
|
||||
component: 'BasicLayout',
|
||||
meta: {
|
||||
order: -1,
|
||||
title: 'page.dashboard.title',
|
||||
},
|
||||
name: 'Dashboard',
|
||||
path: '/',
|
||||
redirect: '/analytics',
|
||||
children: [
|
||||
{
|
||||
name: 'Analytics',
|
||||
path: '/analytics',
|
||||
// 这里为页面的路径,需要去掉 views/ 和 .vue
|
||||
component: '/dashboard/analytics/index',
|
||||
meta: {
|
||||
affixTab: true,
|
||||
title: 'page.dashboard.analytics',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Workspace',
|
||||
path: '/workspace',
|
||||
component: '/dashboard/workspace/index',
|
||||
meta: {
|
||||
title: 'page.dashboard.workspace',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
到这里,就已经配置完成,你需要确保登录后,接口返回的菜单格式正确,否则无法访问。
|
||||
|
||||
## 按钮细粒度控制
|
||||
|
||||
在某些情况下,我们需要对按钮进行细粒度的控制,我们可以借助接口或者角色来控制按钮的显示。
|
||||
|
||||
### 权限码
|
||||
|
||||
权限码为接口返回的权限码,通过权限码来判断按钮是否显示,逻辑在`src/store/auth`下:
|
||||
|
||||
```ts
|
||||
const [fetchUserInfoResult, accessCodes] = await Promise.all([
|
||||
fetchUserInfo(),
|
||||
getAccessCodes(),
|
||||
]);
|
||||
|
||||
userInfo = fetchUserInfoResult;
|
||||
authStore.setUserInfo(userInfo);
|
||||
accessStore.setAccessCodes(accessCodes);
|
||||
```
|
||||
|
||||
找到 `getAccessCodes` 对应的接口,可根据业务逻辑进行调整。
|
||||
|
||||
权限码返回的数据结构为字符串数组,例如:`['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']`
|
||||
|
||||
有了权限码,就可以使用 `@vben/access` 提供的`AccessControl`组件及API来进行按钮的显示与隐藏。
|
||||
|
||||
#### 组件方式
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
import { AccessControl, useAccess } from '@vben/access';
|
||||
|
||||
const { accessMode, hasAccessByCodes } = useAccess();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 需要指明 type="code" -->
|
||||
<AccessControl :codes="['AC_100100']" type="code">
|
||||
<Button> Super 账号可见 ["AC_1000001"] </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['AC_100030']" type="code">
|
||||
<Button> Admin 账号可见 ["AC_100010"] </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['AC_1000001']" type="code">
|
||||
<Button> User 账号可见 ["AC_1000001"] </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['AC_100100', 'AC_100010']" type="code">
|
||||
<Button> Super & Admin 账号可见 ["AC_100100","AC_1000001"] </Button>
|
||||
</AccessControl>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### API方式
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
import { AccessControl, useAccess } from '@vben/access';
|
||||
|
||||
const { hasAccessByCodes } = useAccess();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button v-if="hasAccessByCodes(['AC_100100'])">
|
||||
Super 账号可见 ["AC_1000001"]
|
||||
</Button>
|
||||
<Button v-if="hasAccessByCodes(['AC_100030'])">
|
||||
Admin 账号可见 ["AC_100010"]
|
||||
</Button>
|
||||
<Button v-if="hasAccessByCodes(['AC_1000001'])">
|
||||
User 账号可见 ["AC_1000001"]
|
||||
</Button>
|
||||
<Button v-if="hasAccessByCodes(['AC_100100', 'AC_1000001'])">
|
||||
Super & Admin 账号可见 ["AC_100100","AC_1000001"]
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### 指令方式
|
||||
|
||||
> 指令支持绑定单个或多个权限码。单个时可以直接传入字符串或数组中包含一个权限码,多个权限码则传入数组。
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<Button class="mr-4" v-access:code="'AC_100100'">
|
||||
Super 账号可见 'AC_100100'
|
||||
</Button>
|
||||
<Button class="mr-4" v-access:code="['AC_100030']">
|
||||
Admin 账号可见 ["AC_100010"]
|
||||
</Button>
|
||||
<Button class="mr-4" v-access:code="['AC_1000001']">
|
||||
User 账号可见 ["AC_1000001"]
|
||||
</Button>
|
||||
<Button class="mr-4" v-access:code="['AC_100100', 'AC_1000001']">
|
||||
Super & Admin 账号可见 ["AC_100100","AC_1000001"]
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 角色
|
||||
|
||||
角色判断方式不需要接口返回的权限码,直接通过角色来判断按钮是否显示。
|
||||
|
||||
#### 组件方式
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
import { AccessControl } from '@vben/access';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AccessControl :codes="['super']">
|
||||
<Button> Super 角色可见 </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['admin']">
|
||||
<Button> Admin 角色可见 </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['user']">
|
||||
<Button> User 角色可见 </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['super', 'admin']">
|
||||
<Button> Super & Admin 角色可见 </Button>
|
||||
</AccessControl>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### API方式
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
import { useAccess } from '@vben/access';
|
||||
|
||||
const { hasAccessByRoles } = useAccess();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button v-if="hasAccessByRoles(['super'])"> Super 账号可见 </Button>
|
||||
<Button v-if="hasAccessByRoles(['admin'])"> Admin 账号可见 </Button>
|
||||
<Button v-if="hasAccessByRoles(['user'])"> User 账号可见 </Button>
|
||||
<Button v-if="hasAccessByRoles(['super', 'admin'])">
|
||||
Super & Admin 账号可见
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### 指令方式
|
||||
|
||||
> 指令支持绑定单个或多个角色。单个时可以直接传入字符串或数组中包含一个角色,多个角色均可访问则传入数组。
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<Button class="mr-4" v-access:role="'super'"> Super 角色可见 </Button>
|
||||
<Button class="mr-4" v-access:role="['super']"> Super 角色可见 </Button>
|
||||
<Button class="mr-4" v-access:role="['admin']"> Admin 角色可见 </Button>
|
||||
<Button class="mr-4" v-access:role="['user']"> User 角色可见 </Button>
|
||||
<Button class="mr-4" v-access:role="['super', 'admin']">
|
||||
Super & Admin 角色可见
|
||||
</Button>
|
||||
</template>
|
||||
```
|
@ -1,48 +0,0 @@
|
||||
# 检查更新
|
||||
|
||||
## 介绍
|
||||
|
||||
当网站有更新时,您可能需要检查更新。框架提供了这一功能,通过定时检查更新,您可以在应用的 preferences.ts 文件中配置 `checkUpdatesInterval`和 `enableCheckUpdates` 字段,以开启和设置检查更新的时间间隔(单位:分钟)。
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
// 是否开启检查更新
|
||||
enableCheckUpdates: true,
|
||||
// 检查更新的时间间隔,单位为分钟
|
||||
checkUpdatesInterval: 1,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 效果
|
||||
|
||||
检测到更新时,会弹出提示框,询问用户是否刷新页面:
|
||||
|
||||

|
||||
|
||||
## 替换为其他检查更新方式
|
||||
|
||||
如果需要通过其他方式检查更新,例如通过接口来更灵活地控制更新逻辑(如强制刷新、显示更新内容等),你可以通过修改 `@vben/layouts` 下面的 `src/widgets/check-updates/check-updates.vue`文件来实现。
|
||||
|
||||
```ts
|
||||
// 这里可以替换为你的检查更新逻辑
|
||||
async function getVersionTag() {
|
||||
try {
|
||||
const response = await fetch('/', {
|
||||
cache: 'no-cache',
|
||||
method: 'HEAD',
|
||||
});
|
||||
|
||||
return (
|
||||
response.headers.get('etag') || response.headers.get('last-modified')
|
||||
);
|
||||
} catch {
|
||||
console.error('Failed to fetch version tag');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
@ -1,84 +0,0 @@
|
||||
# 常用功能
|
||||
|
||||
一些常用的功能合集。
|
||||
|
||||
## 登录认证过期
|
||||
|
||||
当接口返回`401`状态码时,框架会认为登录认证过期,登录超时会跳转到登录页或者打开登录弹窗。在应用目录下的`preferences.ts`可以配置:
|
||||
|
||||
### 跳转登录页面
|
||||
|
||||
登录超时会跳转到登录页
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
loginExpiredMode: 'page',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### 打开登录弹窗
|
||||
|
||||
登录超时会打开登录弹窗
|
||||
|
||||

|
||||
|
||||
配置:
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
loginExpiredMode: 'modal',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 动态标题
|
||||
|
||||
- 默认值:`true`
|
||||
|
||||
开启后网页标题随着路由的`title`而变化。在应用目录下的`preferences.ts`,开启或者关闭即可。
|
||||
|
||||
```ts
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
dynamicTitle: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 页面水印
|
||||
|
||||
- 默认值:`false`
|
||||
|
||||
开启后网页会显示水印,在应用目录下的`preferences.ts`,开启或者关闭即可。
|
||||
|
||||
```ts
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
watermark: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
如果你想更新水印的内容,可以这么做,参数可以参考 [watermark-js-plus](https://zhensherlock.github.io/watermark-js-plus/):
|
||||
|
||||
```ts
|
||||
import { useWatermark } from '@vben/hooks';
|
||||
|
||||
const { destroyWatermark, updateWatermark } = useWatermark();
|
||||
|
||||
await updateWatermark({
|
||||
// 水印内容
|
||||
content: 'hello my watermark',
|
||||
});
|
||||
```
|
@ -1 +0,0 @@
|
||||
# 布局
|
@ -1,46 +0,0 @@
|
||||
# 全局loading
|
||||
|
||||
全局 loading 指的是页面刷新时出现的加载效果,通常是一个旋转的图标:
|
||||
|
||||

|
||||
|
||||
## 原理
|
||||
|
||||
由 `vite-plugin-inject-app-loading` 插件实现,插件会在每个应用都注入一个全局的 `loading html`。
|
||||
|
||||
## 关闭
|
||||
|
||||
如果你不需要全局 loading,可以在 `.env` 文件中关闭:
|
||||
|
||||
```bash
|
||||
VITE_INJECT_APP_LOADING=false
|
||||
```
|
||||
|
||||
## 自定义
|
||||
|
||||
如果你想要自定义全局 loading,可以在应用目录下,与`index.html`同级,创建一个`loading.html`文件,插件会自动读取并注入。这个html可以自行定义样式和动画。
|
||||
|
||||
::: tip
|
||||
|
||||
- 你可以使用跟`index.html`一样的语法,比如`VITE_APP_TITLE`变量,来获取应用的标题。
|
||||
- 必须保证有一个`id="__app-loading__"`的元素。
|
||||
- 给`id="__app-loading__"`的元素,加一个 `hidden` class。
|
||||
- 必须保证有一个`style[data-app-loading="inject-css"]`的元素。
|
||||
|
||||
```html{1,4}
|
||||
<style data-app-loading="inject-css">
|
||||
#__app-loading__.hidden {
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: all 1s ease-out;
|
||||
}
|
||||
/* ... */
|
||||
</style>
|
||||
<div id="__app-loading__">
|
||||
<!-- ... -->
|
||||
<div class="title"><%= VITE_APP_TITLE %></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
:::
|
@ -1,227 +0,0 @@
|
||||
# 国际化
|
||||
|
||||
项目已经集成了 [Vue i18n](https://kazupon.github.io/vue-i18n/),并且已经配置好了中文和英文的语言包。
|
||||
|
||||
## IDE 插件
|
||||
|
||||
如果你使用的 vscode 开发工具,则推荐安装 [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) 这个插件。它可以帮助你更方便的管理国际化的文案,安装了该插件后,你的代码内可以实时看到对应的语言内容:
|
||||
|
||||

|
||||
|
||||
## 配置默认语言
|
||||
|
||||
只需要覆盖默认的偏好设置即可,在对应的应用内,找到 `src/preferences.ts` 文件,修改 `locale` 的值即可:
|
||||
|
||||
```ts {3}
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
app: {
|
||||
locale: 'en-US',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 动态切换语言
|
||||
|
||||
切换语言有两部分组成:
|
||||
|
||||
- 更新偏好设置
|
||||
- 加载对应的语言包
|
||||
|
||||
```ts
|
||||
import type { SupportedLanguagesType } from '@vben/locales';
|
||||
import { loadLocaleMessages } from '@vben/locales';
|
||||
import { updatePreferences } from '@vben/preferences';
|
||||
|
||||
async function updateLocale(value: string) {
|
||||
// 1. 更新偏好设置
|
||||
const locale = value as SupportedLanguagesType;
|
||||
updatePreferences({
|
||||
app: {
|
||||
locale,
|
||||
},
|
||||
});
|
||||
// 2. 加载对应的语言包
|
||||
await loadLocaleMessages(locale);
|
||||
}
|
||||
|
||||
updateLocale('en-US');
|
||||
```
|
||||
|
||||
## 新增翻译文本
|
||||
|
||||
::: warning 注意
|
||||
|
||||
- 请不要将业务翻译文本放到 `@vben/locales` 内,这样可以更好的管理业务和通用的翻译文本。
|
||||
- 有多个语言包的情况下,新增翻译文本时,需要在所有语言包内新增对应的文本。
|
||||
|
||||
:::
|
||||
|
||||
新增翻译文本,只需要在对应的应用内,找到 `src/locales/langs/`,新增对应的文本即可,例:
|
||||
|
||||
**src/locales/langs/zh-CN/\*.json**
|
||||
|
||||
````ts
|
||||
```json
|
||||
{
|
||||
"about": {
|
||||
"desc": "y-code-platform 是一个现代的管理模版。"
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
**src/locales/langs/en-US.ts**
|
||||
|
||||
````ts
|
||||
```json
|
||||
{
|
||||
"about": {
|
||||
"desc": "y-code-platform is a modern management template."
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
## 使用翻译文本
|
||||
|
||||
通过 `@vben/locales`,你可以很方便的使用翻译文本:
|
||||
|
||||
### 在代码中使用
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
const items = computed(() => [{ title: $t('about.desc') }]);
|
||||
</script>
|
||||
<template>
|
||||
<div>{{ $t('about.desc') }}</div>
|
||||
<template v-for="item in items.value">
|
||||
<div>{{ item.title }}</div>
|
||||
</template>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 新增语言包
|
||||
|
||||
如果你需要新增语言包,需要按照以下步骤进行:
|
||||
|
||||
- 在 `packages/locales/langs` 目录下新增对应的语言包文件,例:`zh-TW.json`,并翻译对应的文本。
|
||||
- 在对应的应用内,找到 `src/locales/langs` 文件,新增对应的语言包 `zh-TW.json`
|
||||
- 在 `packages/constants/src/core.ts`内,新增对应的语言:
|
||||
|
||||
```ts
|
||||
export interface LanguageOption {
|
||||
label: string;
|
||||
value: 'en-US' | 'zh-CN'; // [!code --]
|
||||
value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
|
||||
}
|
||||
export const SUPPORT_LANGUAGES: LanguageOption[] = [
|
||||
{
|
||||
label: '简体中文',
|
||||
value: 'zh-CN',
|
||||
},
|
||||
{
|
||||
label: 'English',
|
||||
value: 'en-US',
|
||||
},
|
||||
{
|
||||
label: '繁体中文', // [!code ++]
|
||||
value: 'zh-TW', // [!code ++]
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
- 在 `packages/locales/typing.ts`内,新增 Typescript 类型:
|
||||
|
||||
```ts
|
||||
export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --]
|
||||
export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
|
||||
```
|
||||
|
||||
到这里,你就可以在项目内使用新增的语言包了。
|
||||
|
||||
## 界面切换语言功能
|
||||
|
||||
如果你想关闭界面上的语言切换显示按钮,在对应的应用内,找到 `src/preferences.ts` 文件,修改 `locale` 的值即可:
|
||||
|
||||
```ts {3}
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
widget: {
|
||||
languageToggle: false,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 远程加载语言包
|
||||
|
||||
::: tip 提示
|
||||
|
||||
通过项目自带的`request`工具进行接口请求时,默认请求头里会带上 [Accept-Language](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept-Language) ,服务端可根据请求头进行动态数据国际化处理。
|
||||
|
||||
:::
|
||||
|
||||
每个应用都有一个独立的语言包,它可以覆盖通用的语言配置,你可以通过远程加载的方式来获取对应的语言包,只需要在对应的应用内,找到 `src/locales/index.ts` 文件,修改 `loadMessages` 方法即可:
|
||||
|
||||
```ts {3-4}
|
||||
async function loadMessages(lang: SupportedLanguagesType) {
|
||||
const [appLocaleMessages] = await Promise.all([
|
||||
// 这里修改为远程接口加载数据即可
|
||||
localesMap[lang](),
|
||||
loadThirdPartyMessage(lang),
|
||||
]);
|
||||
return appLocaleMessages.default;
|
||||
}
|
||||
```
|
||||
|
||||
## 第三方语言包
|
||||
|
||||
不同应用内使用的第三方组件库或者插件国际化方式可能不一致,所以需要差别处理。 如果你需要引入第三方的语言包,你可以在对应的应用内,找到 `src/locales/index.ts` 文件,修改 `loadThirdPartyMessage` 方法即可:
|
||||
|
||||
```ts
|
||||
/**
|
||||
* 加载dayjs的语言包
|
||||
* @param lang
|
||||
*/
|
||||
async function loadDayjsLocale(lang: SupportedLanguagesType) {
|
||||
let locale;
|
||||
switch (lang) {
|
||||
case 'zh-CN': {
|
||||
locale = await import('dayjs/locale/zh-cn');
|
||||
break;
|
||||
}
|
||||
case 'en-US': {
|
||||
locale = await import('dayjs/locale/en');
|
||||
break;
|
||||
}
|
||||
// 默认使用英语
|
||||
default: {
|
||||
locale = await import('dayjs/locale/en');
|
||||
}
|
||||
}
|
||||
if (locale) {
|
||||
dayjs.locale(locale);
|
||||
} else {
|
||||
console.error(`Failed to load dayjs locale for ${lang}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 移除国际化
|
||||
|
||||
首先,不是很建议移除国际化,因为国际化是一个很好的开发习惯,但是如果你真的需要移除国际化,你可以直接使用中文文案,然后保留项目自带的语言包即可,整体开发体验不会影响。移除国际化的步骤如下:
|
||||
|
||||
- 隐藏界面上的语言切换按钮,见:[界面切换语言功能](#界面切换语言功能)
|
||||
- 修改默认语言,见:[配置默认语言](#配置默认语言)
|
||||
- 关闭 `vue-i18n`的警告提示,在`src/locales/index.ts`文件内,修改`missingWarn`为`false`即可:
|
||||
|
||||
```ts
|
||||
async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
|
||||
await coreSetup(app, {
|
||||
defaultLocale: preferences.app.locale,
|
||||
loadMessages,
|
||||
missingWarn: !import.meta.env.PROD, // [!code --]
|
||||
missingWarn: false, // [!code ++]
|
||||
...options,
|
||||
});
|
||||
}
|
||||
```
|
@ -1,220 +0,0 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# 登录
|
||||
|
||||
本文介绍如何去改造自己的应用程序登录页以及如何快速的对接登录页面接口。
|
||||
|
||||
## 登录页面调整
|
||||
|
||||
如果你想调整登录页面的标题、描述和图标以及工具栏,你可以通过配置 `AuthPageLayout` 组件的参数来实现。
|
||||
|
||||

|
||||
|
||||
只需要在应用下的 `src/layouts/auth.vue` 内,配置`AuthPageLayout`的 `props`参数即可:
|
||||
|
||||
```vue {2-7}
|
||||
<AuthPageLayout
|
||||
:copyright="true"
|
||||
:toolbar="true"
|
||||
:toolbarList="['color', 'language', 'layout', 'theme']"
|
||||
:app-name="appName"
|
||||
:logo="logo"
|
||||
:page-description="$t('authentication.pageDesc')"
|
||||
:page-title="$t('authentication.pageTitle')"
|
||||
>
|
||||
</AuthPageLayout>
|
||||
```
|
||||
|
||||
## 登录表单调整
|
||||
|
||||
如果你想调整登录表单的相关内容,你可以在应用下的 `src/views/_core/authentication/login.vue` 内,配置`AuthenticationLogin` 组件参数即可:
|
||||
|
||||
```vue
|
||||
<AuthenticationLogin
|
||||
:loading="authStore.loginLoading"
|
||||
@submit="authStore.authLogin"
|
||||
/>
|
||||
```
|
||||
|
||||
::: details AuthenticationLogin 组件参数
|
||||
|
||||
```ts
|
||||
{
|
||||
/**
|
||||
* @zh_CN 验证码登录路径
|
||||
*/
|
||||
codeLoginPath?: string;
|
||||
/**
|
||||
* @zh_CN 忘记密码路径
|
||||
*/
|
||||
forgetPasswordPath?: string;
|
||||
|
||||
/**
|
||||
* @zh_CN 是否处于加载处理状态
|
||||
*/
|
||||
loading?: boolean;
|
||||
|
||||
/**
|
||||
* @zh_CN 二维码登录路径
|
||||
*/
|
||||
qrCodeLoginPath?: string;
|
||||
|
||||
/**
|
||||
* @zh_CN 注册路径
|
||||
*/
|
||||
registerPath?: string;
|
||||
|
||||
/**
|
||||
* @zh_CN 是否显示验证码登录
|
||||
*/
|
||||
showCodeLogin?: boolean;
|
||||
/**
|
||||
* @zh_CN 是否显示忘记密码
|
||||
*/
|
||||
showForgetPassword?: boolean;
|
||||
|
||||
/**
|
||||
* @zh_CN 是否显示二维码登录
|
||||
*/
|
||||
showQrcodeLogin?: boolean;
|
||||
|
||||
/**
|
||||
* @zh_CN 是否显示注册按钮
|
||||
*/
|
||||
showRegister?: boolean;
|
||||
|
||||
/**
|
||||
* @zh_CN 是否显示记住账号
|
||||
*/
|
||||
showRememberMe?: boolean;
|
||||
|
||||
/**
|
||||
* @zh_CN 是否显示第三方登录
|
||||
*/
|
||||
showThirdPartyLogin?: boolean;
|
||||
|
||||
/**
|
||||
* @zh_CN 登录框子标题
|
||||
*/
|
||||
subTitle?: string;
|
||||
|
||||
/**
|
||||
* @zh_CN 登录框标题
|
||||
*/
|
||||
title?: string;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tip Note
|
||||
|
||||
如果这些配置不能满足你的需求,你可以自行实现登录表单及相关登录逻辑或者给我们提交 `PR`。
|
||||
|
||||
:::
|
||||
|
||||
## 接口对接流程
|
||||
|
||||
这里将会快速的介绍如何快速对接自己的后端。
|
||||
|
||||
### 前置条件
|
||||
|
||||
- 首先文档用的后端服务,接口返回的格式统一如下:
|
||||
|
||||
```ts
|
||||
interface HttpResponse<T = any> {
|
||||
/**
|
||||
* 0 表示成功 其他表示失败
|
||||
* 0 means success, others means fail
|
||||
*/
|
||||
code: number;
|
||||
data: T;
|
||||
message: string;
|
||||
}
|
||||
```
|
||||
|
||||
如果你不符合这个格式,你需要先阅读 [服务端交互](../essentials/server.md) 文档,改造你的`request.ts`配置。
|
||||
|
||||
- 其次你需要在先将本地代理地址改为你的真实后端地址,你可以在应用下的 `vite.config.mts` 内配置:
|
||||
|
||||
```ts
|
||||
import { defineConfig } from '@vben/vite-config';
|
||||
|
||||
export default defineConfig(async () => {
|
||||
return {
|
||||
vite: {
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
// 这里改为你的真实接口地址
|
||||
target: 'http://localhost:5320/api',
|
||||
ws: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
### 登录接口
|
||||
|
||||
为了能正常登录,你的后端最少需要提供 `2-3` 个接口:
|
||||
|
||||
- 登录接口
|
||||
|
||||
接口地址可在应用下的 `src/api/core/auth` 内修改,以下为默认接口地址:
|
||||
|
||||
```ts
|
||||
/**
|
||||
* 登录
|
||||
*/
|
||||
export async function loginApi(data: AuthApi.LoginParams) {
|
||||
return requestClient.post<AuthApi.LoginResult>('/auth/login', data);
|
||||
}
|
||||
|
||||
/** 只需要保证登录接口返回值有 `accessToken` 字段即可 */
|
||||
export interface LoginResult {
|
||||
accessToken: string;
|
||||
}
|
||||
```
|
||||
|
||||
- 获取用户信息接口
|
||||
|
||||
接口地址可在应用下的 `src/api/core/user` 内修改,以下为默认接口地址:
|
||||
|
||||
```ts
|
||||
export async function getUserInfoApi() {
|
||||
return requestClient.get<UserInfo>('/user/info');
|
||||
}
|
||||
|
||||
/** 只需要保证登录接口返回值有以下字段即可,多的字段可以自行使用 */
|
||||
export interface UserInfo {
|
||||
roles: string[];
|
||||
realName: string;
|
||||
}
|
||||
```
|
||||
|
||||
- 获取权限码 (可选)
|
||||
|
||||
这个接口用于获取用户的权限码,权限码是用于控制用户的权限的,接口地址可在应用下的 `src/api/core/auth` 内修改,以下为默认接口地址:
|
||||
|
||||
```ts
|
||||
export async function getAccessCodesApi() {
|
||||
return requestClient.get<string[]>('/auth/codes');
|
||||
}
|
||||
```
|
||||
|
||||
如果你不需要这个权限,你只需要把代码改为返回一个空数组即可。
|
||||
|
||||
```ts {2}
|
||||
export async function getAccessCodesApi() {
|
||||
// 这里返回一个空数组即可
|
||||
return [];
|
||||
}
|
||||
```
|
5
apps/docs/src/guide/in-depth/materials.md
Normal file
5
apps/docs/src/guide/in-depth/materials.md
Normal file
@ -0,0 +1,5 @@
|
||||
# 物料创建
|
||||
|
||||
```bash
|
||||
npm create vtj@latest --registry=https://registry.npmmirror.com -- -t material
|
||||
```
|
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
||||
# 组件库切换
|
||||
|
||||
`Vue Admin` 支持你自由选择组件库,目前演示站点的默认组件库是 `Ant Design Vue`,与旧版本保持一致。同时框架还内置了 `Element Plus` 版本和 `Naive UI` 版本,你可以根据自己的喜好选择。
|
||||
|
||||
## 新增组件库应用
|
||||
|
||||
如果你想用其他别的组件库,你只需要按以下步骤进行操作:
|
||||
|
||||
1. 在`apps`内创建一个新的文件夹,例如`apps/web-xxx`。
|
||||
2. 更改`apps/web-xxx/package.json`的`name`字段为`web-xxx`。
|
||||
3. 移除其他组件库依赖及代码,并用你的组件库进行替换相应逻辑,需要改动的地方不多。
|
||||
4. 调整`locales`内的语言文件。
|
||||
5. 调整 `app.vue` 内的组件。
|
||||
6. 自行适配组件库的主题,与 `y-code-platform` 契合。
|
||||
7. 调整 `.env` 内的应用名
|
||||
8. 在大仓根目录增加 `dev:xxx` 脚本
|
||||
9. 执行 `pnpm install` 安装依赖
|
Loading…
x
Reference in New Issue
Block a user