Browse Source

refactor: adjust all sample pages and use page components (#4118)

Vben 7 months ago
parent
commit
517acada1a
75 changed files with 254 additions and 354 deletions
  1. 3 1
      .github/release-drafter.yml
  2. 2 1
      .vscode/settings.json
  3. 23 43
      apps/web-antd/src/views/demos/antd/index.vue
  4. 25 41
      apps/web-ele/src/views/demos/element/index.vue
  5. 20 40
      apps/web-naive/src/views/demos/naive/index.vue
  6. 4 4
      apps/web-naive/src/views/demos/table/index.vue
  7. 2 3
      packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue
  8. 1 2
      packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue
  9. 2 2
      packages/@core/ui-kit/shadcn-ui/src/components/button/icon-button.vue
  10. 3 4
      packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue
  11. 7 8
      packages/@core/ui-kit/shadcn-ui/src/components/hover-card/hover-card.vue
  12. 1 3
      packages/@core/ui-kit/shadcn-ui/src/components/input/interface.ts
  13. 1 3
      packages/@core/ui-kit/shadcn-ui/src/components/link/link.vue
  14. 1 3
      packages/@core/ui-kit/shadcn-ui/src/components/pin-input/interface.ts
  15. 7 11
      packages/@core/ui-kit/shadcn-ui/src/components/popover/popover.vue
  16. 2 3
      packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue
  17. 2 4
      packages/@core/ui-kit/shadcn-ui/src/components/segmented/tabs-indicator.vue
  18. 3 3
      packages/@core/ui-kit/shadcn-ui/src/components/tooltip/tooltip.vue
  19. 1 1
      packages/effects/README.md
  20. 11 4
      packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue
  21. 0 0
      packages/effects/common-ui/src/components/ellipsis-text/index.ts
  22. 2 0
      packages/effects/common-ui/src/components/index.ts
  23. 0 0
      packages/effects/common-ui/src/components/page/index.ts
  24. 0 0
      packages/effects/common-ui/src/components/page/page-footer.vue
  25. 2 4
      packages/effects/common-ui/src/components/page/page-header.vue
  26. 2 2
      packages/effects/common-ui/src/components/page/page.ts
  27. 9 5
      packages/effects/common-ui/src/components/page/page.vue
  28. 2 6
      packages/effects/common-ui/src/index.ts
  29. 0 0
      packages/effects/common-ui/src/ui/about/about.ts
  30. 13 11
      packages/effects/common-ui/src/ui/about/about.vue
  31. 0 0
      packages/effects/common-ui/src/ui/about/index.ts
  32. 0 0
      packages/effects/common-ui/src/ui/authentication/auth-title.vue
  33. 0 0
      packages/effects/common-ui/src/ui/authentication/code-login.vue
  34. 0 0
      packages/effects/common-ui/src/ui/authentication/forget-password.vue
  35. 0 0
      packages/effects/common-ui/src/ui/authentication/index.ts
  36. 0 0
      packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue
  37. 0 0
      packages/effects/common-ui/src/ui/authentication/login.vue
  38. 0 0
      packages/effects/common-ui/src/ui/authentication/qrcode-login.vue
  39. 0 0
      packages/effects/common-ui/src/ui/authentication/register.vue
  40. 0 0
      packages/effects/common-ui/src/ui/authentication/third-party-login.vue
  41. 0 0
      packages/effects/common-ui/src/ui/authentication/typings.ts
  42. 0 0
      packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue
  43. 0 0
      packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue
  44. 0 0
      packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue
  45. 0 0
      packages/effects/common-ui/src/ui/dashboard/analysis/index.ts
  46. 0 0
      packages/effects/common-ui/src/ui/dashboard/index.ts
  47. 0 0
      packages/effects/common-ui/src/ui/dashboard/typing.ts
  48. 0 0
      packages/effects/common-ui/src/ui/dashboard/workbench/index.ts
  49. 0 0
      packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue
  50. 0 0
      packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue
  51. 0 0
      packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue
  52. 0 0
      packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue
  53. 0 0
      packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue
  54. 0 0
      packages/effects/common-ui/src/ui/fallback/fallback.ts
  55. 0 0
      packages/effects/common-ui/src/ui/fallback/fallback.vue
  56. 0 0
      packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue
  57. 0 0
      packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue
  58. 0 0
      packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue
  59. 0 0
      packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue
  60. 0 0
      packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue
  61. 0 0
      packages/effects/common-ui/src/ui/fallback/icons/warning.svg
  62. 0 0
      packages/effects/common-ui/src/ui/fallback/index.ts
  63. 4 0
      packages/effects/common-ui/src/ui/index.ts
  64. 2 6
      playground/src/views/demos/access/admin-visible.vue
  65. 26 30
      playground/src/views/demos/access/button-control.vue
  66. 12 24
      playground/src/views/demos/access/index.vue
  67. 2 6
      playground/src/views/demos/access/super-visible.vue
  68. 2 6
      playground/src/views/demos/access/user-visible.vue
  69. 11 11
      playground/src/views/demos/features/icons/index.vue
  70. 13 16
      playground/src/views/demos/features/login-expired/index.vue
  71. 13 19
      playground/src/views/demos/features/tabs/index.vue
  72. 4 8
      playground/src/views/demos/features/tabs/tab-detail.vue
  73. 12 12
      playground/src/views/demos/features/watermark/index.vue
  74. 0 1
      playground/src/views/examples/ellipsis/data.ts
  75. 2 3
      playground/src/views/examples/ellipsis/index.vue

+ 3 - 1
.github/release-drafter.yml

@@ -17,12 +17,14 @@ categories:
   - title: "🐞 Bug Fixes"
     labels:
       - "bug"
+  - title: "📈 Performance"
+    labels:
+      - "perf"
   - title: 📝 Documentation
     labels:
       - "documentation"
   - title: 👻 Maintenance
     labels:
-      - "perf"
       - "chore"
       - "dependencies"
     # collapse-after: 12

+ 2 - 1
.vscode/settings.json

@@ -192,5 +192,6 @@
   "i18n-ally.keystyle": "nested",
   "commentTranslate.multiLineMerge": true,
   "vue.server.hybridMode": true,
-  "typescript.tsdk": "node_modules/typescript/lib"
+  "typescript.tsdk": "node_modules/typescript/lib",
+  "vitest.disableWorkspaceWarning": true
 }

