Forráskód Böngészése

feat: Improve the front-end permission access logic and sample code

vince 9 hónapja
szülő
commit
a60467b01c

+ 108 - 2
apps/web-antd/src/views/demos/access/frontend/button-control.vue

@@ -1,9 +1,115 @@
 <script lang="ts" setup>
-import { Fallback } from '@vben/universal-ui';
+import type { LoginAndRegisterParams } from '@vben/universal-ui';
+
+import { useRouter } from 'vue-router';
+
+import { RoleAuthority, useAccess } from '@vben/access';
+
+import { Button } from 'ant-design-vue';
+
+import { useAccessStore, useAppStore } from '#/store';
 
 defineOptions({ name: 'AccessFrontendButtonControl' });
+
+const { accessMode, hasAuthByRole } = useAccess();
+const accessStore = useAccessStore();
+const appStore = useAppStore();
+const router = useRouter();
+
+function roleButtonType(role: string) {
+  return accessStore.userRoles.includes(role) ? 'primary' : 'default';
+}
+
+async function changeAccount(role: string) {
+  if (accessStore.userRoles.includes(role)) {
+    return;
+  }
+  const accounts: Record<string, LoginAndRegisterParams> = {
+    admin: {
+      password: '123456',
+      username: 'admin',
+    },
+    super: {
+      password: '123456',
+      username: 'vben',
+    },
+    user: {
+      password: '123456',
+      username: 'jack',
+    },
+  };
+  const account = accounts[role];
+  await appStore.resetAppState();
+  await accessStore.authLogin(account, async () => {
+    router.go(0);
+  });
+}
 </script>
 
 <template>
-  <Fallback status="comming-soon" />
+  <div class="p-5">
+    <div class="card-box p-5">
+      <h1 class="text-xl font-semibold">前端按钮访问权限演示</h1>
+      <div class="text-foreground/80 mt-2">
+        切换不同的账号,观察按钮显示变化
+      </div>
+    </div>
+
+    <template v-if="accessMode === 'frontend'">
+      <div class="card-box mt-5 p-5 font-semibold">
+        <div class="mb-3">
+          <span class="text-lg">当前账号:</span>
+          <span class="text-primary mx-4">
+            {{ accessStore.userRoles }}
+          </span>
+        </div>
+
+        <Button :type="roleButtonType('super')" @click="changeAccount('super')">
+          切换为 Super 账号
+        </Button>
+
+        <Button
+          :type="roleButtonType('admin')"
+          class="mx-4"
+          @click="changeAccount('admin')"
+        >
+          切换为 Admin 账号
+        </Button>
+        <Button :type="roleButtonType('user')" @click="changeAccount('user')">
+          切换为 User 账号
+        </Button>
+      </div>
+      <div class="card-box mt-5 p-5 font-semibold">
+        <div class="mb-3 text-lg">组件形式控制</div>
+        <RoleAuthority :roles="['super']">
+          <Button class="mr-4"> Super 角色可见 </Button>
+        </RoleAuthority>
+        <RoleAuthority :roles="['admin']">
+          <Button class="mr-4"> Admin 角色可见 </Button>
+        </RoleAuthority>
+        <RoleAuthority :roles="['user']">
+          <Button class="mr-4"> User 角色可见 </Button>
+        </RoleAuthority>
+        <RoleAuthority :roles="['super', 'admin']">
+          <Button class="mr-4"> Super 和 Admin 角色都可见 </Button>
+        </RoleAuthority>
+      </div>
+
+      <div class="card-box mt-5 p-5 font-semibold">
+        <div class="mb-3 text-lg">函数形式控制</div>
+        <Button v-if="hasAuthByRole(['super'])" class="mr-4">
+          Super 角色可见
+        </Button>
+        <Button v-if="hasAuthByRole(['admin'])" class="mr-4">
+          Admin 角色可见
+        </Button>
+        <Button v-if="hasAuthByRole(['user'])" class="mr-4">
+          User 角色可见
+        </Button>
+        <Button v-if="hasAuthByRole(['super', 'admin'])" class="mr-4">
+          Super 和 Admin 角色都可见
+        </Button>
+      </div>
+    </template>
+  </div>
 </template>

