Explorar o código

feat(page-wrapper): added pageWrapper component

vben %!s(int64=4) %!d(string=hai) anos
pai
achega
31ff0559fe
Modificáronse 79 ficheiros con 756 adicións e 471 borrados
  1. 19 21
      .vscode/settings.json
  2. 1 0
      CHANGELOG.zh_CN.md
  3. 1 1
      src/components/Form/src/hooks/useFormContext.ts
  4. 2 0
      src/components/Page/index.ts
  5. 9 6
      src/components/Page/src/PageFooter.vue
  6. 153 0
      src/components/Page/src/PageWrapper.vue
  7. 4 2
      src/components/Table/src/hooks/useDataSource.ts
  8. 4 2
      src/components/Upload/index.ts
  9. 20 0
      src/hooks/component/usePageContext.ts
  10. 11 10
      src/hooks/core/useContext.ts
  11. 3 0
      src/layouts/default/content/index.vue
  12. 19 0
      src/layouts/default/content/useContentContext.ts
  13. 30 0
      src/layouts/default/content/useContentViewHeight.ts
  14. 2 0
      src/layouts/default/header/MultipleHeader.vue
  15. 1 9
      src/layouts/page/index.tsx
  16. 1 1
      src/settings/projectSetting.ts
  17. 10 13
      src/views/demo/comp/button/index.vue
  18. 5 5
      src/views/demo/comp/count-to/index.vue
  19. 6 5
      src/views/demo/comp/desc/index.vue
  20. 4 3
      src/views/demo/comp/drawer/index.vue
  21. 6 8
      src/views/demo/comp/lazy/Transition.vue
  22. 6 8
      src/views/demo/comp/lazy/index.vue
  23. 5 3
      src/views/demo/comp/loading/index.vue
  24. 5 3
      src/views/demo/comp/modal/index.vue
  25. 57 49
      src/views/demo/comp/qrcode/index.vue
  26. 5 6
      src/views/demo/comp/scroll/Action.vue
  27. 6 5
      src/views/demo/comp/scroll/VirtualScroll.vue
  28. 5 8
      src/views/demo/comp/scroll/index.vue
  29. 12 10
      src/views/demo/comp/strength-meter/index.vue
  30. 5 3
      src/views/demo/comp/transition/index.vue
  31. 4 3
      src/views/demo/comp/upload/index.vue
  32. 6 3
      src/views/demo/comp/verify/Rotate.vue
  33. 5 3
      src/views/demo/comp/verify/index.vue
  34. 4 3
      src/views/demo/editor/markdown/Editor.vue
  35. 5 3
      src/views/demo/editor/markdown/index.vue
  36. 4 3
      src/views/demo/editor/tinymce/Editor.vue
  37. 4 3
      src/views/demo/editor/tinymce/index.vue
  38. 4 3
      src/views/demo/excel/ArrayExport.vue
  39. 4 3
      src/views/demo/excel/CustomExport.vue
  40. 4 3
      src/views/demo/excel/ImportExcel.vue
  41. 4 3
      src/views/demo/excel/JsonExport.vue
  42. 6 3
      src/views/demo/feat/breadcrumb/ChildrenList.vue
  43. 6 3
      src/views/demo/feat/breadcrumb/FlatList.vue
  44. 6 6
      src/views/demo/feat/click-out-side/index.vue
  45. 5 3
      src/views/demo/feat/context-menu/index.vue
  46. 4 3
      src/views/demo/feat/copy/index.vue
  47. 5 2
      src/views/demo/feat/download/index.vue
  48. 5 3
      src/views/demo/feat/full-screen/index.vue
  49. 4 2
      src/views/demo/feat/icon/index.vue
  50. 5 3
      src/views/demo/feat/img-preview/index.vue
  51. 5 3
      src/views/demo/feat/msg/index.vue
  52. 5 7
      src/views/demo/feat/ripple/index.vue
  53. 5 2
      src/views/demo/feat/tab-params/index.vue
  54. 4 3
      src/views/demo/feat/tabs/index.vue
  55. 4 3
      src/views/demo/feat/watermark/index.vue
  56. 4 3
      src/views/demo/form/AdvancedForm.vue
  57. 5 3
      src/views/demo/form/CustomerForm.vue
  58. 5 3
      src/views/demo/form/DynamicForm.vue
  59. 5 3
      src/views/demo/form/RefForm.vue
  60. 5 3
      src/views/demo/form/RuleForm.vue
  61. 5 3
      src/views/demo/form/UseForm.vue
  62. 4 3
      src/views/demo/form/index.vue
  63. 25 28
      src/views/demo/page/desc/basic/index.vue
  64. 18 23
      src/views/demo/page/desc/high/index.vue
  65. 10 10
      src/views/demo/page/form/basic/index.vue
  66. 21 25
      src/views/demo/page/form/high/index.vue
  67. 25 25
      src/views/demo/page/form/step/index.vue
  68. 5 6
      src/views/demo/page/list/basic/index.vue
  69. 1 1
      src/views/demo/page/list/card/data.tsx
  70. 6 10
      src/views/demo/page/list/card/index.vue
  71. 6 6
      src/views/demo/page/list/search/index.vue
  72. 5 3
      src/views/demo/permission/back/Btn.vue
  73. 10 9
      src/views/demo/permission/back/index.vue
  74. 9 7
      src/views/demo/permission/front/Btn.vue
  75. 9 7
      src/views/demo/permission/front/index.vue
  76. 2 1
      src/views/demo/table/Basic.vue
  77. 4 3
      src/views/demo/tree/ActionTree.vue
  78. 13 9
      src/views/demo/tree/EditTree.vue
  79. 20 17
      src/views/demo/tree/index.vue

+ 19 - 21
.vscode/settings.json

@@ -12,6 +12,7 @@
   "editor.cursorSmoothCaretAnimation": true,
   "editor.detectIndentation": false,
   "diffEditor.ignoreTrimWhitespace": false,
+  "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
   "editor.formatOnPaste": true,
   "editor.formatOnSave": true,
   "editor.suggestSelection": "first",
@@ -108,18 +109,22 @@
   // ===========================================
   // ================ Eslint ===================
   // ===========================================
-  "eslint.enable": true,
+  // "eslint.enable": true,
+  "eslint.alwaysShowStatus": true,
   "eslint.options": {
     // 配置
-    "plugins": [
-      "html",
-      "vue",
-      "javascript",
-      "jsx",
-      "typescript"
-    ]
-  },
-  "eslint.autoFixOnSave": true,
+    "plugins": ["html", "vue", "javascript", "jsx", "typescript"],
+    "extensions": [".js", ".jsx", ".ts", ".tsx", ".vue"]
+  },
+  "eslint.validate": [
+    "javascript",
+    "typescript",
+    "reacttypescript",
+    "reactjavascript",
+    "html",
+    "vue"
+  ],
+  // "eslint.autoFixOnSave": true,
   // ===========================================
   // ================ Vetur ====================
   // ===========================================
@@ -181,19 +186,12 @@
   "editor.codeActionsOnSave": {
     "source.fixAll.eslint": true
   },
-  "i18n-ally.localesPaths": [
-    "src/locales/lang",
-  ],
+  "i18n-ally.localesPaths": ["src/locales/lang"],
   "i18n-ally.keystyle": "nested",
   "i18n-ally.sortKeys": true,
   "i18n-ally.namespace": true,
   "i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
-  "i18n-ally.enabledParsers": [
-    "ts"
-  ],
+  "i18n-ally.enabledParsers": ["ts"],
   "i18n-ally.sourceLanguage": "zh",
-  "i18n-ally.enabledFrameworks": [
-    "vue",
-    "react"
-  ]
-}
+  "i18n-ally.enabledFrameworks": ["vue", "react"]
+}

+ 1 - 0
CHANGELOG.zh_CN.md

@@ -5,6 +5,7 @@
 - 新增`mixSideTrigger`配置。用于配置左侧混合模式菜单打开方式。可选`hover`,默认`click`
 - 新增`mixSideFixed`配置。用于固定左侧混合模式菜单
 - modal 组件新增`height`和`min-height`属性
+- 新增`PageWrapper`组件。并应用于示例页面
 
 ### 🐛 Bug Fixes
 

+ 1 - 1
src/components/Form/src/hooks/useFormContext.ts

