fix: 一些基本功能

This commit is contained in:
2025-03-06 19:11:29 +08:00
parent 68a7e790d8
commit 024f641a41
20 changed files with 8 additions and 861 deletions

View File

@@ -1,3 +0,0 @@
PORT=5320
ACCESS_TOKEN_SECRET=access_token_secret
REFRESH_TOKEN_SECRET=refresh_token_secret

View File

@@ -1,13 +0,0 @@
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse } from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const menus =
MOCK_MENUS.find((item) => item.username === userinfo.username)?.menus ?? [];
return useResponseSuccess(menus);
});

View File

@@ -1,7 +0,0 @@
export default defineEventHandler((event) => {
if (event.method === 'OPTIONS') {
event.node.res.statusCode = 204;
event.node.res.statusMessage = 'No Content.';
return 'OK';
}
});

View File

@@ -1,12 +0,0 @@
export default defineEventHandler(() => {
return `
<h1>Hello Vben Admin</h1>
<h2>Mock service is starting</h2>
<ul>
<li><a href="/api/user">/api/user/info</a></li>
<li><a href="/api/menu">/api/menu/all</a></li>
<li><a href="/api/auth/codes">/api/auth/codes</a></li>
<li><a href="/api/auth/login">/api/auth/login</a></li>
</ul>
`;
});

View File

@@ -1,5 +1,8 @@
# 应用标题
VITE_APP_TITLE=Vben Admin Antd
VITE_APP_TITLE=萧康云医
# 应用命名空间用于缓存、store等功能的前缀确保隔离
VITE_APP_NAMESPACE=vben-web-antd
VITE_APP_NAMESPACE=xk-admin-
# 应用版本
XK_APP_VERSION=1.0.0

View File

@@ -7,7 +7,7 @@ VITE_BASE=/
VITE_GLOB_API_URL=/api
# 是否开启 Nitro Mock服务true 为开启false 为关闭
VITE_NITRO_MOCK=true
VITE_NITRO_MOCK=false
# 是否打开 devtoolstrue 为打开false 为关闭
VITE_DEVTOOLS=false

View File

@@ -1,7 +1,7 @@
VITE_BASE=/
# 接口地址
VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
VITE_GLOB_API_URL=/api/admin
# 是否开启压缩,可以设置为 none, brotli, gzip
VITE_COMPRESS=none
@@ -10,7 +10,7 @@ VITE_COMPRESS=none
VITE_PWA=false
# vue-router 的模式
VITE_ROUTER_HISTORY=hash
VITE_ROUTER_HISTORY=createWebHashHistory
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true

View File

@@ -1,5 +0,0 @@
# 应用标题
VITE_APP_TITLE=Vben Admin Ele
# 应用命名空间用于缓存、store等功能的前缀确保隔离
VITE_APP_NAMESPACE=vben-web-ele

View File

@@ -1,7 +0,0 @@
# public path
VITE_BASE=/
# Basic interface address SPA
VITE_GLOB_API_URL=/api
VITE_VISUALIZER=true

View File

@@ -1,16 +0,0 @@
# 端口号
VITE_PORT=5777
VITE_BASE=/
# 接口地址
VITE_GLOB_API_URL=/api
# 是否开启 Nitro Mock服务true 为开启false 为关闭
VITE_NITRO_MOCK=true
# 是否打开 devtoolstrue 为打开false 为关闭
VITE_DEVTOOLS=false
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true

View File

@@ -1,19 +0,0 @@
VITE_BASE=/
# 接口地址
VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
# 是否开启压缩,可以设置为 none, brotli, gzip
VITE_COMPRESS=none
# 是否开启 PWA
VITE_PWA=false
# vue-router 的模式
VITE_ROUTER_HISTORY=hash
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true
# 打包后是否生成dist.zip
VITE_ARCHIVER=true

View File