+ 3 - 3
apps/web-antd/src/views/demos/access/frontend/index.vue

@@ -49,7 +49,7 @@ async function changeAccount(role: string) {
 <template>
   <div class="p-5">
     <div class="card-box p-5">
-      <h1 class="text-xl font-semibold">前端页面访问演示</h1>
+      <h1 class="text-xl font-semibold">前端页面访问权限演示</h1>
       <div class="text-foreground/80 mt-2">
         切换不同的账号,观察左侧菜单变化。
       </div>
@@ -57,14 +57,14 @@ async function changeAccount(role: string) {
 
     <template v-if="accessMode === 'frontend'">
       <div class="card-box mt-5 p-5 font-semibold">
-        当前权限模式:
+        <span class="text-lg">当前权限模式:</span>
         <span class="text-primary mx-4">{{ accessMode }}</span>
         <Button type="primary">切换权限模式</Button>
       </div>
 
       <div class="card-box mt-5 p-5 font-semibold">
         <div class="mb-3">
-          当前账号:
+          <span class="text-lg">当前账号:</span>
           <span class="text-primary mx-4">
             {{ accessStore.userRoles }}
           </span>

+ 29 - 0
packages/business/access/src/code-authority.vue

@@ -0,0 +1,29 @@
+<!--
+ Access control component for fine-grained access control.
+-->
+<script lang="ts" setup>
+import { useAccess } from './use-access';
+
+interface Props {
+  /**
+   * Specified codes is visible
+   * @default []
+   */
+  codes?: string[];
+}
+
+defineOptions({
+  name: 'CodeAuthority',
+});
+
+withDefaults(defineProps<Props>(), {
+  codes: () => [],
+});
+
+const { hasAuthByRole } = useAccess();
+</script>
+
+<template>
+  <slot v-if="!codes"></slot>
+  <slot v-else-if="hasAuthByRole(codes)"></slot>
+</template>

+ 1 - 0
packages/business/access/src/index.ts

@@ -1,3 +1,4 @@
+export { default as CodeAuthority } from './code-authority.vue';
 export * from './generate-menu-and-routes';
 export { default as RoleAuthority } from './role-authority.vue';
 export type * from './types';

+ 8 - 5
packages/business/access/src/role-authority.vue

@@ -2,25 +2,28 @@
  Access control component for fine-grained access control.
 -->
 <script lang="ts" setup>
+import { useAccess } from './use-access';
+
 interface Props {
   /**
    * Specified role is visible
-   * - When the permission mode is 'frontend', the value can be a role value.
-   * - When the permission mode is 'backend', the value can be a code permission value.
-   * @default ''
+   * @default []
    */
   roles?: string[];
 }
 
 defineOptions({
-  name: 'FrontendAuthority',
+  name: 'RoleAuthority',
 });
 
 withDefaults(defineProps<Props>(), {
   roles: undefined,
 });
+
+const { hasAuthByRole } = useAccess();
 </script>
 
 <template>
-  <slot></slot>
+  <slot v-if="!roles"></slot>
+  <slot v-else-if="hasAuthByRole(roles)"></slot>
 </template>

+ 14 - 1
packages/business/access/src/use-access.ts

@@ -1,13 +1,26 @@
 import { computed } from 'vue';
 
 import { preferences } from '@vben-core/preferences';
+import { useCoreAccessStore } from '@vben-core/stores';
 
 function useAccess() {
+  const coreAccessStore = useCoreAccessStore();
   const accessMode = computed(() => {
     return preferences.app.accessMode;
   });
 
-  return { accessMode };
+  /**
+   * 基于角色判断是否有权限
+   * @description: Determine whether there is permission,The role is judged by the user's role
+   * @param roles
+   */
+  function hasAuthByRole(roles: string[]) {
+    const userRoleSet = new Set(coreAccessStore.getUserRoles);
+    const intersection = roles.filter((item) => userRoleSet.has(item));
+    return intersection.length > 0;
+  }
+
+  return { accessMode, hasAuthByRole };
 }
 
 export { useAccess };