@@ -1,4 +1,4 @@
-import { InjectionKey } from 'vue';
+import type { InjectionKey } from 'vue';
 import { createContext, useContext } from '/@/hooks/core/useContext';
 
 export interface FormContextProps {

+ 2 - 0
src/components/Page/index.ts

@@ -1,2 +1,4 @@
 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
 export const PageFooter = createAsyncComponent(() => import('./src/PageFooter.vue'));
+
+export { default as PageWrapper } from './src/PageWrapper.vue';

+ 9 - 6
src/components/Page/src/PageFooter.vue

@@ -1,9 +1,10 @@
 <template>
-  <div class="app-footer" :style="{ width: getCalcContentWidth }">
-    <div class="app-footer__left">
+  <div :class="prefixCls" :style="{ width: getCalcContentWidth }">
+    <div :class="`${prefixCls}__left`">
       <slot name="left" />
     </div>
-    <div class="app-footer__right">
+    <slot />
+    <div :class="`${prefixCls}__right`">
       <slot name="right" />
     </div>
   </div>
@@ -12,19 +13,21 @@
   import { defineComponent } from 'vue';
 
   import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
+  import { useDesign } from '/@/hooks/web/useDesign';
 
   export default defineComponent({
     name: 'PageFooter',
     setup() {
+      const { prefixCls } = useDesign('page-footer');
       const { getCalcContentWidth } = useMenuSetting();
-      return { getCalcContentWidth };
+      return { prefixCls, getCalcContentWidth };
     },
   });
 </script>
 <style lang="less" scoped>
-  @import (reference) '../../../design/index.less';
+  @prefix-cls: ~'@{namespace}-page-footer';
 
-  .app-footer {
+  .@{prefix-cls} {
     position: fixed;
     right: 0;
     bottom: 0;

+ 153 - 0
src/components/Page/src/PageWrapper.vue

@@ -0,0 +1,153 @@
+<template>
+  <div :class="getClass">
+    <PageHeader :ghost="ghost" v-bind="$attrs" ref="headerRef">
+      <template #default>
+        <template v-if="content">
+          {{ content }}
+        </template>
+        <slot name="headerContent" v-else />
+      </template>
+      <template #[item]="data" v-for="item in getHeaderSlots">
+        <slot :name="item" v-bind="data" />
+      </template>
+    </PageHeader>
+    <div :class="[`${prefixCls}-content`, $attrs.contentClass]" :style="getContentStyle">
+      <slot />
+    </div>
+    <PageFooter v-if="getShowFooter" ref="footerRef">
+      <template #left>
+        <slot name="leftFooter" />
+      </template>
+      <template #right>
+        <slot name="rightFooter" />
+      </template>
+    </PageFooter>
+  </div>
+</template>
+<script lang="ts">
+  import type { CSSProperties, PropType } from 'vue';
+
+  import { defineComponent, computed, watch, nextTick, ref, unref } from 'vue';
+  import PageFooter from './PageFooter.vue';
+  import { usePageContext } from '/@/hooks/component/usePageContext';
+
+  import { useDesign } from '/@/hooks/web/useDesign';
+  import { propTypes } from '/@/utils/propTypes';
+  import { omit } from 'lodash-es';
+  import { PageHeader } from 'ant-design-vue';
+  export default defineComponent({
+    name: 'PageWrapper',
+    components: { PageFooter, PageHeader },
+    props: {
+      dense: propTypes.bool,
+      ghost: propTypes.bool,
+      content: propTypes.string,
+      contentStyle: {
+        type: Object as PropType<CSSProperties>,
+      },
+      contentBackgrond: propTypes.bool,
+      contentFullHeight: propTypes.bool,
+    },
+    setup(props, { slots }) {
+      const headerRef = ref<ComponentRef>(null);
+      const footerRef = ref<ComponentRef>(null);
+      const { prefixCls } = useDesign('page-wrapper');
+      const { contentHeight, setPageHeight, pageHeight } = usePageContext();
+
+      const getClass = computed(() => {
+        return [
+          prefixCls,
+          {
+            [`${prefixCls}--dense`]: props.dense,
+          },
+        ];
+      });
+
+      const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);
+
+      const getHeaderSlots = computed(() => {
+        return Object.keys(omit(slots, 'default', 'leftFooter', 'rightFooter', 'headerContent'));
+      });
+
+      const getContentStyle = computed(
+        (): CSSProperties => {
+          const { contentBackgrond, contentFullHeight, contentStyle } = props;
+          const bg = contentBackgrond ? { backgroundColor: '#fff' } : {};
+          if (!contentFullHeight) {
+            return { ...bg, ...contentStyle };
+          }
+          return {
+            ...bg,
+            ...contentStyle,
+            minHeight: `${unref(pageHeight)}px`,
+          };
+        }
+      );
+
+      watch(
+        () => contentHeight?.value,
+        (height) => {
+          if (!props.contentFullHeight) {
+            return;
+          }
+          nextTick(() => {
+            const footer = unref(footerRef);
+            const header = unref(headerRef);
+            let footetHeight = 0;
+            const footerEl = footer?.$el;
+            if (footerEl) {
+              footetHeight += footerEl?.offsetHeight ?? 0;
+            }
+            let headerHeight = 0;
+            const headerEl = header?.$el;
+            if (headerEl) {
+              headerHeight += headerEl?.offsetHeight ?? 0;
+            }
+            setPageHeight?.(height - footetHeight - headerHeight);
+          });
+        },
+        {
+          immediate: true,
+        }
+      );
+
+      return {
+        getContentStyle,
+        footerRef,
+        headerRef,
+        getClass,
+        getHeaderSlots,
+        prefixCls,
+        getShowFooter,
+        pageHeight,
+        omit,
+      };
+    },
+  });
+</script>
+<style lang="less">
+  @prefix-cls: ~'@{namespace}-page-wrapper';
+
+  .@{prefix-cls} {
+    position: relative;
+
+    .ant-page-header {
+      padding: 12px 16px;
+
+      &:empty {
+        padding: 0;
+      }
+    }
+
+    &-content {
+      // padding: 12px;
+      margin: 16px;
+    }
+
+    &--dense {
+      .@{prefix-cls}-content {
+        margin: 0;
+      }
+    }
+  }
+</style>

+ 4 - 2
src/components/Table/src/hooks/useDataSource.ts

@@ -7,7 +7,7 @@ import { useTimeoutFn } from '/@/hooks/core/useTimeout';
 
 import { buildUUID } from '/@/utils/uuid';
 import { isFunction, isBoolean } from '/@/utils/is';
-import { get } from 'lodash-es';
+import { get, cloneDeep } from 'lodash-es';
 
 import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from '../const';
 
@@ -114,7 +114,8 @@ export function useDataSource(
 
       if (firstItem && lastItem) {
         if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) {
-          unref(dataSourceRef).forEach((item) => {
+          const data = cloneDeep(unref(dataSourceRef));
+          data.forEach((item) => {
             if (!item[ROW_KEY]) {
               item[ROW_KEY] = buildUUID();
             }
@@ -122,6 +123,7 @@ export function useDataSource(
               setTableKey(item.children);
             }
           });
+          dataSourceRef.value = data;
         }
       }
     }

+ 4 - 2
src/components/Upload/index.ts

@@ -1,2 +1,4 @@
-import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
-export const BasicUpload = createAsyncComponent(() => import('./src/BasicUpload.vue'));
+// import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+// export const BasicUpload = createAsyncComponent(() => import('./src/BasicUpload.vue'));
+
+export { default as BasicUpload } from './src/BasicUpload.vue';

+ 20 - 0
src/hooks/component/usePageContext.ts

@@ -0,0 +1,20 @@
+import type { InjectionKey, ComputedRef, Ref } from 'vue';
+import { createContext, useContext } from '/@/hooks/core/useContext';
+
+import {} from 'vue';
+
+export interface PageContextProps {
+  contentHeight: ComputedRef<number>;
+  pageHeight: Ref<number>;
+  setPageHeight: (height: number) => Promise<void>;
+}
+
+const key: InjectionKey<PageContextProps> = Symbol();
+
+export function createPageContext(context: PageContextProps) {
+  return createContext<PageContextProps>(context, key, { native: true });
+}
+
+export function usePageContext() {
+  return useContext<PageContextProps>(key);
+}

+ 11 - 10
src/hooks/core/useContext.ts

@@ -11,6 +11,7 @@ import {
 export interface CreateContextOptions {
   readonly?: boolean;
   createProvider?: boolean;
+  native?: boolean;
 }
 
 type ShallowUnwrap<T> = {
@@ -22,11 +23,11 @@ export function createContext<T>(
   key: InjectionKey<T> = Symbol(),
   options: CreateContextOptions = {}
 ) {
-  const { readonly = true, createProvider = false } = options;
+  const { readonly = true, createProvider = false, native = false } = options;
 
   const state = reactive(context);
   const provideData = readonly ? defineReadonly(state) : state;
-  !createProvider && provide(key, provideData);
+  !createProvider && provide(key, native ? context : provideData);
 
   const Provider = createProvider
     ? defineComponent({
@@ -42,12 +43,12 @@ export function createContext<T>(
   return { Provider, state };
 }
 
-export const useContext = <T>(
-  key: InjectionKey<T> = Symbol(),
-  defaultValue?: any,
-  readonly = false
-): ShallowUnwrap<T> => {
-  const state = inject(key, defaultValue || {});
+export function useContext<T>(key: InjectionKey<T>, native?: boolean): T;
+export function useContext<T>(key: InjectionKey<T>, defaultValue?: any, native?: boolean): T;
 
-  return readonly ? defineReadonly(state) : state;
-};
+export function useContext<T>(
+  key: InjectionKey<T> = Symbol(),
+  defaultValue?: any
+): ShallowUnwrap<T> {
+  return inject(key, defaultValue || {});
+}

+ 3 - 0
src/layouts/default/content/index.vue

@@ -19,6 +19,7 @@
   import { useRootSetting } from '/@/hooks/setting/useRootSetting';
   import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
   import PageLayout from '/@/layouts/page/index';
+  import { useContentViewHeight } from './useContentViewHeight';
   import { Loading } from '/@/components/Loading';
 
   export default defineComponent({
@@ -28,6 +29,8 @@
       const { prefixCls } = useDesign('layout-content');
       const { getOpenPageLoading } = useTransitionSetting();
       const { getLayoutContentMode, getPageLoading } = useRootSetting();
+
+      useContentViewHeight();
       return {
         prefixCls,
         getOpenPageLoading,

+ 19 - 0
src/layouts/default/content/useContentContext.ts

@@ -0,0 +1,19 @@
+import type { InjectionKey, ComputedRef } from 'vue';
+import { createContext, useContext } from '/@/hooks/core/useContext';
+
+import {} from 'vue';
+
+export interface ContentContextProps {
+  contentHeight: ComputedRef<number>;
+  setPageHeight: (height: number) => Promise<void>;
+}
+
+const key: InjectionKey<ContentContextProps> = Symbol();
+
+export function createContentContext(context: ContentContextProps) {
+  return createContext<ContentContextProps>(context, key, { native: true });
+}
+
+export function useContentContext() {
+  return useContext<ContentContextProps>(key);
+}

+ 30 - 0
src/layouts/default/content/useContentViewHeight.ts

@@ -0,0 +1,30 @@
+import { ref, computed, unref } from 'vue';
+import { createPageContext } from '/@/hooks/component/usePageContext';
+import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
+export const headerHeightRef = ref(0);
+
+export function useContentViewHeight() {
+  const contentHeight = ref(window.innerHeight);
+  const pageHeight = ref(window.innerHeight);
+  const getViewHeight = computed(() => {
+    return unref(contentHeight) - unref(headerHeightRef) || 0;
+  });
+
+  useWindowSizeFn(
+    () => {
+      contentHeight.value = window.innerHeight;
+    },
+    100,
+    { immediate: true }
+  );
+
+  async function setPageHeight(height: number) {
+    pageHeight.value = height;
+  }
+
+  createPageContext({
+    contentHeight: getViewHeight,
+    setPageHeight,
+    pageHeight,
+  });
+}

+ 2 - 0
src/layouts/default/header/MultipleHeader.vue

@@ -17,6 +17,7 @@
   import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
   import { useAppInject } from '/@/hooks/web/useAppInject';
   import { useDesign } from '/@/hooks/web/useDesign';
+  import { headerHeightRef } from '../content/useContentViewHeight';
 
   const HEADER_HEIGHT = 48;
 
@@ -75,6 +76,7 @@
           if (unref(getShowMultipleTab)) {
             height += TABS_HEIGHT;
           }
+          headerHeightRef.value = height;
           return {
             height: `${height}px`,
           };

+ 1 - 9
src/layouts/page/index.tsx

@@ -1,8 +1,7 @@
-import type { FunctionalComponent } from 'vue';
 import type { DefaultContext } from './transition';
 
 import { computed, defineComponent, unref, Transition, KeepAlive } from 'vue';
-import { RouterView, RouteLocation } from 'vue-router';
+import { RouterView } from 'vue-router';
 
 import FrameLayout from '/@/layouts/iframe/index.vue';
 
@@ -12,14 +11,7 @@ import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
 import { useCache } from './useCache';
 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
 import { getTransitionName } from './transition';
-// import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
 
-interface DefaultContext {
-  Component: FunctionalComponent & { type: Indexable };
-  route: RouteLocation;
-}
-
-// const FrameLayout=createAsyncComponent(()=>'/@/layouts/iframe/index.vue')
 export default defineComponent({
   name: 'PageLayout',
   setup() {

+ 1 - 1
src/settings/projectSetting.ts

@@ -85,7 +85,7 @@ const setting: ProjectConfig = {
     collapsedShowTitle: false,
     // Whether it can be dragged
     // Only limited to the opening of the left menu, the mouse has a drag bar on the right side of the menu
-    canDrag: true,
+    canDrag: false,
     // Whether to show no dom
     show: true,
     // Whether to show dom

+ 10 - 13
src/views/demo/comp/button/index.vue

@@ -1,11 +1,11 @@
 <template>
-  <div class="p-4">
-    <Alert
-      message="温馨提醒"
-      description="基础组件依赖于 ant-design-vue,组件库已有的基础组件,项目中不会再次进行demo展示(二次封装组件除外)"
-      type="info"
-      show-icon
-    />
+  <PageWrapper
+    title="基础组件"
+    content=" 基础组件依赖于ant-design-vue,组件库已有的基础组件,项目中不会再次进行demo展示(二次封装组件除外)"
+  >
+    <template #rightFooter>
+      <a-button type="primary">确认</a-button>
+    </template>
 
     <div class="my-2">
       <h3>success</h3>
@@ -73,15 +73,12 @@
       <a-button type="dashed" class="ml-2" disabled> 禁用 </a-button>
       <a-button type="dashed" class="ml-2" loading> loading </a-button>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  import { Alert } from 'ant-design-vue';
+  import { PageWrapper } from '/@/components/Page';
   export default defineComponent({
-    components: { Alert },
-    setup() {
-      return {};
-    },
+    components: { PageWrapper },
   });
 </script>

+ 5 - 5
src/views/demo/comp/count-to/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4 count-to-demo">
+  <PageWrapper title="数字动画示例">
     <Card>
       <CardGrid class="count-to-demo-card">
         <CountTo prefix="$" :startVal="1" :endVal="200000" :duration="8000" />
@@ -14,20 +14,20 @@
         <CountTo separator="-" :startVal="10000" :endVal="500000" :duration="8000" />
       </CardGrid>
     </Card>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { Card } from 'ant-design-vue';
   import { CountTo } from '/@/components/CountTo/index';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
     components: {
       Card,
       CardGrid: Card.Grid,
       CountTo,
-    },
-    setup() {
-      return {};
+      PageWrapper,
     },
   });
 </script>

+ 6 - 5
src/views/demo/comp/desc/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="详情组件示例">
     <Description
       title="基础示例"
       :collapseOptions="{ canExpand: true, helpMessage: 'help me' }"
@@ -20,13 +20,14 @@
 
     <Description @register="register" class="mt-4" />
     <Description @register="register1" class="mt-4" />
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  import { Alert } from 'ant-design-vue';
   import { Description, DescItem, useDescription } from '/@/components/Description/index';
-  const mockData: any = {
+  import { PageWrapper } from '/@/components/Page';
+
+  const mockData: Recordable = {
     username: 'test',
     nickName: 'VB',
     age: 25,
@@ -63,7 +64,7 @@
     },
   ];
   export default defineComponent({
-    components: { Description, Alert },
+    components: { Description, PageWrapper },
     setup() {
       const [register] = useDescription({
         title: 'useDescription',

+ 4 - 3
src/views/demo/comp/drawer/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="px-10 py-4">
+  <PageWrapper title="抽屉组件使用示例">
     <Alert message="使用 useDrawer 进行抽屉操作" show-icon />
     <a-button type="primary" class="my-4" @click="openDrawerLoading">打开Drawer</a-button>
 
@@ -20,7 +20,7 @@
     <Drawer3 @register="register3" />
     <Drawer4 @register="register4" />
     <Drawer5 @register="register5" />
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
@@ -31,9 +31,10 @@
   import Drawer3 from './Drawer3.vue';
   import Drawer4 from './Drawer4.vue';
   import Drawer5 from './Drawer5.vue';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { Alert, Drawer1, Drawer2, Drawer3, Drawer4, Drawer5 },
+    components: { Alert, PageWrapper, Drawer1, Drawer2, Drawer3, Drawer4, Drawer5 },
     setup() {
       const [register1, { openDrawer: openDrawer1, setDrawerProps }] = useDrawer();
       const [register2, { openDrawer: openDrawer2 }] = useDrawer();

+ 6 - 8
src/views/demo/comp/lazy/Transition.vue

@@ -1,6 +1,5 @@
 <template>
-  <div class="p-4 lazy-base-demo">
-    <Alert message="自定义动画" description="懒加载组件显示动画" type="info" show-icon />
+  <PageWrapper title="懒加载自定义动画示例" content="懒加载组件显示动画">
     <div class="lazy-base-demo-wrap">
       <h1>向下滚动</h1>
 
@@ -10,18 +9,17 @@
         </LazyContainer>
       </div>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  import { Skeleton, Alert } from 'ant-design-vue';
+  import { Skeleton } from 'ant-design-vue';
   import TargetContent from './TargetContent.vue';
   import { LazyContainer } from '/@/components/Container/index';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { LazyContainer, TargetContent, Skeleton, Alert },
-    setup() {
-      return {};
-    },
+    components: { LazyContainer, TargetContent, Skeleton, PageWrapper },
   });
 </script>
 <style lang="less">

+ 6 - 8
src/views/demo/comp/lazy/index.vue

@@ -1,6 +1,5 @@
 <template>
-  <div class="p-4 lazy-base-demo">
-    <Alert message="基础示例" description="向下滚动到可见区域才会加载组件" type="info" show-icon />
+  <PageWrapper title="懒加载基础示例" content="向下滚动到可见区域才会加载组件">
     <div class="lazy-base-demo-wrap">
       <h1>向下滚动</h1>
 
@@ -13,18 +12,17 @@
         </LazyContainer>
       </div>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  import { Skeleton, Alert } from 'ant-design-vue';
+  import { Skeleton } from 'ant-design-vue';
   import TargetContent from './TargetContent.vue';
   import { LazyContainer } from '/@/components/Container/index';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { LazyContainer, TargetContent, Skeleton, Alert },
-    setup() {
-      return {};
-    },
+    components: { LazyContainer, PageWrapper, TargetContent, Skeleton },
   });
 </script>
 <style lang="less">

+ 5 - 3
src/views/demo/comp/loading/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-5" ref="wrapEl" v-loading="loadingRef" loading-tip="加载中...">
+  <PageWrapper v-loading="loadingRef" loading-tip="加载中..." title="Loading组件示例">
     <a-alert message="组件方式" />
     <a-button class="my-4 mr-4" type="primary" @click="openCompFullLoading">全屏 Loading</a-button>
     <a-button class="my-4" type="primary" @click="openCompAbsolute">容器内 Loading</a-button>
@@ -14,13 +14,15 @@
     <a-button class="my-4 mr-4" type="primary" @click="openDirectiveLoading">
       打开指令Loading
     </a-button>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, reactive, toRefs, ref } from 'vue';
   import { Loading, useLoading } from '/@/components/Loading';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { Loading },
+    components: { Loading, PageWrapper },
     setup() {
       const wrapEl = ref<ElRef>(null);
 

+ 5 - 3
src/views/demo/comp/modal/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="px-10 py-4">
+  <PageWrapper title="modal组件使用示例">
     <Alert
       message="使用 useModal 进行弹窗操作,默认可以拖动,可以通过 draggable
     参数进行控制是否可以拖动/全屏"
@@ -24,7 +24,7 @@
     <Modal2 @register="register2" />
     <Modal3 @register="register3" />
     <Modal4 @register="register4" />
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
@@ -34,8 +34,10 @@
   import Modal2 from './Modal2.vue';
   import Modal3 from './Modal3.vue';
   import Modal4 from './Modal4.vue';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { Alert, Modal1, Modal2, Modal3, Modal4 },
+    components: { Alert, Modal1, Modal2, Modal3, Modal4, PageWrapper },
     setup() {
       const [register1, { openModal: openModal1, setModalProps }] = useModal();
       const [register2, { openModal: openModal2 }] = useModal();

+ 57 - 49
src/views/demo/comp/qrcode/index.vue

@@ -1,68 +1,76 @@
 <template>
-  <div class="p-4 flex flex-wrap">
-    <CollapseContainer title="基础示例" :canExpan="true" class="text-center mb-6 qrcode-demo-item">
-      <QrCode :value="qrCodeUrl" />
-    </CollapseContainer>
+  <PageWrapper title="二维码组件使用示例">
+    <div class="flex flex-wrap">
+      <CollapseContainer
+        title="基础示例"
+        :canExpan="true"
+        class="text-center mb-6 qrcode-demo-item"
+      >
+        <QrCode :value="qrCodeUrl" />
+      </CollapseContainer>
 
-    <CollapseContainer title="渲染成img标签示例" class="text-center mb-6 qrcode-demo-item">
-      <QrCode :value="qrCodeUrl" tag="img" />
-    </CollapseContainer>
+      <CollapseContainer title="渲染成img标签示例" class="text-center mb-6 qrcode-demo-item">
+        <QrCode :value="qrCodeUrl" tag="img" />
+      </CollapseContainer>
 
-    <CollapseContainer title="配置样式示例" class="text-center mb-6 qrcode-demo-item">
-      <QrCode
-        :value="qrCodeUrl"
-        :options="{
-          color: { dark: '#55D187' },
-        }"
-      />
-    </CollapseContainer>
+      <CollapseContainer title="配置样式示例" class="text-center mb-6 qrcode-demo-item">
+        <QrCode
+          :value="qrCodeUrl"
+          :options="{
+            color: { dark: '#55D187' },
+          }"
+        />
+      </CollapseContainer>
 
-    <CollapseContainer title="本地logo示例" class="text-center mb-6 qrcode-demo-item">
-      <QrCode :value="qrCodeUrl" :logo="LogoImg" />
-    </CollapseContainer>
+      <CollapseContainer title="本地logo示例" class="text-center mb-6 qrcode-demo-item">
+        <QrCode :value="qrCodeUrl" :logo="LogoImg" />
+      </CollapseContainer>
 
-    <CollapseContainer title="在线logo示例" class="text-center mb-6 qrcode-demo-item">
-      <QrCode
-        :value="qrCodeUrl"
-        logo="https://vebn.oss-cn-beijing.aliyuncs.com/vben/logo.png"
-        :options="{
-          color: { dark: '#55D187' },
-        }"
-      />
-    </CollapseContainer>
+      <CollapseContainer title="在线logo示例" class="text-center mb-6 qrcode-demo-item">
+        <QrCode
+          :value="qrCodeUrl"
+          logo="https://vebn.oss-cn-beijing.aliyuncs.com/vben/logo.png"
+          :options="{
+            color: { dark: '#55D187' },
+          }"
+        />
+      </CollapseContainer>
 
-    <CollapseContainer title="logo配置示例" class="text-center mb-6 qrcode-demo-item">
-      <QrCode
-        :value="qrCodeUrl"
-        :logo="{
-          src: 'https://vebn.oss-cn-beijing.aliyuncs.com/vben/logo.png',
-          logoSize: 0.2,
-          borderSize: 0.05,
-          borderRadius: 50,
-          bgColor: 'blue',
-        }"
-      />
-    </CollapseContainer>
+      <CollapseContainer title="logo配置示例" class="text-center mb-6 qrcode-demo-item">
+        <QrCode
+          :value="qrCodeUrl"
+          :logo="{
+            src: 'https://vebn.oss-cn-beijing.aliyuncs.com/vben/logo.png',
+            logoSize: 0.2,
+            borderSize: 0.05,
+            borderRadius: 50,
+            bgColor: 'blue',
+          }"
+        />
+      </CollapseContainer>
 
-    <CollapseContainer title="下载示例" class="text-center qrcode-demo-item">
-      <QrCode :value="qrCodeUrl" ref="qrRef" :logo="LogoImg" />
-      <a-button class="mb-2" type="primary" @click="download"> 下载 </a-button>
-      <div class="msg">(在线logo会导致图片跨域,需要下载图片需要自行解决跨域问题)</div>
-    </CollapseContainer>
+      <CollapseContainer title="下载示例" class="text-center qrcode-demo-item">
+        <QrCode :value="qrCodeUrl" ref="qrRef" :logo="LogoImg" />
+        <a-button class="mb-2" type="primary" @click="download"> 下载 </a-button>
+        <div class="msg">(在线logo会导致图片跨域,需要下载图片需要自行解决跨域问题)</div>
+      </CollapseContainer>
 
-    <CollapseContainer title="配置大小示例" class="text-center qrcode-demo-item">
-      <QrCode :value="qrCodeUrl" :width="300" />
-    </CollapseContainer>
-  </div>
+      <CollapseContainer title="配置大小示例" class="text-center qrcode-demo-item">
+        <QrCode :value="qrCodeUrl" :width="300" />
+      </CollapseContainer>
+    </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref, unref } from 'vue';
   import { QrCode, QrCodeActionType } from '/@/components/Qrcode/index';
   import LogoImg from '/@/assets/images/logo.png';
   import { CollapseContainer } from '/@/components/Container/index';
+  import { PageWrapper } from '/@/components/Page';
+
   const qrCodeUrl = 'https://www.vvbin.cn';
   export default defineComponent({
-    components: { CollapseContainer, QrCode },
+    components: { CollapseContainer, QrCode, PageWrapper },
     setup() {
       const qrRef = ref<Nullable<QrCodeActionType>>(null);
       function download() {

+ 5 - 6
src/views/demo/comp/scroll/Action.vue

@@ -1,7 +1,5 @@
 <template>
-  <div class="p-4">
-    <Alert message="抽取el-scrollbar,并对其进行扩展,滚动条美化,适用于各个浏览器" type="info" />
-
+  <PageWrapper title="滚动组件函数示例" content="基于el-scrollbar">
     <div class="my-4">
       <a-button @click="scrollTo(100)" class="mr-2">滚动到100px位置</a-button>
       <a-button @click="scrollTo(800)" class="mr-2">滚动到800px位置</a-button>
@@ -17,15 +15,16 @@
         </ul>
       </ScrollContainer>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref, unref } from 'vue';
   import { CollapseContainer } from '/@/components/Container/index';
   import { ScrollContainer, ScrollActionType } from '/@/components/Container/index';
-  import { Alert } from 'ant-design-vue';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { CollapseContainer, ScrollContainer, Alert },
+    components: { CollapseContainer, ScrollContainer, PageWrapper },
     setup() {
       const scrollRef = ref<Nullable<ScrollActionType>>(null);
       const getScroll = () => {

+ 6 - 5
src/views/demo/comp/scroll/VirtualScroll.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4 virtual-scroll-demo">
+  <PageWrapper class="virtual-scroll-demo">
     <Divider>基础滚动示例</Divider>
     <div class="virtual-scroll-demo-wrap">
       <VScroll :itemHeight="41" :items="data" :height="300" :width="300">
@@ -17,15 +17,16 @@
         </template>
       </VScroll>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { VScroll } from '/@/components/VirtualScroll/index';
 
   import { Divider } from 'ant-design-vue';
-  const data: any[] = (() => {
-    const arr: any[] = [];
+  import { PageWrapper } from '/@/components/Page';
+  const data: Recordable[] = (() => {
+    const arr: Recordable[] = [];
     for (let index = 1; index < 20000; index++) {
       arr.push({
         title: '列表项' + index,
@@ -34,7 +35,7 @@
     return arr;
   })();
   export default defineComponent({
-    components: { VScroll: VScroll, Divider },
+    components: { VScroll: VScroll, Divider, PageWrapper },
     setup() {
       return { data: data };
     },

+ 5 - 8
src/views/demo/comp/scroll/index.vue

@@ -1,6 +1,5 @@
 <template>
-  <div class="p-4">
-    <Alert message="抽取el-scrollbar,并对其进行扩展,滚动条美化,适用于各个浏览器" type="info" />
+  <PageWrapper title="滚动组件示例" content="基于el-scrollbar">
     <div class="scroll-wrap">
       <ScrollContainer class="mt-4">
         <ul class="p-3">
@@ -10,18 +9,16 @@
         </ul>
       </ScrollContainer>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { CollapseContainer } from '/@/components/Container/index';
   import { ScrollContainer } from '/@/components/Container/index';
-  import { Alert } from 'ant-design-vue';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { CollapseContainer, ScrollContainer, Alert },
-    setup() {
-      return {};
-    },
+    components: { CollapseContainer, ScrollContainer, PageWrapper },
   });
 </script>
 <style lang="less" scoped>

+ 12 - 10
src/views/demo/comp/strength-meter/index.vue

@@ -1,23 +1,25 @@
 <template>
-  <div class="p-4 flex justify-center">
-    <div class="demo-wrap p-10">
-      <StrengthMeter placeholder="默认" />
-      <StrengthMeter placeholder="禁用" disabled />
-      <br />
-      <StrengthMeter placeholder="隐藏input" :show-input="false" value="!@#qwe12345" />
+  <PageWrapper title="密码强度校验组件">
+    <div class="flex justify-center">
+      <div class="demo-wrap p-10">
+        <StrengthMeter placeholder="默认" />
+        <StrengthMeter placeholder="禁用" disabled />
+        <br />
+        <StrengthMeter placeholder="隐藏input" :show-input="false" value="!@#qwe12345" />
+      </div>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { StrengthMeter } from '/@/components/StrengthMeter';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
     components: {
       StrengthMeter,
-    },
-    setup() {
-      return {};
+      PageWrapper,
     },
   });
 </script>

+ 5 - 3
src/views/demo/comp/transition/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="动画组件示例">
     <div class="flex">
       <Select
         :options="options"
@@ -12,11 +12,12 @@
     <component :is="`${value}Transition`">
       <div class="box" v-show="show"></div>
     </component>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
   import { Select } from 'ant-design-vue';
+  import { PageWrapper } from '/@/components/Page';
   import {
     FadeTransition,
     ScaleTransition,
@@ -57,6 +58,7 @@
   export default defineComponent({
     components: {
       Select,
+      PageWrapper,
       FadeTransition,
       ScaleTransition,
       SlideYTransition,
@@ -89,6 +91,6 @@
     width: 150px;
     height: 150px;
     margin-top: 20px;
-    background: pink;
+    background: rgb(126, 170, 236);
   }
 </style>

+ 4 - 3
src/views/demo/comp/upload/index.vue

@@ -1,18 +1,19 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="上传组件示例">
     <a-alert message="基础示例" class="my-5"></a-alert>
     <BasicUpload :maxSize="20" :maxNumber="10" @change="handleChange" :api="uploadApi" />
 
     <a-alert message="嵌入表单,加入表单校验" class="my-5"></a-alert>
 
     <BasicForm @register="register" />
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { BasicUpload } from '/@/components/Upload';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { PageWrapper } from '/@/components/Page';
 
   import { uploadApi } from '/@/api/sys/upload';
 
@@ -31,7 +32,7 @@
     },
   ];
   export default defineComponent({
-    components: { BasicUpload, BasicForm },
+    components: { BasicUpload, BasicForm, PageWrapper },
     setup() {
       const { createMessage } = useMessage();
       const [register] = useForm({

+ 6 - 3
src/views/demo/comp/verify/Rotate.vue

@@ -1,17 +1,20 @@
 <template>
-  <div class="p-10">
+  <PageWrapper title="旋转校验示例">
     <div class="flex justify-center p-4 items-center bg-gray-700">
       <RotateDragVerify :src="img" ref="el" @success="handleSuccess" />
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { RotateDragVerify } from '/@/components/Verify/index';
 
   import img from '/@/assets/images/header.jpg';
+
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { RotateDragVerify },
+    components: { RotateDragVerify, PageWrapper },
     setup() {
       const handleSuccess = () => {
         console.log('success!');

+ 5 - 3
src/views/demo/comp/verify/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-10">
+  <PageWrapper title="拖动校验示例">
     <div class="flex justify-center p-4 items-center bg-gray-700">
       <BasicDragVerify ref="el1" @success="handleSuccess" />
       <a-button type="primary" class="ml-2" @click="handleBtnClick(el1)">还原</a-button>
@@ -48,15 +48,17 @@
       </BasicDragVerify>
       <a-button type="primary" class="ml-2" @click="handleBtnClick(el5)">还原</a-button>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
   import { BasicDragVerify, DragVerifyActionType, PassingData } from '/@/components/Verify/index';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { BugOutlined, RightOutlined } from '@ant-design/icons-vue';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { BasicDragVerify, BugOutlined, RightOutlined },
+    components: { BasicDragVerify, BugOutlined, RightOutlined, PageWrapper },
     setup() {
       const { createMessage } = useMessage();
       const el1 = ref<Nullable<DragVerifyActionType>>(null);

+ 4 - 3
src/views/demo/editor/markdown/Editor.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="MarkDown组件嵌入Form示例">
     <CollapseContainer title="MarkDown表单">
       <BasicForm
         :labelWidth="100"
@@ -9,7 +9,7 @@
       >
       </BasicForm>
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, h } from 'vue';
@@ -17,6 +17,7 @@
   import { CollapseContainer } from '/@/components/Container/index';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { MarkDown } from '/@/components/Markdown';
+  import { PageWrapper } from '/@/components/Page';
 
   const schemas: FormSchema[] = [
     {
@@ -43,7 +44,7 @@
     },
   ];
   export default defineComponent({
-    components: { BasicForm, CollapseContainer },
+    components: { BasicForm, CollapseContainer, PageWrapper },
     setup() {
       const { createMessage } = useMessage();
 

+ 5 - 3
src/views/demo/editor/markdown/index.vue

@@ -1,14 +1,16 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="MarkDown组件示例">
     <a-button @click="toggleTheme" class="mb-2" type="primary">黑暗主题</a-button>
     <MarkDown :value="value" @change="handleChange" ref="markDownRef" />
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref, unref } from 'vue';
   import { MarkDown, MarkDownActionType } from '/@/components/Markdown';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { MarkDown },
+    components: { MarkDown, PageWrapper },
     setup() {
       const markDownRef = ref<Nullable<MarkDownActionType>>(null);
       const valueRef = ref(`

+ 4 - 3
src/views/demo/editor/tinymce/Editor.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="富文本嵌入表单示例">
     <CollapseContainer title="富文本表单">
       <BasicForm
         :labelWidth="100"
@@ -9,7 +9,7 @@
       >
       </BasicForm>
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, h } from 'vue';
@@ -17,6 +17,7 @@
   import { CollapseContainer } from '/@/components/Container/index';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { Tinymce } from '/@/components/Tinymce/index';
+  import { PageWrapper } from '/@/components/Page';
 
   const schemas: FormSchema[] = [
     {
@@ -43,7 +44,7 @@
     },
   ];
   export default defineComponent({
-    components: { BasicForm, CollapseContainer },
+    components: { BasicForm, CollapseContainer, PageWrapper },
     setup() {
       const { createMessage } = useMessage();
 

+ 4 - 3
src/views/demo/editor/tinymce/index.vue

@@ -1,14 +1,15 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="富文本组件示例">
     <Tinymce v-model="value" @change="handleChange" width="100%" />
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
   import { Tinymce } from '/@/components/Tinymce/index';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { Tinymce },
+    components: { Tinymce, PageWrapper },
     setup() {
       const value = ref('hello world!');
       function handleChange(value: string) {

+ 4 - 3
src/views/demo/excel/ArrayExport.vue

@@ -1,11 +1,11 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="导出示例" content="根据数组格式的数据进行导出">
     <BasicTable title="基础表格" :columns="columns" :dataSource="data">
       <template #toolbar>
         <a-button @click="aoaToExcel">导出</a-button>
       </template>
     </BasicTable>
-  </div>
+  </PageWrapper>
 </template>
 
 <script lang="ts">
@@ -13,9 +13,10 @@
   import { BasicTable } from '/@/components/Table';
   import { aoaToSheetXlsx } from '/@/components/Excel';
   import { arrHeader, arrData, columns, data } from './data';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { BasicTable },
+    components: { BasicTable, PageWrapper },
     setup() {
       function aoaToExcel() {
         // 保证data顺序与header一致

+ 4 - 3
src/views/demo/excel/CustomExport.vue

@@ -1,12 +1,12 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="导出示例" content="可以选择导出格式">
     <BasicTable title="基础表格" :columns="columns" :dataSource="data">
       <template #toolbar>
         <a-button @click="openModal">导出</a-button>
       </template>
     </BasicTable>
     <ExpExcelModel @register="register" @success="defaultHeader" />
-  </div>
+  </PageWrapper>
 </template>
 
 <script lang="ts">
@@ -15,9 +15,10 @@
   import { jsonToSheetXlsx, ExpExcelModel, ExportModalResult } from '/@/components/Excel';
   import { columns, data } from './data';
   import { useModal } from '/@/components/Modal';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { BasicTable, ExpExcelModel },
+    components: { BasicTable, ExpExcelModel, PageWrapper },
     setup() {
       function defaultHeader({ filename, bookType }: ExportModalResult) {
         // 默认Object.keys(data[0])作为header

+ 4 - 3
src/views/demo/excel/ImportExcel.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="excel数据导入示例">
     <ImpExcel @success="loadDataSuccess">
       <a-button class="m-3">导入Excel</a-button>
     </ImpExcel>
@@ -10,16 +10,17 @@
       :columns="table.columns"
       :dataSource="table.dataSource"
     ></BasicTable>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
 
   import { ImpExcel, ExcelData } from '/@/components/Excel';
   import { BasicTable, BasicColumn } from '/@/components/Table';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { BasicTable, ImpExcel },
+    components: { BasicTable, ImpExcel, PageWrapper },
 
     setup() {
       const tableListRef = ref<

+ 4 - 3
src/views/demo/excel/JsonExport.vue

@@ -1,12 +1,12 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="导出示例" content="根据JSON格式的数据进行导出">
     <BasicTable title="基础表格" :columns="columns" :dataSource="data">
       <template #toolbar>
         <a-button @click="defaultHeader">导出:默认头部</a-button>
         <a-button @click="customHeader">导出:自定义头部</a-button>
       </template>
     </BasicTable>
-  </div>
+  </PageWrapper>
 </template>
 
 <script lang="ts">
@@ -14,9 +14,10 @@
   import { BasicTable } from '/@/components/Table';
   import { jsonToSheetXlsx } from '/@/components/Excel';
   import { columns, data } from './data';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { BasicTable },
+    components: { BasicTable, PageWrapper },
     setup() {
       function defaultHeader() {
         // 默认Object.keys(data[0])作为header

+ 6 - 3
src/views/demo/feat/breadcrumb/ChildrenList.vue

@@ -1,10 +1,13 @@
 <template>
-  <div class="p-5">
+  <PageWrapper title="层级面包屑示例" content="子级页面面包屑会添加到当前层级后面">
     <router-link to="/feat/breadcrumb/children/childrenDetail">进入子级详情页</router-link>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
+  import { PageWrapper } from '/@/components/Page';
 
-  export default defineComponent({});
+  export default defineComponent({
+    components: { PageWrapper },
+  });
 </script>

+ 6 - 3
src/views/demo/feat/breadcrumb/FlatList.vue

@@ -1,10 +1,13 @@
 <template>
-  <div class="p-5">
+  <PageWrapper title="平级面包屑示例" content="子级页面面包屑会覆盖当前层级">
     <router-link to="/feat/breadcrumb/flatDetail">进入平级详情页</router-link>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
+  import { PageWrapper } from '/@/components/Page';
 
-  export default defineComponent({});
+  export default defineComponent({
+    components: { PageWrapper },
+  });
 </script>

+ 6 - 6
src/views/demo/feat/click-out-side/index.vue

@@ -1,19 +1,19 @@
 <template>
-  <div class="p-10">
-    <Alert message="点内外部触发事件" show-icon></Alert>
-    <ClickOutSide @clickOutside="handleClickOutside" class="flex justify-center mt-10">
+  <PageWrapper title="点内外部触发事件">
+    <ClickOutSide @clickOutside="handleClickOutside" class="flex justify-center">
       <div @click="innerClick" class="demo-box">
         {{ text }}
       </div>
     </ClickOutSide>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
-  import { Alert } from 'ant-design-vue';
   import { ClickOutSide } from '/@/components/ClickOutSide';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { ClickOutSide, Alert },
+    components: { ClickOutSide, PageWrapper },
     setup() {
       const text = ref('Click');
       function handleClickOutside() {

+ 5 - 3
src/views/demo/feat/context-menu/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="右键菜单示例">
     <CollapseContainer title="Simple">
       <a-button type="primary" @contextmenu="handleContext">Right Click on me</a-button>
     </CollapseContainer>
@@ -7,15 +7,17 @@
     <CollapseContainer title="Multiple" class="mt-4">
       <a-button type="primary" @contextmenu="handleMultipleContext">Right Click on me</a-button>
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { useContextMenu } from '/@/hooks/web/useContextMenu';
   import { CollapseContainer } from '/@/components/Container';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { CollapseContainer },
+    components: { CollapseContainer, PageWrapper },
     setup() {
       const [createContextMenu] = useContextMenu();
       const { createMessage } = useMessage();

+ 4 - 3
src/views/demo/feat/copy/index.vue

@@ -1,22 +1,23 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="文本复制示例">
     <CollapseContainer class="px-20 bg-white w-full h-32 rounded-md" title="Copy Example">
       <div class="flex justify-center">
         <a-input placeholder="请输入" v-model:value="value" />
         <a-button type="primary" @click="handleCopy">Copy</a-button>
       </div>
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, unref, ref } from 'vue';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
     name: 'Copy',
-    components: { CollapseContainer },
+    components: { CollapseContainer, PageWrapper },
     setup() {
       const valueRef = ref('');
       const { createMessage } = useMessage();

+ 5 - 2
src/views/demo/feat/download/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-5 demo-box">
+  <PageWrapper title="文件下载示例">
     <a-alert message="根据后台接口文件流下载" />
     <a-button type="primary" class="my-4" @click="handleDownByData"> 文件流下载 </a-button>
 
@@ -13,7 +13,7 @@
     <a-button type="primary" class="my-4" @click="handleDownloadByOnlineUrl">
       图片Url下载
     </a-button>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
@@ -24,7 +24,10 @@
     downloadByOnlineUrl,
   } from '/@/utils/file/download';
   import imgBase64 from './imgBase64';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
+    components: { PageWrapper },
     setup() {
       function handleDownByData() {
         downloadByData('text content', 'testName.txt');

+ 5 - 3
src/views/demo/feat/full-screen/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="全屏示例">
     <CollapseContainer class="px-20 bg-white w-full h-32 rounded-md" title="Window Full Screen">
       <a-button type="primary" @click="enterFullscreen" class="mr-2">
         Enter Window Full Screen
@@ -25,14 +25,16 @@
     >
       <a-button type="primary" @click="toggleDom" class="mr-2"> Exit Dom Full Screen </a-button>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useFullscreen } from '/@/hooks/web/useFullScreen';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { CollapseContainer },
+    components: { CollapseContainer, PageWrapper },
     setup() {
       const domRef = ref<Nullable<HTMLElement>>(null);
       const {

+ 4 - 2
src/views/demo/feat/icon/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="Icon组件示例">
     <CollapseContainer title="Antv Icon使用 (直接按需引入相应组件即可)">
       <div class="flex justify-around">
         <GithubFilled :style="{ fontSize: '30px' }" />
@@ -27,7 +27,7 @@
       description="Icon组件基本包含所有的图标,在下面网址内你可以查询到你想要的任何图标。并且打包只会打包所用到的图标。唯一不足的可能就是需要连接外网进行使用。"
     />
     <a-button type="link" @click="toIconify">Iconify 图标大全</a-button>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
@@ -46,9 +46,11 @@
   import Icon from '/@/components/Icon/index';
 
   import { openWindow } from '/@/utils';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
     components: {
+      PageWrapper,
       CollapseContainer,
       GithubFilled,
       QqCircleFilled,

+ 5 - 3
src/views/demo/feat/img-preview/index.vue

@@ -1,24 +1,26 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="图片预览示例">
     <Alert message="有预览图" type="info" />
     <div class="flex justify-center mt-4">
       <img :src="img" v-for="img in imgList" :key="img" class="mr-2" @click="handleClick(img)" />
     </div>
     <Alert message="无预览图" type="info" />
     <a-button @click="handlePreview" type="primary" class="mt-4">预览图片</a-button>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { Alert } from 'ant-design-vue';
   import { createImgPreview } from '/@/components/Preview/index';
+  import { PageWrapper } from '/@/components/Page';
+
   const imgList: string[] = [
     'https://picsum.photos/id/66/346/216',
     'https://picsum.photos/id/67/346/216',
     'https://picsum.photos/id/68/346/216',
   ];
   export default defineComponent({
-    components: { Alert },
+    components: { Alert, PageWrapper },
     setup() {
       function handleClick(img: string) {
         createImgPreview({ imageList: [img] });

+ 5 - 3
src/views/demo/feat/msg/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="消息示例">
     <CollapseContainer class="px-20 bg-white w-full h-32 rounded-md" title="Message">
       <a-button @click="infoMsg('Info message')" class="mr-2"> Info </a-button>
       <a-button @click="successMsg('Success message')" class="mr-2" color="success">
@@ -32,14 +32,16 @@
     >
       <a-button @click="handleNotify" color="success" class="mr-2">Success</a-button>
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { CollapseContainer },
+    components: { CollapseContainer, PageWrapper },
     setup() {
       const {
         createMessage,

+ 5 - 7
src/views/demo/feat/ripple/index.vue

@@ -1,20 +1,18 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="Ripple示例">
     <div class="demo-box" v-ripple>content</div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  import { Alert } from 'ant-design-vue';
   import RippleDirective from '/@/directives/ripple';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { Alert },
+    components: { PageWrapper },
     directives: {
       Ripple: RippleDirective,
     },
-    setup() {
-      return {};
-    },
   });
 </script>
 

+ 5 - 2
src/views/demo/feat/tab-params/index.vue

@@ -1,16 +1,19 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="带参数标签页" content="支持带参数多tab缓存">
     Current Param : {{ params }}
     <br />
     Keep Alive
     <input />
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { computed, defineComponent, unref } from 'vue';
   import { useRouter } from 'vue-router';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
     name: 'TestTab',
+    components: { PageWrapper },
     setup() {
       const { currentRoute } = useRouter();
       return {

+ 4 - 3
src/views/demo/feat/tabs/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="标签页操作示例">
     <CollapseContainer title="在下面输入框输入文本,切换后回来内容会保存">
       <a-input placeholder="请输入" />
     </CollapseContainer>
@@ -12,15 +12,16 @@
       <a-button class="mr-2" @click="closeCurrent">关闭当前</a-button>
       <a-button class="mr-2" @click="refreshPage">刷新当前</a-button>
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useTabs } from '/@/hooks/web/useTabs';
+  import { PageWrapper } from '/@/components/Page';
   export default defineComponent({
     name: 'TabsDemo',
-    components: { CollapseContainer },
+    components: { CollapseContainer, PageWrapper },
     setup() {
       const { closeAll, closeLeft, closeRight, closeOther, closeCurrent, refreshPage } = useTabs();
 

+ 4 - 3
src/views/demo/feat/watermark/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="水印示例">
     <CollapseContainer class="px-20 bg-white w-full h-32 rounded-md" title="Global WaterMark">
       <a-button type="primary" class="mr-2" @click="setWatermark('WaterMark Info')">
         Create
@@ -9,15 +9,16 @@
         Reset
       </a-button>
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useWatermark } from '/@/hooks/web/useWatermark';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { CollapseContainer },
+    components: { CollapseContainer, PageWrapper },
     setup() {
       const areaRef = ref<Nullable<HTMLElement>>(null);
       const { setWatermark, clear } = useWatermark();

+ 4 - 3
src/views/demo/form/AdvancedForm.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="可折叠表单示例">
     <CollapseContainer title="基础收缩示例">
       <BasicForm @register="register" />
     </CollapseContainer>
@@ -7,12 +7,13 @@
     <CollapseContainer title="超过3行自动收起" class="mt-4">
       <BasicForm @register="register1" />
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
   import { CollapseContainer } from '/@/components/Container/index';
+  import { PageWrapper } from '/@/components/Page';
 
   const getSchamas = (): FormSchema[] => {
     return [
@@ -148,7 +149,7 @@
     ];
   }
   export default defineComponent({
-    components: { BasicForm, CollapseContainer },
+    components: { BasicForm, CollapseContainer, PageWrapper },
     setup() {
       const [register] = useForm({
         labelWidth: 120,

+ 5 - 3
src/views/demo/form/CustomerForm.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="自定义组件示例">
     <CollapseContainer title="自定义表单">
       <BasicForm @register="register" @submit="handleSubmit">
         <template #f3="{ model, field }">
@@ -7,7 +7,7 @@
         </template>
       </BasicForm>
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, h } from 'vue';
@@ -15,6 +15,8 @@
   import { CollapseContainer } from '/@/components/Container/index';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { Input } from 'ant-design-vue';
+  import { PageWrapper } from '/@/components/Page';
+
   const schemas: FormSchema[] = [
     {
       field: 'field1',
@@ -60,7 +62,7 @@
     },
   ];
   export default defineComponent({
-    components: { BasicForm, CollapseContainer },
+    components: { BasicForm, CollapseContainer, PageWrapper },
     setup() {
       const { createMessage } = useMessage();
       const [register, { setProps }] = useForm({

+ 5 - 3
src/views/demo/form/DynamicForm.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="动态表单示例">
     <div class="mb-4">
       <a-button @click="changeLabel3" class="mr-2">更改字段3label</a-button>
       <a-button @click="changeLabel34" class="mr-2">同时更改字段3,4label</a-button>
@@ -13,12 +13,14 @@
     <CollapseContainer class="mt-5" title="componentProps动态改变">
       <BasicForm @register="register1" />
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
   import { CollapseContainer } from '/@/components/Container/index';
+  import { PageWrapper } from '/@/components/Page';
+
   const schemas: FormSchema[] = [
     {
       field: 'field1',
@@ -177,7 +179,7 @@
   ];
 
   export default defineComponent({
-    components: { BasicForm, CollapseContainer },
+    components: { BasicForm, CollapseContainer, PageWrapper },
     setup() {
       const [
         register,

+ 5 - 3
src/views/demo/form/RefForm.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="Ref操作示例">
     <div class="mb-4">
       <a-button @click="setProps({ labelWidth: 150 })" class="mr-2">更改labelWidth</a-button>
       <a-button @click="setProps({ labelWidth: 120 })" class="mr-2">还原labelWidth</a-button>
@@ -62,13 +62,15 @@
         :actionColOptions="{ span: 24 }"
       />
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
   import { BasicForm, FormSchema, FormActionType, FormProps } from '/@/components/Form/index';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
+
   const schemas: FormSchema[] = [
     {
       field: 'field1',
@@ -165,7 +167,7 @@
   ];
 
   export default defineComponent({
-    components: { BasicForm, CollapseContainer },
+    components: { BasicForm, CollapseContainer, PageWrapper },
     setup() {
       const formElRef = ref<Nullable<FormActionType>>(null);
       const { createMessage } = useMessage();

+ 5 - 3
src/views/demo/form/RuleForm.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="表单校验示例">
     <div class="mb-4">
       <a-button @click="validateForm" class="mr-2">手动校验表单</a-button>
       <a-button @click="resetValidate" class="mr-2">清空校验信息</a-button>
@@ -9,13 +9,15 @@
     <CollapseContainer title="表单校验">
       <BasicForm @register="register" @submit="handleSubmit" />
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
+
   const schemas: FormSchema[] = [
     {
       field: 'field1',
@@ -141,7 +143,7 @@
   ];
 
   export default defineComponent({
-    components: { BasicForm, CollapseContainer },
+    components: { BasicForm, CollapseContainer, PageWrapper },
     setup() {
       const { createMessage } = useMessage();
       const [register, { validateFields, clearValidate, getFieldsValue, setFieldsValue }] = useForm(

+ 5 - 3
src/views/demo/form/UseForm.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="UseForm操作示例">
     <div class="mb-4">
       <a-button @click="setProps({ labelWidth: 150 })" class="mr-2">更改labelWidth</a-button>
       <a-button @click="setProps({ labelWidth: 120 })" class="mr-2">还原labelWidth</a-button>
@@ -56,13 +56,15 @@
     <CollapseContainer title="useForm示例">
       <BasicForm @register="register" @submit="handleSubmit" />
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
+
   const schemas: FormSchema[] = [
     {
       field: 'field1',
@@ -159,7 +161,7 @@
   ];
 
   export default defineComponent({
-    components: { BasicForm, CollapseContainer },
+    components: { BasicForm, CollapseContainer, PageWrapper },
     setup() {
       const { createMessage } = useMessage();
 

+ 4 - 3
src/views/demo/form/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="m-4">
+  <PageWrapper title="表单基础示例">
     <CollapseContainer title="基础示例">
       <BasicForm
         autoFocusFirstItem
@@ -9,13 +9,14 @@
         @submit="handleSubmit"
       />
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
   import { BasicForm, FormSchema } from '/@/components/Form/index';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
 
   import { optionsListApi } from '/@/api/demo/select';
   const schemas: FormSchema[] = [
@@ -238,7 +239,7 @@
   ];
 
   export default defineComponent({
-    components: { BasicForm, CollapseContainer },
+    components: { BasicForm, CollapseContainer, PageWrapper },
     setup() {
       const check = ref(null);
       const { createMessage } = useMessage();

+ 25 - 28
src/views/demo/page/desc/basic/index.vue

@@ -1,37 +1,34 @@
 <template>
-  <div>
-    <a-page-header title="基础详情页" :ghost="false" />
+  <PageWrapper title="基础详情页" contentBackgrond>
+    <Description
+      size="middle"
+      title="退款申请"
+      :bordered="false"
+      :column="3"
+      :data="refundData"
+      :schema="refundSchema"
+    />
+    <a-divider />
+    <Description
+      size="middle"
+      title="用户信息"
+      :bordered="false"
+      :column="3"
+      :data="personData"
+      :schema="personSchema"
+    />
+    <a-divider />
 
-    <div class="m-5 desc-wrap">
-      <Description
-        size="middle"
-        title="退款申请"
-        :bordered="false"
-        :column="3"
-        :data="refundData"
-        :schema="refundSchema"
-      />
-      <a-divider />
-      <Description
-        size="middle"
-        title="用户信息"
-        :bordered="false"
-        :column="3"
-        :data="personData"
-        :schema="personSchema"
-      />
-      <a-divider />
-
-      <BasicTable @register="registerRefundTable" />
-      <a-divider />
-      <BasicTable @register="registerTimeTable" />
-    </div>
-  </div>
+    <BasicTable @register="registerRefundTable" />
+    <a-divider />
+    <BasicTable @register="registerTimeTable" />
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { Description } from '/@/components/Description/index';
   import { BasicTable, useTable } from '/@/components/Table';
+  import { PageWrapper } from '/@/components/Page';
 
   import {
     refundSchema,
@@ -44,7 +41,7 @@
     refundTimeTableData,
   } from './data';
   export default defineComponent({
-    components: { Description, BasicTable },
+    components: { Description, BasicTable, PageWrapper },
     setup() {
       const [registerRefundTable] = useTable({
         title: '退货商品',

+ 18 - 23
src/views/demo/page/desc/high/index.vue

@@ -1,17 +1,19 @@
 <template>
-  <div>
-    <a-page-header title="单号:234231029431" class="high-desc">
-      <template #extra>
-        <a-button key="3"> 操作一 </a-button>
-        <a-button key="2"> 操作二 </a-button>
-        <a-button key="1" type="primary"> 主操作 </a-button>
-      </template>
-      <template #footer>
-        <a-tabs default-active-key="1">
-          <a-tab-pane key="1" tab="详情" />
-          <a-tab-pane key="2" tab="规则" />
-        </a-tabs>
-      </template>
+  <PageWrapper title="单号:234231029431" contentBackgrond>
+    <template #extra>
+      <a-button key="3"> 操作一 </a-button>
+      <a-button key="2"> 操作二 </a-button>
+      <a-button key="1" type="primary"> 主操作 </a-button>
+    </template>
+
+    <template #footer>
+      <a-tabs default-active-key="1">
+        <a-tab-pane key="1" tab="详情" />
+        <a-tab-pane key="2" tab="规则" />
+      </a-tabs>
+    </template>
+
+    <div class="m-4 pt-4 desc-wrap">
       <a-descriptions size="small" :column="2">
         <a-descriptions-item label="创建人"> 曲丽丽 </a-descriptions-item>
         <a-descriptions-item label="订购产品"> XX 服务 </a-descriptions-item>
@@ -20,9 +22,6 @@
         <a-descriptions-item label="生效日期"> 2017-07-07 ~ 2017-08-08 </a-descriptions-item>
         <a-descriptions-item label="备注"> 请于两个工作日内确认 </a-descriptions-item>
       </a-descriptions>
-    </a-page-header>
-
-    <div class="m-5 desc-wrap">
       <a-card title="流程进度" :bordered="false">
         <a-steps :current="1" progress-dot size="small">
           <a-step title="创建项目">
@@ -84,16 +83,17 @@
       </a-card>
       <BasicTable @register="registerTimeTable" />
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { Description } from '/@/components/Description/index';
   import { BasicTable, useTable } from '/@/components/Table';
+  import { PageWrapper } from '/@/components/Page';
 
   import { refundTimeTableSchema, refundTimeTableData } from './data';
   export default defineComponent({
-    components: { Description, BasicTable },
+    components: { Description, BasicTable, PageWrapper },
     setup() {
       const [registerTimeTable] = useTable({
         title: '退货进度',
@@ -110,8 +110,3 @@
     },
   });
 </script>
-<style lang="less" scoped>
-  .high-desc {
-    background: #fff;
-  }
-</style>

+ 10 - 10
src/views/demo/page/form/basic/index.vue

@@ -1,21 +1,21 @@
 <template>
-  <div>
-    <a-page-header title="基础表单" :ghost="false">
-      表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。
-    </a-page-header>
-
-    <div class="m-5 form-wrap">
-      <BasicForm @register="register" />
-    </div>
-  </div>
+  <PageWrapper
+    title="基础表单"
+    contentBackgrond
+    content=" 表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。"
+  >
+    <BasicForm @register="register" />
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { BasicForm, useForm } from '/@/components/Form';
   import { defineComponent } from 'vue';
   import { schemas } from './data';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { BasicForm },
+    components: { BasicForm, PageWrapper },
     setup() {
       const { createMessage } = useMessage();
       const [register, { validate, setProps }] = useForm({

+ 21 - 25
src/views/demo/page/form/high/index.vue

@@ -1,38 +1,34 @@
 <template>
-  <div class="high-form">
-    <a-page-header title="高级表单" :ghost="false">
-      高级表单常见于一次性输入和提交大批量数据的场景。
-    </a-page-header>
+  <PageWrapper
+    class="high-form"
+    title="高级表单"
+    contentBackgrond
+    content=" 高级表单常见于一次性输入和提交大批量数据的场景。"
+  >
+    <a-card title="仓库管理" :bordered="false">
+      <BasicForm @register="register" />
+    </a-card>
+    <a-card title="任务管理" :bordered="false" class="mt-5">
+      <BasicForm @register="registerTask" />
+    </a-card>
+    <a-card title="成员管理" :bordered="false" class="mt-5">
+      <PersonTable ref="tableRef" />
+    </a-card>
 
-    <div class="m-5">
-      <a-card title="仓库管理" :bordered="false">
-        <BasicForm @register="register" />
-      </a-card>
-      <a-card title="任务管理" :bordered="false" class="mt-5">
-        <BasicForm @register="registerTask" />
-      </a-card>
-      <a-card title="成员管理" :bordered="false" class="mt-5">
-        <PersonTable ref="tableRef" />
-      </a-card>
-    </div>
-
-    <PageFooter>
-      <template #right>
-        <a-button type="primary" @click="submitAll">提交</a-button>
-      </template>
-    </PageFooter>
-  </div>
+    <template #rightFooter>
+      <a-button type="primary" @click="submitAll">提交</a-button>
+    </template>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { BasicForm, useForm } from '/@/components/Form';
   import { defineComponent, ref } from 'vue';
   import PersonTable from './PersonTable.vue';
-  import { PageFooter } from '/@/components/Page';
-
+  import { PageWrapper } from '/@/components/Page';
   import { schemas, taskSchemas } from './data';
 
   export default defineComponent({
-    components: { BasicForm, PersonTable, PageFooter },
+    components: { BasicForm, PersonTable, PageWrapper },
     setup() {
       const tableRef = ref<{ getDataSource: () => any } | null>(null);
 

+ 25 - 25
src/views/demo/page/form/step/index.vue

@@ -1,37 +1,37 @@
 <template>
-  <div>
-    <a-page-header title="分步表单" :ghost="false">
-      将一个冗长或用户不熟悉的表单任务分成多个步骤,指导用户完成。
-    </a-page-header>
-
-    <div class="m-5 step-form-content">
-      <div class="step-form-form">
-        <a-steps :current="current">
-          <a-step title="填写转账信息"> </a-step>
-          <a-step title="确认转账信息"> </a-step>
-          <a-step title="完成"> </a-step>
-        </a-steps>
-      </div>
-      <div class="mt-5">
-        <Step1 @next="handleStep1Next" v-show="current === 0" />
-        <Step2
-          @prev="handleStepPrev"
-          @next="handleStep2Next"
-          v-show="current === 1"
-          v-if="initSetp2"
-        />
-        <Step3 v-show="current === 2" @redo="handleRedo" v-if="initSetp3" />
-      </div>
+  <PageWrapper
+    title="分步表单"
+    contentBackgrond
+    content=" 将一个冗长或用户不熟悉的表单任务分成多个步骤,指导用户完成。"
+  >
+    <div class="step-form-form">
+      <a-steps :current="current">
+        <a-step title="填写转账信息"> </a-step>
+        <a-step title="确认转账信息"> </a-step>
+        <a-step title="完成"> </a-step>
+      </a-steps>
+    </div>
+    <div class="mt-5">
+      <Step1 @next="handleStep1Next" v-show="current === 0" />
+      <Step2
+        @prev="handleStepPrev"
+        @next="handleStep2Next"
+        v-show="current === 1"
+        v-if="initSetp2"
+      />
+      <Step3 v-show="current === 2" @redo="handleRedo" v-if="initSetp3" />
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref, reactive, toRefs } from 'vue';
   import Step1 from './Step1.vue';
   import Step2 from './Step2.vue';
   import Step3 from './Step3.vue';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { Step1, Step2, Step3 },
+    components: { Step1, Step2, Step3, PageWrapper },
     setup() {
       const current = ref(0);
 

+ 5 - 6
src/views/demo/page/list/basic/index.vue

@@ -1,6 +1,5 @@
 <template>
-  <div :class="prefixCls">
-    <a-page-header title="标准列表" :ghost="false" />
+  <PageWrapper :class="prefixCls" title="标准列表">
     <div :class="`${prefixCls}__top`">
       <a-row :gutter="12">
         <a-col :span="8" :class="`${prefixCls}__top-col`">
@@ -47,16 +46,17 @@
         </template>
       </a-list>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { Progress } from 'ant-design-vue';
   import { defineComponent } from 'vue';
   import Icon from '/@/components/Icon/index';
   import { cardList } from './data';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { Icon, Progress },
+    components: { Icon, Progress, PageWrapper },
     setup() {
       return {
         prefixCls: 'list-basic',
@@ -73,7 +73,6 @@
   .list-basic {
     &__top {
       padding: 24px;
-      margin: 24px 24px 0 24px;
       text-align: center;
       background: #fff;
 
@@ -100,7 +99,7 @@
 
     &__content {
       padding: 24px;
-      margin: 12px 24px;
+      margin-top: 12px;
       background: #fff;
 
       .list {

+ 1 - 1
src/views/demo/page/list/card/data.tsx

@@ -3,7 +3,7 @@ export const cardList = (() => {
   for (let i = 0; i < 12; i++) {
     result.push({
       title: 'Vben Admin',
-      icon: 'logos:ant-design',
+      icon: 'logos:vue',
       color: '#1890ff',
       active: '100',
       new: '1,799',

+ 6 - 10
src/views/demo/page/list/card/index.vue

@@ -1,13 +1,13 @@
 <template>
-  <div :class="prefixCls">
-    <a-page-header title="卡片列表" :ghost="false">
+  <PageWrapper :class="prefixCls" title="卡片列表">
+    <template #headerContent>
       基于Vue Next, TypeScript, Ant Design Vue实现的一套完整的企业级后台管理系统。
       <div :class="`${prefixCls}__link`">
         <a><Icon icon="bx:bx-paper-plane" color="#1890ff" /><span>开始</span></a>
         <a><Icon icon="carbon:warning" color="#1890ff" /><span>简介</span></a>
         <a><Icon icon="gg:loadbar-doc" color="#1890ff" /><span>文档</span></a>
       </div>
-    </a-page-header>
+    </template>
 
     <div :class="`${prefixCls}__content`">
       <a-list>
@@ -30,15 +30,16 @@
         </a-row>
       </a-list>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import Icon from '/@/components/Icon/index';
   import { cardList } from './data';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { Icon },
+    components: { Icon, PageWrapper },
     setup() {
       return {
         prefixCls: 'list-card',
@@ -62,11 +63,6 @@
       }
     }
 
-    &__content {
-      padding: 12px 24px;
-      // background: #fff;
-    }
-
     &__card {
       width: 100%;
       margin-bottom: -8px;

+ 6 - 6
src/views/demo/page/list/search/index.vue

@@ -1,13 +1,13 @@
 <template>
-  <div :class="prefixCls">
-    <a-page-header title="搜索列表" :ghost="false" :class="`${prefixCls}__header`">
+  <PageWrapper :class="prefixCls" title="搜索列表">
+    <template #headerContent>
       <BasicForm
         :class="`${prefixCls}__header-form`"
         :labelWidth="100"
         :schemas="schemas"
         :showActionButtonGroup="false"
       />
-    </a-page-header>
+    </template>
 
     <div :class="`${prefixCls}__container`">
       <a-list>
@@ -44,7 +44,7 @@
         </template>
       </a-list>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { Tag } from 'ant-design-vue';
@@ -52,9 +52,10 @@
   import Icon from '/@/components/Icon/index';
   import { BasicForm } from '/@/components/Form/index';
   import { actions, searchList, schemas } from './data';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { Icon, Tag, BasicForm },
+    components: { Icon, Tag, BasicForm, PageWrapper },
     setup() {
       return {
         prefixCls: 'list-search',
@@ -75,7 +76,6 @@
 
     &__container {
       padding: 12px;
-      margin: 24px;
       background: #fff;
     }
 

+ 5 - 3
src/views/demo/permission/back/Btn.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4 m-4 demo">
+  <PageWrapper contentBackgrond title="按钮权限控制" contentClass="p-4">
     <Alert message="刷新后会还原" show-icon />
 
     <CurrentPermissionMode />
@@ -51,7 +51,7 @@
     <a-button v-auth="['1000', '2000']" color="error" class="mx-4">
       拥有code ['1000','2000']角色权限可见
     </a-button>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
@@ -62,8 +62,10 @@
   import { getPermCodeByUserId } from '/@/api/sys/user';
   import { permissionStore } from '/@/store/modules/permission';
   import { PermissionModeEnum } from '/@/enums/appEnum';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { Alert, CurrentPermissionMode, Divider, Authority },
+    components: { Alert, PageWrapper, CurrentPermissionMode, Divider, Authority },
     setup() {
       const { hasPermission } = usePermission();
 

+ 10 - 9
src/views/demo/permission/back/index.vue

@@ -1,9 +1,10 @@
 <template>
-  <div class="p-4 m-4 demo">
-    <Alert
-      message="目前mock了两组数据, id为1 和 2 具体返回的菜单可以在mock/sys/menu.ts内查看"
-      show-icon
-    />
+  <PageWrapper
+    title="后台权限示例"
+    contentBackgrond
+    contentClass="p-4"
+    content="目前mock了两组数据, id为1 和 2 具体返回的菜单可以在mock/sys/menu.ts内查看"
+  >
     <CurrentPermissionMode />
 
     <Alert class="mt-4" type="info" message="点击后请查看左侧菜单变化" show-icon />
@@ -15,17 +16,17 @@
         <a-button @click="changeMenu('2')"> 获取用户id为2的菜单 </a-button>
       </a-button-group>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  import { Alert } from 'ant-design-vue';
   import CurrentPermissionMode from '../CurrentPermissionMode.vue';
   import { RoleEnum } from '/@/enums/roleEnum';
   import { usePermission } from '/@/hooks/web/usePermission';
-
+  import { PageWrapper } from '/@/components/Page';
+  import { Alert } from 'ant-design-vue';
   export default defineComponent({
-    components: { Alert, CurrentPermissionMode },
+    components: { Alert, CurrentPermissionMode, PageWrapper },
     setup() {
       const { changeMenu } = usePermission();
       return {

+ 9 - 7
src/views/demo/permission/front/Btn.vue

@@ -1,9 +1,10 @@
 <template>
-  <div class="demo p-4 m-4">
-    <Alert
-      message="由于刷新的时候会请求用户信息接口,会根据接口重置角色信息,所以刷新后界面会恢复原样,如果不需要,可以注释 src/layout/default/index内的获取用户信息接口"
-      show-icon
-    />
+  <PageWrapper
+    title="前端权限按钮示例"
+    contentBackgrond
+    contentClass="p-4"
+    content="由于刷新的时候会请求用户信息接口,会根据接口重置角色信息,所以刷新后界面会恢复原样,如果不需要,可以注释 src/layout/default/index内的获取用户信息接口"
+  >
     <CurrentPermissionMode />
 
     <p>
@@ -56,7 +57,7 @@
     <a-button v-auth="[RoleEnum.TEST, RoleEnum.SUPER]" color="error" class="mx-4">
       拥有[test,super]角色权限可见
     </a-button>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { computed, defineComponent } from 'vue';
@@ -66,9 +67,10 @@
   import { RoleEnum } from '/@/enums/roleEnum';
   import { usePermission } from '/@/hooks/web/usePermission';
   import { Authority } from '/@/components/Authority';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { Alert, CurrentPermissionMode, Divider, Authority },
+    components: { Alert, PageWrapper, CurrentPermissionMode, Divider, Authority },
     setup() {
       const { changeRole, hasPermission } = usePermission();
       return {

+ 9 - 7
src/views/demo/permission/front/index.vue

@@ -1,9 +1,10 @@
 <template>
-  <div class="p-4 m-4 demo">
-    <Alert
-      message="由于刷新的时候会请求用户信息接口,会根据接口重置角色信息,所以刷新后界面会恢复原样,如果不需要,可以注释 src/layout/default/index内的获取用户信息接口"
-      show-icon
-    />
+  <PageWrapper
+    title="前端权限示例"
+    contentBackgrond
+    contentClass="p-4"
+    content="由于刷新的时候会请求用户信息接口,会根据接口重置角色信息,所以刷新后界面会恢复原样,如果不需要,可以注释 src/layout/default/index内的获取用户信息接口"
+  >
     <CurrentPermissionMode />
 
     <p>
@@ -22,7 +23,7 @@
         </a-button>
       </a-button-group>
     </div>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { computed, defineComponent } from 'vue';
@@ -31,9 +32,10 @@
   import { userStore } from '/@/store/modules/user';
   import { RoleEnum } from '/@/enums/roleEnum';
   import { usePermission } from '/@/hooks/web/usePermission';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { Alert, CurrentPermissionMode },
+    components: { Alert, CurrentPermissionMode, PageWrapper },
     setup() {
       const { changeRole } = usePermission();
       return {

+ 2 - 1
src/views/demo/table/Basic.vue

@@ -31,9 +31,10 @@
   import { defineComponent, ref } from 'vue';
   import { BasicTable } from '/@/components/Table';
   import { getBasicColumns, getBasicData } from './tableData';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { BasicTable },
+    components: { BasicTable, PageWrapper },
     setup() {
       const canResize = ref(false);
       const loading = ref(false);

+ 4 - 3
src/views/demo/tree/ActionTree.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="p-4">
+  <PageWrapper title="Tree函数操作示例" contentBackgrond contentClass="p-4">
     <div class="mb-4">
       <a-button @click="handleLevel(2)" class="mr-2">显示到第2级</a-button>
       <a-button @click="handleLevel(1)" class="mr-2">显示到第1级</a-button>
@@ -20,7 +20,7 @@
     <CollapseContainer title="函数操作" class="mr-4" :canExpan="false" :style="{ width: '33%' }">
       <BasicTree :treeData="treeData" ref="treeRef" :checkable="true" />
     </CollapseContainer>
-  </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, ref, unref } from 'vue';
@@ -28,9 +28,10 @@
   import { treeData } from './data';
   import { CollapseContainer } from '/@/components/Container/index';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { BasicTree, CollapseContainer },
+    components: { BasicTree, CollapseContainer, PageWrapper },
     setup() {
       const treeRef = ref<Nullable<TreeActionType>>(null);
       const { createMessage } = useMessage();

+ 13 - 9
src/views/demo/tree/EditTree.vue

@@ -1,13 +1,15 @@
 <template>
-  <div class="flex p-4">
-    <CollapseContainer title="右侧操作按钮" class="mr-4" :style="{ width: '33%' }">
-      <BasicTree :treeData="treeData" :actionList="actionList" />
-    </CollapseContainer>
+  <PageWrapper title="Tree函数操作示例">
+    <div class="flex">
+      <CollapseContainer title="右侧操作按钮" class="mr-4" :style="{ width: '33%' }">
+        <BasicTree :treeData="treeData" :actionList="actionList" />
+      </CollapseContainer>
 
-    <CollapseContainer title="右键菜单" class="mr-4" :style="{ width: '33%' }">
-      <BasicTree :treeData="treeData" :beforeRightClick="getRightMenuList" />
-    </CollapseContainer>
-  </div>
+      <CollapseContainer title="右键菜单" class="mr-4" :style="{ width: '33%' }">
+        <BasicTree :treeData="treeData" :beforeRightClick="getRightMenuList" />
+      </CollapseContainer>
+    </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent, h } from 'vue';
@@ -15,8 +17,10 @@
   import { treeData } from './data';
   import { CollapseContainer } from '/@/components/Container/index';
   import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
+  import { PageWrapper } from '/@/components/Page';
+
   export default defineComponent({
-    components: { BasicTree, CollapseContainer },
+    components: { BasicTree, CollapseContainer, PageWrapper },
     setup() {
       function handlePlus(node: any) {
         console.log(node);

+ 20 - 17
src/views/demo/tree/index.vue

@@ -1,31 +1,34 @@
 <template>
-  <div class="flex p-4">
-    <CollapseContainer title="基础示例" :style="{ width: '33%' }" class="mr-4">
-      <BasicTree :treeData="treeData" />
-    </CollapseContainer>
+  <PageWrapper title="Tree基础示例">
+    <div class="flex">
+      <CollapseContainer title="基础示例" :style="{ width: '33%' }" class="mr-4">
+        <BasicTree :treeData="treeData" />
+      </CollapseContainer>
 
-    <CollapseContainer title="可勾选" class="mr-4" :style="{ width: '33%' }">
-      <BasicTree :treeData="treeData" :checkable="true" />
-    </CollapseContainer>
+      <CollapseContainer title="可勾选" class="mr-4" :style="{ width: '33%' }">
+        <BasicTree :treeData="treeData" :checkable="true" />
+      </CollapseContainer>
 
-    <CollapseContainer title="默认展开/勾选示例" :style="{ width: '33%' }">
-      <BasicTree
-        :treeData="treeData"
-        :checkable="true"
-        :expandedKeys="['0-0']"
-        :checkedKeys="['0-0']"
-      />
-    </CollapseContainer>
-  </div>
+      <CollapseContainer title="默认展开/勾选示例" :style="{ width: '33%' }">
+        <BasicTree
+          :treeData="treeData"
+          :checkable="true"
+          :expandedKeys="['0-0']"
+          :checkedKeys="['0-0']"
+        />
+      </CollapseContainer>
+    </div>
+  </PageWrapper>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { BasicTree } from '/@/components/Tree/index';
   import { treeData } from './data';
   import { CollapseContainer } from '/@/components/Container/index';
+  import { PageWrapper } from '/@/components/Page';
 
   export default defineComponent({
-    components: { BasicTree, CollapseContainer },
+    components: { BasicTree, CollapseContainer, PageWrapper },
     setup() {
       return { treeData };
     },