+ 23 - 43
apps/web-antd/src/views/demos/antd/index.vue

@@ -1,4 +1,6 @@
 <script lang="ts" setup>
+import { Page } from '@vben/common-ui';
+
 import { Button, Card, message, notification, Space } from 'ant-design-vue';
 
 type NotificationType = 'error' | 'info' | 'success' | 'warning';
@@ -31,56 +33,34 @@ function notify(type: NotificationType) {
 </script>
 
 <template>
-  <div class="p-5">
-    <div class="card-box p-5">
-      <h1 class="text-xl font-semibold">Ant Design Vue组件使用演示</h1>
-      <div class="text-foreground/80 mt-2">支持多语言,主题功能集成切换等</div>
-    </div>
-
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">按钮</span>
-      </div>
-      <div>
-        <Space>
-          <Button>Default</Button>
-          <Button type="primary"> Primary </Button>
-          <Button> Info </Button>
-          <Button danger> Error </Button>
-        </Space>
-      </div>
-    </div>
-
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">卡片</span>
-      </div>
-      <div>
-        <Card title="卡片"> 卡片内容 </Card>
-      </div>
-    </div>
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">信息 Message </span>
-      </div>
-      <div class="flex gap-3">
+  <Page
+    description="支持多语言,主题功能集成切换等"
+    title="Ant Design Vue组件使用演示"
+  >
+    <Card title="按钮">
+      <Space>
+        <Button>Default</Button>
+        <Button type="primary"> Primary </Button>
+        <Button> Info </Button>
+        <Button danger> Error </Button>
+      </Space>
+    </Card>
+    <Card class="mb-5" title="Message">
+      <Space>
         <Button @click="info"> 信息 </Button>
         <Button danger @click="error"> 错误 </Button>
         <Button @click="warning"> 警告 </Button>
         <Button @click="success"> 成功 </Button>
-      </div>
-    </div>
+      </Space>
+    </Card>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">通知 Notification </span>
-      </div>
-      <div class="flex gap-3">
+    <Card class="mb-5" title="Notification">
+      <Space>
         <Button @click="notify('info')"> 信息 </Button>
         <Button danger @click="notify('error')"> 错误 </Button>
         <Button @click="notify('warning')"> 警告 </Button>
         <Button @click="notify('success')"> 成功 </Button>
-      </div>
-    </div>
-  </div>
+      </Space>
+    </Card>
+  </Page>
 </template>

+ 25 - 41
apps/web-ele/src/views/demos/element/index.vue

@@ -41,54 +41,38 @@ function notify(type: NotificationType) {
 </script>
 
 <template>
-  <Page title="Element Plus组件使用演示">
-    <template #header> 支持多语言,主题功能集成切换等 </template>
-    <div class="card-box p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">按钮</span>
-      </div>
-      <div>
-        <ElSpace>
-          <ElButton>Default</ElButton>
-          <ElButton type="primary"> Primary </ElButton>
-          <ElButton type="info"> Info </ElButton>
-          <ElButton type="success"> Success </ElButton>
-          <ElButton type="warning"> Warning </ElButton>
-          <ElButton type="danger"> Error </ElButton>
-        </ElSpace>
-      </div>
-    </div>
-
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">卡片</span>
-      </div>
-      <div>
-        <ElCard title="卡片"> 卡片内容 </ElCard>
-      </div>
-    </div>
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">信息 Message </span>
-      </div>
-      <div class="flex gap-3">
+  <Page
+    description="支持多语言,主题功能集成切换等"
+    title="Element Plus组件使用演示"
+  >
+    <ElCard class="mb-5">
+      <template #header> 按钮 </template>
+      <ElSpace>
+        <ElButton>Default</ElButton>
+        <ElButton type="primary"> Primary </ElButton>
+        <ElButton type="info"> Info </ElButton>
+        <ElButton type="success"> Success </ElButton>
+        <ElButton type="warning"> Warning </ElButton>
+        <ElButton type="danger"> Error </ElButton>
+      </ElSpace>
+    </ElCard>
+    <ElCard class="mb-5">
+      <template #header> Message </template>
+      <ElSpace>
         <ElButton type="info" @click="info"> 信息 </ElButton>
         <ElButton type="danger" @click="error"> 错误 </ElButton>
         <ElButton type="warning" @click="warning"> 警告 </ElButton>
         <ElButton type="success" @click="success"> 成功 </ElButton>
-      </div>
-    </div>
-
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">通知 Notification </span>
-      </div>
-      <div class="flex gap-3">
+      </ElSpace>
+    </ElCard>
+    <ElCard class="mb-5">
+      <template #header> Notification </template>
+      <ElSpace>
         <ElButton type="info" @click="notify('info')"> 信息 </ElButton>
         <ElButton type="danger" @click="notify('error')"> 错误 </ElButton>
         <ElButton type="warning" @click="notify('warning')"> 警告 </ElButton>
         <ElButton type="success" @click="notify('success')"> 成功 </ElButton>
-      </div>
-    </div>
+      </ElSpace>
+    </ElCard>
   </Page>
 </template>

+ 20 - 40
apps/web-naive/src/views/demos/naive/index.vue

@@ -34,55 +34,35 @@ function notify(type: NotificationType) {
 </script>
 
 <template>
-  <Page title="naive组件使用演示">
-    <template #header> 支持多语言,主题功能集成切换等 </template>
-    <div class="card-box p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">按钮</span>
-      </div>
-      <div>
-        <NSpace>
-          <NButton>Default</NButton>
-          <NButton type="tertiary"> Tertiary </NButton>
-          <NButton type="primary"> Primary </NButton>
-          <NButton type="info"> Info </NButton>
-          <NButton type="success"> Success </NButton>
-          <NButton type="warning"> Warning </NButton>
-          <NButton type="error"> Error </NButton>
-        </NSpace>
-      </div>
-    </div>
+  <Page description="支持多语言,主题功能集成切换等" title="naive组件使用演示">
+    <NCard class="mb-5" title="按钮">
+      <NSpace>
+        <NButton>Default</NButton>
+        <NButton type="tertiary"> Tertiary </NButton>
+        <NButton type="primary"> Primary </NButton>
+        <NButton type="info"> Info </NButton>
+        <NButton type="success"> Success </NButton>
+        <NButton type="warning"> Warning </NButton>
+        <NButton type="error"> Error </NButton>
+      </NSpace>
+    </NCard>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">卡片</span>
-      </div>
-      <div>
-        <NCard title="卡片"> 卡片内容 </NCard>
-      </div>
-    </div>
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">信息 Message </span>
-      </div>
-      <div class="flex gap-3">
+    <NCard class="mb-5" title="Message">
+      <NSpace>
         <NButton type="error" @click="error"> 错误 </NButton>
         <NButton type="warning" @click="warning"> 警告 </NButton>
         <NButton type="success" @click="success"> 成功 </NButton>
         <NButton type="primary" @click="loading"> 加载中 </NButton>
-      </div>
-    </div>
+      </NSpace>
+    </NCard>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">通知 Notification </span>
-      </div>
-      <div class="flex gap-3">
+    <NCard class="mb-5" title="Notification">
+      <NSpace>
         <NButton type="error" @click="notify('error')"> 错误 </NButton>
         <NButton type="warning" @click="notify('warning')"> 警告 </NButton>
         <NButton type="success" @click="notify('success')"> 成功 </NButton>
         <NButton type="primary" @click="notify('info')"> 加载中 </NButton>
-      </div>
-    </div>
+      </NSpace>
+    </NCard>
   </Page>
 </template>

+ 4 - 4
apps/web-naive/src/views/demos/table/index.vue

@@ -27,10 +27,10 @@ const data = [
 </script>
 
 <template>
-  <Page title="NDataTable">
-    <template #header>
-      表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。
-    </template>
+  <Page
+    description="表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。"
+    title="NDataTable"
+  >
     <NDataTable :columns="columns" :data="data" />
   </Page>
 </template>

+ 2 - 3
packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue

@@ -5,7 +5,6 @@ import type {
   AvatarRootProps,
 } from 'radix-vue';
 
-import type { HTMLAttributes } from 'vue';
 import { computed } from 'vue';
 
 import {
@@ -16,9 +15,9 @@ import {
 
 interface Props extends AvatarRootProps, AvatarFallbackProps, AvatarImageProps {
   alt?: string;
-  class?: HTMLAttributes['class'];
+  class?: any;
   dot?: boolean;
-  dotClass?: HTMLAttributes['class'];
+  dotClass?: any;
 }
 
 defineOptions({

+ 1 - 2
packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue

@@ -1,5 +1,4 @@
 <script setup lang="ts">
-import type { HTMLAttributes } from 'vue';
 import { computed } from 'vue';
 
 import { LoaderCircle } from '@vben-core/icons';
@@ -12,7 +11,7 @@ import { cn } from '@vben-core/shared';
 import { Primitive, type PrimitiveProps } from 'radix-vue';
 
 interface Props extends PrimitiveProps {
-  class?: HTMLAttributes['class'];
+  class?: any;
   disabled?: boolean;
   loading?: boolean;
   size?: ButtonVariants['size'];

+ 2 - 2
packages/@core/ui-kit/shadcn-ui/src/components/button/icon-button.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { ButtonVariants } from '@vben-core/shadcn-ui/components/ui/button';
 
-import { computed, type HTMLAttributes, useSlots } from 'vue';
+import { computed, useSlots } from 'vue';
 
 import { VbenTooltip } from '@vben-core/shadcn-ui/components/tooltip';
 import { cn } from '@vben-core/shared';
@@ -11,7 +11,7 @@ import { type PrimitiveProps } from 'radix-vue';
 import VbenButton from './button.vue';
 
 interface Props extends PrimitiveProps {
-  class?: HTMLAttributes['class'];
+  class?: any;
   disabled?: boolean;
   onClick?: () => void;
   tooltip?: string;

+ 3 - 4
packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue

@@ -7,7 +7,6 @@ import type {
 
 import type { IContextMenuItem } from './interface';
 
-import type { HTMLAttributes } from 'vue';
 import { computed } from 'vue';
 
 import {
@@ -23,11 +22,11 @@ import { useForwardPropsEmits } from 'radix-vue';
 
 const props = defineProps<
   {
-    class?: HTMLAttributes['class'];
-    contentClass?: HTMLAttributes['class'];
+    class?: any;
+    contentClass?: any;
     contentProps?: ContextMenuContentProps;
     handlerData?: Record<string, any>;
-    itemClass?: HTMLAttributes['class'];
+    itemClass?: any;
     menus: (data: any) => IContextMenuItem[];
   } & ContextMenuRootProps
 >();

+ 7 - 8
packages/@core/ui-kit/shadcn-ui/src/components/hover-card/hover-card.vue

@@ -5,7 +5,6 @@ import type {
   HoverCardRootProps,
 } from 'radix-vue';
 
-import type { HTMLAttributes } from 'vue';
 import { computed } from 'vue';
 
 import {
@@ -16,13 +15,13 @@ import {
 
 import { useForwardPropsEmits } from 'radix-vue';
 
-const props = defineProps<
-  {
-    class?: HTMLAttributes['class'];
-    contentClass?: HTMLAttributes['class'];
-    contentProps?: HoverCardContentProps;
-  } & HoverCardRootProps
->();
+interface Props extends HoverCardRootProps {
+  class?: any;
+  contentClass?: any;
+  contentProps?: HoverCardContentProps;
+}
+
+const props = defineProps<Props>();
 
 const emits = defineEmits<HoverCardRootEmits>();
 

+ 1 - 3
packages/@core/ui-kit/shadcn-ui/src/components/input/interface.ts

@@ -1,7 +1,5 @@
-import type { HTMLAttributes } from 'vue';
-
 interface InputProps {
-  class?: HTMLAttributes['class'];
+  class?: any;
   /**
    * 错误提示信息
    */

+ 1 - 3
packages/@core/ui-kit/shadcn-ui/src/components/link/link.vue

@@ -1,12 +1,10 @@
 <script setup lang="ts">
-import type { HTMLAttributes } from 'vue';
-
 import { cn } from '@vben-core/shared';
 
 import { Primitive, type PrimitiveProps } from 'radix-vue';
 
 interface Props extends PrimitiveProps {
-  class?: HTMLAttributes['class'];
+  class?: any;
   href: string;
 }
 

+ 1 - 3
packages/@core/ui-kit/shadcn-ui/src/components/pin-input/interface.ts

@@ -1,5 +1,3 @@
-import type { HTMLAttributes } from 'vue';
-
 interface PinInputProps {
   /**
    * 发送验证码按钮loading
@@ -9,7 +7,7 @@ interface PinInputProps {
    * 发送验证码按钮文本
    */
   btnText?: string;
-  class?: HTMLAttributes['class'];
+  class?: any;
   /**
    * 验证码长度
    */

+ 7 - 11
packages/@core/ui-kit/shadcn-ui/src/components/popover/popover.vue

@@ -5,7 +5,6 @@ import type {
   PopoverRootProps,
 } from 'radix-vue';
 
-import type { HTMLAttributes } from 'vue';
 import { computed } from 'vue';
 
 import {
@@ -16,16 +15,13 @@ import {
 
 import { useForwardPropsEmits } from 'radix-vue';
 
-const props = withDefaults(
-  defineProps<
-    {
-      class?: HTMLAttributes['class'];
-      contentClass?: HTMLAttributes['class'];
-      contentProps?: PopoverContentProps;
-    } & PopoverRootProps
-  >(),
-  {},
-);
+interface Props extends PopoverRootProps {
+  class?: any;
+  contentClass?: any;
+  contentProps?: PopoverContentProps;
+}
+
+const props = withDefaults(defineProps<Props>(), {});
 
 const emits = defineEmits<PopoverRootEmits>();
 

+ 2 - 3
packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue

@@ -1,5 +1,4 @@
 <script setup lang="ts">
-import type { HTMLAttributes } from 'vue';
 import { ref } from 'vue';
 
 import {
@@ -9,9 +8,9 @@ import {
 import { cn } from '@vben-core/shared';
 
 interface Props {
-  class?: HTMLAttributes['class'];
+  class?: any;
   horizontal?: boolean;
-  scrollBarClass?: HTMLAttributes['class'];
+  scrollBarClass?: any;
   shadow?: boolean;
   shadowBorder?: boolean;
 }

+ 2 - 4
packages/@core/ui-kit/shadcn-ui/src/components/segmented/tabs-indicator.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { computed, type HTMLAttributes } from 'vue';
+import { computed } from 'vue';
 
 import { cn } from '@vben-core/shared';
 
@@ -9,9 +9,7 @@ import {
   useForwardProps,
 } from 'radix-vue';
 
-const props = defineProps<
-  { class?: HTMLAttributes['class'] } & TabsIndicatorProps
->();
+const props = defineProps<{ class?: any } & TabsIndicatorProps>();
 
 const delegatedProps = computed(() => {
   const { class: _, ...delegated } = props;

+ 3 - 3
packages/@core/ui-kit/shadcn-ui/src/components/tooltip/tooltip.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { TooltipContentProps } from 'radix-vue';
 
-import type { HTMLAttributes } from 'vue';
+import type { StyleValue } from 'vue';
 
 import {
   Tooltip,
@@ -11,8 +11,8 @@ import {
 } from '@vben-core/shadcn-ui/components/ui/tooltip';
 
 interface Props {
-  contentClass?: HTMLAttributes['class'];
-  contentStyle?: HTMLAttributes['style'];
+  contentClass?: any;
+  contentStyle?: StyleValue;
   delayDuration?: number;
   side: TooltipContentProps['side'];
 }

+ 1 - 1
packages/effects/README.md

@@ -1,6 +1,6 @@
 ## Effects 目录
 
-`effects` 目录专门用于存放与副作用相关的代码和逻辑。如果你的包具有以下特点,建议将其放置在 `effects` 目录下:
+`effects` 目录专门用于存放与轻微耦合相关的代码和逻辑。如果你的包具有以下特点,建议将其放置在 `effects` 目录下:
 
 - **状态管理**:使用状态管理框架 `pinia`,并包含处理副作用(如异步操作、API 调用)的部分。
 - **用户偏好设置**:使用 `@vben-core/preferences` 处理用户偏好设置,涉及本地存储或浏览器缓存逻辑(如使用 `localStorage`)。

+ 11 - 4
packages/effects/common-ui/src/ellipsis-text/ellipsis-text.vue → packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue

@@ -23,7 +23,7 @@ interface Props {
    * 提示框位置
    * @default 'top'
    */
-  placement: 'bottom' | 'left' | 'right' | 'top';
+  placement?: 'bottom' | 'left' | 'right' | 'top';
   /**
    * 是否启用文本提示框
    * @default true
@@ -49,7 +49,7 @@ interface Props {
    * 提示框内容区域样式
    * @default { textAlign: 'justify' }
    */
-  tooltipOverlayStyle?: CSSProperties; // 提示框内容区域样式
+  tooltipOverlayStyle?: CSSProperties;
 }
 const props = withDefaults(defineProps<Props>(), {
   expand: false,
@@ -99,6 +99,14 @@ function onExpand() {
 
   emit('expandChange', !isExpanded);
 }
+
+function handleExpand() {
+  if (props.expand) {
+    onExpand();
+  } else {
+    return false;
+  }
+}
 </script>
 <template>
   <VbenTooltip
@@ -110,7 +118,6 @@ function onExpand() {
       backgroundColor: tooltipBackgroundColor,
     }"
     :disabled="!showTooltip"
-    :overlay-style="tooltipOverlayStyle"
     :side="placement"
   >
     <slot name="tooltip">
@@ -127,7 +134,7 @@ function onExpand() {
         }"
         :style="`-webkit-line-clamp: ${line}; max-width: ${textMaxWidth};`"
         class="cursor-text overflow-hidden"
-        @click="expand ? onExpand() : () => false"
+        @click="handleExpand"
         v-bind="$attrs"
       >
         <slot></slot>

+ 0 - 0
packages/effects/common-ui/src/ellipsis-text/index.ts → packages/effects/common-ui/src/components/ellipsis-text/index.ts


+ 2 - 0
packages/effects/common-ui/src/components/index.ts

@@ -0,0 +1,2 @@
+export * from './ellipsis-text';
+export * from './page';

+ 0 - 0
packages/effects/common-ui/src/page/index.ts → packages/effects/common-ui/src/components/page/index.ts


+ 0 - 0
packages/effects/common-ui/src/page/page-footer.vue → packages/effects/common-ui/src/components/page/page-footer.vue


+ 2 - 4
packages/effects/common-ui/src/page/page-header.vue → packages/effects/common-ui/src/components/page/page-header.vue

@@ -10,11 +10,9 @@ const props = defineProps<PageHeaderProps>();
 
 <template>
   <div class="bg-card px-6 py-4">
-    <div class="flex justify-between text-lg font-bold">
+    <div class="mb-2 flex justify-between text-xl font-bold leading-10">
       {{ props.title }}
     </div>
-    <div class="pt-3">
-      <slot></slot>
-    </div>
+    <slot></slot>
   </div>
 </template>

+ 2 - 2
packages/effects/common-ui/src/page/page.ts → packages/effects/common-ui/src/components/page/page.ts

@@ -1,11 +1,11 @@
 interface PageHeaderProps {
   title?: string;
+  description?: string;
 }
 
 interface Props extends PageHeaderProps {
-  headerSticky?: boolean;
+  contentClass?: string;
   showFooter?: boolean;
-  showHeader?: boolean;
 }
 
 export type { PageHeaderProps, Props };

+ 9 - 5
packages/effects/common-ui/src/page/page.vue → packages/effects/common-ui/src/components/page/page.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import type { Props } from './page.ts';
+import type { Props } from './page';
 
 import PageFooter from './page-footer.vue';
 import PageHeader from './page-header.vue';
@@ -9,20 +9,24 @@ defineOptions({
 });
 
 const props = withDefaults(defineProps<Props>(), {
+  description: '',
   showFooter: false,
-  showHeader: true,
   title: '',
 });
 </script>
 
 <template>
   <div class="relative h-full">
-    <PageHeader v-if="props.showHeader" :title="props.title">
+    <PageHeader
+      v-if="description || $slots.description || title"
+      :title="props.title"
+    >
       <template #default>
-        <slot name="header"></slot>
+        <template v-if="description">{{ description }}</template>
+        <slot v-else name="description"></slot>
       </template>
     </PageHeader>
-    <div class="m-4 overflow-hidden">
+    <div :class="contentClass" class="m-4">
       <slot></slot>
     </div>
     <PageFooter v-if="props.showFooter">

+ 2 - 6
packages/effects/common-ui/src/index.ts

@@ -1,7 +1,3 @@
-export * from './about';
-export * from './authentication';
-export * from './dashboard';
-export * from './ellipsis-text';
-export * from './fallback';
-export * from './page';
+export * from './components';
+export * from './ui';
 export { useToast } from '@vben-core/shadcn-ui';

+ 0 - 0
packages/effects/common-ui/src/about/about.ts → packages/effects/common-ui/src/ui/about/about.ts


+ 13 - 11
packages/effects/common-ui/src/about/about.vue → packages/effects/common-ui/src/ui/about/about.vue

@@ -10,6 +10,8 @@ import {
 } from '@vben/constants';
 import { VbenLink, VbenRenderContent } from '@vben-core/shadcn-ui';
 
+import { Page } from '../../components';
+
 interface Props extends AboutProps {}
 
 defineOptions({
@@ -119,18 +121,18 @@ const devDependenciesItems = Object.keys(devDependencies).map((key) => ({
 </script>
 
 <template>
-  <div class="m-5">
+  <Page :title="title">
+    <template #description>
+      <p class="text-foreground mt-3 text-sm leading-6">
+        <VbenLink :href="VBEN_GITHUB_URL">
+          {{ name }}
+        </VbenLink>
+        {{ description }}
+      </p>
+    </template>
     <div class="card-box p-5">
       <div>
-        <h3 class="text-foreground text-2xl font-semibold leading-7">
-          {{ title }}
-        </h3>
-        <p class="text-foreground mt-3 text-sm leading-6">
-          <VbenLink :href="VBEN_GITHUB_URL">
-            {{ name }}
-          </VbenLink>
-          {{ description }}
-        </p>
+        <h5 class="text-foreground text-lg">基本信息</h5>
       </div>
       <div class="mt-4">
         <dl class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
@@ -186,5 +188,5 @@ const devDependenciesItems = Object.keys(devDependencies).map((key) => ({
         </dl>
       </div>
     </div>
-  </div>
+  </Page>
 </template>

+ 0 - 0
packages/effects/common-ui/src/about/index.ts → packages/effects/common-ui/src/ui/about/index.ts


+ 0 - 0
packages/effects/common-ui/src/authentication/auth-title.vue → packages/effects/common-ui/src/ui/authentication/auth-title.vue


+ 0 - 0
packages/effects/common-ui/src/authentication/code-login.vue → packages/effects/common-ui/src/ui/authentication/code-login.vue


+ 0 - 0
packages/effects/common-ui/src/authentication/forget-password.vue → packages/effects/common-ui/src/ui/authentication/forget-password.vue


+ 0 - 0
packages/effects/common-ui/src/authentication/index.ts → packages/effects/common-ui/src/ui/authentication/index.ts


+ 0 - 0
packages/effects/common-ui/src/authentication/login-expired-modal.vue → packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue


+ 0 - 0
packages/effects/common-ui/src/authentication/login.vue → packages/effects/common-ui/src/ui/authentication/login.vue


+ 0 - 0
packages/effects/common-ui/src/authentication/qrcode-login.vue → packages/effects/common-ui/src/ui/authentication/qrcode-login.vue


+ 0 - 0
packages/effects/common-ui/src/authentication/register.vue → packages/effects/common-ui/src/ui/authentication/register.vue


+ 0 - 0
packages/effects/common-ui/src/authentication/third-party-login.vue → packages/effects/common-ui/src/ui/authentication/third-party-login.vue


+ 0 - 0
packages/effects/common-ui/src/authentication/typings.ts → packages/effects/common-ui/src/ui/authentication/typings.ts


+ 0 - 0
packages/effects/common-ui/src/dashboard/analysis/analysis-chart-card.vue → packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue


+ 0 - 0
packages/effects/common-ui/src/dashboard/analysis/analysis-charts-tabs.vue → packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue


+ 0 - 0
packages/effects/common-ui/src/dashboard/analysis/analysis-overview.vue → packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue


+ 0 - 0
packages/effects/common-ui/src/dashboard/analysis/index.ts → packages/effects/common-ui/src/ui/dashboard/analysis/index.ts


+ 0 - 0
packages/effects/common-ui/src/dashboard/index.ts → packages/effects/common-ui/src/ui/dashboard/index.ts


+ 0 - 0
packages/effects/common-ui/src/dashboard/typing.ts → packages/effects/common-ui/src/ui/dashboard/typing.ts


+ 0 - 0
packages/effects/common-ui/src/dashboard/workbench/index.ts → packages/effects/common-ui/src/ui/dashboard/workbench/index.ts


+ 0 - 0
packages/effects/common-ui/src/dashboard/workbench/workbench-header.vue → packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue


+ 0 - 0
packages/effects/common-ui/src/dashboard/workbench/workbench-project.vue → packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue


+ 0 - 0
packages/effects/common-ui/src/dashboard/workbench/workbench-quick-nav.vue → packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue


+ 0 - 0
packages/effects/common-ui/src/dashboard/workbench/workbench-todo.vue → packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue


+ 0 - 0
packages/effects/common-ui/src/dashboard/workbench/workbench-trends.vue → packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue


+ 0 - 0
packages/effects/common-ui/src/fallback/fallback.ts → packages/effects/common-ui/src/ui/fallback/fallback.ts


+ 0 - 0
packages/effects/common-ui/src/fallback/fallback.vue → packages/effects/common-ui/src/ui/fallback/fallback.vue


+ 0 - 0
packages/effects/common-ui/src/fallback/icons/icon-403.vue → packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue


+ 0 - 0
packages/effects/common-ui/src/fallback/icons/icon-404.vue → packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue


+ 0 - 0
packages/effects/common-ui/src/fallback/icons/icon-500.vue → packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue


+ 0 - 0
packages/effects/common-ui/src/fallback/icons/icon-coming-soon.vue → packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue


+ 0 - 0
packages/effects/common-ui/src/fallback/icons/icon-offline.vue → packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue


+ 0 - 0
packages/effects/common-ui/src/fallback/icons/warning.svg → packages/effects/common-ui/src/ui/fallback/icons/warning.svg


+ 0 - 0
packages/effects/common-ui/src/fallback/index.ts → packages/effects/common-ui/src/ui/fallback/index.ts


+ 4 - 0
packages/effects/common-ui/src/ui/index.ts

@@ -0,0 +1,4 @@
+export * from './about';
+export * from './authentication';
+export * from './dashboard';
+export * from './fallback';

+ 2 - 6
playground/src/views/demos/access/admin-visible.vue

@@ -1,11 +1,7 @@
 <script lang="ts" setup>
-import { Fallback } from '@vben/common-ui';
+import { Page } from '@vben/common-ui';
 </script>
 
 <template>
-  <Fallback
-    description="当前页面仅 Admin 账号可见"
-    status="coming-soon"
-    title="页面访问测试"
-  />
+  <Page description="当前页面仅 Admin 账号可见" title="页面访问测试" />
 </template>

+ 26 - 30
playground/src/views/demos/access/button-control.vue

@@ -4,9 +4,10 @@ import type { LoginAndRegisterParams } from '@vben/common-ui';
 import { useRouter } from 'vue-router';
 
 import { AccessControl, useAccess } from '@vben/access';
+import { Page } from '@vben/common-ui';
 import { resetAllStores, useUserStore } from '@vben/stores';
 
-import { Button } from 'ant-design-vue';
+import { Button, Card } from 'ant-design-vue';
 
 import { useAuthStore } from '#/store';
 
@@ -50,21 +51,17 @@ async function changeAccount(role: string) {
 </script>
 
 <template>
-  <div class="p-5">
-    <div class="card-box p-5">
-      <h1 class="text-xl font-semibold">
-        {{ accessMode === 'frontend' ? '前端' : '后端' }}页面访问权限演示
-      </h1>
-      <div class="text-foreground/80 mt-2">切换不同的账号,观察按钮变化。</div>
-    </div>
-
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">当前角色:</span>
+  <Page
+    :title="`${accessMode === 'frontend' ? '前端' : '后端'}按钮访问权限演示`"
+    description="切换不同的账号,观察按钮变化。"
+  >
+    <Card class="mb-5">
+      <template #title>
+        <span class="font-semibold">当前角色:</span>
         <span class="text-primary mx-4 text-lg">
           {{ userStore.userRoles?.[0] }}
         </span>
-      </div>
+      </template>
 
       <Button :type="roleButtonType('super')" @click="changeAccount('super')">
         切换为 Super 账号
@@ -80,10 +77,9 @@ async function changeAccount(role: string) {
       <Button :type="roleButtonType('user')" @click="changeAccount('user')">
         切换为 User 账号
       </Button>
-    </div>
+    </Card>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3 text-lg font-semibold">组件形式控制 - 权限码方式</div>
+    <Card class="mb-5" title="组件形式控制 - 权限码">
       <AccessControl :codes="['AC_100100']" type="code">
         <Button class="mr-4"> Super 账号可见 ["AC_1000001"] </Button>
       </AccessControl>
@@ -98,10 +94,13 @@ async function changeAccount(role: string) {
           Super & Admin 账号可见 ["AC_100100","AC_1000001"]
         </Button>
       </AccessControl>
-    </div>
+    </Card>
 
-    <div v-if="accessMode === 'frontend'" class="card-box mt-5 p-5">
-      <div class="mb-3 text-lg font-semibold">组件形式控制 - 用户角色方式</div>
+    <Card
+      v-if="accessMode === 'frontend'"
+      class="mb-5"
+      title="组件形式控制 - 角色"
+    >
       <AccessControl :codes="['super']" type="role">
         <Button class="mr-4"> Super 角色可见 </Button>
       </AccessControl>
@@ -114,10 +113,9 @@ async function changeAccount(role: string) {
       <AccessControl :codes="['super', 'admin']" type="role">
         <Button class="mr-4"> Super & Admin 角色可见 </Button>
       </AccessControl>
-    </div>
+    </Card>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3 text-lg font-semibold">函数形式控制</div>
+    <Card class="mb-5" title="函数形式控制">
       <Button v-if="hasAccessByCodes(['AC_100100'])" class="mr-4">
         Super 账号可见 ["AC_1000001"]
       </Button>
@@ -130,10 +128,9 @@ async function changeAccount(role: string) {
       <Button v-if="hasAccessByCodes(['AC_100100', 'AC_1000001'])" class="mr-4">
         Super & Admin 账号可见 ["AC_100100","AC_1000001"]
       </Button>
-    </div>
+    </Card>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3 text-lg font-semibold">指令方式 - 权限码</div>
+    <Card class="mb-5" title="指令方式 - 权限码">
       <Button class="mr-4" v-access:code="['AC_100100']">
         Super 账号可见 ["AC_1000001"]
       </Button>
@@ -146,16 +143,15 @@ async function changeAccount(role: string) {
       <Button class="mr-4" v-access:code="['AC_100100', 'AC_1000001']">
         Super & Admin 账号可见 ["AC_100100","AC_1000001"]
       </Button>
-    </div>
+    </Card>
 
-    <div v-if="accessMode === 'frontend'" class="card-box mt-5 p-5">
-      <div class="mb-3 text-lg font-semibold">指令方式 - 角色</div>
+    <Card class="mb-5" title="指令方式 - 角色">
       <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>
-    </div>
-  </div>
+    </Card>
+  </Page>
 </template>

+ 12 - 24
playground/src/views/demos/access/index.vue

@@ -4,9 +4,10 @@ import type { LoginAndRegisterParams } from '@vben/common-ui';
 import { useRouter } from 'vue-router';
 
 import { useAccess } from '@vben/access';
+import { Page } from '@vben/common-ui';
 import { resetAllStores, useUserStore } from '@vben/stores';
 
-import { Button } from 'ant-design-vue';
+import { Button, Card } from 'ant-design-vue';
 
 import { useAuthStore } from '#/store';
 
@@ -64,33 +65,20 @@ async function handleToggleAccessMode() {
 </script>
 
 <template>
-  <div class="p-5">
-    <div class="card-box p-5">
-      <h1 class="text-xl font-semibold">
-        {{ accessMode === 'frontend' ? '前端' : '后端' }}页面访问权限演示
-      </h1>
-      <div class="text-foreground/80 mt-2">
-        切换不同的账号,观察左侧菜单变化。
-      </div>
-    </div>
-
-    <div class="card-box mt-5 p-5">
-      <span class="text-lg font-semibold">当前权限模式:</span>
+  <Page
+    :title="`${accessMode === 'frontend' ? '前端' : '后端'}页面访问权限演示`"
+    description="切换不同的账号,观察左侧菜单变化。"
+  >
+    <Card class="mb-5" title="权限模式">
+      <span class="font-semibold">当前权限模式:</span>
       <span class="text-primary mx-4">{{
         accessMode === 'frontend' ? '前端权限控制' : '后端权限控制'
       }}</span>
       <Button type="primary" @click="handleToggleAccessMode">
         切换为{{ accessMode === 'frontend' ? '后端' : '前端' }}权限模式
       </Button>
-    </div>
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3">
-        <span class="text-lg font-semibold">当前账号:</span>
-        <span class="text-primary mx-4 text-lg">
-          {{ userStore.userRoles?.[0] }}
-        </span>
-      </div>
-
+    </Card>
+    <Card title="账号切换">
       <Button :type="roleButtonType('super')" @click="changeAccount('super')">
         切换为 Super 账号
       </Button>
@@ -105,6 +93,6 @@ async function handleToggleAccessMode() {
       <Button :type="roleButtonType('user')" @click="changeAccount('user')">
         切换为 User 账号
       </Button>
-    </div>
-  </div>
+    </Card>
+  </Page>
 </template>

+ 2 - 6
playground/src/views/demos/access/super-visible.vue

@@ -1,11 +1,7 @@
 <script lang="ts" setup>
-import { Fallback } from '@vben/common-ui';
+import { Page } from '@vben/common-ui';
 </script>
 
 <template>
-  <Fallback
-    description="当前页面仅 Super 账号可见"
-    status="coming-soon"
-    title="页面访问测试"
-  />
+  <Page description="当前页面仅 Super 账号可见" title="页面访问测试" />
 </template>

+ 2 - 6
playground/src/views/demos/access/user-visible.vue

@@ -1,11 +1,7 @@
 <script lang="ts" setup>
-import { Fallback } from '@vben/common-ui';
+import { Page } from '@vben/common-ui';
 </script>
 
 <template>
-  <Fallback
-    description="当前页面仅 User 可见"
-    status="coming-soon"
-    title="页面访问测试"
-  />
+  <Page description="当前页面仅 User 账号可见" title="页面访问测试" />
 </template>

+ 11 - 11
playground/src/views/demos/features/icons/index.vue

@@ -1,4 +1,5 @@
 <script lang="ts" setup>
+import { Page } from '@vben/common-ui';
 import {
   MdiGithub,
   MdiGoogle,
@@ -14,12 +15,13 @@ import {
   SvgCardIcon,
   SvgDownloadIcon,
 } from '@vben/icons';
+
+import { Card } from 'ant-design-vue';
 </script>
 
 <template>
-  <div class="p-5">
-    <div class="card-box p-5">
-      <h1 class="text-xl font-semibold">图标</h1>
+  <Page title="图标">
+    <template #description>
       <div class="text-foreground/80 mt-2">
         图标可在
         <a
@@ -31,10 +33,9 @@ import {
         </a>
         中查找,支持多种图标库,如 Material Design, Font Awesome, Jam Icons 等。
       </div>
-    </div>
+    </template>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3 text-lg font-semibold">Iconify</div>
+    <Card class="mb-5" title="Iconify">
       <div class="flex items-center gap-5">
         <MdiGithub class="size-8" />
         <MdiGoogle class="size-8 text-red-500" />
@@ -42,10 +43,9 @@ import {
         <MdiWechat class="size-8" />
         <MdiKeyboardEsc class="size-8" />
       </div>
-    </div>
+    </Card>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3 text-lg font-semibold">Svg Icons</div>
+    <Card title="Svg Icons">
       <div class="flex items-center gap-5">
         <SvgAvatar1Icon class="size-8" />
         <SvgAvatar2Icon class="size-8 text-red-500" />
@@ -56,6 +56,6 @@ import {
         <SvgCardIcon class="size-8" />
         <SvgDownloadIcon class="size-8" />
       </div>
-    </div>
-  </div>
+    </Card>
+  </Page>
 </template>

+ 13 - 16
playground/src/views/demos/features/login-expired/index.vue

@@ -1,9 +1,10 @@
 <script lang="ts" setup>
 import type { LoginExpiredModeType } from '@vben/types';
 
+import { Page } from '@vben/common-ui';
 import { preferences, updatePreferences } from '@vben/preferences';
 
-import { Button } from 'ant-design-vue';
+import { Button, Card } from 'ant-design-vue';
 
 import { getMockStatusApi } from '#/api';
 
@@ -17,26 +18,22 @@ async function handleClick(type: LoginExpiredModeType) {
 </script>
 
 <template>
-  <div class="p-5">
-    <div class="card-box p-5">
-      <h1 class="text-xl font-semibold">登录过期演示</h1>
+  <Page title="登录过期演示">
+    <template #description>
       <div class="text-foreground/80 mt-2">
         接口请求遇到401状态码时,需要重新登录。有两种方式:
-        <div>1.转到登录页,登录成功后跳转回原页面</div>
-        <div>
+        <p>1.转到登录页,登录成功后跳转回原页面</p>
+        <p>
           2.弹出重新登录弹窗,登录后关闭弹窗,不进行任何页面跳转(刷新后调整登录页面)
-        </div>
+        </p>
       </div>
-    </div>
+    </template>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3 text-lg font-semibold">跳转登录页面方式</div>
+    <Card class="mb-5" title="跳转登录页面方式">
       <Button type="primary" @click="handleClick('page')"> 点击触发 </Button>
-    </div>
-
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3 text-lg font-semibold">登录弹窗方式</div>
+    </Card>
+    <Card class="mb-5" title="登录弹窗方式">
       <Button type="primary" @click="handleClick('modal')"> 点击触发 </Button>
-    </div>
-  </div>
+    </Card>
+  </Page>
 </template>

+ 13 - 19
playground/src/views/demos/features/tabs/index.vue

@@ -2,9 +2,10 @@
 import { ref } from 'vue';
 import { useRouter } from 'vue-router';
 
+import { Page } from '@vben/common-ui';
 import { useTabs } from '@vben/hooks';
 
-import { Input as AInput, Button } from 'ant-design-vue';
+import { Button, Card, Input } from 'ant-design-vue';
 
 const router = useRouter();
 const newTabTitle = ref('');
@@ -38,14 +39,8 @@ function reset() {
 </script>
 
 <template>
-  <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>
-
-    <div class="card-box mt-5 p-5">
-      <div class="text-lg font-semibold">打开/关闭标签页</div>
+  <Page description="用于需要操作标签页的场景" title="标签页">
+    <Card class="mb-5" title="打开/关闭标签页">
       <div class="text-foreground/80 my-3">
         如果标签页存在,直接跳转切换。如果标签页不存在,则打开新的标签页。
       </div>
@@ -55,10 +50,9 @@ function reset() {
           关闭 "关于" 标签页
         </Button>
       </div>
-    </div>
+    </Card>
 
-    <div class="card-box mt-5 p-5">
-      <div class="text-lg font-semibold">标签页操作</div>
+    <Card class="mb-5" title="标签页操作">
       <div class="text-foreground/80 my-3">用于动态控制标签页的各种操作</div>
       <div class="flex flex-wrap gap-3">
         <Button type="primary" @click="closeCurrentTab()">
@@ -76,15 +70,15 @@ function reset() {
         </Button>
         <Button type="primary" @click="refreshTab()"> 刷新当前标签页 </Button>
       </div>
-    </div>
+    </Card>
 
-    <div class="card-box mt-5 p-5">
+    <Card class="mb-5" title="动态标题">
       <div class="text-lg font-semibold">动态标题</div>
       <div class="text-foreground/80 my-3">
         该操作不会影响页面标题,仅修改Tab标题
       </div>
       <div class="flex flex-wrap items-center gap-3">
-        <AInput
+        <Input
           v-model:value="newTabTitle"
           class="w-40"
           placeholder="请输入新标题"
@@ -94,9 +88,9 @@ function reset() {
         </Button>
         <Button @click="reset"> 重置 </Button>
       </div>
-    </div>
+    </Card>
 
-    <div class="card-box mt-5 p-5">
+    <Card class="mb-5" title="最大打开数量">
       <div class="text-lg font-semibold">最大打开数量</div>
       <div class="text-foreground/80 my-3">
         限制带参数的tab打开的最大数量,由 `route.meta.maxNumOfOpenTab` 控制
@@ -108,6 +102,6 @@ function reset() {
           </Button>
         </template>
       </div>
-    </div>
-  </div>
+    </Card>
+  </Page>
 </template>

+ 4 - 8
playground/src/views/demos/features/tabs/tab-detail.vue

@@ -2,6 +2,7 @@
 import { computed } from 'vue';
 import { useRoute } from 'vue-router';
 
+import { Page } from '@vben/common-ui';
 import { useTabs } from '@vben/hooks';
 
 const route = useRoute();
@@ -16,12 +17,7 @@ setTabTitle(`No.${index.value} - 详情信息`);
 </script>
 
 <template>
-  <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>{{ index }} - 详情页内容在此</div>
-      </div>
-    </div>
-  </div>
+  <Page :title="`标签页${index}详情页`">
+    <template #description> {{ index }} - 详情页内容在此 </template>
+  </Page>
 </template>

+ 12 - 12
playground/src/views/demos/features/watermark/index.vue

@@ -1,7 +1,8 @@
 <script lang="ts" setup>
+import { Page } from '@vben/common-ui';
 import { useWatermark } from '@vben/hooks';
 
-import { Button } from 'ant-design-vue';
+import { Button, Card } from 'ant-design-vue';
 
 const { destroyWatermark, updateWatermark } = useWatermark();
 
@@ -40,9 +41,8 @@ async function createWaterMark() {
 </script>
 
 <template>
-  <div class="p-5">
-    <div class="card-box p-5">
-      <h1 class="text-xl font-semibold">水印</h1>
+  <Page title="水印">
+    <template #description>
       <div class="text-foreground/80 mt-2">
         水印使用了
         <a
@@ -54,13 +54,13 @@ async function createWaterMark() {
         </a>
         开源插件,详细配置可见插件配置。
       </div>
-    </div>
+    </template>
 
-    <div class="card-box mt-5 p-5">
-      <div class="mb-3 flex gap-3 text-lg font-semibold">
-        <Button type="primary" @click="createWaterMark()">创建水印</Button>
-        <Button danger @click="destroyWatermark">移除水印</Button>
-      </div>
-    </div>
-  </div>
+    <Card title="使用">
+      <Button class="mr-2" type="primary" @click="createWaterMark()">
+        创建水印
+      </Button>
+      <Button danger @click="destroyWatermark">移除水印</Button>
+    </Card>
+  </Page>
 </template>

File diff suppressed because it is too large
+ 0 - 1
playground/src/views/examples/ellipsis/data.ts


File diff suppressed because it is too large
+ 2 - 3
playground/src/views/examples/ellipsis/index.vue


Some files were not shown because too many files changed in this diff