瀏覽代碼

feat: add v-access directive

vince 8 月之前
父節點
當前提交
01e95e029f

+ 1 - 0
apps/web-antd/src/layouts/basic.vue

@@ -144,6 +144,7 @@ function handleLockScreen(password: string) {
     <template #extra>
       <AuthenticationLoginExpiredModal
         v-model:open="openLoginExpiredModal"
+        :avatar
         :loading="loginLoading"
         password-placeholder="123456"
         username-placeholder="vben"

+ 1 - 1
apps/web-antd/src/router/routes/modules/demos.ts

@@ -14,7 +14,7 @@ const routes: RouteRecordRaw[] = [
     },
     name: 'Demos',
     path: '/demos',
-    redirect: '/access',
+    redirect: '/demos/access',
     children: [
       {
         meta: {

+ 13 - 13
apps/web-antd/src/views/demos/access/button-control.vue

@@ -26,7 +26,7 @@ const accounts: Record<string, LoginAndRegisterParams> = {
   },
 };
 
-const { accessMode, hasAuthByCodes } = useAccess();
+const { accessMode, hasAccessByCodes } = useAccess();
 const accessStore = useAccessStore();
 const appStore = useAppStore();
 const router = useRouter();
@@ -83,16 +83,16 @@ async function changeAccount(role: string) {
 
     <div class="card-box mt-5 p-5 font-semibold">
       <div class="mb-3 text-lg">组件形式控制 - 权限码方式</div>
-      <AccessControl :value="['AC_100100']" type="code">
+      <AccessControl :permissions="['AC_100100']" type="code">
         <Button class="mr-4"> Super 账号可见 ["AC_1000001"] </Button>
       </AccessControl>
-      <AccessControl :value="['AC_100030']" type="code">
+      <AccessControl :permissions="['AC_100030']" type="code">
         <Button class="mr-4"> Admin 账号可见 ["AC_100010"] </Button>
       </AccessControl>
-      <AccessControl :value="['AC_1000001']" type="code">
+      <AccessControl :permissions="['AC_1000001']" type="code">
         <Button class="mr-4"> User 账号可见 ["AC_1000001"] </Button>
       </AccessControl>
-      <AccessControl :value="['AC_100100', 'AC_100010']" type="code">
+      <AccessControl :permissions="['AC_100100', 'AC_100010']" type="code">
         <Button class="mr-4">
           Super & Admin 账号可见 ["AC_100100","AC_1000001"]
         </Button>
@@ -104,32 +104,32 @@ async function changeAccount(role: string) {
       class="card-box mt-5 p-5 font-semibold"
     >
       <div class="mb-3 text-lg">组件形式控制 - 用户角色方式</div>
-      <AccessControl :value="['super']">
+      <AccessControl :permissions="['super']">
         <Button class="mr-4"> Super 角色可见 </Button>
       </AccessControl>
-      <AccessControl :value="['admin']">
+      <AccessControl :permissions="['admin']">
         <Button class="mr-4"> Admin 角色可见 </Button>
       </AccessControl>
-      <AccessControl :value="['user']">
+      <AccessControl :permissions="['user']">
         <Button class="mr-4"> User 角色可见 </Button>
       </AccessControl>
-      <AccessControl :value="['super', 'admin']">
+      <AccessControl :permissions="['super', 'admin']">
         <Button class="mr-4"> Super & Admin 角色可见 </Button>
       </AccessControl>
     </div>
 
     <div class="card-box mt-5 p-5 font-semibold">
       <div class="mb-3 text-lg">函数形式控制</div>
-      <Button v-if="hasAuthByCodes(['AC_100100'])" class="mr-4">
+      <Button v-if="hasAccessByCodes(['AC_100100'])" class="mr-4">
         Super 账号可见 ["AC_1000001"]
       </Button>
-      <Button v-if="hasAuthByCodes(['AC_100030'])" class="mr-4">
+      <Button v-if="hasAccessByCodes(['AC_100030'])" class="mr-4">
         Admin 账号可见 ["AC_100010"]
       </Button>
-      <Button v-if="hasAuthByCodes(['AC_1000001'])" class="mr-4">
+      <Button v-if="hasAccessByCodes(['AC_1000001'])" class="mr-4">
         User 账号可见 ["AC_1000001"]
       </Button>
-      <Button v-if="hasAuthByCodes(['AC_100100', 'AC_1000001'])" class="mr-4">
+      <Button v-if="hasAccessByCodes(['AC_100100', 'AC_1000001'])" class="mr-4">
         Super & Admin 账号可见 ["AC_100100","AC_1000001"]
       </Button>
     </div>

+ 2 - 1
packages/@core/forward/preferences/src/config.ts

@@ -66,11 +66,12 @@ const defaultPreferences: Preferences = {
     expandOnHover: true,
     extraCollapse: true,
     hidden: false,
-    width: 240,
+    width: 220,
   },
   tabbar: {
     dragable: true,
     enable: true,
+    height: 36,
     keepAlive: true,
     persist: true,
     showIcon: true,

+ 2 - 0
packages/@core/forward/preferences/src/types.ts

@@ -140,6 +140,8 @@ interface TabbarPreferences {
   dragable: boolean;
   /** 是否开启多标签页 */
   enable: boolean;
+  /** 标签页高度 */
+  height: number;
   /** 开启标签页缓存功能 */
   keepAlive: boolean;
   /** 是否持久化标签 */

+ 1 - 1
packages/@core/locales/src/langs/zh-CN.json

@@ -44,7 +44,7 @@
       "requestTimeout": "请求超时,请稍后再试。",
       "networkError": "网络异常,请检查您的网络连接后重试。",
       "badRequest": "请求错误。请检查您的输入并重试。",
-      "unauthorized": "未授权。请登录以继续。",
+      "unauthorized": "登录认证过期。请重新登录后继续。",
       "forbidden": "禁止访问, 您没有权限访问此资源。",
       "notFound": "未找到, 请求的资源不存在。",
       "internalServerError": "内部服务器错误,请稍后再试。"

+ 1 - 1
packages/@core/ui-kit/layout-ui/src/vben-layout.vue

@@ -45,7 +45,7 @@ const props = withDefaults(defineProps<Props>(), {
   sidebarTheme: 'dark',
   sidebarWidth: 180,
   tabbarEnable: true,
-  tabbarHeight: 38,
+  tabbarHeight: 36,
   zIndex: 200,
 });
 

+ 1 - 1
packages/@core/ui-kit/shadcn-ui/src/components/ui/card/Card.vue

@@ -12,7 +12,7 @@ const props = defineProps<{
   <div
     :class="
       cn(
-        'bg-card text-card-foreground border-border rounded-xl border shadow',
+        'bg-card text-card-foreground border-border rounded-xl border shadow-sm',
         props.class,
       )
     "

+ 13 - 11
packages/effects/access/src/access-control.vue

@@ -8,16 +8,16 @@ import { useAccess } from './use-access';
 
 interface Props {
   /**
-   * 通过什么方式来控制组件,如果是 role,则传入角色,如果是 code,则传入权限码
-   * @default 'role'
+   * Specified codes is visible
+   * @default []
    */
-  type?: 'code' | 'role';
+  permissions?: string[];
 
   /**
-   * Specified codes is visible
-   * @default []
+   * 通过什么方式来控制组件,如果是 role,则传入角色,如果是 code,则传入权限码
+   * @default 'role'
    */
-  value?: string[];
+  type?: 'code' | 'role';
 }
 
 defineOptions({
@@ -25,19 +25,21 @@ defineOptions({
 });
 
 const props = withDefaults(defineProps<Props>(), {
+  permissions: () => [],
   type: 'role',
-  value: () => [],
 });
 
-const { hasAuthByCodes, hasAuthByRoles } = useAccess();
+const { hasAccessByCodes, hasAccessByRoles } = useAccess();
 
 const hasAuth = computed(() => {
-  const { type, value } = props;
-  return type === 'role' ? hasAuthByRoles(value) : hasAuthByCodes(value);
+  const { permissions, type } = props;
+  return type === 'role'
+    ? hasAccessByRoles(permissions)
+    : hasAccessByCodes(permissions);
 });
 </script>
 
 <template>
-  <slot v-if="!value"></slot>
+  <slot v-if="!permissions"></slot>
   <slot v-else-if="hasAuth"></slot>
 </template>

+ 38 - 0
packages/effects/access/src/directive.ts

@@ -0,0 +1,38 @@
+/**
+ * Global authority directive
+ * Used for fine-grained control of component permissions
+ * @Example v-auth="RoleEnum.TEST"
+ */
+import type { App, Directive, DirectiveBinding } from 'vue';
+
+import { useAccess } from './use-access';
+
+function isAccessible(el: Element, binding: any) {
+  const { accessMode, hasAccessByCodes, hasAccessByRoles } = useAccess();
+
+  const value = binding.value;
+
+  if (!value) {
+    return;
+  }
+  const authMethod =
+    accessMode.value === 'frontend' ? hasAccessByRoles : hasAccessByCodes;
+
+  if (!authMethod(value)) {
+    el?.remove();
+  }
+}
+
+const mounted = (el: Element, binding: DirectiveBinding<string | string[]>) => {
+  isAccessible(el, binding);
+};
+
+const authDirective: Directive = {
+  mounted,
+};
+
+export function installAccessDirective(app: App) {
+  app.directive('access', authDirective);
+}
+
+export default authDirective;

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

@@ -1,3 +1,4 @@
 export { default as AccessControl } from './access-control.vue';
+export * from './directive';
 export * from './generate-accessible';
 export * from './use-access';

+ 4 - 4
packages/effects/access/src/use-access.ts

@@ -14,7 +14,7 @@ function useAccess() {
    * @description: Determine whether there is permission,The role is judged by the user's role
    * @param roles
    */
-  function hasAuthByRoles(roles: string[]) {
+  function hasAccessByRoles(roles: string[]) {
     const userRoleSet = new Set(coreAccessStore.userRoles);
     const intersection = roles.filter((item) => userRoleSet.has(item));
     return intersection.length > 0;
@@ -25,7 +25,7 @@ function useAccess() {
    * @description: Determine whether there is permission,The permission code is judged by the user's permission code
    * @param codes
    */
-  function hasAuthByCodes(codes: string[]) {
+  function hasAccessByCodes(codes: string[]) {
     const userCodesSet = new Set(coreAccessStore.accessCodes);
 
     const intersection = codes.filter((item) => userCodesSet.has(item));
@@ -43,8 +43,8 @@ function useAccess() {
 
   return {
     accessMode,
-    hasAuthByCodes,
-    hasAuthByRoles,
+    hasAccessByCodes,
+    hasAccessByRoles,
     toggleAccessMode,
   };
 }

+ 10 - 3
packages/effects/common-ui/src/authentication/login-expired-modal.vue

@@ -5,19 +5,24 @@ import {
   DialogContent,
   DialogDescription,
   DialogTitle,
+  VbenAvatar,
   VisuallyHidden,
 } from '@vben-core/shadcn-ui';
 
 import AuthenticationLogin from './login.vue';
 import { AuthenticationProps, LoginAndRegisterParams } from './typings';
 
-interface Props extends AuthenticationProps {}
+interface Props extends AuthenticationProps {
+  avatar?: string;
+}
 
 defineOptions({
   name: 'LoginExpiredModal',
 });
 
-const props = withDefaults(defineProps<Props>(), {});
+const props = withDefaults(defineProps<Props>(), {
+  avatar: '',
+});
 
 const emit = defineEmits<{
   submit: [LoginAndRegisterParams];
@@ -37,8 +42,10 @@ const forwarded = useForwardPropsEmits(props, emit);
         @escape-key-down="(e) => e.preventDefault()"
         @interact-outside="(e) => e.preventDefault()"
       >
+        <DialogTitle>
+          <VbenAvatar :src="avatar" class="mx-auto size-20" />
+        </DialogTitle>
         <VisuallyHidden>
-          <DialogTitle />
           <DialogDescription />
         </VisuallyHidden>
         <AuthenticationLogin

+ 1 - 0
packages/effects/layouts/src/basic/layout.vue

@@ -135,6 +135,7 @@ function clearPreferencesAndLogout() {
     :sidebar-theme="theme"
     :sidebar-width="preferences.sidebar.width"
     :tabbar-enable="preferences.tabbar.enable"
+    :tabbar-height="preferences.tabbar.height"
     @side-mouse-leave="handleSideMouseLeave"
     @toggle-sidebar="toggleSidebar"
     @update:sidebar-collapse="