@@ -1,42 +0,0 @@
import type {
ComponentRecordType,
GenerateMenuAndRoutesOptions,
} from '@vben/types';
import { generateAccessible } from '@vben/access';
import { preferences } from '@vben/preferences';
import { ElMessage } from 'element-plus';
import { getAllMenusApi } from '#/api';
import { BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
const layoutMap: ComponentRecordType = {
BasicLayout,
IFrameView,
};
return await generateAccessible(preferences.app.accessMode, {
...options,
fetchMenuListAsync: async () => {
ElMessage({
duration: 1500,
message: `${$t('common.loadingMenu')}...`,
});
return await getAllMenusApi();
},
// 可以指定没有权限跳转403页面
forbiddenComponent,
// 如果 route.meta.menuVisibleWithForbidden = true
layoutMap,
pageMap,
});
}
export { generateAccess };

View File

@@ -1,5 +0,0 @@
# 应用标题
VITE_APP_TITLE=Vben Admin Naive
# 应用命名空间用于缓存、store等功能的前缀确保隔离
VITE_APP_NAMESPACE=vben-web-naive

View File

@@ -1,7 +0,0 @@
# public path
VITE_BASE=/
# Basic interface address SPA
VITE_GLOB_API_URL=/api
VITE_VISUALIZER=true

View File

@@ -1,16 +0,0 @@
# 端口号
VITE_PORT=5888
VITE_BASE=/
# 接口地址
VITE_GLOB_API_URL=/api
# 是否开启 Nitro Mock服务true 为开启false 为关闭
VITE_NITRO_MOCK=true
# 是否打开 devtoolstrue 为打开false 为关闭
VITE_DEVTOOLS=false
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true

View File

@@ -1,19 +0,0 @@
VITE_BASE=/
# 接口地址
VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
# 是否开启压缩,可以设置为 none, brotli, gzip
VITE_COMPRESS=none
# 是否开启 PWA
VITE_PWA=false
# vue-router 的模式
VITE_ROUTER_HISTORY=hash
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true
# 打包后是否生成dist.zip
VITE_ARCHIVER=true

View File

@@ -1,40 +0,0 @@
import type {
ComponentRecordType,
GenerateMenuAndRoutesOptions,
} from '@vben/types';
import { generateAccessible } from '@vben/access';
import { preferences } from '@vben/preferences';
import { message } from '#/adapter/naive';
import { getAllMenusApi } from '#/api';
import { BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
const layoutMap: ComponentRecordType = {
BasicLayout,
IFrameView,
};
return await generateAccessible(preferences.app.accessMode, {
...options,
fetchMenuListAsync: async () => {
message.loading(`${$t('common.loadingMenu')}...`, {
duration: 1.5,
});
return await getAllMenusApi();
},
// 可以指定没有权限跳转403页面
forbiddenComponent,
// 如果 route.meta.menuVisibleWithForbidden = true
layoutMap,
pageMap,
});
}
export { generateAccess };

View File

@@ -1,318 +0,0 @@
---
outline: deep
---
# Access Control
The framework has built-in two types of access control methods:
- Determining whether a menu or button can be accessed based on user roles
- Determining whether a menu or button can be accessed through an API
## Frontend Access Control
**Implementation Principle**: The permissions for routes are hardcoded on the frontend, specifying which permissions are required to view certain routes. Only general routes are initialized, and routes that require permissions are not added to the route table. After logging in or obtaining user roles through other means, the roles are used to traverse the route table to generate a route table that the role can access. This table is then added to the router instance using `router.addRoute`, achieving permission filtering.
**Disadvantage**: The permissions are relatively inflexible; if the backend changes roles, the frontend needs to be adjusted accordingly. This is suitable for systems with relatively fixed roles.
### Steps
- Ensure the current mode is set to frontend access control
Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='frontend'`.
```ts
import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
// Default value, optional
accessMode: 'frontend',
},
});
```
- Configure route permissions
#### If not configured, it is visible by default
```ts {3}
{
meta: {
authority: ['super'],
},
},
```
- Ensure the roles returned by the interface match the permissions in the route table
You can look under `src/store/auth` in the application to find the following code:
```ts
// Set the login user information, ensuring that userInfo.roles is an array and contains permissions from the route table
// For example: userInfo.roles=['super', 'admin']
authStore.setUserInfo(userInfo);
```
At this point, the configuration is complete. You need to ensure that the roles returned by the interface after login match the permissions in the route table; otherwise, access will not be possible.
### Menu Visible but Access Forbidden
Sometimes, we need the menu to be visible but access to it forbidden. This can be achieved by setting `menuVisibleWithForbidden` to `true`. In this case, the menu will be visible, but access will be forbidden, redirecting to a 403 page.
```ts
{
meta: {
menuVisibleWithForbidden: true,
},
},
```
## Backend Access Control
**Implementation Principle**: It is achieved by dynamically generating a routing table through an API, which returns data following a certain structure. The frontend processes this data into a recognizable structure, then adds it to the routing instance using `router.addRoute`, realizing the dynamic generation of permissions.
**Disadvantage**: The backend needs to provide a data structure that meets the standards, and the frontend needs to process this structure. This is suitable for systems with more complex permissions.
### Steps
- Ensure the current mode is set to backend access control
Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='backend'`.
```ts
import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
accessMode: 'backend',
},
});
```
- Ensure the structure of the menu data returned by the interface is correct
You can look under `src/router/access.ts` in the application to find the following code:
```ts
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
return await generateAccessible(preferences.app.accessMode, {
fetchMenuListAsync: async () => {
// This interface is for the menu data returned by the backend
return await getAllMenus();
},
});
}
```
- Interface returns menu data, see comments for explanation
::: details Example of Interface Returning Menu Data
```ts
const dashboardMenus = [
{
// Here, 'BasicLayout' is hardcoded and cannot be changed
component: 'BasicLayout',
meta: {
order: -1,
title: 'page.dashboard.title',
},
name: 'Dashboard',
path: '/',
redirect: '/analytics',
children: [
{
name: 'Analytics',
path: '/analytics',
// Here is the path of the page, need to remove 'views/' and '.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',
},
},
],
},
];
```
:::
At this point, the configuration is complete. You need to ensure that after logging in, the format of the menu returned by the interface is correct; otherwise, access will not be possible.
## Fine-grained Control of Buttons
In some cases, we need to control the display of buttons with fine granularity. We can control the display of buttons through interfaces or roles.
### Permission Code
The permission code is the code returned by the interface. The logic to determine whether a button is displayed is located under `src/store/auth`:
```ts
const [fetchUserInfoResult, accessCodes] = await Promise.all([
fetchUserInfo(),
getAccessCodes(),
]);
userInfo = fetchUserInfoResult;
authStore.setUserInfo(userInfo);
accessStore.setAccessCodes(accessCodes);
```
Locate the `getAccessCodes` corresponding interface, which can be adjusted according to business logic.
The data structure returned by the permission code is an array of strings, for example: `['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']`
With the permission codes, you can use the `AccessControl` component and API provided by `@vben/access` to show and hide buttons.
#### Component Method
```vue
<script lang="ts" setup>
import { AccessControl, useAccess } from '@vben/access';
const { accessMode, hasAccessByCodes } = useAccess();
</script>
<template>
<!-- You need to specify type="code" -->
<AccessControl :codes="['AC_100100']" type="code">
<Button> Visible to Super account ["AC_1000001"] </Button>
</AccessControl>
<AccessControl :codes="['AC_100030']" type="code">
<Button> Visible to Admin account ["AC_100010"] </Button>
</AccessControl>
<AccessControl :codes="['AC_1000001']" type="code">
<Button> Visible to User account ["AC_1000001"] </Button>
</AccessControl>
<AccessControl :codes="['AC_100100', 'AC_100010']" type="code">
<Button>
Visible to Super & Admin account ["AC_100100","AC_1000001"]
</Button>
</AccessControl>
</template>
```
#### API Method
```vue
<script lang="ts" setup>
import { AccessControl, useAccess } from '@vben/access';
const { hasAccessByCodes } = useAccess();
</script>
<template>
<Button v-if="hasAccessByCodes(['AC_100100'])">
Visible to Super account ["AC_1000001"]
</Button>
<Button v-if="hasAccessByCodes(['AC_100030'])">
Visible to Admin account ["AC_100010"]
</Button>
<Button v-if="hasAccessByCodes(['AC_1000001'])">
Visible to User account ["AC_1000001"]
</Button>
<Button v-if="hasAccessByCodes(['AC_100100', 'AC_1000001'])">
Visible to Super & Admin account ["AC_100100","AC_1000001"]
</Button>
</template>
```
#### Directive Method
> The directive supports binding single or multiple permission codes. For a single one, you can pass a string or an array containing one permission code, and for multiple permission codes, you can pass an array.
```vue
<template>
<Button class="mr-4" v-access:code="'AC_100100'">
Visible to Super account 'AC_100100'
</Button>
<Button class="mr-4" v-access:code="['AC_100030']">
Visible to Admin account ["AC_100010"]
</Button>
<Button class="mr-4" v-access:code="['AC_1000001']">
Visible to User account ["AC_1000001"]
</Button>
<Button class="mr-4" v-access:code="['AC_100100', 'AC_1000001']">
Visible to Super & Admin account ["AC_100100","AC_1000001"]
</Button>
</template>
```
### Roles
The method of determining roles does not require permission codes returned by the interface; it directly determines whether buttons are displayed based on roles.
#### Component Method
```vue
<script lang="ts" setup>
import { AccessControl } from '@vben/access';
</script>
<template>
<AccessControl :codes="['super']">
<Button> Visible to Super account </Button>
</AccessControl>
<AccessControl :codes="['admin']">
<Button> Visible to Admin account </Button>
</AccessControl>
<AccessControl :codes="['user']">
<Button> Visible to User account </Button>
</AccessControl>
<AccessControl :codes="['super', 'admin']">
<Button> Super & Visible to Admin account </Button>
</AccessControl>
</template>
```
#### API Method
```vue
<script lang="ts" setup>
import { useAccess } from '@vben/access';
const { hasAccessByRoles } = useAccess();
</script>
<template>
<Button v-if="hasAccessByRoles(['super'])"> Visible to Super account </Button>
<Button v-if="hasAccessByRoles(['admin'])"> Visible to Admin account </Button>
<Button v-if="hasAccessByRoles(['user'])"> Visible to User account </Button>
<Button v-if="hasAccessByRoles(['super', 'admin'])">
Super & Visible to Admin account
</Button>
</template>
```
#### Directive Method
> The directive supports binding single or multiple permission codes. For a single one, you can pass a string or an array containing one permission code, and for multiple permission codes, you can pass an array.
```vue
<template>
<Button class="mr-4" v-access:role="'super'">
Visible to Super account
</Button>
<Button class="mr-4" v-access:role="['admin']">
Visible to Admin account
</Button>
<Button class="mr-4" v-access:role="['user']">
Visible to User account
</Button>
<Button class="mr-4" v-access:role="['super', 'admin']">
Super & Visible to Admin account
</Button>
</template>
```

View File

@@ -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>
```

View File

@@ -1,25 +1,9 @@
{
"folders": [
{
"name": "@vben/backend-mock",
"path": "apps/backend-mock",
},
{
"name": "@vben/web-antd",
"path": "apps/web-antd",
},
{
"name": "@vben/web-ele",
"path": "apps/web-ele",
},
{
"name": "@vben/web-naive",
"path": "apps/web-naive",
},
{
"name": "@vben/docs",
"path": "docs",
},
{
"name": "@vben/commitlint-config",
"path": "internal/lint-configs/commitlint-config",