Browse Source

refactor: components use setup (#3299)

* refactor: /@/ => @/

* refactor: table demo use script setup

* refactor: change /@/ to @/
xingyu 1 năm trước cách đây
mục cha
commit
bab28af986
100 tập tin đã thay đổi với 2989 bổ sung3341 xóa
  1. 23 25
      .vscode/settings.json
  2. 1 1
      src/components/Application/index.ts
  3. 9 7
      src/components/Application/src/AppDarkModeToggle.vue
  4. 4 4
      src/components/Application/src/AppLocalePicker.vue
  5. 6 6
      src/components/Application/src/AppLogo.vue
  6. 4 4
      src/components/Application/src/AppProvider.vue
  7. 1 1
      src/components/Application/src/search/AppSearch.vue
  8. 5 3
      src/components/Application/src/search/AppSearchFooter.vue
  9. 4 4
      src/components/Application/src/search/AppSearchModal.vue
  10. 5 5
      src/components/Application/src/search/useMenuSearch.ts
  11. 1 1
      src/components/Application/src/useAppContext.ts
  12. 1 1
      src/components/Authority/index.ts
  13. 3 3
      src/components/Authority/src/Authority.vue
  14. 1 1
      src/components/Basic/index.ts
  15. 1 1
      src/components/Basic/src/BasicArrow.vue
  16. 4 4
      src/components/Basic/src/BasicHelp.vue
  17. 1 1
      src/components/Basic/src/BasicTitle.vue
  18. 1 1
      src/components/Button/index.ts
  19. 2 2
      src/components/Button/src/PopConfirmButton.vue
  20. 1 1
      src/components/CardList/index.ts
  21. 12 12
      src/components/CardList/src/CardList.vue
  22. 1 1
      src/components/ClickOutSide/index.ts
  23. 1 1
      src/components/CodeEditor/index.ts
  24. 1 1
      src/components/CodeEditor/src/CodeEditor.vue
  25. 1 1
      src/components/CodeEditor/src/codemirror/CodeMirror.vue
  26. 1 1
      src/components/Container/index.ts
  27. 53 64
      src/components/Container/src/ScrollContainer.vue
  28. 3 3
      src/components/Container/src/collapse/CollapseContainer.vue
  29. 2 2
      src/components/Container/src/collapse/CollapseHeader.vue
  30. 1 1
      src/components/ContextMenu/src/createContextMenu.ts
  31. 1 1
      src/components/CountDown/index.ts
  32. 35 42
      src/components/CountDown/src/CountButton.vue
  33. 11 19
      src/components/CountDown/src/CountdownInput.vue
  34. 1 1
      src/components/CountTo/index.ts
  35. 59 62
      src/components/CountTo/src/CountTo.vue
  36. 1 1
      src/components/Cropper/index.ts
  37. 114 116
      src/components/Cropper/src/Cropper.vue
  38. 49 75
      src/components/Cropper/src/CropperAvatar.vue
  39. 274 289
      src/components/Cropper/src/CropperModal.vue
  40. 1 1
      src/components/Description/index.ts
  41. 7 7
      src/components/Description/src/Description.vue
  42. 2 2
      src/components/Description/src/typing.ts
  43. 1 1
      src/components/Description/src/useDescription.ts
  44. 1 1
      src/components/Drawer/index.ts
  45. 113 137
      src/components/Drawer/src/BasicDrawer.vue
  46. 27 30
      src/components/Drawer/src/components/DrawerFooter.vue
  47. 15 22
      src/components/Drawer/src/components/DrawerHeader.vue
  48. 1 1
      src/components/Drawer/src/props.ts
  49. 1 1
      src/components/Drawer/src/typing.ts
  50. 3 3
      src/components/Drawer/src/useDrawer.ts
  51. 1 1
      src/components/Dropdown/index.ts
  52. 1 1
      src/components/Excel/index.ts
  53. 17 29
      src/components/Excel/src/ExportExcelModal.vue
  54. 185 189
      src/components/Excel/src/ImportExcel.vue
  55. 1 1
      src/components/FlowChart/index.ts
  56. 120 131
      src/components/FlowChart/src/FlowChart.vue
  57. 100 103
      src/components/FlowChart/src/FlowChartToolbar.vue
  58. 219 240
      src/components/Form/src/BasicForm.vue
  59. 5 5
      src/components/Form/src/componentMap.ts
  60. 140 154
      src/components/Form/src/components/ApiCascader.vue
  61. 92 102
      src/components/Form/src/components/ApiRadioGroup.vue
  62. 102 111
      src/components/Form/src/components/ApiSelect.vue
  63. 97 108
      src/components/Form/src/components/ApiTransfer.vue
  64. 76 78
      src/components/Form/src/components/ApiTree.vue
  65. 82 84
      src/components/Form/src/components/ApiTreeSelect.vue
  66. 66 83
      src/components/Form/src/components/FormAction.vue
  67. 5 5
      src/components/Form/src/components/FormItem.vue
  68. 33 40
      src/components/Form/src/components/RadioButtonGroup.vue
  69. 4 4
      src/components/Form/src/helper.ts
  70. 2 2
      src/components/Form/src/hooks/useAdvanced.ts
  71. 1 1
      src/components/Form/src/hooks/useComponentRegister.ts
  72. 3 3
      src/components/Form/src/hooks/useForm.ts
  73. 1 1
      src/components/Form/src/hooks/useFormContext.ts
  74. 4 4
      src/components/Form/src/hooks/useFormEvents.ts
  75. 2 2
      src/components/Form/src/hooks/useFormValues.ts
  76. 1 1
      src/components/Form/src/hooks/useLabelWidth.ts
  77. 2 2
      src/components/Form/src/props.ts
  78. 3 3
      src/components/Form/src/types/form.ts
  79. 56 69
      src/components/Icon/Icon.vue
  80. 13 20
      src/components/Icon/src/IconPicker.vue
  81. 33 36
      src/components/Icon/src/SvgIcon.vue
  82. 29 31
      src/components/Loading/src/Loading.vue
  83. 1 1
      src/components/Loading/src/typing.ts
  84. 1 1
      src/components/Markdown/index.ts
  85. 124 127
      src/components/Markdown/src/Markdown.vue
  86. 1 1
      src/components/Markdown/src/MarkdownViewer.vue
  87. 121 136
      src/components/Menu/src/BasicMenu.vue
  88. 6 13
      src/components/Menu/src/components/BasicMenuItem.vue
  89. 17 33
      src/components/Menu/src/components/BasicSubMenuItem.vue
  90. 12 24
      src/components/Menu/src/components/MenuItemContent.vue
  91. 4 4
      src/components/Menu/src/props.ts
  92. 3 3
      src/components/Menu/src/useOpenKeys.ts
  93. 1 1
      src/components/Modal/index.ts
  94. 151 164
      src/components/Modal/src/BasicModal.vue
  95. 1 1
      src/components/Modal/src/components/Modal.tsx
  96. 30 40
      src/components/Modal/src/components/ModalClose.vue
  97. 12 17
      src/components/Modal/src/components/ModalFooter.vue
  98. 8 11
      src/components/Modal/src/components/ModalHeader.vue
  99. 126 142
      src/components/Modal/src/components/ModalWrapper.vue
  100. 3 3
      src/components/Modal/src/hooks/useModal.ts

+ 23 - 25
.vscode/settings.json

@@ -104,38 +104,36 @@
   "i18n-ally.displayLanguage": "zh-CN",
   "i18n-ally.enabledFrameworks": ["vue", "react"],
   "cSpell.words": [
-    "vben",
+    "antd",
+    "antv",
+    "brotli",
     "browserslist",
-    "tailwindcss",
+    "codemirror",
+    "commitlint",
+    "cropperjs",
+    "echarts",
     "esnext",
-    "antv",
-    "tinymce",
-    "qrcode",
-    "sider",
+    "esno",
+    "iconify",
+    "INTLIFY",
+    "lintstagedrc",
+    "logicflow",
+    "mockjs",
+    "nprogress",
     "pinia",
+    "pnpm",
+    "qrcode",
     "sider",
-    "nprogress",
-    "INTLIFY",
-    "stylelint",
-    "esno",
-    "vitejs",
     "sortablejs",
-    "mockjs",
-    "codemirror",
-    "iconify",
-    "commitlint",
+    "stylelint",
+    "tailwindcss",
+    "tinymce",
+    "unref",
+    "vben",
     "vditor",
-    "echarts",
-    "cropperjs",
-    "logicflow",
+    "vitejs",
     "vueuse",
-    "zxcvbn",
-    "lintstagedrc",
-    "brotli",
-    "tailwindcss",
-    "sider",
-    "pnpm",
-    "antd"
+    "zxcvbn"
   ],
   "vetur.format.scriptInitialIndent": true,
   "vetur.format.styleInitialIndent": true,

+ 1 - 1
src/components/Application/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 
 import appLogo from './src/AppLogo.vue';
 import appProvider from './src/AppProvider.vue';

+ 9 - 7
src/components/Application/src/AppDarkModeToggle.vue

@@ -7,12 +7,12 @@
 </template>
 <script lang="ts" setup>
   import { computed, unref } from 'vue';
-  import { SvgIcon } from '/@/components/Icon';
-  import { ThemeEnum } from '/@/enums/appEnum';
-  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { updateDarkTheme } from '/@/logics/theme/dark';
-  import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
+  import { SvgIcon } from '@/components/Icon';
+  import { ThemeEnum } from '@/enums/appEnum';
+  import { useRootSetting } from '@/hooks/setting/useRootSetting';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { updateDarkTheme } from '@/logics/theme/dark';
+  import { updateHeaderBgColor, updateSidebarBgColor } from '@/logics/theme/updateBackground';
 
   const { prefixCls } = useDesign('dark-switch');
   const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting();
@@ -61,7 +61,9 @@
       z-index: 1;
       width: 18px;
       height: 18px;
-      transition: transform 0.5s, background-color 0.5s;
+      transition:
+        transform 0.5s,
+        background-color 0.5s;
       border-radius: 50%;
       background-color: #fff;
       will-change: transform;

+ 4 - 4
src/components/Application/src/AppLocalePicker.vue

@@ -19,12 +19,12 @@
 </template>
 <script lang="ts" setup>
   import type { LocaleType } from '/#/config';
-  import type { DropMenu } from '/@/components/Dropdown';
+  import type { DropMenu } from '@/components/Dropdown';
   import { ref, watchEffect, unref, computed } from 'vue';
-  import { Dropdown } from '/@/components/Dropdown';
+  import { Dropdown } from '@/components/Dropdown';
   import Icon from '@/components/Icon/Icon.vue';
-  import { useLocale } from '/@/locales/useLocale';
-  import { localeList } from '/@/settings/localeSetting';
+  import { useLocale } from '@/locales/useLocale';
+  import { localeList } from '@/settings/localeSetting';
 
   const props = defineProps({
     /**

+ 6 - 6
src/components/Application/src/AppLogo.vue

@@ -12,12 +12,12 @@
 </template>
 <script lang="ts" setup>
   import { computed, unref } from 'vue';
-  import { useGlobSetting } from '/@/hooks/setting';
-  import { useGo } from '/@/hooks/web/usePage';
-  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { PageEnum } from '/@/enums/pageEnum';
-  import { useUserStore } from '/@/store/modules/user';
+  import { useGlobSetting } from '@/hooks/setting';
+  import { useGo } from '@/hooks/web/usePage';
+  import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { PageEnum } from '@/enums/pageEnum';
+  import { useUserStore } from '@/store/modules/user';
 
   const props = defineProps({
     /**

+ 4 - 4
src/components/Application/src/AppProvider.vue

@@ -1,10 +1,10 @@
 <script lang="ts">
   import { defineComponent, toRefs, ref, unref } from 'vue';
   import { createAppProviderContext } from './useAppContext';
-  import { createBreakpointListen } from '/@/hooks/event/useBreakpoint';
-  import { prefixCls } from '/@/settings/designSetting';
-  import { useAppStore } from '/@/store/modules/app';
-  import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
+  import { createBreakpointListen } from '@/hooks/event/useBreakpoint';
+  import { prefixCls } from '@/settings/designSetting';
+  import { useAppStore } from '@/store/modules/app';
+  import { MenuModeEnum, MenuTypeEnum } from '@/enums/menuEnum';
 
   const props = {
     /**

+ 1 - 1
src/components/Application/src/search/AppSearch.vue

@@ -3,7 +3,7 @@
   import { Tooltip } from 'ant-design-vue';
   import { SearchOutlined } from '@ant-design/icons-vue';
   import AppSearchModal from './AppSearchModal.vue';
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useI18n } from '@/hooks/web/useI18n';
 
   export default defineComponent({
     name: 'AppSearch',

+ 5 - 3
src/components/Application/src/search/AppSearchFooter.vue

@@ -12,8 +12,8 @@
 
 <script lang="ts" setup>
   import AppSearchKeyItem from './AppSearchKeyItem.vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { useI18n } from '@/hooks/web/useI18n';
 
   const { prefixCls } = useDesign('app-search-footer');
   const { t } = useI18n();
@@ -44,7 +44,9 @@
       padding-bottom: 2px;
       border-radius: 2px;
       background-color: linear-gradient(-225deg, #d5dbe4, #f8f8f8);
-      box-shadow: inset 0 -2px 0 0 #cdcde6, inset 0 0 1px 1px #fff,
+      box-shadow:
+        inset 0 -2px 0 0 #cdcde6,
+        inset 0 0 1px 1px #fff,
         0 1px 2px 1px rgb(30 35 90 / 40%);
 
       &:nth-child(2),

+ 4 - 4
src/components/Application/src/search/AppSearchModal.vue

@@ -63,12 +63,12 @@
   import AppSearchFooter from './AppSearchFooter.vue';
   import Icon from '@/components/Icon/Icon.vue';
   // @ts-ignore
-  import vClickOutside from '/@/directives/clickOutside';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import vClickOutside from '@/directives/clickOutside';
+  import { useDesign } from '@/hooks/web/useDesign';
   import { useRefs } from '@vben/hooks';
   import { useMenuSearch } from './useMenuSearch';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { useAppInject } from '/@/hooks/web/useAppInject';
+  import { useI18n } from '@/hooks/web/useI18n';
+  import { useAppInject } from '@/hooks/web/useAppInject';
 
   const props = defineProps({
     visible: { type: Boolean },

+ 5 - 5
src/components/Application/src/search/useMenuSearch.ts

@@ -1,13 +1,13 @@
-import { type Menu } from '/@/router/types';
+import { type Menu } from '@/router/types';
 import { type AnyFunction } from '@vben/types';
 import { ref, onBeforeMount, unref, Ref, nextTick } from 'vue';
-import { getMenus } from '/@/router/menus';
+import { getMenus } from '@/router/menus';
 import { cloneDeep } from 'lodash-es';
-import { filter, forEach } from '/@/utils/helper/treeHelper';
-import { useGo } from '/@/hooks/web/usePage';
+import { filter, forEach } from '@/utils/helper/treeHelper';
+import { useGo } from '@/hooks/web/usePage';
 import { useScrollTo } from '@vben/hooks';
 import { onKeyStroke, useDebounceFn } from '@vueuse/core';
-import { useI18n } from '/@/hooks/web/useI18n';
+import { useI18n } from '@/hooks/web/useI18n';
 
 export interface SearchResult {
   name: string;

+ 1 - 1
src/components/Application/src/useAppContext.ts

@@ -1,5 +1,5 @@
 import { InjectionKey, Ref } from 'vue';
-import { createContext, useContext } from '/@/hooks/core/useContext';
+import { createContext, useContext } from '@/hooks/core/useContext';
 
 export interface AppProviderContextProps {
   prefixCls: Ref<string>;

+ 1 - 1
src/components/Authority/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import authority from './src/Authority.vue';
 
 export const Authority = withInstall(authority);

+ 3 - 3
src/components/Authority/src/Authority.vue

@@ -4,9 +4,9 @@
 <script lang="ts">
   import type { PropType } from 'vue';
   import { defineComponent } from 'vue';
-  import { RoleEnum } from '/@/enums/roleEnum';
-  import { usePermission } from '/@/hooks/web/usePermission';
-  import { getSlot } from '/@/utils/helper/tsxHelper';
+  import { RoleEnum } from '@/enums/roleEnum';
+  import { usePermission } from '@/hooks/web/usePermission';
+  import { getSlot } from '@/utils/helper/tsxHelper';
 
   export default defineComponent({
     name: 'Authority',

+ 1 - 1
src/components/Basic/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import basicArrow from './src/BasicArrow.vue';
 import basicTitle from './src/BasicTitle.vue';
 import basicHelp from './src/BasicHelp.vue';

+ 1 - 1
src/components/Basic/src/BasicArrow.vue

@@ -10,7 +10,7 @@
 <script lang="ts" setup>
   import { computed } from 'vue';
   import Icon from '@/components/Icon/Icon.vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useDesign } from '@/hooks/web/useDesign';
 
   const props = defineProps({
     /**

+ 4 - 4
src/components/Basic/src/BasicHelp.vue

@@ -3,10 +3,10 @@
   import { defineComponent, computed, unref } from 'vue';
   import { Tooltip } from 'ant-design-vue';
   import { InfoCircleOutlined } from '@ant-design/icons-vue';
-  import { getPopupContainer } from '/@/utils';
-  import { isString, isArray } from '/@/utils/is';
-  import { getSlot } from '/@/utils/helper/tsxHelper';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { getPopupContainer } from '@/utils';
+  import { isString, isArray } from '@/utils/is';
+  import { getSlot } from '@/utils/helper/tsxHelper';
+  import { useDesign } from '@/hooks/web/useDesign';
 
   const props = {
     /**

+ 1 - 1
src/components/Basic/src/BasicTitle.vue

@@ -8,7 +8,7 @@
   import type { PropType } from 'vue';
   import { useSlots, computed } from 'vue';
   import BasicHelp from './BasicHelp.vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useDesign } from '@/hooks/web/useDesign';
 
   const props = defineProps({
     /**

+ 1 - 1
src/components/Button/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import type { ExtractPropTypes } from 'vue';
 import button from './src/BasicButton.vue';
 import popConfirmButton from './src/PopConfirmButton.vue';

+ 2 - 2
src/components/Button/src/PopConfirmButton.vue

@@ -2,10 +2,10 @@
   import { computed, defineComponent, h, unref } from 'vue';
   import BasicButton from './BasicButton.vue';
   import { Popconfirm } from 'ant-design-vue';
-  import { extendSlots } from '/@/utils/helper/tsxHelper';
+  import { extendSlots } from '@/utils/helper/tsxHelper';
   import { omit } from 'lodash-es';
   import { useAttrs } from '@vben/hooks';
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useI18n } from '@/hooks/web/useI18n';
 
   const props = {
     /**

+ 1 - 1
src/components/CardList/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import cardList from './src/CardList.vue';
 
 export const CardList = withInstall(cardList);

+ 12 - 12
src/components/CardList/src/CardList.vue

@@ -10,22 +10,23 @@
         :pagination="paginationProp"
       >
         <template #header>
-          <div class="flex justify-end space-x-2"
-            ><slot name="header"></slot>
+          <div class="flex justify-end space-x-2">
+            <slot name="header"> </slot>
             <Tooltip>
               <template #title>
-                <div class="w-50">每行显示数量</div
-                ><Slider
+                <div class="w-50">每行显示数量</div>
+                <Slider
                   id="slider"
                   v-bind="sliderProp"
                   v-model:value="grid"
                   @change="sliderChange"
-              /></template>
-              <Button><TableOutlined /></Button>
+                />
+              </template>
+              <a-button><TableOutlined /></a-button>
             </Tooltip>
             <Tooltip @click="fetch">
               <template #title>刷新</template>
-              <Button><RedoOutlined /></Button>
+              <a-button><RedoOutlined /></a-button>
             </Tooltip>
           </div>
         </template>
@@ -83,11 +84,10 @@
     TableOutlined,
   } from '@ant-design/icons-vue';
   import { List, Card, Image, Typography, Tooltip, Slider, Avatar } from 'ant-design-vue';
-  import { Dropdown } from '/@/components/Dropdown';
-  import { BasicForm, useForm } from '/@/components/Form';
-  import { propTypes } from '/@/utils/propTypes';
-  import { Button } from '/@/components/Button';
-  import { isFunction } from '/@/utils/is';
+  import { Dropdown } from '@/components/Dropdown';
+  import { BasicForm, useForm } from '@/components/Form';
+  import { propTypes } from '@/utils/propTypes';
+  import { isFunction } from '@/utils/is';
   import { useSlider, grid } from './data';
 
   const ListItem = List.Item;

+ 1 - 1
src/components/ClickOutSide/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import clickOutSide from './src/ClickOutSide.vue';
 
 export const ClickOutSide = withInstall(clickOutSide);

+ 1 - 1
src/components/CodeEditor/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import codeEditor from './src/CodeEditor.vue';
 import jsonPreview from './src/json-preview/JsonPreview.vue';
 

+ 1 - 1
src/components/CodeEditor/src/CodeEditor.vue

@@ -12,7 +12,7 @@
 <script lang="ts" setup>
   import { computed } from 'vue';
   import CodeMirrorEditor from './codemirror/CodeMirror.vue';
-  import { isString } from '/@/utils/is';
+  import { isString } from '@/utils/is';
   import { MODE } from './typing';
 
   const props = defineProps({

+ 1 - 1
src/components/CodeEditor/src/codemirror/CodeMirror.vue

@@ -20,7 +20,7 @@
   import type { Nullable } from '@vben/types';
   import { useWindowSizeFn } from '@vben/hooks';
   import { useDebounceFn } from '@vueuse/core';
-  import { useAppStore } from '/@/store/modules/app';
+  import { useAppStore } from '@/store/modules/app';
   import CodeMirror from 'codemirror';
   import { MODE } from './../typing';
   // css

+ 1 - 1
src/components/Container/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import collapseContainer from './src/collapse/CollapseContainer.vue';
 import scrollContainer from './src/ScrollContainer.vue';
 

+ 53 - 64
src/components/Container/src/ScrollContainer.vue

@@ -9,80 +9,69 @@
   </Scrollbar>
 </template>
 
-<script lang="ts">
-  import { defineComponent, ref, unref, nextTick } from 'vue';
-  import { Scrollbar, ScrollbarType } from '/@/components/Scrollbar';
+<script lang="ts" setup>
+  import { ref, unref, nextTick } from 'vue';
+  import { Scrollbar, ScrollbarType } from '@/components/Scrollbar';
   import { useScrollTo } from '@vben/hooks';
   import { type Nullable } from '@vben/types';
 
-  export default defineComponent({
-    name: 'ScrollContainer',
-    components: { Scrollbar },
-    props: {
-      scrollHeight: { type: Number },
+  defineOptions({ name: 'ScrollContainer' });
+
+  defineProps({
+    scrollHeight: {
+      type: Number,
     },
-    setup() {
-      const scrollbarRef = ref<Nullable<ScrollbarType>>(null);
+  });
 
-      /**
-       * Scroll to the specified position
-       */
-      function scrollTo(to: number, duration = 500) {
-        const scrollbar = unref(scrollbarRef);
-        if (!scrollbar) {
-          return;
-        }
-        nextTick(() => {
-          const wrap = unref(scrollbar.wrap);
-          if (!wrap) {
-            return;
-          }
-          const { start } = useScrollTo({
-            el: wrap,
-            to,
-            duration,
-          });
-          start();
-        });
-      }
+  const scrollbarRef = ref<Nullable<ScrollbarType>>(null);
 
-      function getScrollWrap() {
-        const scrollbar = unref(scrollbarRef);
-        if (!scrollbar) {
-          return null;
-        }
-        return scrollbar.wrap;
+  function getScrollWrap() {
+    const scrollbar = unref(scrollbarRef);
+    if (!scrollbar) {
+      return null;
+    }
+    return scrollbar.wrap;
+  }
+
+  /**
+   * Scroll to the specified position
+   */
+  function scrollTo(to: number, duration = 500) {
+    const wrap = unref(getScrollWrap());
+    nextTick(() => {
+      if (!wrap) {
+        return;
       }
+      const { start } = useScrollTo({
+        el: wrap,
+        to,
+        duration,
+      });
+      start();
+    });
+  }
 
-      /**
-       * Scroll to the bottom
-       */
-      function scrollBottom() {
-        const scrollbar = unref(scrollbarRef);
-        if (!scrollbar) {
-          return;
-        }
-        nextTick(() => {
-          const wrap = unref(scrollbar.wrap) as any;
-          if (!wrap) {
-            return;
-          }
-          const scrollHeight = wrap.scrollHeight as number;
-          const { start } = useScrollTo({
-            el: wrap,
-            to: scrollHeight,
-          });
-          start();
-        });
+  /**
+   * Scroll to the bottom
+   */
+  function scrollBottom() {
+    const wrap = unref(getScrollWrap());
+    nextTick(() => {
+      if (!wrap) {
+        return;
       }
+      const scrollHeight = wrap.scrollHeight as number;
+      const { start } = useScrollTo({
+        el: wrap,
+        to: scrollHeight,
+      });
+      start();
+    });
+  }
 
-      return {
-        scrollbarRef,
-        scrollTo,
-        scrollBottom,
-        getScrollWrap,
-      };
-    },
+  defineExpose({
+    scrollTo,
+    scrollBottom,
   });
 </script>
 <style lang="less">

+ 3 - 3
src/components/Container/src/collapse/CollapseContainer.vue

@@ -3,10 +3,10 @@
   import { isNil } from 'lodash-es';
   import { Skeleton } from 'ant-design-vue';
   import { useTimeoutFn } from '@vben/hooks';
-  import { CollapseTransition } from '/@/components/Transition';
+  import { CollapseTransition } from '@/components/Transition';
   import CollapseHeader from './CollapseHeader.vue';
-  import { triggerWindowResize } from '/@/utils/event';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { triggerWindowResize } from '@/utils/event';
+  import { useDesign } from '@/hooks/web/useDesign';
 
   const collapseContainerProps = {
     title: { type: String, default: '' },

+ 2 - 2
src/components/Container/src/collapse/CollapseHeader.vue

@@ -1,7 +1,7 @@
 <script lang="tsx">
   import { defineComponent, computed, unref, type ExtractPropTypes, PropType } from 'vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { BasicArrow, BasicTitle } from '/@/components/Basic';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { BasicArrow, BasicTitle } from '@/components/Basic';
 
   const collapseHeaderProps = {
     prefixCls: String,

+ 1 - 1
src/components/ContextMenu/src/createContextMenu.ts

@@ -1,5 +1,5 @@
 import contextMenuVue from './ContextMenu.vue';
-import { isClient } from '/@/utils/is';
+import { isClient } from '@/utils/is';
 import { CreateContextOptions, ContextMenuProps } from './typing';
 import { createVNode, render } from 'vue';
 

+ 1 - 1
src/components/CountDown/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import countButton from './src/CountButton.vue';
 import countdownInput from './src/CountdownInput.vue';
 

+ 35 - 42
src/components/CountDown/src/CountButton.vue

@@ -3,60 +3,53 @@
     {{ getButtonText }}
   </Button>
 </template>
-<script lang="ts">
-  import { defineComponent, ref, watchEffect, computed, unref } from 'vue';
+<script lang="ts" setup>
+  import { ref, watchEffect, computed, unref } from 'vue';
   import { Button } from 'ant-design-vue';
   import { useCountdown } from './useCountdown';
-  import { isFunction } from '/@/utils/is';
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { isFunction } from '@/utils/is';
+  import { useI18n } from '@/hooks/web/useI18n';
 
-  const props = {
+  defineOptions({ name: 'CountButton' });
+
+  const props = defineProps({
     value: { type: [Object, Number, String, Array] },
     count: { type: Number, default: 60 },
     beforeStartFunc: {
       type: Function as PropType<() => Promise<boolean>>,
       default: null,
     },
-  };
-
-  export default defineComponent({
-    name: 'CountButton',
-    components: { Button },
-    props,
-    setup(props) {
-      const loading = ref(false);
+  });
 
-      const { currentCount, isStart, start, reset } = useCountdown(props.count);
-      const { t } = useI18n();
+  const { t } = useI18n();
+  const loading = ref(false);
+  const { currentCount, isStart, start, reset } = useCountdown(props.count);
 
-      const getButtonText = computed(() => {
-        return !unref(isStart)
-          ? t('component.countdown.normalText')
-          : t('component.countdown.sendText', [unref(currentCount)]);
-      });
+  const getButtonText = computed(() => {
+    return !unref(isStart)
+      ? t('component.countdown.normalText')
+      : t('component.countdown.sendText', [unref(currentCount)]);
+  });
 
-      watchEffect(() => {
-        props.value === undefined && reset();
-      });
+  watchEffect(() => {
+    props.value === undefined && reset();
+  });
 
-      /**
-       * @description: Judge whether there is an external function before execution, and decide whether to start after execution
-       */
-      async function handleStart() {
-        const { beforeStartFunc } = props;
-        if (beforeStartFunc && isFunction(beforeStartFunc)) {
-          loading.value = true;
-          try {
-            const canStart = await beforeStartFunc();
-            canStart && start();
-          } finally {
-            loading.value = false;
-          }
-        } else {
-          start();
-        }
+  /**
+   * @description: Judge whether there is an external function before execution, and decide whether to start after execution
+   */
+  async function handleStart() {
+    const { beforeStartFunc } = props;
+    if (beforeStartFunc && isFunction(beforeStartFunc)) {
+      loading.value = true;
+      try {
+        const canStart = await beforeStartFunc();
+        canStart && start();
+      } finally {
+        loading.value = false;
       }
-      return { handleStart, currentCount, loading, getButtonText, isStart };
-    },
-  });
+    } else {
+      start();
+    }
+  }
 </script>

+ 11 - 19
src/components/CountDown/src/CountdownInput.vue

@@ -8,34 +8,26 @@
     </template>
   </a-input>
 </template>
-<script lang="ts">
-  import { defineComponent, PropType } from 'vue';
+<script lang="ts" setup>
+  import { PropType } from 'vue';
   import CountButton from './CountButton.vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { useRuleFormItem } from '/@/hooks/component/useFormItem';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { useRuleFormItem } from '@/hooks/component/useFormItem';
 
-  const props = {
+  defineOptions({ name: 'CountDownInput', inheritAttrs: false });
+
+  const props = defineProps({
     value: { type: String },
-    size: { type: String, validator: (v) => ['default', 'large', 'small'].includes(v) },
+    size: { type: String, validator: (v: string) => ['default', 'large', 'small'].includes(v) },
     count: { type: Number, default: 60 },
     sendCodeApi: {
       type: Function as PropType<() => Promise<boolean>>,
       default: null,
     },
-  };
-
-  export default defineComponent({
-    name: 'CountDownInput',
-    components: { CountButton },
-    inheritAttrs: false,
-    props,
-    setup(props) {
-      const { prefixCls } = useDesign('countdown-input');
-      const [state] = useRuleFormItem(props);
-
-      return { prefixCls, state };
-    },
   });
+
+  const { prefixCls } = useDesign('countdown-input');
+  const [state] = useRuleFormItem(props);
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-countdown-input';

+ 1 - 1
src/components/CountTo/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import countTo from './src/CountTo.vue';
 
 export const CountTo = withInstall(countTo);

+ 59 - 62
src/components/CountTo/src/CountTo.vue

@@ -3,12 +3,14 @@
     {{ value }}
   </span>
 </template>
-<script lang="ts">
-  import { defineComponent, ref, computed, watchEffect, unref, onMounted, watch } from 'vue';
+<script lang="ts" setup>
+  import { ref, computed, watchEffect, unref, onMounted, watch } from 'vue';
   import { useTransition, TransitionPresets } from '@vueuse/core';
-  import { isNumber } from '/@/utils/is';
+  import { isNumber } from '@/utils/is';
 
-  const props = {
+  defineOptions({ name: 'CountTo' });
+
+  const props = defineProps({
     startVal: { type: Number, default: 0 },
     endVal: { type: Number, default: 2021 },
     duration: { type: Number, default: 1500 },
@@ -36,75 +38,70 @@
      * Digital animation
      */
     transition: { type: String, default: 'linear' },
-  };
+  });
 
-  export default defineComponent({
-    name: 'CountTo',
-    props,
-    emits: ['onStarted', 'onFinished'],
-    setup(props, { emit }) {
-      const source = ref(props.startVal);
-      const disabled = ref(false);
-      let outputValue = useTransition(source);
+  const emit = defineEmits(['onStarted', 'onFinished']);
 
-      const value = computed(() => formatNumber(unref(outputValue)));
+  const source = ref(props.startVal);
+  const disabled = ref(false);
+  let outputValue = useTransition(source);
 
-      watchEffect(() => {
-        source.value = props.startVal;
-      });
+  const value = computed(() => formatNumber(unref(outputValue)));
 
-      watch([() => props.startVal, () => props.endVal], () => {
-        if (props.autoplay) {
-          start();
-        }
-      });
+  watchEffect(() => {
+    source.value = props.startVal;
+  });
 
-      onMounted(() => {
-        props.autoplay && start();
-      });
+  watch([() => props.startVal, () => props.endVal], () => {
+    if (props.autoplay) {
+      start();
+    }
+  });
 
-      function start() {
-        run();
-        source.value = props.endVal;
-      }
+  onMounted(() => {
+    props.autoplay && start();
+  });
 
-      function reset() {
-        source.value = props.startVal;
-        run();
-      }
+  function start() {
+    run();
+    source.value = props.endVal;
+  }
 
-      function run() {
-        outputValue = useTransition(source, {
-          disabled,
-          duration: props.duration,
-          onFinished: () => emit('onFinished'),
-          onStarted: () => emit('onStarted'),
-          ...(props.useEasing ? { transition: TransitionPresets[props.transition] } : {}),
-        });
-      }
+  function reset() {
+    source.value = props.startVal;
+    run();
+  }
+
+  function run() {
+    outputValue = useTransition(source, {
+      disabled,
+      duration: props.duration,
+      onFinished: () => emit('onFinished'),
+      onStarted: () => emit('onStarted'),
+      ...(props.useEasing ? { transition: TransitionPresets[props.transition] } : {}),
+    });
+  }
 
-      function formatNumber(num: number | string) {
-        if (!num && num !== 0) {
-          return '';
-        }
-        const { decimals, decimal, separator, suffix, prefix } = props;
-        num = Number(num).toFixed(decimals);
-        num += '';
+  function formatNumber(num: number | string) {
+    if (!num && num !== 0) {
+      return '';
+    }
+    const { decimals, decimal, separator, suffix, prefix } = props;
+    num = Number(num).toFixed(decimals);
+    num += '';
 
-        const x = num.split('.');
-        let x1 = x[0];
-        const x2 = x.length > 1 ? decimal + x[1] : '';
+    const x = num.split('.');
+    let x1 = x[0];
+    const x2 = x.length > 1 ? decimal + x[1] : '';
 
-        const rgx = /(\d+)(\d{3})/;
-        if (separator && !isNumber(separator)) {
-          while (rgx.test(x1)) {
-            x1 = x1.replace(rgx, '$1' + separator + '$2');
-          }
-        }
-        return prefix + x1 + x2 + suffix;
+    const rgx = /(\d+)(\d{3})/;
+    if (separator && !isNumber(separator)) {
+      while (rgx.test(x1)) {
+        x1 = x1.replace(rgx, '$1' + separator + '$2');
       }
+    }
+    return prefix + x1 + x2 + suffix;
+  }
 
-      return { value, start, reset };
-    },
-  });
+  defineExpose({ reset });
 </script>

+ 1 - 1
src/components/Cropper/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import cropperImage from './src/Cropper.vue';
 import avatarCropper from './src/CropperAvatar.vue';
 

+ 114 - 116
src/components/Cropper/src/Cropper.vue

@@ -10,13 +10,14 @@
     />
   </div>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { CSSProperties } from 'vue';
-  import { defineComponent, onMounted, ref, unref, computed, onUnmounted } from 'vue';
+  import { onMounted, ref, unref, computed, onUnmounted } from 'vue';
   import Cropper from 'cropperjs';
   import 'cropperjs/dist/cropper.css';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useDesign } from '@/hooks/web/useDesign';
   import { useDebounceFn } from '@vueuse/shared';
+  import { useAttrs } from '@vben/hooks';
 
   type Options = Cropper.Options;
 
@@ -43,7 +44,9 @@
     rotatable: true,
   };
 
-  const props = {
+  defineOptions({ name: 'CropperImage' });
+
+  const props = defineProps({
     src: { type: String, required: true },
     alt: { type: String },
     circled: { type: Boolean, default: false },
@@ -55,124 +58,119 @@
     },
     imageStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
     options: { type: Object as PropType<Options>, default: () => ({}) },
-  };
+  });
 
-  export default defineComponent({
-    name: 'CropperImage',
-    props,
-    emits: ['cropend', 'ready', 'cropendError'],
-    setup(props, { attrs, emit }) {
-      const imgElRef = ref<ElRef<HTMLImageElement>>();
-      const cropper = ref<Nullable<Cropper>>();
-      const isReady = ref(false);
-
-      const { prefixCls } = useDesign('cropper-image');
-      const debounceRealTimeCroppered = useDebounceFn(realTimeCroppered, 80);
-
-      const getImageStyle = computed((): CSSProperties => {
-        return {
-          height: props.height,
-          maxWidth: '100%',
-          ...props.imageStyle,
-        };
-      });
-
-      const getClass = computed(() => {
-        return [
-          prefixCls,
-          attrs.class,
-          {
-            [`${prefixCls}--circled`]: props.circled,
-          },
-        ];
-      });
-
-      const getWrapperStyle = computed((): CSSProperties => {
-        return { height: `${props.height}`.replace(/px/, '') + 'px' };
-      });
-
-      onMounted(init);
-
-      onUnmounted(() => {
-        cropper.value?.destroy();
-      });
-
-      async function init() {
-        const imgEl = unref(imgElRef);
-        if (!imgEl) {
-          return;
-        }
-        cropper.value = new Cropper(imgEl, {
-          ...defaultOptions,
-          ready: () => {
-            isReady.value = true;
-            realTimeCroppered();
-            emit('ready', cropper.value);
-          },
-          crop() {
-            debounceRealTimeCroppered();
-          },
-          zoom() {
-            debounceRealTimeCroppered();
-          },
-          cropmove() {
-            debounceRealTimeCroppered();
-          },
-          ...props.options,
-        });
-      }
+  const emit = defineEmits(['cropend', 'ready', 'cropendError']);
 
-      // Real-time display preview
-      function realTimeCroppered() {
-        props.realTimePreview && croppered();
-      }
+  const attrs = useAttrs();
 
-      // event: return base64 and width and height information after cropping
-      function croppered() {
-        if (!cropper.value) {
-          return;
-        }
-        let imgInfo = cropper.value.getData();
-        const canvas = props.circled ? getRoundedCanvas() : cropper.value.getCroppedCanvas();
-        canvas.toBlob((blob) => {
-          if (!blob) {
-            return;
-          }
-          let fileReader: FileReader = new FileReader();
-          fileReader.readAsDataURL(blob);
-          fileReader.onloadend = (e) => {
-            emit('cropend', {
-              imgBase64: e.target?.result ?? '',
-              imgInfo,
-            });
-          };
-          fileReader.onerror = () => {
-            emit('cropendError');
-          };
-        }, 'image/png');
-      }
+  const imgElRef = ref<ElRef<HTMLImageElement>>();
+  const cropper = ref<Nullable<Cropper>>();
+  const isReady = ref(false);
 
-      // Get a circular picture canvas
-      function getRoundedCanvas() {
-        const sourceCanvas = cropper.value!.getCroppedCanvas();
-        const canvas = document.createElement('canvas');
-        const context = canvas.getContext('2d')!;
-        const width = sourceCanvas.width;
-        const height = sourceCanvas.height;
-        canvas.width = width;
-        canvas.height = height;
-        context.imageSmoothingEnabled = true;
-        context.drawImage(sourceCanvas, 0, 0, width, height);
-        context.globalCompositeOperation = 'destination-in';
-        context.beginPath();
-        context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true);
-        context.fill();
-        return canvas;
-      }
+  const { prefixCls } = useDesign('cropper-image');
+  const debounceRealTimeCroppered = useDebounceFn(realTimeCroppered, 80);
 
-      return { getClass, imgElRef, getWrapperStyle, getImageStyle, isReady, croppered };
-    },
+  const getImageStyle = computed((): CSSProperties => {
+    return {
+      height: props.height,
+      maxWidth: '100%',
+      ...props.imageStyle,
+    };
+  });
+
+  const getClass = computed(() => {
+    return [
+      prefixCls,
+      attrs.class,
+      {
+        [`${prefixCls}--circled`]: props.circled,
+      },
+    ];
+  });
+
+  const getWrapperStyle = computed((): CSSProperties => {
+    return { height: `${props.height}`.replace(/px/, '') + 'px' };
+  });
+
+  onMounted(init);
+
+  onUnmounted(() => {
+    cropper.value?.destroy();
   });
+
+  async function init() {
+    const imgEl = unref(imgElRef);
+    if (!imgEl) {
+      return;
+    }
+    cropper.value = new Cropper(imgEl, {
+      ...defaultOptions,
+      ready: () => {
+        isReady.value = true;
+        realTimeCroppered();
+        emit('ready', cropper.value);
+      },
+      crop() {
+        debounceRealTimeCroppered();
+      },
+      zoom() {
+        debounceRealTimeCroppered();
+      },
+      cropmove() {
+        debounceRealTimeCroppered();
+      },
+      ...props.options,
+    });
+  }
+
+  // Real-time display preview
+  function realTimeCroppered() {
+    props.realTimePreview && croppered();
+  }
+
+  // event: return base64 and width and height information after cropping
+  function croppered() {
+    if (!cropper.value) {
+      return;
+    }
+    let imgInfo = cropper.value.getData();
+    const canvas = props.circled ? getRoundedCanvas() : cropper.value.getCroppedCanvas();
+    canvas.toBlob((blob) => {
+      if (!blob) {
+        return;
+      }
+      let fileReader: FileReader = new FileReader();
+      fileReader.readAsDataURL(blob);
+      fileReader.onloadend = (e) => {
+        emit('cropend', {
+          imgBase64: e.target?.result ?? '',
+          imgInfo,
+        });
+      };
+      fileReader.onerror = () => {
+        emit('cropendError');
+      };
+    }, 'image/png');
+  }
+
+  // Get a circular picture canvas
+  function getRoundedCanvas() {
+    const sourceCanvas = cropper.value!.getCroppedCanvas();
+    const canvas = document.createElement('canvas');
+    const context = canvas.getContext('2d')!;
+    const width = sourceCanvas.width;
+    const height = sourceCanvas.height;
+    canvas.width = width;
+    canvas.height = height;
+    context.imageSmoothingEnabled = true;
+    context.drawImage(sourceCanvas, 0, 0, width, height);
+    context.globalCompositeOperation = 'destination-in';
+    context.beginPath();
+    context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true);
+    context.fill();
+    return canvas;
+  }
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-cropper-image';

+ 49 - 75
src/components/Cropper/src/CropperAvatar.vue

@@ -1,6 +1,6 @@
 <template>
   <div :class="getClass" :style="getStyle">
-    <div :class="`${prefixCls}-image-wrapper`" :style="getImageWrapperStyle" @click="openModal">
+    <div :class="`${prefixCls}-image-wrapper`" :style="getImageWrapperStyle" @click="openModal()">
       <div :class="`${prefixCls}-image-mask`" :style="getImageWrapperStyle">
         <Icon
           icon="ant-design:cloud-upload-outlined"
@@ -29,26 +29,19 @@
     />
   </div>
 </template>
-<script lang="ts">
-  import {
-    defineComponent,
-    computed,
-    CSSProperties,
-    unref,
-    ref,
-    watchEffect,
-    watch,
-    PropType,
-  } from 'vue';
+<script lang="ts" setup>
+  import { computed, CSSProperties, unref, ref, watchEffect, watch, PropType } from 'vue';
   import CropperModal from './CropperModal.vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { useModal } from '/@/components/Modal';
-  import { useMessage } from '/@/hooks/web/useMessage';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import type { ButtonProps } from '/@/components/Button';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { useModal } from '@/components/Modal';
+  import { useMessage } from '@/hooks/web/useMessage';
+  import { useI18n } from '@/hooks/web/useI18n';
+  import type { ButtonProps } from '@/components/Button';
   import Icon from '@/components/Icon/Icon.vue';
 
-  const props = {
+  defineOptions({ name: 'CropperAvatar' });
+
+  const props = defineProps({
     width: { type: [String, Number], default: '200px' },
     value: { type: String },
     showBtn: { type: Boolean, default: true },
@@ -59,65 +52,46 @@
     },
 
     size: { type: Number, default: 5 },
-  };
-
-  export default defineComponent({
-    name: 'CropperAvatar',
-    components: { CropperModal, Icon },
-    props,
-    emits: ['update:value', 'change'],
-    setup(props, { emit, expose }) {
-      const sourceValue = ref(props.value || '');
-      const { prefixCls } = useDesign('cropper-avatar');
-      const [register, { openModal, closeModal }] = useModal();
-      const { createMessage } = useMessage();
-      const { t } = useI18n();
-
-      const getClass = computed(() => [prefixCls]);
-
-      const getWidth = computed(() => `${props.width}`.replace(/px/, '') + 'px');
-
-      const getIconWidth = computed(() => parseInt(`${props.width}`.replace(/px/, '')) / 2 + 'px');
-
-      const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
-
-      const getImageWrapperStyle = computed(
-        (): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }),
-      );
-
-      watchEffect(() => {
-        sourceValue.value = props.value || '';
-      });
-
-      watch(
-        () => sourceValue.value,
-        (v: string) => {
-          emit('update:value', v);
-        },
-      );
-
-      function handleUploadSuccess({ source, data }) {
-        sourceValue.value = source;
-        emit('change', { source, data });
-        createMessage.success(t('component.cropper.uploadSuccess'));
-      }
+  });
 
-      expose({ openModal: openModal.bind(null, true), closeModal });
-
-      return {
-        t,
-        prefixCls,
-        register,
-        openModal: openModal as any,
-        getIconWidth,
-        sourceValue,
-        getClass,
-        getImageWrapperStyle,
-        getStyle,
-        handleUploadSuccess,
-      };
-    },
+  const emit = defineEmits(['update:value', 'change']);
+
+  const sourceValue = ref(props.value || '');
+  const { prefixCls } = useDesign('cropper-avatar');
+  const [register, { openModal, closeModal }] = useModal();
+  const { createMessage } = useMessage();
+  const { t } = useI18n();
+
+  const getClass = computed(() => [prefixCls]);
+
+  const getWidth = computed(() => `${props.width}`.replace(/px/, '') + 'px');
+
+  const getIconWidth = computed(() => parseInt(`${props.width}`.replace(/px/, '')) / 2 + 'px');
+
+  const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
+
+  const getImageWrapperStyle = computed(
+    (): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }),
+  );
+
+  watchEffect(() => {
+    sourceValue.value = props.value || '';
   });
+
+  watch(
+    () => sourceValue.value,
+    (v: string) => {
+      emit('update:value', v);
+    },
+  );
+
+  function handleUploadSuccess({ source, data }) {
+    sourceValue.value = source;
+    emit('change', { source, data });
+    createMessage.success(t('component.cropper.uploadSuccess'));
+  }
+
+  defineExpose({ openModal: openModal.bind(null, true), closeModal });
 </script>
 
 <style lang="less" scoped>

+ 274 - 289
src/components/Cropper/src/CropperModal.vue

@@ -1,289 +1,274 @@
-<template>
-  <BasicModal
-    v-bind="$attrs"
-    @register="register"
-    :title="t('component.cropper.modalTitle')"
-    width="800px"
-    :canFullscreen="false"
-    @ok="handleOk"
-    :okText="t('component.cropper.okText')"
-  >
-    <div :class="prefixCls">
-      <div :class="`${prefixCls}-left`">
-        <div :class="`${prefixCls}-cropper`">
-          <CropperImage
-            v-if="src"
-            :src="src"
-            height="300px"
-            :circled="circled"
-            @cropend="handleCropend"
-            @ready="handleReady"
-          />
-        </div>
-
-        <div :class="`${prefixCls}-toolbar`">
-          <Upload :fileList="[]" accept="image/*" :beforeUpload="handleBeforeUpload">
-            <Tooltip :title="t('component.cropper.selectImage')" placement="bottom">
-              <a-button size="small" preIcon="ant-design:upload-outlined" type="primary" />
-            </Tooltip>
-          </Upload>
-          <Space>
-            <Tooltip :title="t('component.cropper.btn_reset')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:reload-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('reset')"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_rotate_left')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:rotate-left-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('rotate', -45)"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_rotate_right')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:rotate-right-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('rotate', 45)"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_scale_x')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="vaadin:arrows-long-h"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('scaleX')"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_scale_y')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="vaadin:arrows-long-v"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('scaleY')"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_zoom_in')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:zoom-in-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('zoom', 0.1)"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_zoom_out')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:zoom-out-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('zoom', -0.1)"
-              />
-            </Tooltip>
-          </Space>
-        </div>
-      </div>
-      <div :class="`${prefixCls}-right`">
-        <div :class="`${prefixCls}-preview`">
-          <img :src="previewSource" v-if="previewSource" :alt="t('component.cropper.preview')" />
-        </div>
-        <template v-if="previewSource">
-          <div :class="`${prefixCls}-group`">
-            <Avatar :src="previewSource" size="large" />
-            <Avatar :src="previewSource" :size="48" />
-            <Avatar :src="previewSource" :size="64" />
-            <Avatar :src="previewSource" :size="80" />
-          </div>
-        </template>
-      </div>
-    </div>
-  </BasicModal>
-</template>
-<script lang="ts">
-  import type { CropendResult, Cropper } from './typing';
-
-  import { defineComponent, ref, PropType } from 'vue';
-  import CropperImage from './Cropper.vue';
-  import { Space, Upload, Avatar, Tooltip } from 'ant-design-vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { BasicModal, useModalInner } from '/@/components/Modal';
-  import { dataURLtoBlob } from '/@/utils/file/base64Conver';
-  import { isFunction } from '/@/utils/is';
-  import { useI18n } from '/@/hooks/web/useI18n';
-
-  type apiFunParams = { file: Blob; name: string; filename: string };
-
-  const props = {
-    circled: { type: Boolean, default: true },
-    uploadApi: {
-      type: Function as PropType<(params: apiFunParams) => Promise<any>>,
-    },
-    src: { type: String },
-    size: { type: Number },
-  };
-
-  export default defineComponent({
-    name: 'CropperModal',
-    components: { BasicModal, Space, CropperImage, Upload, Avatar, Tooltip },
-    props,
-    emits: ['uploadSuccess', 'uploadError', 'register'],
-    setup(props, { emit }) {
-      let filename = '';
-      const src = ref(props.src || '');
-      const previewSource = ref('');
-      const cropper = ref<Cropper>();
-      let scaleX = 1;
-      let scaleY = 1;
-
-      const { prefixCls } = useDesign('cropper-am');
-      const [register, { closeModal, setModalProps }] = useModalInner();
-      const { t } = useI18n();
-
-      // Block upload
-      function handleBeforeUpload(file: File) {
-        if (props.size && file.size > 1024 * 1024 * props.size) {
-          emit('uploadError', { msg: t('component.cropper.imageTooBig') });
-          return;
-        }
-        const reader = new FileReader();
-        reader.readAsDataURL(file);
-        src.value = '';
-        previewSource.value = '';
-        reader.onload = function (e) {
-          src.value = (e.target?.result as string) ?? '';
-          filename = file.name;
-        };
-        return false;
-      }
-
-      function handleCropend({ imgBase64 }: CropendResult) {
-        previewSource.value = imgBase64;
-      }
-
-      function handleReady(cropperInstance: Cropper) {
-        cropper.value = cropperInstance;
-      }
-
-      function handlerToolbar(event: string, arg?: number) {
-        if (event === 'scaleX') {
-          scaleX = arg = scaleX === -1 ? 1 : -1;
-        }
-        if (event === 'scaleY') {
-          scaleY = arg = scaleY === -1 ? 1 : -1;
-        }
-        cropper?.value?.[event]?.(arg);
-      }
-
-      async function handleOk() {
-        const uploadApi = props.uploadApi;
-        if (uploadApi && isFunction(uploadApi)) {
-          const blob = dataURLtoBlob(previewSource.value);
-          try {
-            setModalProps({ confirmLoading: true });
-            const result = await uploadApi({ name: 'file', file: blob, filename });
-            emit('uploadSuccess', { source: previewSource.value, data: result.url });
-            closeModal();
-          } finally {
-            setModalProps({ confirmLoading: false });
-          }
-        }
-      }
-
-      return {
-        t,
-        prefixCls,
-        src,
-        register,
-        previewSource,
-        handleBeforeUpload,
-        handleCropend,
-        handleReady,
-        handlerToolbar,
-        handleOk,
-      };
-    },
-  });
-</script>
-
-<style lang="less">
-  @prefix-cls: ~'@{namespace}-cropper-am';
-
-  .@{prefix-cls} {
-    display: flex;
-
-    &-left,
-    &-right {
-      height: 340px;
-    }
-
-    &-left {
-      width: 55%;
-    }
-
-    &-right {
-      width: 45%;
-    }
-
-    &-cropper {
-      height: 300px;
-      background: #eee;
-      background-image: linear-gradient(
-          45deg,
-          rgb(0 0 0 / 25%) 25%,
-          transparent 0,
-          transparent 75%,
-          rgb(0 0 0 / 25%) 0
-        ),
-        linear-gradient(
-          45deg,
-          rgb(0 0 0 / 25%) 25%,
-          transparent 0,
-          transparent 75%,
-          rgb(0 0 0 / 25%) 0
-        );
-      background-position: 0 0, 12px 12px;
-      background-size: 24px 24px;
-    }
-
-    &-toolbar {
-      display: flex;
-      align-items: center;
-      justify-content: space-between;
-      margin-top: 10px;
-    }
-
-    &-preview {
-      width: 220px;
-      height: 220px;
-      margin: 0 auto;
-      overflow: hidden;
-      border: 1px solid @border-color-base;
-      border-radius: 50%;
-
-      img {
-        width: 100%;
-        height: 100%;
-      }
-    }
-
-    &-group {
-      display: flex;
-      align-items: center;
-      justify-content: space-around;
-      margin-top: 8px;
-      padding-top: 8px;
-      border-top: 1px solid @border-color-base;
-    }
-  }
-</style>
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    :title="t('component.cropper.modalTitle')"
+    width="800px"
+    :canFullscreen="false"
+    @ok="handleOk"
+    :okText="t('component.cropper.okText')"
+  >
+    <div :class="prefixCls">
+      <div :class="`${prefixCls}-left`">
+        <div :class="`${prefixCls}-cropper`">
+          <CropperImage
+            v-if="src"
+            :src="src"
+            height="300px"
+            :circled="circled"
+            @cropend="handleCropend"
+            @ready="handleReady"
+          />
+        </div>
+
+        <div :class="`${prefixCls}-toolbar`">
+          <Upload :fileList="[]" accept="image/*" :beforeUpload="handleBeforeUpload">
+            <Tooltip :title="t('component.cropper.selectImage')" placement="bottom">
+              <a-button size="small" preIcon="ant-design:upload-outlined" type="primary" />
+            </Tooltip>
+          </Upload>
+          <Space>
+            <Tooltip :title="t('component.cropper.btn_reset')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:reload-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('reset')"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_rotate_left')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:rotate-left-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('rotate', -45)"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_rotate_right')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:rotate-right-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('rotate', 45)"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_scale_x')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="vaadin:arrows-long-h"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('scaleX')"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_scale_y')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="vaadin:arrows-long-v"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('scaleY')"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_zoom_in')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:zoom-in-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('zoom', 0.1)"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_zoom_out')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:zoom-out-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('zoom', -0.1)"
+              />
+            </Tooltip>
+          </Space>
+        </div>
+      </div>
+      <div :class="`${prefixCls}-right`">
+        <div :class="`${prefixCls}-preview`">
+          <img :src="previewSource" v-if="previewSource" :alt="t('component.cropper.preview')" />
+        </div>
+        <template v-if="previewSource">
+          <div :class="`${prefixCls}-group`">
+            <Avatar :src="previewSource" size="large" />
+            <Avatar :src="previewSource" :size="48" />
+            <Avatar :src="previewSource" :size="64" />
+            <Avatar :src="previewSource" :size="80" />
+          </div>
+        </template>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts" setup>
+  import type { CropendResult, Cropper } from './typing';
+
+  import { ref, PropType } from 'vue';
+  import CropperImage from './Cropper.vue';
+  import { Space, Upload, Avatar, Tooltip } from 'ant-design-vue';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { BasicModal, useModalInner } from '@/components/Modal';
+  import { dataURLtoBlob } from '@/utils/file/base64Conver';
+  import { isFunction } from '@/utils/is';
+  import { useI18n } from '@/hooks/web/useI18n';
+
+  type apiFunParams = { file: Blob; name: string; filename: string };
+
+  defineOptions({ name: 'CropperModal' });
+
+  const props = defineProps({
+    circled: { type: Boolean, default: true },
+    uploadApi: {
+      type: Function as PropType<(params: apiFunParams) => Promise<any>>,
+    },
+    src: { type: String },
+    size: { type: Number },
+  });
+
+  const emit = defineEmits(['uploadSuccess', 'uploadError', 'register']);
+
+  let filename = '';
+  const src = ref(props.src || '');
+  const previewSource = ref('');
+  const cropper = ref<Cropper>();
+  let scaleX = 1;
+  let scaleY = 1;
+
+  const { prefixCls } = useDesign('cropper-am');
+  const [register, { closeModal, setModalProps }] = useModalInner();
+  const { t } = useI18n();
+
+  // Block upload
+  function handleBeforeUpload(file: File) {
+    if (props.size && file.size > 1024 * 1024 * props.size) {
+      emit('uploadError', { msg: t('component.cropper.imageTooBig') });
+      return;
+    }
+    const reader = new FileReader();
+    reader.readAsDataURL(file);
+    src.value = '';
+    previewSource.value = '';
+    reader.onload = function (e) {
+      src.value = (e.target?.result as string) ?? '';
+      filename = file.name;
+    };
+    return false;
+  }
+
+  function handleCropend({ imgBase64 }: CropendResult) {
+    previewSource.value = imgBase64;
+  }
+
+  function handleReady(cropperInstance: Cropper) {
+    cropper.value = cropperInstance;
+  }
+
+  function handlerToolbar(event: string, arg?: number) {
+    if (event === 'scaleX') {
+      scaleX = arg = scaleX === -1 ? 1 : -1;
+    }
+    if (event === 'scaleY') {
+      scaleY = arg = scaleY === -1 ? 1 : -1;
+    }
+    cropper?.value?.[event]?.(arg);
+  }
+
+  async function handleOk() {
+    const uploadApi = props.uploadApi;
+    if (uploadApi && isFunction(uploadApi)) {
+      const blob = dataURLtoBlob(previewSource.value);
+      try {
+        setModalProps({ confirmLoading: true });
+        const result = await uploadApi({ name: 'file', file: blob, filename });
+        emit('uploadSuccess', { source: previewSource.value, data: result.url });
+        closeModal();
+      } finally {
+        setModalProps({ confirmLoading: false });
+      }
+    }
+  }
+</script>
+
+<style lang="less">
+  @prefix-cls: ~'@{namespace}-cropper-am';
+
+  .@{prefix-cls} {
+    display: flex;
+
+    &-left,
+    &-right {
+      height: 340px;
+    }
+
+    &-left {
+      width: 55%;
+    }
+
+    &-right {
+      width: 45%;
+    }
+
+    &-cropper {
+      height: 300px;
+      background: #eee;
+      background-image: linear-gradient(
+          45deg,
+          rgb(0 0 0 / 25%) 25%,
+          transparent 0,
+          transparent 75%,
+          rgb(0 0 0 / 25%) 0
+        ),
+        linear-gradient(
+          45deg,
+          rgb(0 0 0 / 25%) 25%,
+          transparent 0,
+          transparent 75%,
+          rgb(0 0 0 / 25%) 0
+        );
+      background-position:
+        0 0,
+        12px 12px;
+      background-size: 24px 24px;
+    }
+
+    &-toolbar {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-top: 10px;
+    }
+
+    &-preview {
+      width: 220px;
+      height: 220px;
+      margin: 0 auto;
+      overflow: hidden;
+      border: 1px solid @border-color-base;
+      border-radius: 50%;
+
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    &-group {
+      display: flex;
+      align-items: center;
+      justify-content: space-around;
+      margin-top: 8px;
+      padding-top: 8px;
+      border-top: 1px solid @border-color-base;
+    }
+  }
+</style>

+ 1 - 1
src/components/Description/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import description from './src/Description.vue';
 
 export * from './src/typing';

+ 7 - 7
src/components/Description/src/Description.vue

@@ -1,7 +1,7 @@
 <script lang="tsx">
   import type { DescriptionProps, DescInstance, DescItem } from './typing';
-  import type { DescriptionsProps } from 'ant-design-vue/es/descriptions/index';
-  import type { CollapseContainerOptions } from '/@/components/Container/index';
+  import type { DescriptionsProps } from 'ant-design-vue/es/descriptions';
+  import type { CollapseContainerOptions } from '@/components/Container';
   import {
     type CSSProperties,
     type PropType,
@@ -13,10 +13,10 @@
   } from 'vue';
   import { get } from 'lodash-es';
   import { Descriptions } from 'ant-design-vue';
-  import { CollapseContainer } from '/@/components/Container/index';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { isFunction } from '/@/utils/is';
-  import { getSlot } from '/@/utils/helper/tsxHelper';
+  import { CollapseContainer } from '@/components/Container';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { isFunction } from '@/utils/is';
+  import { getSlot } from '@/utils/helper/tsxHelper';
   import { useAttrs } from '@vben/hooks';
 
   const props = {
@@ -24,7 +24,7 @@
     title: { type: String, default: '' },
     size: {
       type: String,
-      validator: (v) => ['small', 'default', 'middle', undefined].includes(v),
+      validator: (v: string) => ['small', 'default', 'middle', undefined].includes(v),
       default: 'small',
     },
     bordered: { type: Boolean, default: true },

+ 2 - 2
src/components/Description/src/typing.ts

@@ -1,6 +1,6 @@
 import type { VNode, CSSProperties } from 'vue';
-import type { CollapseContainerOptions } from '/@/components/Container/index';
-import type { DescriptionsProps } from 'ant-design-vue/es/descriptions/index';
+import type { CollapseContainerOptions } from '@/components/Container';
+import type { DescriptionsProps } from 'ant-design-vue/es/descriptions';
 
 export interface DescItem {
   labelMinWidth?: number;

+ 1 - 1
src/components/Description/src/useDescription.ts

@@ -1,6 +1,6 @@
 import type { DescriptionProps, DescInstance, UseDescReturnType } from './typing';
 import { ref, getCurrentInstance, unref } from 'vue';
-import { isProdMode } from '/@/utils/env';
+import { isProdMode } from '@/utils/env';
 
 export function useDescription(props?: Partial<DescriptionProps>): UseDescReturnType {
   if (!getCurrentInstance()) {

+ 1 - 1
src/components/Drawer/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import basicDrawer from './src/BasicDrawer.vue';
 
 export const BasicDrawer = withInstall(basicDrawer);

+ 113 - 137
src/components/Drawer/src/BasicDrawer.vue

@@ -2,7 +2,7 @@
   <Drawer v-bind="getBindValues" :class="prefixCls" @close="onClose">
     <template #title v-if="!$slots.title">
       <DrawerHeader
-        :title="getMergeProps.title"
+        :title="mergeProps.title"
         :isDetail="isDetail"
         :showDetailBack="showDetailBack"
         @close="onClose"
@@ -30,166 +30,142 @@
     </DrawerFooter>
   </Drawer>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { DrawerInstance, DrawerProps } from './typing';
   import type { CSSProperties } from 'vue';
-  import {
-    defineComponent,
-    ref,
-    computed,
-    watch,
-    unref,
-    nextTick,
-    toRaw,
-    getCurrentInstance,
-  } from 'vue';
+  import { ref, computed, watch, unref, nextTick, toRaw, getCurrentInstance } from 'vue';
   import { Drawer } from 'ant-design-vue';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { isFunction, isNumber } from '/@/utils/is';
-  import { deepMerge } from '/@/utils';
+  import { useI18n } from '@/hooks/web/useI18n';
+  import { isFunction, isNumber } from '@/utils/is';
+  import { deepMerge } from '@/utils';
   import DrawerFooter from './components/DrawerFooter.vue';
   import DrawerHeader from './components/DrawerHeader.vue';
-  import { ScrollContainer } from '/@/components/Container';
+  import { ScrollContainer } from '@/components/Container';
   import { basicProps } from './props';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useDesign } from '@/hooks/web/useDesign';
   import { useAttrs } from '@vben/hooks';
 
-  export default defineComponent({
-    components: { Drawer, ScrollContainer, DrawerFooter, DrawerHeader },
-    inheritAttrs: false,
-    props: basicProps,
-    emits: ['open-change', 'ok', 'close', 'register'],
-    setup(props, { emit }) {
-      const openRef = ref(false);
-      const attrs = useAttrs();
-      const propsRef = ref<Partial<DrawerProps | null>>(null);
+  defineOptions({ inheritAttrs: false });
 
-      const { t } = useI18n();
-      const { prefixVar, prefixCls } = useDesign('basic-drawer');
+  const props = defineProps(basicProps);
 
-      const drawerInstance: DrawerInstance = {
-        setDrawerProps: setDrawerProps as any,
-        emitOpen: undefined,
-      };
+  const emit = defineEmits(['open-change', 'ok', 'close', 'register']);
 
-      const instance = getCurrentInstance();
+  const openRef = ref(false);
+  const attrs = useAttrs();
+  const propsRef = ref<Partial<DrawerProps | null>>(null);
 
-      instance && emit('register', drawerInstance, instance.uid);
+  const { t } = useI18n();
+  const { prefixVar, prefixCls } = useDesign('basic-drawer');
 
-      const getMergeProps = computed((): DrawerProps => {
-        return deepMerge(toRaw(props), unref(propsRef)) as any;
-      });
-
-      const getProps = computed((): DrawerProps => {
-        const opt = {
-          placement: 'right',
-          ...unref(attrs),
-          ...unref(getMergeProps),
-          open: unref(openRef),
-        };
-        opt.title = undefined;
-        const { isDetail, width, wrapClassName, getContainer } = opt;
-        if (isDetail) {
-          if (!width) {
-            opt.width = '100%';
-          }
-          const detailCls = `${prefixCls}__detail`;
-          opt.rootClassName = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls;
-
-          if (!getContainer) {
-            opt.getContainer = `.${prefixVar}-layout-content`;
-          }
-        }
-        return opt as DrawerProps;
-      });
+  const drawerInstance: DrawerInstance = {
+    setDrawerProps: setDrawerProps as any,
+    emitOpen: undefined,
+  };
 
-      const getBindValues = computed((): DrawerProps => {
-        return {
-          ...attrs,
-          ...unref(getProps),
-        };
-      });
+  const instance = getCurrentInstance();
 
-      // Custom implementation of the bottom button,
-      const getFooterHeight = computed(() => {
-        const { footerHeight, showFooter } = unref(getProps);
-        if (showFooter && footerHeight) {
-          return isNumber(footerHeight)
-            ? `${footerHeight}px`
-            : `${footerHeight.replace('px', '')}px`;
-        }
-        return `0px`;
-      });
+  instance && emit('register', drawerInstance, instance.uid);
 
-      const getScrollContentStyle = computed((): CSSProperties => {
-        const footerHeight = unref(getFooterHeight);
-        return {
-          position: 'relative',
-          height: `calc(100% - ${footerHeight})`,
-        };
-      });
+  const getMergeProps = computed((): DrawerProps => {
+    return deepMerge(toRaw(props), unref(propsRef)) as any;
+  });
 
-      const getLoading = computed(() => {
-        return !!unref(getProps)?.loading;
-      });
+  const getProps = computed((): DrawerProps => {
+    const opt = {
+      placement: 'right',
+      ...unref(attrs),
+      ...unref(getMergeProps),
+      open: unref(openRef),
+    };
+    opt.title = undefined;
+    const { isDetail, width, wrapClassName, getContainer } = opt;
+    if (isDetail) {
+      if (!width) {
+        opt.width = '100%';
+      }
+      const detailCls = `${prefixCls}__detail`;
+      opt.rootClassName = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls;
 
-      watch(
-        () => props.open,
-        (newVal, oldVal) => {
-          if (newVal !== oldVal) openRef.value = newVal;
-        },
-        { deep: true },
-      );
-
-      watch(
-        () => openRef.value,
-        (open) => {
-          nextTick(() => {
-            emit('open-change', open);
-            instance && drawerInstance.emitOpen?.(open, instance.uid);
-          });
-        },
-      );
-
-      // Cancel event
-      async function onClose(e) {
-        const { closeFunc } = unref(getProps);
-        emit('close', e);
-        if (closeFunc && isFunction(closeFunc)) {
-          const res = await closeFunc();
-          openRef.value = !res;
-          return;
-        }
-        openRef.value = false;
+      if (!getContainer) {
+        opt.getContainer = `.${prefixVar}-layout-content`;
       }
+    }
+    return opt as DrawerProps;
+  });
 
-      function setDrawerProps(props: Partial<DrawerProps>): void {
-        // Keep the last setDrawerProps
-        propsRef.value = deepMerge(unref(propsRef) || ({} as any), props);
+  const getBindValues = computed((): DrawerProps => {
+    return {
+      ...attrs,
+      ...unref(getProps),
+    };
+  });
 
-        if (Reflect.has(props, 'open')) {
-          openRef.value = !!props.open;
-        }
-      }
+  // Custom implementation of the bottom button,
+  const getFooterHeight = computed(() => {
+    const { footerHeight, showFooter } = unref(getProps);
+    if (showFooter && footerHeight) {
+      return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`;
+    }
+    return `0px`;
+  });
 
-      function handleOk() {
-        emit('ok');
-      }
+  const getScrollContentStyle = computed((): CSSProperties => {
+    const footerHeight = unref(getFooterHeight);
+    return {
+      position: 'relative',
+      height: `calc(100% - ${footerHeight})`,
+    };
+  });
 
-      return {
-        onClose,
-        t,
-        prefixCls,
-        getMergeProps: getMergeProps as any,
-        getScrollContentStyle,
-        getProps: getProps as any,
-        getLoading,
-        getBindValues,
-        getFooterHeight,
-        handleOk,
-      };
-    },
+  const getLoading = computed(() => {
+    return !!unref(getProps)?.loading;
   });
+
+  watch(
+    () => props.open,
+    (newVal, oldVal) => {
+      if (newVal !== oldVal) openRef.value = newVal;
+    },
+    { deep: true },
+  );
+
+  watch(
+    () => openRef.value,
+    (open) => {
+      nextTick(() => {
+        emit('open-change', open);
+        instance && drawerInstance.emitOpen?.(open, instance.uid);
+      });
+    },
+  );
+
+  // Cancel event
+  async function onClose(e) {
+    const { closeFunc } = unref(getProps);
+    emit('close', e);
+    if (closeFunc && isFunction(closeFunc)) {
+      const res = await closeFunc();
+      openRef.value = !res;
+      return;
+    }
+    openRef.value = false;
+  }
+
+  function setDrawerProps(props: Partial<DrawerProps>): void {
+    // Keep the last setDrawerProps
+    propsRef.value = deepMerge(unref(propsRef) || ({} as any), props);
+
+    if (Reflect.has(props, 'open')) {
+      openRef.value = !!props.open;
+    }
+  }
+
+  function handleOk() {
+    emit('ok');
+  }
+
+  const mergeProps = getMergeProps as any;
 </script>
 <style lang="less">
   @header-height: 60px;

+ 27 - 30
src/components/Drawer/src/components/DrawerFooter.vue

@@ -24,44 +24,41 @@
     </template>
   </div>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { CSSProperties } from 'vue';
-  import { defineComponent, computed } from 'vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-
+  import { computed } from 'vue';
+  import { useDesign } from '@/hooks/web/useDesign';
   import { footerProps } from '../props';
 
-  export default defineComponent({
-    name: 'BasicDrawerFooter',
-    props: {
-      ...footerProps,
-      height: {
-        type: String,
-        default: '60px',
-      },
+  defineOptions({ name: 'BasicDrawerFooter' });
+
+  const props = defineProps({
+    ...footerProps,
+    height: {
+      type: String,
+      default: '60px',
     },
-    emits: ['ok', 'close'],
-    setup(props, { emit }) {
-      const { prefixCls } = useDesign('basic-drawer-footer');
+  });
 
-      const getStyle = computed((): CSSProperties => {
-        const heightStr = `${props.height}`;
-        return {
-          height: heightStr,
-          lineHeight: `calc(${heightStr} - 1px)`,
-        };
-      });
+  const emit = defineEmits(['ok', 'close']);
 
-      function handleOk() {
-        emit('ok');
-      }
+  const { prefixCls } = useDesign('basic-drawer-footer');
 
-      function handleClose() {
-        emit('close');
-      }
-      return { handleOk, prefixCls, handleClose, getStyle };
-    },
+  const getStyle = computed((): CSSProperties => {
+    const heightStr = `${props.height}`;
+    return {
+      height: heightStr,
+      lineHeight: `calc(${heightStr} - 1px)`,
+    };
   });
+
+  function handleOk() {
+    emit('ok');
+  }
+
+  function handleClose() {
+    emit('close');
+  }
 </script>
 
 <style lang="less">

+ 15 - 22
src/components/Drawer/src/components/DrawerHeader.vue

@@ -17,34 +17,27 @@
     </span>
   </div>
 </template>
-<script lang="ts">
-  import { defineComponent } from 'vue';
-  import { BasicTitle } from '/@/components/Basic';
+<script lang="ts" setup>
+  import { BasicTitle } from '@/components/Basic';
   import { ArrowLeftOutlined } from '@ant-design/icons-vue';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { propTypes } from '@/utils/propTypes';
 
-  import { useDesign } from '/@/hooks/web/useDesign';
+  defineOptions({ name: 'BasicDrawerHeader' });
 
-  import { propTypes } from '/@/utils/propTypes';
+  defineProps({
+    isDetail: propTypes.bool,
+    showDetailBack: propTypes.bool,
+    title: propTypes.string,
+  });
 
-  export default defineComponent({
-    name: 'BasicDrawerHeader',
-    components: { BasicTitle, ArrowLeftOutlined },
-    props: {
-      isDetail: propTypes.bool,
-      showDetailBack: propTypes.bool,
-      title: propTypes.string,
-    },
-    emits: ['close'],
-    setup(_, { emit }) {
-      const { prefixCls } = useDesign('basic-drawer-header');
+  const emit = defineEmits(['close']);
 
-      function handleClose() {
-        emit('close');
-      }
+  const { prefixCls } = useDesign('basic-drawer-header');
 
-      return { prefixCls, handleClose };
-    },
-  });
+  function handleClose() {
+    emit('close');
+  }
 </script>
 
 <style lang="less">

+ 1 - 1
src/components/Drawer/src/props.ts

@@ -1,6 +1,6 @@
 import type { PropType } from 'vue';
 
-import { useI18n } from '/@/hooks/web/useI18n';
+import { useI18n } from '@/hooks/web/useI18n';
 
 const { t } = useI18n();
 

+ 1 - 1
src/components/Drawer/src/typing.ts

@@ -1,6 +1,6 @@
 import type { ButtonProps } from 'ant-design-vue/lib/button/buttonTypes';
 import type { CSSProperties, VNodeChild, ComputedRef } from 'vue';
-import type { ScrollContainerOptions } from '/@/components/Container/index';
+import type { ScrollContainerOptions } from '@/components/Container';
 
 export interface DrawerInstance {
   setDrawerProps: (props: Partial<DrawerProps>) => void;

+ 3 - 3
src/components/Drawer/src/useDrawer.ts

@@ -15,11 +15,11 @@ import {
   toRaw,
   computed,
 } from 'vue';
-import { isProdMode } from '/@/utils/env';
-import { isFunction } from '/@/utils/is';
+import { isProdMode } from '@/utils/env';
+import { isFunction } from '@/utils/is';
 import { tryOnUnmounted } from '@vueuse/core';
 import { isEqual } from 'lodash-es';
-import { error } from '/@/utils/log';
+import { error } from '@/utils/log';
 
 const dataTransferRef = reactive<any>({});
 

+ 1 - 1
src/components/Dropdown/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import dropdown from './src/Dropdown.vue';
 
 export * from './src/typing';

+ 1 - 1
src/components/Excel/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import impExcel from './src/ImportExcel.vue';
 import expExcelModal from './src/ExportExcelModal.vue';
 

+ 17 - 29
src/components/Excel/src/ExportExcelModal.vue

@@ -13,13 +13,12 @@
     />
   </BasicModal>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { ExportModalResult } from './typing';
-  import { defineComponent } from 'vue';
-  import { BasicModal, useModalInner } from '/@/components/Modal';
-  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { BasicModal, useModalInner } from '@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '@/components/Form';
 
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useI18n } from '@/hooks/web/useI18n';
 
   const { t } = useI18n();
 
@@ -62,30 +61,19 @@
       },
     },
   ];
-  export default defineComponent({
-    components: { BasicModal, BasicForm },
-    emits: ['success', 'register'],
-    setup(_, { emit }) {
-      const [registerForm, { validate }] = useForm();
-      const [registerModal, { closeModal }] = useModalInner();
 
-      const handleOk = async () => {
-        const res = await validate<ExportModalResult>();
-        const { filename, bookType } = res;
-        emit('success', {
-          filename: `${filename.split('.').shift()}.${bookType}`,
-          bookType,
-        });
-        closeModal();
-      };
+  const emit = defineEmits(['success', 'register']);
 
-      return {
-        schemas,
-        handleOk,
-        registerForm,
-        registerModal,
-        t,
-      };
-    },
-  });
+  const [registerForm, { validate }] = useForm();
+  const [registerModal, { closeModal }] = useModalInner();
+
+  const handleOk = async () => {
+    const res = await validate<ExportModalResult>();
+    const { filename, bookType } = res;
+    emit('success', {
+      filename: `${filename.split('.').shift()}.${bookType}`,
+      bookType,
+    });
+    closeModal();
+  };
 </script>

+ 185 - 189
src/components/Excel/src/ImportExcel.vue

@@ -12,214 +12,210 @@
     </div>
   </div>
 </template>
-<script lang="ts">
-  import { defineComponent, ref, unref } from 'vue';
+<script lang="ts" setup>
+  import { ref, unref } from 'vue';
   import * as XLSX from 'xlsx';
-  import { dateUtil } from '/@/utils/dateUtil';
-
+  import { dateUtil } from '@/utils/dateUtil';
   import type { ExcelData } from './typing';
 
-  export default defineComponent({
-    name: 'ImportExcel',
-    props: {
-      // 日期时间格式。如果不提供或者提供空值,将返回原始Date对象
-      dateFormat: {
-        type: String,
-      },
-      // 时区调整。实验性功能,仅为了解决读取日期时间值有偏差的问题。目前仅提供了+08:00时区的偏差修正值
-      // https://github.com/SheetJS/sheetjs/issues/1470#issuecomment-501108554
-      timeZone: {
-        type: Number,
-        default: 8,
-      },
-      // 是否直接返回选中文件
-      isReturnFile: {
-        type: Boolean,
-        default: false,
-      },
+  defineOptions({ name: 'ImportExcel' });
+
+  const props = defineProps({
+    // 日期时间格式。如果不提供或者提供空值,将返回原始Date对象
+    dateFormat: {
+      type: String,
     },
-    emits: ['success', 'error', 'cancel'],
-    setup(props, { emit }) {
-      const inputRef = ref<HTMLInputElement | null>(null);
-      const loadingRef = ref<Boolean>(false);
-      const cancelRef = ref<Boolean>(true);
-
-      function shapeWorkSheel(sheet: XLSX.WorkSheet, range: XLSX.Range) {
-        let str = ' ',
-          char = 65,
-          customWorkSheet = {
-            t: 's',
-            v: str,
-            r: '<t> </t><phoneticPr fontId="1" type="noConversion"/>',
-            h: str,
-            w: str,
-          };
-        if (!sheet || !sheet['!ref']) return [];
-        let c = 0,
-          r = 1;
-        while (c < range.e.c + 1) {
-          while (r < range.e.r + 1) {
-            if (!sheet[String.fromCharCode(char) + r]) {
-              sheet[String.fromCharCode(char) + r] = customWorkSheet;
-            }
-            r++;
-          }
-          r = 1;
-          str += ' ';
-          customWorkSheet = {
-            t: 's',
-            v: str,
-            r: '<t> </t><phoneticPr fontId="1" type="noConversion"/>',
-            h: str,
-            w: str,
-          };
-          c++;
-          char++;
-        }
-      }
+    // 时区调整。实验性功能,仅为了解决读取日期时间值有偏差的问题。目前仅提供了+08:00时区的偏差修正值
+    // https://github.com/SheetJS/sheetjs/issues/1470#issuecomment-501108554
+    timeZone: {
+      type: Number,
+      default: 8,
+    },
+    // 是否直接返回选中文件
+    isReturnFile: {
+      type: Boolean,
+      default: false,
+    },
+  });
+
+  const emit = defineEmits(['success', 'error', 'cancel']);
 
-      /**
-       * @description: 第一行作为头部
-       */
-      function getHeaderRow(sheet: XLSX.WorkSheet) {
-        if (!sheet || !sheet['!ref']) return [];
-        const headers: string[] = [];
-        // A3:B7=>{s:{c:0, r:2}, e:{c:1, r:6}}
-        const range: XLSX.Range = XLSX.utils.decode_range(sheet['!ref']);
-        shapeWorkSheel(sheet, range);
-        const R = range.s.r;
-        /* start in the first row */
-        for (let C = range.s.c; C <= range.e.c; ++C) {
-          /* walk every column in the range */
-          const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })];
-          /* find the cell in the first row */
-          let hdr = 'UNKNOWN ' + C; // <-- replace with your desired default
-          if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
-          headers.push(hdr);
+  const inputRef = ref<HTMLInputElement | null>(null);
+  const loadingRef = ref<Boolean>(false);
+  const cancelRef = ref<Boolean>(true);
+
+  function shapeWorkSheel(sheet: XLSX.WorkSheet, range: XLSX.Range) {
+    let str = ' ',
+      char = 65,
+      customWorkSheet = {
+        t: 's',
+        v: str,
+        r: '<t> </t><phoneticPr fontId="1" type="noConversion"/>',
+        h: str,
+        w: str,
+      };
+    if (!sheet || !sheet['!ref']) return [];
+    let c = 0,
+      r = 1;
+    while (c < range.e.c + 1) {
+      while (r < range.e.r + 1) {
+        if (!sheet[String.fromCharCode(char) + r]) {
+          sheet[String.fromCharCode(char) + r] = customWorkSheet;
         }
-        return headers;
+        r++;
       }
+      r = 1;
+      str += ' ';
+      customWorkSheet = {
+        t: 's',
+        v: str,
+        r: '<t> </t><phoneticPr fontId="1" type="noConversion"/>',
+        h: str,
+        w: str,
+      };
+      c++;
+      char++;
+    }
+  }
+
+  /**
+   * @description: 第一行作为头部
+   */
+  function getHeaderRow(sheet: XLSX.WorkSheet) {
+    if (!sheet || !sheet['!ref']) return [];
+    const headers: string[] = [];
+    // A3:B7=>{s:{c:0, r:2}, e:{c:1, r:6}}
+    const range: XLSX.Range = XLSX.utils.decode_range(sheet['!ref']);
+    shapeWorkSheel(sheet, range);
+    const R = range.s.r;
+    /* start in the first row */
+    for (let C = range.s.c; C <= range.e.c; ++C) {
+      /* walk every column in the range */
+      const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })];
+      /* find the cell in the first row */
+      let hdr = 'UNKNOWN ' + C; // <-- replace with your desired default
+      if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
+      headers.push(hdr);
+    }
+    return headers;
+  }
 
-      /**
-       * @description: 获得excel数据
-       */
-      function getExcelData(workbook: XLSX.WorkBook) {
-        const excelData: ExcelData[] = [];
-        const { dateFormat, timeZone } = props;
-        for (const sheetName of workbook.SheetNames) {
-          const worksheet = workbook.Sheets[sheetName];
-          const header: string[] = getHeaderRow(worksheet);
-          let results = XLSX.utils.sheet_to_json(worksheet, {
-            raw: true,
-            dateNF: dateFormat, //Not worked
-          }) as object[];
-          results = results.map((row: object) => {
-            for (let field in row) {
-              if (row[field] instanceof Date) {
-                if (timeZone === 8) {
-                  row[field].setSeconds(row[field].getSeconds() + 43);
-                }
-                if (dateFormat) {
-                  row[field] = dateUtil(row[field]).format(dateFormat);
-                }
-              }
+  /**
+   * @description: 获得excel数据
+   */
+  function getExcelData(workbook: XLSX.WorkBook) {
+    const excelData: ExcelData[] = [];
+    const { dateFormat, timeZone } = props;
+    for (const sheetName of workbook.SheetNames) {
+      const worksheet = workbook.Sheets[sheetName];
+      const header: string[] = getHeaderRow(worksheet);
+      let results = XLSX.utils.sheet_to_json(worksheet, {
+        raw: true,
+        dateNF: dateFormat, //Not worked
+      }) as object[];
+      results = results.map((row: object) => {
+        for (let field in row) {
+          if (row[field] instanceof Date) {
+            if (timeZone === 8) {
+              row[field].setSeconds(row[field].getSeconds() + 43);
+            }
+            if (dateFormat) {
+              row[field] = dateUtil(row[field]).format(dateFormat);
             }
-            return row;
-          });
-
-          excelData.push({
-            header,
-            results,
-            meta: {
-              sheetName,
-            },
-          });
+          }
         }
-        return excelData;
-      }
+        return row;
+      });
 
-      /**
-       * @description: 读取excel数据
-       */
-      function readerData(rawFile: File) {
-        loadingRef.value = true;
-        return new Promise((resolve, reject) => {
-          const reader = new FileReader();
-          reader.onload = async (e) => {
-            try {
-              const data = e.target && e.target.result;
-              const workbook = XLSX.read(data, { type: 'array', cellDates: true });
-              // console.log(workbook);
-              /* DO SOMETHING WITH workbook HERE */
-              const excelData = getExcelData(workbook);
-              emit('success', excelData);
-              resolve('');
-            } catch (error) {
-              reject(error);
-              emit('error');
-            } finally {
-              loadingRef.value = false;
-            }
-          };
-          reader.readAsArrayBuffer(rawFile);
-        });
-      }
+      excelData.push({
+        header,
+        results,
+        meta: {
+          sheetName,
+        },
+      });
+    }
+    return excelData;
+  }
 
-      async function upload(rawFile: File) {
-        const inputRefDom = unref(inputRef);
-        if (inputRefDom) {
-          // fix can't select the same excel
-          inputRefDom.value = '';
+  /**
+   * @description: 读取excel数据
+   */
+  function readerData(rawFile: File) {
+    loadingRef.value = true;
+    return new Promise((resolve, reject) => {
+      const reader = new FileReader();
+      reader.onload = async (e) => {
+        try {
+          const data = e.target && e.target.result;
+          const workbook = XLSX.read(data, { type: 'array', cellDates: true });
+          // console.log(workbook);
+          /* DO SOMETHING WITH workbook HERE */
+          const excelData = getExcelData(workbook);
+          emit('success', excelData);
+          resolve('');
+        } catch (error) {
+          reject(error);
+          emit('error');
+        } finally {
+          loadingRef.value = false;
         }
-        await readerData(rawFile);
-      }
+      };
+      reader.readAsArrayBuffer(rawFile);
+    });
+  }
 
-      /**
-       * @description: 触发选择文件管理器
-       */
-      function handleInputClick(e: Event) {
-        const target = e && (e.target as HTMLInputElement);
-        const files = target?.files;
-        const rawFile = files && files[0]; // only setting files[0]
+  async function upload(rawFile: File) {
+    const inputRefDom = unref(inputRef);
+    if (inputRefDom) {
+      // fix can't select the same excel
+      inputRefDom.value = '';
+    }
+    await readerData(rawFile);
+  }
 
-        target.value = '';
+  /**
+   * @description: 触发选择文件管理器
+   */
+  function handleInputClick(e: Event) {
+    const target = e && (e.target as HTMLInputElement);
+    const files = target?.files;
+    const rawFile = files && files[0]; // only setting files[0]
 
-        if (!rawFile) return;
+    target.value = '';
 
-        cancelRef.value = false;
-        if (props.isReturnFile) {
-          emit('success', rawFile);
-          return;
-        }
-        upload(rawFile);
-      }
+    if (!rawFile) return;
 
-      /**
-       * @description 文件选择器关闭后,判断取消状态
-       */
-      function handleFocusChange() {
-        const timeId = setInterval(() => {
-          if (cancelRef.value === true) {
-            emit('cancel');
-          }
-          clearInterval(timeId);
-          window.removeEventListener('focus', handleFocusChange);
-        }, 1000);
-      }
+    cancelRef.value = false;
+    if (props.isReturnFile) {
+      emit('success', rawFile);
+      return;
+    }
+    upload(rawFile);
+  }
 
-      /**
-       * @description: 点击上传按钮
-       */
-      function handleUpload() {
-        const inputRefDom = unref(inputRef);
-        if (inputRefDom) {
-          cancelRef.value = true;
-          inputRefDom.click();
-          window.addEventListener('focus', handleFocusChange);
-        }
+  /**
+   * @description 文件选择器关闭后,判断取消状态
+   */
+  function handleFocusChange() {
+    const timeId = setInterval(() => {
+      if (cancelRef.value === true) {
+        emit('cancel');
       }
+      clearInterval(timeId);
+      window.removeEventListener('focus', handleFocusChange);
+    }, 1000);
+  }
 
-      return { handleUpload, handleInputClick, inputRef };
-    },
-  });
+  /**
+   * @description: 点击上传按钮
+   */
+  function handleUpload() {
+    const inputRefDom = unref(inputRef);
+    if (inputRefDom) {
+      cancelRef.value = true;
+      inputRefDom.click();
+      window.addEventListener('focus', handleFocusChange);
+    }
+  }
 </script>

+ 1 - 1
src/components/FlowChart/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import flowChart from './src/FlowChart.vue';
 
 export const FlowChart = withInstall(flowChart);

+ 120 - 131
src/components/FlowChart/src/FlowChart.vue

@@ -7,152 +7,141 @@
     </BasicModal>
   </div>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { Ref } from 'vue';
   import type { Definition } from '@logicflow/core';
-  import { defineComponent, ref, onMounted, unref, nextTick, computed, watch } from 'vue';
+  import { ref, onMounted, unref, nextTick, computed, watch } from 'vue';
   import FlowChartToolbar from './FlowChartToolbar.vue';
   import LogicFlow from '@logicflow/core';
   import { Snapshot, BpmnElement, Menu, DndPanel, SelectionSelect } from '@logicflow/extension';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { useAppStore } from '/@/store/modules/app';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { useAppStore } from '@/store/modules/app';
   import { createFlowChartContext } from './useFlowContext';
   import { toLogicFlowData } from './adpterForTurbo';
-  import { useModal, BasicModal } from '/@/components/Modal';
-  import { JsonPreview } from '/@/components/CodeEditor';
+  import { useModal, BasicModal } from '@/components/Modal';
+  import { JsonPreview } from '@/components/CodeEditor';
   import { configDefaultDndPanel } from './config';
   import '@logicflow/core/dist/style/index.css';
   import '@logicflow/extension/lib/style/index.css';
 
-  export default defineComponent({
-    name: 'FlowChart',
-    components: { BasicModal, FlowChartToolbar, JsonPreview },
-    props: {
-      flowOptions: {
-        type: Object as PropType<Definition>,
-        default: () => ({}),
-      },
+  defineOptions({ name: 'FlowChart' });
 
-      data: {
-        type: Object as PropType<any>,
-        default: () => ({}),
-      },
+  const props = defineProps({
+    flowOptions: {
+      type: Object as PropType<Definition>,
+      default: () => ({}),
+    },
+
+    data: {
+      type: Object as PropType<any>,
+      default: () => ({}),
+    },
+
+    toolbar: {
+      type: Boolean,
+      default: true,
+    },
+    patternItems: {
+      type: Array,
+    },
+  });
 
-      toolbar: {
-        type: Boolean,
-        default: true,
+  const lfElRef = ref(null);
+  const graphData = ref({});
+
+  const lfInstance = ref(null) as Ref<LogicFlow | null>;
+
+  const { prefixCls } = useDesign('flow-chart');
+  const appStore = useAppStore();
+  const [register, { openModal }] = useModal();
+  createFlowChartContext({
+    logicFlow: lfInstance as unknown as LogicFlow,
+  });
+
+  const getFlowOptions = computed(() => {
+    const { flowOptions } = props;
+
+    const defaultOptions: Partial<Definition> = {
+      grid: true,
+      background: {
+        color: appStore.getDarkMode === 'light' ? '#f7f9ff' : '#151515',
       },
-      patternItems: {
-        type: Array,
+      keyboard: {
+        enabled: true,
       },
+      ...flowOptions,
+    };
+    return defaultOptions as Definition;
+  });
+
+  watch(
+    () => props.data,
+    () => {
+      onRender();
     },
-    setup(props) {
-      const lfElRef = ref(null);
-      const graphData = ref({});
-
-      const lfInstance = ref(null) as Ref<LogicFlow | null>;
-
-      const { prefixCls } = useDesign('flow-chart');
-      const appStore = useAppStore();
-      const [register, { openModal }] = useModal();
-      createFlowChartContext({
-        logicFlow: lfInstance as unknown as LogicFlow,
-      });
-
-      const getFlowOptions = computed(() => {
-        const { flowOptions } = props;
-
-        const defaultOptions: Partial<Definition> = {
-          grid: true,
-          background: {
-            color: appStore.getDarkMode === 'light' ? '#f7f9ff' : '#151515',
-          },
-          keyboard: {
-            enabled: true,
-          },
-          ...flowOptions,
-        };
-        return defaultOptions as Definition;
-      });
-
-      watch(
-        () => props.data,
-        () => {
-          onRender();
-        },
-      );
-
-      // TODO
-      // watch(
-      //   () => appStore.getDarkMode,
-      //   () => {
-      //     init();
-      //   }
-      // );
-
-      watch(
-        () => unref(getFlowOptions),
-        (options) => {
-          unref(lfInstance)?.updateEditConfig(options);
-        },
-      );
-
-      // init logicFlow
-      async function init() {
-        await nextTick();
-
-        const lfEl = unref(lfElRef);
-        if (!lfEl) {
-          return;
-        }
-        LogicFlow.use(DndPanel);
-
-        // Canvas configuration
-        LogicFlow.use(Snapshot);
-        // Use the bpmn plug-in to introduce bpmn elements, which can be used after conversion in turbo
-        LogicFlow.use(BpmnElement);
-        // Start the right-click menu
-        LogicFlow.use(Menu);
-        LogicFlow.use(SelectionSelect);
-
-        lfInstance.value = new LogicFlow({
-          ...unref(getFlowOptions),
-          container: lfEl,
-        });
-        const lf = unref(lfInstance)!;
-        lf?.setDefaultEdgeType('line');
-        onRender();
-        lf?.setPatternItems(props.patternItems || configDefaultDndPanel(lf));
-      }
-
-      async function onRender() {
-        await nextTick();
-        const lf = unref(lfInstance);
-        if (!lf) {
-          return;
-        }
-        const lFData = toLogicFlowData(props.data);
-        lf.render(lFData);
-      }
-
-      function handlePreview() {
-        const lf = unref(lfInstance);
-        if (!lf) {
-          return;
-        }
-        graphData.value = unref(lf).getGraphData();
-        openModal();
-      }
-
-      onMounted(init);
-
-      return {
-        register,
-        prefixCls,
-        lfElRef,
-        handlePreview,
-        graphData,
-      };
+  );
+
+  // TODO
+  // watch(
+  //   () => appStore.getDarkMode,
+  //   () => {
+  //     init();
+  //   }
+  // );
+
+  watch(
+    () => unref(getFlowOptions),
+    (options) => {
+      unref(lfInstance)?.updateEditConfig(options);
     },
-  });
+  );
+
+  // init logicFlow
+  async function init() {
+    await nextTick();
+
+    const lfEl = unref(lfElRef);
+    if (!lfEl) {
+      return;
+    }
+    LogicFlow.use(DndPanel);
+
+    // Canvas configuration
+    LogicFlow.use(Snapshot);
+    // Use the bpmn plug-in to introduce bpmn elements, which can be used after conversion in turbo
+    LogicFlow.use(BpmnElement);
+    // Start the right-click menu
+    LogicFlow.use(Menu);
+    LogicFlow.use(SelectionSelect);
+
+    lfInstance.value = new LogicFlow({
+      ...unref(getFlowOptions),
+      container: lfEl,
+    });
+    const lf = unref(lfInstance)!;
+    lf?.setDefaultEdgeType('line');
+    onRender();
+    lf?.setPatternItems(props.patternItems || configDefaultDndPanel(lf));
+  }
+
+  async function onRender() {
+    await nextTick();
+    const lf = unref(lfInstance);
+    if (!lf) {
+      return;
+    }
+    const lFData = toLogicFlowData(props.data);
+    lf.render(lFData);
+  }
+
+  function handlePreview() {
+    const lf = unref(lfInstance);
+    if (!lf) {
+      return;
+    }
+    graphData.value = unref(lf).getGraphData();
+    openModal();
+  }
+
+  onMounted(init);
 </script>

+ 100 - 103
src/components/FlowChart/src/FlowChartToolbar.vue

@@ -6,7 +6,7 @@
         <span :class="`${prefixCls}-toolbar__icon`" v-if="item.icon" @click="onControl(item)">
           <Icon
             :icon="item.icon"
-            :class="item.disabled ? 'cursor-not-allowed disabeld' : 'cursor-pointer'"
+            :class="item.disabled ? 'cursor-not-allowed disabled' : 'cursor-pointer'"
           />
         </span>
       </Tooltip>
@@ -14,122 +14,119 @@
     </template>
   </div>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { ToolbarConfig } from './types';
 
-  import { defineComponent, ref, onUnmounted, unref, nextTick, watchEffect } from 'vue';
+  import { ref, onUnmounted, unref, nextTick, watchEffect } from 'vue';
   import { Divider, Tooltip } from 'ant-design-vue';
   import Icon from '@/components/Icon/Icon.vue';
 
   import { useFlowChartContext } from './useFlowContext';
   import { ToolbarTypeEnum } from './enum';
 
-  export default defineComponent({
-    name: 'FlowChartToolbar',
-    components: { Icon, Divider, Tooltip },
-    props: {
-      prefixCls: String,
+  defineOptions({ name: 'FlowChartToolbar' });
+
+  defineProps({
+    prefixCls: String,
+  });
+
+  const emit = defineEmits(['view-data']);
+
+  const toolbarItemList = ref<ToolbarConfig[]>([
+    {
+      type: ToolbarTypeEnum.ZOOM_IN,
+      icon: 'codicon:zoom-out',
+      tooltip: '缩小',
+    },
+    {
+      type: ToolbarTypeEnum.ZOOM_OUT,
+      icon: 'codicon:zoom-in',
+      tooltip: '放大',
+    },
+    {
+      type: ToolbarTypeEnum.RESET_ZOOM,
+      icon: 'codicon:screen-normal',
+      tooltip: '重置比例',
+    },
+    { separate: true },
+    {
+      type: ToolbarTypeEnum.UNDO,
+      icon: 'ion:arrow-undo-outline',
+      tooltip: '后退',
+      disabled: true,
+    },
+    {
+      type: ToolbarTypeEnum.REDO,
+      icon: 'ion:arrow-redo-outline',
+      tooltip: '前进',
+      disabled: true,
+    },
+    { separate: true },
+    {
+      type: ToolbarTypeEnum.SNAPSHOT,
+      icon: 'ion:download-outline',
+      tooltip: '下载',
+    },
+    {
+      type: ToolbarTypeEnum.VIEW_DATA,
+      icon: 'carbon:document-view',
+      tooltip: '查看数据',
     },
-    emits: ['view-data'],
-    setup(_, { emit }) {
-      const toolbarItemList = ref<ToolbarConfig[]>([
-        {
-          type: ToolbarTypeEnum.ZOOM_IN,
-          icon: 'codicon:zoom-out',
-          tooltip: '缩小',
-        },
-        {
-          type: ToolbarTypeEnum.ZOOM_OUT,
-          icon: 'codicon:zoom-in',
-          tooltip: '放大',
-        },
-        {
-          type: ToolbarTypeEnum.RESET_ZOOM,
-          icon: 'codicon:screen-normal',
-          tooltip: '重置比例',
-        },
-        { separate: true },
-        {
-          type: ToolbarTypeEnum.UNDO,
-          icon: 'ion:arrow-undo-outline',
-          tooltip: '后退',
-          disabled: true,
-        },
-        {
-          type: ToolbarTypeEnum.REDO,
-          icon: 'ion:arrow-redo-outline',
-          tooltip: '前进',
-          disabled: true,
-        },
-        { separate: true },
-        {
-          type: ToolbarTypeEnum.SNAPSHOT,
-          icon: 'ion:download-outline',
-          tooltip: '下载',
-        },
-        {
-          type: ToolbarTypeEnum.VIEW_DATA,
-          icon: 'carbon:document-view',
-          tooltip: '查看数据',
-        },
-      ]);
+  ]);
 
-      const { logicFlow } = useFlowChartContext();
+  const { logicFlow } = useFlowChartContext();
 
-      function onHistoryChange({ data: { undoAble, redoAble } }) {
-        const itemsList = unref(toolbarItemList);
-        const undoIndex = itemsList.findIndex((item) => item.type === ToolbarTypeEnum.UNDO);
-        const redoIndex = itemsList.findIndex((item) => item.type === ToolbarTypeEnum.REDO);
-        if (undoIndex !== -1) {
-          unref(toolbarItemList)[undoIndex].disabled = !undoAble;
-        }
-        if (redoIndex !== -1) {
-          unref(toolbarItemList)[redoIndex].disabled = !redoAble;
-        }
-      }
+  function onHistoryChange({ data: { undoAble, redoAble } }) {
+    const itemsList = unref(toolbarItemList);
+    const undoIndex = itemsList.findIndex((item) => item.type === ToolbarTypeEnum.UNDO);
+    const redoIndex = itemsList.findIndex((item) => item.type === ToolbarTypeEnum.REDO);
+    if (undoIndex !== -1) {
+      unref(toolbarItemList)[undoIndex].disabled = !undoAble;
+    }
+    if (redoIndex !== -1) {
+      unref(toolbarItemList)[redoIndex].disabled = !redoAble;
+    }
+  }
 
-      const onControl = (item) => {
-        const lf = unref(logicFlow);
-        if (!lf) {
-          return;
-        }
-        switch (item.type) {
-          case ToolbarTypeEnum.ZOOM_IN:
-            lf.zoom();
-            break;
-          case ToolbarTypeEnum.ZOOM_OUT:
-            lf.zoom(true);
-            break;
-          case ToolbarTypeEnum.RESET_ZOOM:
-            lf.resetZoom();
-            break;
-          case ToolbarTypeEnum.UNDO:
-            lf.undo();
-            break;
-          case ToolbarTypeEnum.REDO:
-            lf.redo();
-            break;
-          case ToolbarTypeEnum.SNAPSHOT:
-            lf.getSnapshot();
-            break;
-          case ToolbarTypeEnum.VIEW_DATA:
-            emit('view-data');
-            break;
-        }
-      };
+  const onControl = (item) => {
+    const lf = unref(logicFlow);
+    if (!lf) {
+      return;
+    }
+    switch (item.type) {
+      case ToolbarTypeEnum.ZOOM_IN:
+        lf.zoom();
+        break;
+      case ToolbarTypeEnum.ZOOM_OUT:
+        lf.zoom(true);
+        break;
+      case ToolbarTypeEnum.RESET_ZOOM:
+        lf.resetZoom();
+        break;
+      case ToolbarTypeEnum.UNDO:
+        lf.undo();
+        break;
+      case ToolbarTypeEnum.REDO:
+        lf.redo();
+        break;
+      case ToolbarTypeEnum.SNAPSHOT:
+        lf.getSnapshot();
+        break;
+      case ToolbarTypeEnum.VIEW_DATA:
+        emit('view-data');
+        break;
+    }
+  };
 
-      watchEffect(async () => {
-        if (unref(logicFlow)) {
-          await nextTick();
-          unref(logicFlow)?.on('history:change', onHistoryChange);
-        }
-      });
+  watchEffect(async () => {
+    if (unref(logicFlow)) {
+      await nextTick();
+      unref(logicFlow)?.on('history:change', onHistoryChange);
+    }
+  });
 
-      onUnmounted(() => {
-        unref(logicFlow)?.off('history:change', onHistoryChange);
-      });
-      return { toolbarItemList, onControl };
-    },
+  onUnmounted(() => {
+    unref(logicFlow)?.off('history:change', onHistoryChange);
   });
 </script>
 <style lang="less">

+ 219 - 240
src/components/Form/src/BasicForm.vue

@@ -37,286 +37,265 @@
     </Row>
   </Form>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { FormActionType, FormProps, FormSchemaInner as FormSchema } from './types/form';
   import type { AdvanceState } from './types/hooks';
   import type { Ref } from 'vue';
 
-  import { defineComponent, reactive, ref, computed, unref, onMounted, watch, nextTick } from 'vue';
+  import { reactive, ref, computed, unref, onMounted, watch, nextTick, useAttrs } from 'vue';
   import { Form, Row, type FormProps as AntFormProps } from 'ant-design-vue';
   import FormItem from './components/FormItem.vue';
   import FormAction from './components/FormAction.vue';
 
   import { dateItemType } from './helper';
-  import { dateUtil } from '/@/utils/dateUtil';
+  import { dateUtil } from '@/utils/dateUtil';
 
-  import { deepMerge } from '/@/utils';
+  import { deepMerge } from '@/utils';
 
   import { useFormValues } from './hooks/useFormValues';
   import useAdvanced from './hooks/useAdvanced';
   import { useFormEvents } from './hooks/useFormEvents';
   import { createFormContext } from './hooks/useFormContext';
   import { useAutoFocus } from './hooks/useAutoFocus';
-  import { useModalContext } from '/@/components/Modal';
+  import { useModalContext } from '@/components/Modal';
   import { useDebounceFn } from '@vueuse/core';
 
   import { basicProps } from './props';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useDesign } from '@/hooks/web/useDesign';
   import { cloneDeep } from 'lodash-es';
 
-  export default defineComponent({
-    name: 'BasicForm',
-    components: { FormItem, Form, Row, FormAction },
-    props: basicProps,
-    emits: ['advanced-change', 'reset', 'submit', 'register', 'field-value-change'],
-    setup(props, { emit, attrs }) {
-      const formModel = reactive({});
-      const modalFn = useModalContext();
-
-      const advanceState = reactive<AdvanceState>({
-        isAdvanced: true,
-        hideAdvanceBtn: false,
-        isLoad: false,
-        actionSpan: 6,
-      });
+  defineOptions({ name: 'BasicForm' });
 
-      const defaultValueRef = ref({});
-      const isInitedDefaultRef = ref(false);
-      const propsRef = ref<Partial<FormProps>>();
-      const schemaRef = ref<FormSchema[] | null>(null);
-      const formElRef = ref<FormActionType | null>(null);
+  const props = defineProps(basicProps);
 
-      const { prefixCls } = useDesign('basic-form');
+  const emit = defineEmits([
+    'advanced-change',
+    'reset',
+    'submit',
+    'register',
+    'field-value-change',
+  ]);
 
-      // Get the basic configuration of the form
-      const getProps = computed(() => {
-        return { ...props, ...unref(propsRef) } as FormProps;
-      });
+  const attrs = useAttrs();
 
-      const getFormClass = computed(() => {
-        return [
-          prefixCls,
-          {
-            [`${prefixCls}--compact`]: unref(getProps).compact,
-          },
-        ];
-      });
+  const formModel = reactive({});
+  const modalFn = useModalContext();
 
-      // Get uniform row style and Row configuration for the entire form
-      const getRow = computed(() => {
-        const { baseRowStyle = {}, rowProps } = unref(getProps);
-        return {
-          style: baseRowStyle,
-          ...rowProps,
-        };
-      });
+  const advanceState = reactive<AdvanceState>({
+    isAdvanced: true,
+    hideAdvanceBtn: false,
+    isLoad: false,
+    actionSpan: 6,
+  });
 
-      const getBindValue = computed(
-        () => ({ ...attrs, ...props, ...unref(getProps) }) as AntFormProps,
-      );
-
-      const getSchema = computed((): FormSchema[] => {
-        const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
-        for (const schema of schemas) {
-          const {
-            defaultValue,
-            component,
-            componentProps,
-            isHandleDateDefaultValue = true,
-          } = schema;
-          // handle date type
-          if (
-            isHandleDateDefaultValue &&
-            defaultValue &&
-            component &&
-            dateItemType.includes(component)
-          ) {
-            const valueFormat = componentProps ? componentProps['valueFormat'] : null;
-            if (!Array.isArray(defaultValue)) {
-              schema.defaultValue = valueFormat
-                ? dateUtil(defaultValue).format(valueFormat)
-                : dateUtil(defaultValue);
-            } else {
-              const def: any[] = [];
-              defaultValue.forEach((item) => {
-                def.push(valueFormat ? dateUtil(item).format(valueFormat) : dateUtil(item));
-              });
-              schema.defaultValue = def;
-            }
-          }
-        }
-        if (unref(getProps).showAdvancedButton) {
-          return cloneDeep(
-            schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[],
-          );
+  const defaultValueRef = ref({});
+  const isInitedDefaultRef = ref(false);
+  const propsRef = ref<Partial<FormProps>>();
+  const schemaRef = ref<FormSchema[] | null>(null);
+  const formElRef = ref<FormActionType | null>(null);
+
+  const { prefixCls } = useDesign('basic-form');
+
+  // Get the basic configuration of the form
+  const getProps = computed(() => {
+    return { ...props, ...unref(propsRef) } as FormProps;
+  });
+
+  const getFormClass = computed(() => {
+    return [
+      prefixCls,
+      {
+        [`${prefixCls}--compact`]: unref(getProps).compact,
+      },
+    ];
+  });
+
+  // Get uniform row style and Row configuration for the entire form
+  const getRow = computed(() => {
+    const { baseRowStyle = {}, rowProps } = unref(getProps);
+    return {
+      style: baseRowStyle,
+      ...rowProps,
+    };
+  });
+
+  const getBindValue = computed(() => ({ ...attrs, ...props, ...unref(getProps) }) as AntFormProps);
+
+  const getSchema = computed((): FormSchema[] => {
+    const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
+    for (const schema of schemas) {
+      const { defaultValue, component, componentProps, isHandleDateDefaultValue = true } = schema;
+      // handle date type
+      if (
+        isHandleDateDefaultValue &&
+        defaultValue &&
+        component &&
+        dateItemType.includes(component)
+      ) {
+        const valueFormat = componentProps ? componentProps['valueFormat'] : null;
+        if (!Array.isArray(defaultValue)) {
+          schema.defaultValue = valueFormat
+            ? dateUtil(defaultValue).format(valueFormat)
+            : dateUtil(defaultValue);
         } else {
-          return cloneDeep(schemas as FormSchema[]);
+          const def: any[] = [];
+          defaultValue.forEach((item) => {
+            def.push(valueFormat ? dateUtil(item).format(valueFormat) : dateUtil(item));
+          });
+          schema.defaultValue = def;
         }
-      });
+      }
+    }
+    if (unref(getProps).showAdvancedButton) {
+      return cloneDeep(schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[]);
+    } else {
+      return cloneDeep(schemas as FormSchema[]);
+    }
+  });
 
-      const { handleToggleAdvanced, fieldsIsAdvancedMap } = useAdvanced({
-        advanceState,
-        emit,
-        getProps,
-        getSchema,
-        formModel,
-        defaultValueRef,
-      });
+  const { handleToggleAdvanced, fieldsIsAdvancedMap } = useAdvanced({
+    advanceState,
+    emit,
+    getProps,
+    getSchema,
+    formModel,
+    defaultValueRef,
+  });
 
-      const { handleFormValues, initDefault } = useFormValues({
-        getProps,
-        defaultValueRef,
-        getSchema,
-        formModel,
-      });
+  const { handleFormValues, initDefault } = useFormValues({
+    getProps,
+    defaultValueRef,
+    getSchema,
+    formModel,
+  });
 
-      useAutoFocus({
-        getSchema,
-        getProps,
-        isInitedDefault: isInitedDefaultRef,
-        formElRef: formElRef as Ref<FormActionType>,
-      });
+  useAutoFocus({
+    getSchema,
+    getProps,
+    isInitedDefault: isInitedDefaultRef,
+    formElRef: formElRef as Ref<FormActionType>,
+  });
 
-      const {
-        handleSubmit,
-        setFieldsValue,
-        clearValidate,
-        validate,
-        validateFields,
-        getFieldsValue,
-        updateSchema,
-        resetSchema,
-        appendSchemaByField,
-        removeSchemaByField,
-        resetFields,
-        scrollToField,
-      } = useFormEvents({
-        emit,
-        getProps,
-        formModel,
-        getSchema,
-        defaultValueRef,
-        formElRef: formElRef as Ref<FormActionType>,
-        schemaRef: schemaRef as Ref<FormSchema[]>,
-        handleFormValues,
-      });
+  const {
+    handleSubmit,
+    setFieldsValue,
+    clearValidate,
+    validate,
+    validateFields,
+    getFieldsValue,
+    updateSchema,
+    resetSchema,
+    appendSchemaByField,
+    removeSchemaByField,
+    resetFields,
+    scrollToField,
+  } = useFormEvents({
+    emit,
+    getProps,
+    formModel,
+    getSchema,
+    defaultValueRef,
+    formElRef: formElRef as Ref<FormActionType>,
+    schemaRef: schemaRef as Ref<FormSchema[]>,
+    handleFormValues,
+  });
 
-      createFormContext({
-        resetAction: resetFields,
-        submitAction: handleSubmit,
-      });
+  createFormContext({
+    resetAction: resetFields,
+    submitAction: handleSubmit,
+  });
 
-      watch(
-        () => unref(getProps).model,
-        () => {
-          const { model } = unref(getProps);
-          if (!model) return;
-          setFieldsValue(model);
-        },
-        {
-          immediate: true,
-        },
-      );
-
-      watch(
-        () => unref(getProps).schemas,
-        (schemas) => {
-          resetSchema(schemas ?? []);
-        },
-      );
-
-      watch(
-        () => getSchema.value,
-        (schema) => {
-          nextTick(() => {
-            //  Solve the problem of modal adaptive height calculation when the form is placed in the modal
-            modalFn?.redoModalHeight?.();
-          });
-          if (unref(isInitedDefaultRef)) {
-            return;
-          }
-          if (schema?.length) {
-            initDefault();
-            isInitedDefaultRef.value = true;
-          }
-        },
-      );
-
-      watch(
-        () => formModel,
-        useDebounceFn(() => {
-          unref(getProps).submitOnChange && handleSubmit();
-        }, 300),
-        { deep: true },
-      );
-
-      async function setProps(formProps: Partial<FormProps>): Promise<void> {
-        propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
-      }
+  watch(
+    () => unref(getProps).model,
+    () => {
+      const { model } = unref(getProps);
+      if (!model) return;
+      setFieldsValue(model);
+    },
+    {
+      immediate: true,
+    },
+  );
 
-      function setFormModel(key: string, value: any, schema: FormSchema) {
-        formModel[key] = value;
-        emit('field-value-change', key, value);
-        // TODO 优化验证,这里如果是autoLink=false手动关联的情况下才会再次触发此函数
-        if (schema && schema.itemProps && !schema.itemProps.autoLink) {
-          validateFields([key]).catch((_) => {});
-        }
+  watch(
+    () => unref(getProps).schemas,
+    (schemas) => {
+      resetSchema(schemas ?? []);
+    },
+  );
+
+  watch(
+    () => getSchema.value,
+    (schema) => {
+      nextTick(() => {
+        //  Solve the problem of modal adaptive height calculation when the form is placed in the modal
+        modalFn?.redoModalHeight?.();
+      });
+      if (unref(isInitedDefaultRef)) {
+        return;
       }
-
-      function handleEnterPress(e: KeyboardEvent) {
-        const { autoSubmitOnEnter } = unref(getProps);
-        if (!autoSubmitOnEnter) return;
-        if (e.key === 'Enter' && e.target && e.target instanceof HTMLElement) {
-          const target: HTMLElement = e.target as HTMLElement;
-          if (target && target.tagName && target.tagName.toUpperCase() == 'INPUT') {
-            handleSubmit();
-          }
-        }
+      if (schema?.length) {
+        initDefault();
+        isInitedDefaultRef.value = true;
       }
+    },
+  );
+
+  watch(
+    () => formModel,
+    useDebounceFn(() => {
+      unref(getProps).submitOnChange && handleSubmit();
+    }, 300),
+    { deep: true },
+  );
+
+  async function setProps(formProps: Partial<FormProps>): Promise<void> {
+    propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
+  }
 
-      const formActionType: Partial<FormActionType> = {
-        getFieldsValue,
-        setFieldsValue,
-        resetFields,
-        updateSchema,
-        resetSchema,
-        setProps,
-        removeSchemaByField,
-        appendSchemaByField,
-        clearValidate,
-        validateFields,
-        validate,
-        submit: handleSubmit,
-        scrollToField: scrollToField,
-      };
-
-      onMounted(() => {
-        initDefault();
-        emit('register', formActionType);
-      });
+  function setFormModel(key: string, value: any, schema: FormSchema) {
+    formModel[key] = value;
+    emit('field-value-change', key, value);
+    // TODO 优化验证,这里如果是autoLink=false手动关联的情况下才会再次触发此函数
+    if (schema && schema.itemProps && !schema.itemProps.autoLink) {
+      validateFields([key]).catch((_) => {});
+    }
+  }
 
-      return {
-        getBindValue,
-        handleToggleAdvanced,
-        handleEnterPress,
-        formModel,
-        defaultValueRef,
-        advanceState,
-        getRow,
-        getProps,
-        formElRef,
-        getSchema,
-        formActionType: formActionType as any,
-        setFormModel,
-        getFormClass,
-        getFormActionBindProps: computed(
-          () =>
-            ({ ...getProps.value, ...advanceState }) as InstanceType<typeof FormAction>['$props'],
-        ),
-        fieldsIsAdvancedMap,
-        ...formActionType,
-      };
-    },
+  function handleEnterPress(e: KeyboardEvent) {
+    const { autoSubmitOnEnter } = unref(getProps);
+    if (!autoSubmitOnEnter) return;
+    if (e.key === 'Enter' && e.target && e.target instanceof HTMLElement) {
+      const target: HTMLElement = e.target as HTMLElement;
+      if (target && target.tagName && target.tagName.toUpperCase() == 'INPUT') {
+        handleSubmit();
+      }
+    }
+  }
+
+  const formActionType: Partial<FormActionType> = {
+    getFieldsValue,
+    setFieldsValue,
+    resetFields,
+    updateSchema,
+    resetSchema,
+    setProps,
+    removeSchemaByField,
+    appendSchemaByField,
+    clearValidate,
+    validateFields,
+    validate,
+    submit: handleSubmit,
+    scrollToField: scrollToField,
+  };
+
+  const getFormActionBindProps = computed(
+    () => ({ ...getProps.value, ...advanceState }) as InstanceType<typeof FormAction>['$props'],
+  );
+
+  onMounted(() => {
+    initDefault();
+    emit('register', formActionType);
   });
 </script>
 <style lang="less">

+ 5 - 5
src/components/Form/src/componentMap.ts

@@ -1,5 +1,5 @@
 import type { Component } from 'vue';
-import type { ComponentType } from './types/index';
+import type { ComponentType } from './types';
 
 /**
  * Component list, register here to setting it in the form
@@ -27,10 +27,10 @@ import ApiTree from './components/ApiTree.vue';
 import ApiTreeSelect from './components/ApiTreeSelect.vue';
 import ApiCascader from './components/ApiCascader.vue';
 import ApiTransfer from './components/ApiTransfer.vue';
-import { BasicUpload, ImageUpload } from '/@/components/Upload';
-import { StrengthMeter } from '/@/components/StrengthMeter';
-import { IconPicker } from '/@/components/Icon';
-import { CountdownInput } from '/@/components/CountDown';
+import { BasicUpload, ImageUpload } from '@/components/Upload';
+import { StrengthMeter } from '@/components/StrengthMeter';
+import { IconPicker } from '@/components/Icon';
+import { CountdownInput } from '@/components/CountDown';
 
 const componentMap = new Map<ComponentType, Component>();
 

+ 140 - 154
src/components/Form/src/components/ApiCascader.vue

@@ -1,5 +1,5 @@
 <template>
-  <a-cascader
+  <Cascader
     v-model:value="state"
     :options="options"
     :load-data="loadData"
@@ -16,18 +16,18 @@
         {{ t('component.form.apiSelectNotFound') }}
       </span>
     </template>
-  </a-cascader>
+  </Cascader>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import { type Recordable } from '@vben/types';
-  import { defineComponent, PropType, ref, unref, watch, watchEffect } from 'vue';
+  import { PropType, ref, unref, watch, watchEffect } from 'vue';
   import { Cascader } from 'ant-design-vue';
-  import { propTypes } from '/@/utils/propTypes';
-  import { isFunction } from '/@/utils/is';
+  import { propTypes } from '@/utils/propTypes';
+  import { isFunction } from '@/utils/is';
   import { get, omit } from 'lodash-es';
-  import { useRuleFormItem } from '/@/hooks/component/useFormItem';
+  import { useRuleFormItem } from '@/hooks/component/useFormItem';
   import { LoadingOutlined } from '@ant-design/icons-vue';
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useI18n } from '@/hooks/web/useI18n';
 
   interface Option {
     value: string;
@@ -36,165 +36,151 @@
     isLeaf?: boolean;
     children?: Option[];
   }
-  export default defineComponent({
-    name: 'ApiCascader',
-    components: {
-      LoadingOutlined,
-      [Cascader.name]: Cascader,
+
+  defineOptions({ name: 'ApiCascader' });
+
+  const props = defineProps({
+    value: {
+      type: Array,
     },
-    props: {
-      value: {
-        type: Array,
-      },
-      api: {
-        type: Function as PropType<(arg?: Recordable<any>) => Promise<Option[]>>,
-        default: null,
-      },
-      numberToString: propTypes.bool,
-      resultField: propTypes.string.def(''),
-      labelField: propTypes.string.def('label'),
-      valueField: propTypes.string.def('value'),
-      childrenField: propTypes.string.def('children'),
-      apiParamKey: propTypes.string.def('parentCode'),
-      immediate: propTypes.bool.def(true),
-      // init fetch params
-      initFetchParams: {
-        type: Object as PropType<Recordable<any>>,
-        default: () => ({}),
-      },
-      // 是否有下级,默认是
-      isLeaf: {
-        type: Function as PropType<(arg: Recordable<any>) => boolean>,
-        default: null,
-      },
-      displayRenderArray: {
-        type: Array,
-      },
+    api: {
+      type: Function as PropType<(arg?: Recordable<any>) => Promise<Option[]>>,
+      default: null,
     },
-    emits: ['change', 'defaultChange'],
-    setup(props, { emit }) {
-      const apiData = ref<any[]>([]);
-      const options = ref<Option[]>([]);
-      const loading = ref<boolean>(false);
-      const emitData = ref<any[]>([]);
-      const isFirstLoad = ref(true);
-      const { t } = useI18n();
-      // Embedded in the form, just use the hook binding to perform form verification
-      const [state] = useRuleFormItem(props, 'value', 'change', emitData);
-
-      watch(
-        apiData,
-        (data) => {
-          const opts = generatorOptions(data);
-          options.value = opts;
-        },
-        { deep: true },
-      );
+    numberToString: propTypes.bool,
+    resultField: propTypes.string.def(''),
+    labelField: propTypes.string.def('label'),
+    valueField: propTypes.string.def('value'),
+    childrenField: propTypes.string.def('children'),
+    apiParamKey: propTypes.string.def('parentCode'),
+    immediate: propTypes.bool.def(true),
+    // init fetch params
+    initFetchParams: {
+      type: Object as PropType<Recordable<any>>,
+      default: () => ({}),
+    },
+    // 是否有下级,默认是
+    isLeaf: {
+      type: Function as PropType<(arg: Recordable<any>) => boolean>,
+      default: null,
+    },
+    displayRenderArray: {
+      type: Array,
+    },
+  });
 
-      function generatorOptions(options: any[]): Option[] {
-        const { labelField, valueField, numberToString, childrenField, isLeaf } = props;
-        return options.reduce((prev, next: Recordable<any>) => {
-          if (next) {
-            const value = next[valueField];
-            const item = {
-              ...omit(next, [labelField, valueField]),
-              label: next[labelField],
-              value: numberToString ? `${value}` : value,
-              isLeaf: isLeaf && typeof isLeaf === 'function' ? isLeaf(next) : false,
-            };
-            const children = Reflect.get(next, childrenField);
-            if (children) {
-              Reflect.set(item, childrenField, generatorOptions(children));
-            }
-            prev.push(item);
-          }
-          return prev;
-        }, [] as Option[]);
-      }
+  const emit = defineEmits(['change', 'defaultChange']);
 
-      async function initialFetch() {
-        const api = props.api;
-        if (!api || !isFunction(api)) return;
-        apiData.value = [];
-        loading.value = true;
-        try {
-          const res = await api(props.initFetchParams);
-          if (Array.isArray(res)) {
-            apiData.value = res;
-            return;
-          }
-          if (props.resultField) {
-            apiData.value = get(res, props.resultField) || [];
-          }
-        } catch (error) {
-          console.warn(error);
-        } finally {
-          loading.value = false;
-        }
-      }
+  const apiData = ref<any[]>([]);
+  const options = ref<Option[]>([]);
+  const loading = ref<boolean>(false);
+  const emitData = ref<any[]>([]);
+  const isFirstLoad = ref(true);
+  const { t } = useI18n();
+  // Embedded in the form, just use the hook binding to perform form verification
+  const [state]: any = useRuleFormItem(props, 'value', 'change', emitData);
 
-      async function loadData(selectedOptions: Option[]) {
-        const targetOption = selectedOptions[selectedOptions.length - 1];
-        targetOption.loading = true;
+  watch(
+    apiData,
+    (data) => {
+      const opts = generatorOptions(data);
+      options.value = opts;
+    },
+    { deep: true },
+  );
 
-        const api = props.api;
-        if (!api || !isFunction(api)) return;
-        try {
-          const res = await api({
-            [props.apiParamKey]: Reflect.get(targetOption, 'value'),
-          });
-          if (Array.isArray(res)) {
-            const children = generatorOptions(res);
-            targetOption.children = children;
-            return;
-          }
-          if (props.resultField) {
-            const children = generatorOptions(get(res, props.resultField) || []);
-            targetOption.children = children;
-          }
-        } catch (e) {
-          console.error(e);
-        } finally {
-          targetOption.loading = false;
+  function generatorOptions(options: any[]): Option[] {
+    const { labelField, valueField, numberToString, childrenField, isLeaf } = props;
+    return options.reduce((prev, next: Recordable<any>) => {
+      if (next) {
+        const value = next[valueField];
+        const item = {
+          ...omit(next, [labelField, valueField]),
+          label: next[labelField],
+          value: numberToString ? `${value}` : value,
+          isLeaf: isLeaf && typeof isLeaf === 'function' ? isLeaf(next) : false,
+        };
+        const children = Reflect.get(next, childrenField);
+        if (children) {
+          Reflect.set(item, childrenField, generatorOptions(children));
         }
+        prev.push(item);
       }
+      return prev;
+    }, [] as Option[]);
+  }
 
-      watchEffect(() => {
-        props.immediate && initialFetch();
-      });
+  async function initialFetch() {
+    const api = props.api;
+    if (!api || !isFunction(api)) return;
+    apiData.value = [];
+    loading.value = true;
+    try {
+      const res = await api(props.initFetchParams);
+      if (Array.isArray(res)) {
+        apiData.value = res;
+        return;
+      }
+      if (props.resultField) {
+        apiData.value = get(res, props.resultField) || [];
+      }
+    } catch (error) {
+      console.warn(error);
+    } finally {
+      loading.value = false;
+    }
+  }
 
-      watch(
-        () => props.initFetchParams,
-        () => {
-          !unref(isFirstLoad) && initialFetch();
-        },
-        { deep: true },
-      );
+  async function loadData(selectedOptions: Option[]) {
+    const targetOption = selectedOptions[selectedOptions.length - 1];
+    targetOption.loading = true;
 
-      function handleChange(keys, args) {
-        emitData.value = args;
-        emit('defaultChange', keys, args);
+    const api = props.api;
+    if (!api || !isFunction(api)) return;
+    try {
+      const res = await api({
+        [props.apiParamKey]: Reflect.get(targetOption, 'value'),
+      });
+      if (Array.isArray(res)) {
+        const children = generatorOptions(res);
+        targetOption.children = children;
+        return;
       }
-
-      function handleRenderDisplay({ labels, selectedOptions }) {
-        if (unref(emitData).length === selectedOptions.length) {
-          return labels.join(' / ');
-        }
-        if (props.displayRenderArray) {
-          return props.displayRenderArray.join(' / ');
-        }
-        return '';
+      if (props.resultField) {
+        const children = generatorOptions(get(res, props.resultField) || []);
+        targetOption.children = children;
       }
+    } catch (e) {
+      console.error(e);
+    } finally {
+      targetOption.loading = false;
+    }
+  }
 
-      return {
-        state,
-        options,
-        loading,
-        t,
-        handleChange,
-        loadData,
-        handleRenderDisplay,
-      };
-    },
+  watchEffect(() => {
+    props.immediate && initialFetch();
   });
+
+  watch(
+    () => props.initFetchParams,
+    () => {
+      !unref(isFirstLoad) && initialFetch();
+    },
+    { deep: true },
+  );
+
+  function handleChange(keys, args) {
+    emitData.value = args;
+    emit('defaultChange', keys, args);
+  }
+
+  function handleRenderDisplay({ labels, selectedOptions }) {
+    if (unref(emitData).length === selectedOptions.length) {
+      return labels.join(' / ');
+    }
+    if (props.displayRenderArray) {
+      return props.displayRenderArray.join(' / ');
+    }
+    return '';
+  }
 </script>

+ 92 - 102
src/components/Form/src/components/ApiRadioGroup.vue

@@ -2,135 +2,125 @@
  * @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
 -->
 <template>
-  <RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
+  <Radio.Group v-bind="attrs" v-model:value="state" button-style="solid">
     <template v-for="item in getOptions" :key="`${item.value}`">
-      <RadioButton
+      <Radio.Button
         v-if="props.isBtn"
         :value="item.value"
         :disabled="item.disabled"
         @click="handleClick(item)"
       >
         {{ item.label }}
-      </RadioButton>
+      </Radio.Button>
       <Radio v-else :value="item.value" :disabled="item.disabled" @click="handleClick(item)">
         {{ item.label }}
       </Radio>
     </template>
-  </RadioGroup>
+  </Radio.Group>
 </template>
-<script lang="ts">
-  import { defineComponent, type PropType, ref, watchEffect, computed, unref, watch } from 'vue';
+<script lang="ts" setup>
+  import { type PropType, ref, watchEffect, computed, unref, watch } from 'vue';
   import { Radio } from 'ant-design-vue';
-  import { isFunction } from '/@/utils/is';
-  import { useRuleFormItem } from '/@/hooks/component/useFormItem';
+  import { isFunction } from '@/utils/is';
+  import { useRuleFormItem } from '@/hooks/component/useFormItem';
   import { useAttrs } from '@vben/hooks';
-  import { propTypes } from '/@/utils/propTypes';
+  import { propTypes } from '@/utils/propTypes';
   import { get, omit } from 'lodash-es';
-  import { useI18n } from '/@/hooks/web/useI18n';
 
   type OptionsItem = { label: string; value: string | number | boolean; disabled?: boolean };
 
-  export default defineComponent({
-    name: 'ApiRadioGroup',
-    components: {
-      RadioGroup: Radio.Group,
-      RadioButton: Radio.Button,
-      Radio,
+  defineOptions({ name: 'ApiRadioGroup' });
+
+  const props = defineProps({
+    api: {
+      type: Function as PropType<(arg?: any | string) => Promise<OptionsItem[]>>,
+      default: null,
     },
-    props: {
-      api: {
-        type: Function as PropType<(arg?: any | string) => Promise<OptionsItem[]>>,
-        default: null,
-      },
-      params: {
-        type: [Object, String] as PropType<any | string>,
-        default: () => ({}),
-      },
-      value: {
-        type: [String, Number, Boolean] as PropType<string | number | boolean>,
-      },
-      isBtn: {
-        type: [Boolean] as PropType<boolean>,
-        default: false,
-      },
-      numberToString: propTypes.bool,
-      resultField: propTypes.string.def(''),
-      labelField: propTypes.string.def('label'),
-      valueField: propTypes.string.def('value'),
-      immediate: propTypes.bool.def(true),
+    params: {
+      type: [Object, String] as PropType<any | string>,
+      default: () => ({}),
     },
-    emits: ['options-change', 'change'],
-    setup(props, { emit }) {
-      const options = ref<OptionsItem[]>([]);
-      const loading = ref(false);
-      const isFirstLoad = ref(true);
-      const emitData = ref<any[]>([]);
-      const attrs = useAttrs();
-      const { t } = useI18n();
-      // Embedded in the form, just use the hook binding to perform form verification
-      const [state] = useRuleFormItem(props, 'value', 'change', emitData);
-
-      // Processing options value
-      const getOptions = computed(() => {
-        const { labelField, valueField, numberToString } = props;
+    value: {
+      type: [String, Number, Boolean] as PropType<string | number | boolean>,
+    },
+    isBtn: {
+      type: [Boolean] as PropType<boolean>,
+      default: false,
+    },
+    numberToString: propTypes.bool,
+    resultField: propTypes.string.def(''),
+    labelField: propTypes.string.def('label'),
+    valueField: propTypes.string.def('value'),
+    immediate: propTypes.bool.def(true),
+  });
 
-        return unref(options).reduce((prev, next: any) => {
-          if (next) {
-            const value = next[valueField];
-            prev.push({
-              label: next[labelField],
-              value: numberToString ? `${value}` : value,
-              ...omit(next, [labelField, valueField]),
-            });
-          }
-          return prev;
-        }, [] as OptionsItem[]);
-      });
+  const emit = defineEmits(['options-change', 'change']);
 
-      watchEffect(() => {
-        props.immediate && fetch();
-      });
+  const options = ref<OptionsItem[]>([]);
+  const loading = ref(false);
+  const isFirstLoad = ref(true);
+  const emitData = ref<any[]>([]);
+  const attrs = useAttrs();
+  // Embedded in the form, just use the hook binding to perform form verification
+  const [state] = useRuleFormItem(props, 'value', 'change', emitData);
 
-      watch(
-        () => props.params,
-        () => {
-          !unref(isFirstLoad) && fetch();
-        },
-        { deep: true },
-      );
+  // Processing options value
+  const getOptions = computed(() => {
+    const { labelField, valueField, numberToString } = props;
 
-      async function fetch() {
-        const api = props.api;
-        if (!api || !isFunction(api)) return;
-        options.value = [];
-        try {
-          loading.value = true;
-          const res = await api(props.params);
-          if (Array.isArray(res)) {
-            options.value = res;
-            emitChange();
-            return;
-          }
-          if (props.resultField) {
-            options.value = get(res, props.resultField) || [];
-          }
-          emitChange();
-        } catch (error) {
-          console.warn(error);
-        } finally {
-          loading.value = false;
-        }
+    return unref(options).reduce((prev, next: any) => {
+      if (next) {
+        const value = next[valueField];
+        prev.push({
+          label: next[labelField],
+          value: numberToString ? `${value}` : value,
+          ...omit(next, [labelField, valueField]),
+        });
       }
+      return prev;
+    }, [] as OptionsItem[]);
+  });
 
-      function emitChange() {
-        emit('options-change', unref(getOptions));
-      }
+  watchEffect(() => {
+    props.immediate && fetch();
+  });
+
+  watch(
+    () => props.params,
+    () => {
+      !unref(isFirstLoad) && fetch();
+    },
+    { deep: true },
+  );
 
-      function handleClick(...args) {
-        emitData.value = args;
+  async function fetch() {
+    const api = props.api;
+    if (!api || !isFunction(api)) return;
+    options.value = [];
+    try {
+      loading.value = true;
+      const res = await api(props.params);
+      if (Array.isArray(res)) {
+        options.value = res;
+        emitChange();
+        return;
+      }
+      if (props.resultField) {
+        options.value = get(res, props.resultField) || [];
       }
+      emitChange();
+    } catch (error) {
+      console.warn(error);
+    } finally {
+      loading.value = false;
+    }
+  }
 
-      return { state, getOptions, attrs, loading, t, handleClick, props };
-    },
-  });
+  function emitChange() {
+    emit('options-change', unref(getOptions));
+  }
+
+  function handleClick(...args) {
+    emitData.value = args;
+  }
 </script>

+ 102 - 111
src/components/Form/src/components/ApiSelect.vue

@@ -20,137 +20,128 @@
     </template>
   </Select>
 </template>
-<script lang="ts">
-  import { defineComponent, PropType, ref, computed, unref, watch } from 'vue';
+<script lang="ts" setup>
+  import { PropType, ref, computed, unref, watch } from 'vue';
   import { Select } from 'ant-design-vue';
   import type { SelectValue } from 'ant-design-vue/es/select';
-  import { isFunction } from '/@/utils/is';
-  import { useRuleFormItem } from '/@/hooks/component/useFormItem';
-  import { useAttrs } from '@vben/hooks';
+  import { isFunction } from '@/utils/is';
+  import { useRuleFormItem } from '@/hooks/component/useFormItem';
   import { get, omit } from 'lodash-es';
   import { LoadingOutlined } from '@ant-design/icons-vue';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { propTypes } from '/@/utils/propTypes';
+  import { useI18n } from '@/hooks/web/useI18n';
+  import { propTypes } from '@/utils/propTypes';
 
   type OptionsItem = { label?: string; value?: string; disabled?: boolean; [name: string]: any };
 
-  export default defineComponent({
-    name: 'ApiSelect',
-    components: {
-      Select,
-      LoadingOutlined,
+  defineOptions({ name: 'ApiSelect', inheritAttrs: false });
+
+  const props = defineProps({
+    value: { type: [Array, Object, String, Number] as PropType<SelectValue> },
+    numberToString: propTypes.bool,
+    api: {
+      type: Function as PropType<(arg?: any) => Promise<OptionsItem[]>>,
+      default: null,
     },
-    inheritAttrs: false,
-    props: {
-      value: { type: [Array, Object, String, Number] as PropType<SelectValue> },
-      numberToString: propTypes.bool,
-      api: {
-        type: Function as PropType<(arg?: any) => Promise<OptionsItem[]>>,
-        default: null,
-      },
-      // api params
-      params: propTypes.any.def({}),
-      // support xxx.xxx.xx
-      resultField: propTypes.string.def(''),
-      labelField: propTypes.string.def('label'),
-      valueField: propTypes.string.def('value'),
-      immediate: propTypes.bool.def(true),
-      alwaysLoad: propTypes.bool.def(false),
-      options: {
-        type: Array<OptionsItem>,
-        default: [],
-      },
+    // api params
+    params: propTypes.any.def({}),
+    // support xxx.xxx.xx
+    resultField: propTypes.string.def(''),
+    labelField: propTypes.string.def('label'),
+    valueField: propTypes.string.def('value'),
+    immediate: propTypes.bool.def(true),
+    alwaysLoad: propTypes.bool.def(false),
+    options: {
+      type: Array<OptionsItem>,
+      default: [],
     },
-    emits: ['options-change', 'change', 'update:value'],
-    setup(props, { emit }) {
-      const options = ref<OptionsItem[]>([]);
-      const loading = ref(false);
-      // 首次是否加载过了
-      const isFirstLoaded = ref(false);
-      const emitData = ref<OptionsItem[]>([]);
-      const attrs = useAttrs();
-      const { t } = useI18n();
+  });
 
-      // Embedded in the form, just use the hook binding to perform form verification
-      const [state] = useRuleFormItem(props, 'value', 'change', emitData);
+  const emit = defineEmits(['options-change', 'change', 'update:value']);
 
-      const getOptions = computed(() => {
-        const { labelField, valueField, numberToString } = props;
+  const optionsRef = ref<OptionsItem[]>([]);
 
-        let data = unref(options).reduce((prev, next: any) => {
-          if (next) {
-            const value = get(next, valueField);
-            prev.push({
-              ...omit(next, [labelField, valueField]),
-              label: get(next, labelField),
-              value: numberToString ? `${value}` : value,
-            });
-          }
-          return prev;
-        }, [] as OptionsItem[]);
-        return data.length > 0 ? data : props.options;
-      });
+  const loading = ref(false);
+  // 首次是否加载过了
+  const isFirstLoaded = ref(false);
+  const emitData = ref<OptionsItem[]>([]);
+  const { t } = useI18n();
 
-      watch(
-        () => state.value,
-        (v) => {
-          emit('update:value', v);
-        },
-      );
+  // Embedded in the form, just use the hook binding to perform form verification
+  const [state] = useRuleFormItem(props, 'value', 'change', emitData);
 
-      watch(
-        () => props.params,
-        () => {
-          !unref(isFirstLoaded) && fetch();
-        },
-        { deep: true, immediate: props.immediate },
-      );
+  const getOptions = computed(() => {
+    const { labelField, valueField, numberToString } = props;
 
-      async function fetch() {
-        const api = props.api;
-        if (!api || !isFunction(api) || loading.value) return;
-        options.value = [];
-        try {
-          loading.value = true;
-          const res = await api(props.params);
-          isFirstLoaded.value = true;
-          if (Array.isArray(res)) {
-            options.value = res;
-            emitChange();
-            return;
-          }
-          if (props.resultField) {
-            options.value = get(res, props.resultField) || [];
-          }
-          emitChange();
-        } catch (error) {
-          console.warn(error);
-        } finally {
-          loading.value = false;
-          // reset status
-          isFirstLoaded.value = false;
-        }
+    let data = unref(optionsRef).reduce((prev, next: any) => {
+      if (next) {
+        const value = get(next, valueField);
+        prev.push({
+          ...omit(next, [labelField, valueField]),
+          label: get(next, labelField),
+          value: numberToString ? `${value}` : value,
+        });
       }
+      return prev;
+    }, [] as OptionsItem[]);
+    return data.length > 0 ? data : props.options;
+  });
 
-      async function handleFetch(visible: boolean) {
-        if (visible) {
-          if (props.alwaysLoad) {
-            await fetch();
-          } else if (!props.immediate && !unref(isFirstLoaded)) {
-            await fetch();
-          }
-        }
-      }
+  watch(
+    () => state.value,
+    (v) => {
+      emit('update:value', v);
+    },
+  );
 
-      function emitChange() {
-        emit('options-change', unref(getOptions));
+  watch(
+    () => props.params,
+    () => {
+      !unref(isFirstLoaded) && fetch();
+    },
+    { deep: true, immediate: props.immediate },
+  );
+
+  async function fetch() {
+    const api = props.api;
+    if (!api || !isFunction(api) || loading.value) return;
+    optionsRef.value = [];
+    try {
+      loading.value = true;
+      const res = await api(props.params);
+      isFirstLoaded.value = true;
+      if (Array.isArray(res)) {
+        optionsRef.value = res;
+        emitChange();
+        return;
+      }
+      if (props.resultField) {
+        optionsRef.value = get(res, props.resultField) || [];
       }
+      emitChange();
+    } catch (error) {
+      console.warn(error);
+    } finally {
+      loading.value = false;
+      // reset status
+      isFirstLoaded.value = false;
+    }
+  }
 
-      function handleChange(_, ...args) {
-        emitData.value = args;
+  async function handleFetch(visible: boolean) {
+    if (visible) {
+      if (props.alwaysLoad) {
+        await fetch();
+      } else if (!props.immediate && !unref(isFirstLoaded)) {
+        await fetch();
       }
+    }
+  }
 
-      return { state, attrs, getOptions, loading, t, handleFetch, handleChange };
-    },
-  });
+  function emitChange() {
+    emit('options-change', unref(getOptions));
+  }
+
+  function handleChange(_, ...args) {
+    emitData.value = args;
+  }
 </script>

+ 97 - 108
src/components/Form/src/components/ApiTransfer.vue

@@ -12,127 +12,116 @@
   />
 </template>
 
-<script lang="ts">
-  import { computed, defineComponent, watch, ref, unref, watchEffect, PropType } from 'vue';
+<script lang="ts" setup>
+  import { computed, watch, ref, unref, watchEffect, PropType } from 'vue';
   import { Transfer } from 'ant-design-vue';
-  import { isFunction } from '/@/utils/is';
+  import { isFunction } from '@/utils/is';
   import { get, omit } from 'lodash-es';
-  import { propTypes } from '/@/utils/propTypes';
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { propTypes } from '@/utils/propTypes';
   import { TransferDirection, TransferItem } from 'ant-design-vue/lib/transfer';
 
-  export default defineComponent({
-    name: 'ApiTransfer',
-    components: { Transfer },
-    props: {
-      value: { type: Array as PropType<Array<string>> },
-      api: {
-        type: Function as PropType<(arg) => Promise<TransferItem[]>>,
-        default: null,
-      },
-      params: { type: Object },
-      dataSource: { type: Array as PropType<Array<TransferItem>> },
-      immediate: propTypes.bool.def(true),
-      alwaysLoad: propTypes.bool.def(false),
-      afterFetch: { type: Function },
-      resultField: propTypes.string.def(''),
-      labelField: propTypes.string.def('title'),
-      valueField: propTypes.string.def('key'),
-      showSearch: { type: Boolean, default: false },
-      disabled: { type: Boolean, default: false },
-      filterOption: {
-        type: Function as PropType<(inputValue: string, item: TransferItem) => boolean>,
-      },
-      selectedKeys: { type: Array as PropType<Array<string>> },
-      showSelectAll: { type: Boolean, default: false },
-      targetKeys: { type: Array as PropType<Array<string>> },
+  defineOptions({ name: 'ApiTransfer' });
+
+  const props = defineProps({
+    value: { type: Array as PropType<Array<string>> },
+    api: {
+      type: Function as PropType<(arg) => Promise<TransferItem[]>>,
+      default: null,
+    },
+    params: { type: Object },
+    dataSource: { type: Array as PropType<Array<TransferItem>> },
+    immediate: propTypes.bool.def(true),
+    alwaysLoad: propTypes.bool.def(false),
+    afterFetch: { type: Function },
+    resultField: propTypes.string.def(''),
+    labelField: propTypes.string.def('title'),
+    valueField: propTypes.string.def('key'),
+    showSearch: { type: Boolean, default: false },
+    disabled: { type: Boolean, default: false },
+    filterOption: {
+      type: Function as PropType<(inputValue: string, item: TransferItem) => boolean>,
     },
-    emits: ['options-change', 'change'],
-    setup(props, { attrs, emit }) {
-      const _dataSource = ref<TransferItem[]>([]);
-      const _targetKeys = ref<string[]>([]);
-      const { t } = useI18n();
+    selectedKeys: { type: Array as PropType<Array<string>> },
+    showSelectAll: { type: Boolean, default: false },
+    targetKeys: { type: Array as PropType<Array<string>> },
+  });
+
+  const emit = defineEmits(['options-change', 'change']);
 
-      const getAttrs = computed(() => {
-        return {
-          ...(!props.api ? { dataSource: unref(_dataSource) } : {}),
-          ...attrs,
-        };
-      });
-      const getdataSource = computed(() => {
-        const { labelField, valueField } = props;
+  const _dataSource = ref<TransferItem[]>([]);
+  const _targetKeys = ref<string[]>([]);
 
-        return unref(_dataSource).reduce((prev, next) => {
-          if (next) {
-            prev.push({
-              ...omit(next, [labelField, valueField]),
-              title: next[labelField],
-              key: next[valueField],
-            });
-          }
-          return prev;
-        }, [] as TransferItem[]);
-      });
-      const getTargetKeys = computed<string[]>(() => {
-        /* if (unref(_targetKeys).length > 0) {
+  const getdataSource = computed(() => {
+    const { labelField, valueField } = props;
+
+    return unref(_dataSource).reduce((prev, next) => {
+      if (next) {
+        prev.push({
+          ...omit(next, [labelField, valueField]),
+          title: next[labelField],
+          key: next[valueField],
+        });
+      }
+      return prev;
+    }, [] as TransferItem[]);
+  });
+  const getTargetKeys = computed<string[]>(() => {
+    /* if (unref(_targetKeys).length > 0) {
           return unref(_targetKeys);
         } */
-        if (Array.isArray(props.value)) {
-          return props.value;
-        }
-        if (Array.isArray(props.targetKeys)) {
-          return props.targetKeys;
-        }
-        return [];
-      });
+    if (Array.isArray(props.value)) {
+      return props.value;
+    }
+    if (Array.isArray(props.targetKeys)) {
+      return props.targetKeys;
+    }
+    return [];
+  });
 
-      function handleChange(keys: string[], direction: TransferDirection, moveKeys: string[]) {
-        _targetKeys.value = keys;
-        console.log(direction);
-        console.log(moveKeys);
-        emit('change', keys);
-      }
+  function handleChange(keys: string[], direction: TransferDirection, moveKeys: string[]) {
+    _targetKeys.value = keys;
+    console.log(direction);
+    console.log(moveKeys);
+    emit('change', keys);
+  }
 
-      watchEffect(() => {
-        props.immediate && !props.alwaysLoad && fetch();
-      });
+  watchEffect(() => {
+    props.immediate && !props.alwaysLoad && fetch();
+  });
 
-      watch(
-        () => props.params,
-        () => {
-          fetch();
-        },
-        { deep: true },
-      );
+  watch(
+    () => props.params,
+    () => {
+      fetch();
+    },
+    { deep: true },
+  );
 
-      async function fetch() {
-        const api = props.api;
-        if (!api || !isFunction(api)) {
-          if (Array.isArray(props.dataSource)) {
-            _dataSource.value = props.dataSource;
-          }
-          return;
-        }
-        _dataSource.value = [];
-        try {
-          const res = await api(props.params);
-          if (Array.isArray(res)) {
-            _dataSource.value = res;
-            emitChange();
-            return;
-          }
-          if (props.resultField) {
-            _dataSource.value = get(res, props.resultField) || [];
-          }
-          emitChange();
-        } catch (error) {
-          console.warn(error);
-        }
+  async function fetch() {
+    const api = props.api;
+    if (!api || !isFunction(api)) {
+      if (Array.isArray(props.dataSource)) {
+        _dataSource.value = props.dataSource;
       }
-      function emitChange() {
-        emit('options-change', unref(getdataSource));
+      return;
+    }
+    _dataSource.value = [];
+    try {
+      const res = await api(props.params);
+      if (Array.isArray(res)) {
+        _dataSource.value = res;
+        emitChange();
+        return;
       }
-      return { getTargetKeys, getdataSource, t, getAttrs, handleChange };
-    },
-  });
+      if (props.resultField) {
+        _dataSource.value = get(res, props.resultField) || [];
+      }
+      emitChange();
+    } catch (error) {
+      console.warn(error);
+    }
+  }
+  function emitChange() {
+    emit('options-change', unref(getdataSource));
+  }
 </script>

+ 76 - 78
src/components/Form/src/components/ApiTree.vue

@@ -1,99 +1,97 @@
 <template>
-  <a-tree v-bind="getAttrs" v-model:selectedKeys="state">
+  <Tree v-bind="getAttrs" v-model:selectedKeys="state">
     <template #[item]="data" v-for="item in Object.keys($slots)">
       <slot :name="item" v-bind="data || {}"></slot>
     </template>
-  </a-tree>
+  </Tree>
 </template>
 
-<script lang="ts">
+<script lang="ts" setup>
   import { type Recordable, type AnyFunction } from '@vben/types';
-  import { type PropType, computed, defineComponent, watch, ref, onMounted, unref } from 'vue';
+  import { type PropType, computed, watch, ref, onMounted, unref, useAttrs } from 'vue';
   import { Tree, TreeProps } from 'ant-design-vue';
-  import { isArray, isFunction } from '/@/utils/is';
+  import { isArray, isFunction } from '@/utils/is';
   import { get } from 'lodash-es';
-  import { propTypes } from '/@/utils/propTypes';
   import { DataNode } from 'ant-design-vue/es/tree';
-  import { useRuleFormItem } from '/@/hooks/component/useFormItem';
+  import { useRuleFormItem } from '@/hooks/component/useFormItem';
 
-  export default defineComponent({
-    name: 'ApiTree',
-    components: { ATree: Tree },
-    props: {
-      api: { type: Function as PropType<(arg?: Recordable<any>) => Promise<Recordable<any>>> },
-      params: { type: Object },
-      immediate: { type: Boolean, default: true },
-      resultField: propTypes.string.def(''),
-      afterFetch: { type: Function as PropType<AnyFunction> },
-      value: {
-        type: Array as PropType<TreeProps['selectedKeys']>,
-      },
+  defineOptions({ name: 'ApiTree' });
+
+  const props = defineProps({
+    api: { type: Function as PropType<(arg?: Recordable<any>) => Promise<Recordable<any>>> },
+    params: { type: Object },
+    immediate: { type: Boolean, default: true },
+    resultField: { type: String, default: '' },
+    afterFetch: { type: Function as PropType<AnyFunction> },
+    value: {
+      type: Array as PropType<TreeProps['selectedKeys']>,
     },
-    emits: ['options-change', 'change', 'update:value'],
-    setup(props, { attrs, emit }) {
-      const treeData = ref<DataNode[]>([]);
-      const isFirstLoaded = ref<Boolean>(false);
-      const loading = ref(false);
-      const emitData = ref<any[]>([]);
+  });
 
-      const [state] = useRuleFormItem(props, 'value', 'change', emitData);
-      const getAttrs = computed(() => {
-        return {
-          ...(props.api ? { treeData: unref(treeData) } : {}),
-          ...attrs,
-        };
-      });
+  const emit = defineEmits(['options-change', 'change', 'update:value']);
 
-      watch(
-        () => state.value,
-        (v) => {
-          emit('update:value', v);
-        },
-      );
+  const attrs = useAttrs();
 
-      watch(
-        () => props.params,
-        () => {
-          !unref(isFirstLoaded) && fetch();
-        },
-        { deep: true },
-      );
+  const treeData = ref<DataNode[]>([]);
+  const isFirstLoaded = ref<Boolean>(false);
+  const loading = ref(false);
+  const emitData = ref<any[]>([]);
+
+  const [state] = useRuleFormItem(props, 'value', 'change', emitData);
+  const getAttrs = computed(() => {
+    return {
+      ...(props.api ? { treeData: unref(treeData) } : {}),
+      ...attrs,
+    };
+  });
 
-      watch(
-        () => props.immediate,
-        (v) => {
-          v && !isFirstLoaded.value && fetch();
-        },
-      );
+  watch(
+    () => state.value,
+    (v) => {
+      emit('update:value', v);
+    },
+  );
 
-      onMounted(() => {
-        props.immediate && fetch();
-      });
+  watch(
+    () => props.params,
+    () => {
+      !unref(isFirstLoaded) && fetch();
+    },
+    { deep: true },
+  );
 
-      async function fetch() {
-        const { api, afterFetch } = props;
-        if (!api || !isFunction(api)) return;
-        loading.value = true;
-        treeData.value = [];
-        let result;
-        try {
-          result = await api(props.params);
-        } catch (e) {
-          console.error(e);
-        }
-        if (afterFetch && isFunction(afterFetch)) {
-          result = afterFetch(result);
-        }
-        loading.value = false;
-        if (!result) return;
-        if (!isArray(result)) {
-          result = get(result, props.resultField);
-        }
-        treeData.value = (result as (Recordable & { key: string | number })[]) || [];
-        isFirstLoaded.value = true;
-        emit('options-change', treeData.value);
-      }
-      return { getAttrs, loading, state };
+  watch(
+    () => props.immediate,
+    (v) => {
+      v && !isFirstLoaded.value && fetch();
     },
+  );
+
+  onMounted(() => {
+    props.immediate && fetch();
   });
+
+  async function fetch() {
+    const { api, afterFetch } = props;
+    if (!api || !isFunction(api)) return;
+    loading.value = true;
+    treeData.value = [];
+    let result;
+    try {
+      result = await api(props.params);
+    } catch (e) {
+      console.error(e);
+    }
+    if (afterFetch && isFunction(afterFetch)) {
+      result = afterFetch(result);
+    }
+    loading.value = false;
+    if (!result) return;
+    if (!isArray(result)) {
+      result = get(result, props.resultField);
+    }
+    treeData.value = (result as (Recordable & { key: string | number })[]) || [];
+    isFirstLoaded.value = true;
+    emit('options-change', treeData.value);
+  }
 </script>

+ 82 - 84
src/components/Form/src/components/ApiTreeSelect.vue

@@ -1,5 +1,5 @@
 <template>
-  <a-tree-select
+  <TreeSelect
     v-bind="getAttrs"
     @change="handleChange"
     :field-names="fieldNames"
@@ -11,102 +11,100 @@
     <template #suffixIcon v-if="loading">
       <LoadingOutlined spin />
     </template>
-  </a-tree-select>
+  </TreeSelect>
 </template>
 
-<script lang="ts">
+<script lang="ts" setup>
   import { type Recordable } from '@vben/types';
-  import { type PropType, computed, defineComponent, watch, ref, onMounted, unref } from 'vue';
+  import { type PropType, computed, watch, ref, onMounted, unref, useAttrs } from 'vue';
   import { TreeSelect } from 'ant-design-vue';
-  import { isArray, isFunction } from '/@/utils/is';
+  import { isArray, isFunction } from '@/utils/is';
   import { get } from 'lodash-es';
-  import { propTypes } from '/@/utils/propTypes';
+  import { propTypes } from '@/utils/propTypes';
   import { LoadingOutlined } from '@ant-design/icons-vue';
 
-  export default defineComponent({
-    name: 'ApiTreeSelect',
-    components: { ATreeSelect: TreeSelect, LoadingOutlined },
-    props: {
-      api: { type: Function as PropType<(arg?: Recordable<any>) => Promise<Recordable<any>>> },
-      params: { type: Object },
-      immediate: { type: Boolean, default: true },
-      async: { type: Boolean, default: false },
-      resultField: propTypes.string.def(''),
-      labelField: propTypes.string.def('title'),
-      valueField: propTypes.string.def('value'),
-      childrenField: propTypes.string.def('children'),
-    },
-    emits: ['options-change', 'change', 'load-data'],
-    setup(props, { attrs, emit }) {
-      const treeData = ref<Recordable<any>[]>([]);
-      const isFirstLoaded = ref<Boolean>(false);
-      const loading = ref(false);
-      const getAttrs = computed(() => {
-        return {
-          ...(props.api ? { treeData: unref(treeData) } : {}),
-          ...attrs,
-        };
-      });
-      const fieldNames = {
-        children: props.childrenField,
-        value: props.valueField,
-        label: props.labelField,
-      };
+  defineOptions({ name: 'ApiTreeSelect' });
 
-      function handleChange(...args) {
-        emit('change', ...args);
-      }
+  const props = defineProps({
+    api: { type: Function as PropType<(arg?: Recordable<any>) => Promise<Recordable<any>>> },
+    params: { type: Object },
+    immediate: { type: Boolean, default: true },
+    async: { type: Boolean, default: false },
+    resultField: propTypes.string.def(''),
+    labelField: propTypes.string.def('title'),
+    valueField: propTypes.string.def('value'),
+    childrenField: propTypes.string.def('children'),
+  });
 
-      watch(
-        () => props.params,
-        () => {
-          !unref(isFirstLoaded) && fetch();
-        },
-        { deep: true },
-      );
+  const emit = defineEmits(['options-change', 'change', 'load-data']);
 
-      watch(
-        () => props.immediate,
-        (v) => {
-          v && !isFirstLoaded.value && fetch();
-        },
-      );
+  const attrs = useAttrs();
+  const treeData = ref<Recordable<any>[]>([]);
+  const isFirstLoaded = ref<Boolean>(false);
+  const loading = ref(false);
+  const getAttrs = computed(() => {
+    return {
+      ...(props.api ? { treeData: unref(treeData) } : {}),
+      ...attrs,
+    };
+  });
+  const fieldNames = {
+    children: props.childrenField,
+    value: props.valueField,
+    label: props.labelField,
+  };
 
-      onMounted(() => {
-        props.immediate && fetch();
-      });
+  function handleChange(...args) {
+    emit('change', ...args);
+  }
 
-      function onLoadData(treeNode) {
-        return new Promise((resolve: (value?: unknown) => void) => {
-          if (isArray(treeNode.children) && treeNode.children.length > 0) {
-            resolve();
-            return;
-          }
-          emit('load-data', { treeData, treeNode, resolve });
-        });
-      }
+  watch(
+    () => props.params,
+    () => {
+      !unref(isFirstLoaded) && fetch();
+    },
+    { deep: true },
+  );
 
-      async function fetch() {
-        const { api } = props;
-        if (!api || !isFunction(api) || loading.value) return;
-        loading.value = true;
-        treeData.value = [];
-        let result;
-        try {
-          result = await api(props.params);
-        } catch (e) {
-          console.error(e);
-        }
-        loading.value = false;
-        if (!result) return;
-        if (!isArray(result)) {
-          result = get(result, props.resultField);
-        }
-        treeData.value = (result as Recordable<any>[]) || [];
-        isFirstLoaded.value = true;
-        emit('options-change', treeData.value);
-      }
-      return { getAttrs, loading, handleChange, fieldNames, onLoadData };
+  watch(
+    () => props.immediate,
+    (v) => {
+      v && !isFirstLoaded.value && fetch();
     },
+  );
+
+  onMounted(() => {
+    props.immediate && fetch();
   });
+
+  function onLoadData(treeNode) {
+    return new Promise((resolve: (value?: unknown) => void) => {
+      if (isArray(treeNode.children) && treeNode.children.length > 0) {
+        resolve();
+        return;
+      }
+      emit('load-data', { treeData, treeNode, resolve });
+    });
+  }
+
+  async function fetch() {
+    const { api } = props;
+    if (!api || !isFunction(api) || loading.value) return;
+    loading.value = true;
+    treeData.value = [];
+    let result;
+    try {
+      result = await api(props.params);
+    } catch (e) {
+      console.error(e);
+    }
+    loading.value = false;
+    if (!result) return;
+    if (!isArray(result)) {
+      result = get(result, props.resultField);
+    }
+    treeData.value = (result as Recordable<any>[]) || [];
+    isFirstLoaded.value = true;
+    emit('options-change', treeData.value);
+  }
 </script>

+ 66 - 83
src/components/Form/src/components/FormAction.vue

@@ -1,7 +1,7 @@
 <template>
-  <a-col v-bind="actionColOpt" v-if="showActionButtonGroup">
+  <Col v-bind="actionColOpt" v-if="showActionButtonGroup">
     <div style="width: 100%" :style="{ textAlign: actionColOpt.style.textAlign }">
-      <FormItem>
+      <Form.Item>
         <slot name="resetBefore"></slot>
         <Button
           type="default"
@@ -35,100 +35,83 @@
           <BasicArrow class="ml-1" :expand="!isAdvanced" up />
         </Button>
         <slot name="advanceAfter"></slot>
-      </FormItem>
+      </Form.Item>
     </div>
-  </a-col>
+  </Col>
 </template>
-<script lang="ts">
-  import type { ColEx } from '../types/index';
-  import { defineComponent, computed, PropType } from 'vue';
+<script lang="ts" setup>
+  import type { ColEx } from '../types';
+  import { computed, PropType } from 'vue';
   import { Form, Col } from 'ant-design-vue';
-  import { Button, ButtonProps } from '/@/components/Button';
-  import { BasicArrow } from '/@/components/Basic';
+  import { Button, ButtonProps } from '@/components/Button';
+  import { BasicArrow } from '@/components/Basic';
   import { useFormContext } from '../hooks/useFormContext';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { propTypes } from '/@/utils/propTypes';
+  import { useI18n } from '@/hooks/web/useI18n';
+  import { propTypes } from '@/utils/propTypes';
 
   type ButtonOptions = Partial<ButtonProps> & { text: string };
 
-  export default defineComponent({
-    name: 'BasicFormAction',
-    components: {
-      FormItem: Form.Item,
-      Button,
-      BasicArrow,
-      [Col.name]: Col,
+  defineOptions({ name: 'BasicFormAction' });
+
+  const props = defineProps({
+    showActionButtonGroup: propTypes.bool.def(true),
+    showResetButton: propTypes.bool.def(true),
+    showSubmitButton: propTypes.bool.def(true),
+    showAdvancedButton: propTypes.bool.def(true),
+    resetButtonOptions: {
+      type: Object as PropType<ButtonOptions>,
+      default: () => ({}),
     },
-    props: {
-      showActionButtonGroup: propTypes.bool.def(true),
-      showResetButton: propTypes.bool.def(true),
-      showSubmitButton: propTypes.bool.def(true),
-      showAdvancedButton: propTypes.bool.def(true),
-      resetButtonOptions: {
-        type: Object as PropType<ButtonOptions>,
-        default: () => ({}),
-      },
-      submitButtonOptions: {
-        type: Object as PropType<ButtonOptions>,
-        default: () => ({}),
-      },
-      actionColOptions: {
-        type: Object as PropType<Partial<ColEx>>,
-        default: () => ({}),
-      },
-      actionSpan: propTypes.number.def(6),
-      isAdvanced: propTypes.bool,
-      hideAdvanceBtn: propTypes.bool,
+    submitButtonOptions: {
+      type: Object as PropType<ButtonOptions>,
+      default: () => ({}),
+    },
+    actionColOptions: {
+      type: Object as PropType<Partial<ColEx>>,
+      default: () => ({}),
     },
-    emits: ['toggle-advanced'],
-    setup(props, { emit }) {
-      const { t } = useI18n();
+    actionSpan: propTypes.number.def(6),
+    isAdvanced: propTypes.bool,
+    hideAdvanceBtn: propTypes.bool,
+  });
 
-      const actionColOpt = computed(() => {
-        const { showAdvancedButton, actionSpan: span, actionColOptions } = props;
-        const actionSpan = 24 - span;
-        const advancedSpanObj = showAdvancedButton
-          ? { span: actionSpan < 6 ? 24 : actionSpan }
-          : {};
-        const actionColOpt: Partial<ColEx> = {
-          style: { textAlign: 'right' },
-          span: showAdvancedButton ? 6 : 4,
-          ...advancedSpanObj,
-          ...actionColOptions,
-        };
-        return actionColOpt;
-      });
+  const emit = defineEmits(['toggle-advanced']);
 
-      const getResetBtnOptions = computed((): ButtonOptions => {
-        return Object.assign(
-          {
-            text: t('common.resetText'),
-          },
-          props.resetButtonOptions,
-        );
-      });
+  const { t } = useI18n();
+  const { resetAction, submitAction } = useFormContext();
 
-      const getSubmitBtnOptions = computed(() => {
-        return Object.assign(
-          {
-            text: t('common.queryText'),
-          },
-          props.submitButtonOptions,
-        );
-      });
+  const actionColOpt = computed(() => {
+    const { showAdvancedButton, actionSpan: span, actionColOptions } = props;
+    const actionSpan = 24 - span;
+    const advancedSpanObj = showAdvancedButton ? { span: actionSpan < 6 ? 24 : actionSpan } : {};
+    const actionColOpt: Partial<ColEx> = {
+      style: { textAlign: 'right' },
+      span: showAdvancedButton ? 6 : 4,
+      ...advancedSpanObj,
+      ...actionColOptions,
+    };
+    return actionColOpt;
+  });
 
-      function toggleAdvanced() {
-        emit('toggle-advanced');
-      }
+  const getResetBtnOptions = computed((): ButtonOptions => {
+    return Object.assign(
+      {
+        text: t('common.resetText'),
+      },
+      props.resetButtonOptions,
+    );
+  });
 
-      return {
-        t,
-        actionColOpt,
-        getResetBtnOptions,
-        getSubmitBtnOptions,
-        toggleAdvanced,
-        ...useFormContext(),
-      };
-    },
+  const getSubmitBtnOptions = computed(() => {
+    return Object.assign(
+      {
+        text: t('common.queryText'),
+      },
+      props.submitButtonOptions,
+    );
   });
+
+  function toggleAdvanced() {
+    emit('toggle-advanced');
+  }
 </script>

+ 5 - 5
src/components/Form/src/components/FormItem.vue

@@ -9,12 +9,12 @@
     type FormSchemaInner as FormSchema,
   } from '../types/form';
   import type { Rule as ValidationRule } from 'ant-design-vue/lib/form/interface';
-  import type { TableActionType } from '/@/components/Table';
+  import type { TableActionType } from '@/components/Table';
   import { Col, Divider, Form } from 'ant-design-vue';
   import { componentMap } from '../componentMap';
-  import { BasicHelp } from '/@/components/Basic';
-  import { isBoolean, isFunction, isNull } from '/@/utils/is';
-  import { getSlot } from '/@/utils/helper/tsxHelper';
+  import { BasicHelp } from '@/components/Basic';
+  import { isBoolean, isFunction, isNull } from '@/utils/is';
+  import { getSlot } from '@/utils/helper/tsxHelper';
   import {
     createPlaceholderMessage,
     NO_AUTO_LINK_COMPONENTS,
@@ -22,7 +22,7 @@
   } from '../helper';
   import { cloneDeep, upperFirst } from 'lodash-es';
   import { useItemLabelWidth } from '../hooks/useLabelWidth';
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useI18n } from '@/hooks/web/useI18n';
 
   export default defineComponent({
     name: 'BasicFormItem',

+ 33 - 40
src/components/Form/src/components/RadioButtonGroup.vue

@@ -2,62 +2,55 @@
  * @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
 -->
 <template>
-  <RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
+  <Radio.Group v-bind="attrs" v-model:value="state" button-style="solid">
     <template v-for="item in getOptions" :key="`${item.value}`">
-      <RadioButton :value="item.value" :disabled="item.disabled" @click="handleClick(item)">
+      <Radio.Button :value="item.value" :disabled="item.disabled" @click="handleClick(item)">
         {{ item.label }}
-      </RadioButton>
+      </Radio.Button>
     </template>
-  </RadioGroup>
+  </Radio.Group>
 </template>
-<script lang="ts">
-  import { defineComponent, PropType, computed, ref } from 'vue';
+<script lang="ts" setup>
+  import { PropType, computed, ref } from 'vue';
   import { Radio } from 'ant-design-vue';
-  import { isString } from '/@/utils/is';
-  import { useRuleFormItem } from '/@/hooks/component/useFormItem';
+  import { isString } from '@/utils/is';
+  import { useRuleFormItem } from '@/hooks/component/useFormItem';
   import { useAttrs } from '@vben/hooks';
 
   type OptionsItem = { label: string; value: string | number | boolean; disabled?: boolean };
   type RadioItem = string | OptionsItem;
 
-  export default defineComponent({
-    name: 'RadioButtonGroup',
-    components: {
-      RadioGroup: Radio.Group,
-      RadioButton: Radio.Button,
+  defineOptions({ name: 'RadioButtonGroup' });
+
+  const props = defineProps({
+    value: {
+      type: [String, Number, Boolean] as PropType<string | number | boolean>,
     },
-    props: {
-      value: {
-        type: [String, Number, Boolean] as PropType<string | number | boolean>,
-      },
-      options: {
-        type: Array as PropType<RadioItem[]>,
-        default: () => [],
-      },
+    options: {
+      type: Array as PropType<RadioItem[]>,
+      default: () => [],
     },
-    emits: ['change'],
-    setup(props) {
-      const attrs = useAttrs();
-      const emitData = ref<any[]>([]);
-      // Embedded in the form, just use the hook binding to perform form verification
-      const [state] = useRuleFormItem(props, 'value', 'change', emitData);
+  });
 
-      // Processing options value
-      const getOptions = computed((): OptionsItem[] => {
-        const { options } = props;
-        if (!options || options?.length === 0) return [];
+  // const emit = defineEmits(['change']);
 
-        const isStringArr = options.some((item) => isString(item));
-        if (!isStringArr) return options as OptionsItem[];
+  const attrs = useAttrs();
+  const emitData = ref<any[]>([]);
+  // Embedded in the form, just use the hook binding to perform form verification
+  const [state] = useRuleFormItem(props, 'value', 'change', emitData);
 
-        return options.map((item) => ({ label: item, value: item })) as OptionsItem[];
-      });
+  // Processing options value
+  const getOptions = computed((): OptionsItem[] => {
+    const { options } = props;
+    if (!options || options?.length === 0) return [];
 
-      function handleClick(...args) {
-        emitData.value = args;
-      }
+    const isStringArr = options.some((item) => isString(item));
+    if (!isStringArr) return options as OptionsItem[];
 
-      return { state, getOptions, attrs, handleClick };
-    },
+    return options.map((item) => ({ label: item, value: item })) as OptionsItem[];
   });
+
+  function handleClick(...args) {
+    emitData.value = args;
+  }
 </script>

+ 4 - 4
src/components/Form/src/helper.ts

@@ -1,8 +1,8 @@
 import type { Rule as ValidationRule } from 'ant-design-vue/lib/form/interface';
-import type { ComponentType } from './types/index';
-import { useI18n } from '/@/hooks/web/useI18n';
-import { dateUtil } from '/@/utils/dateUtil';
-import { isNumber, isObject } from '/@/utils/is';
+import type { ComponentType } from './types';
+import { useI18n } from '@/hooks/web/useI18n';
+import { dateUtil } from '@/utils/dateUtil';
+import { isNumber, isObject } from '@/utils/is';
 
 const { t } = useI18n();
 

+ 2 - 2
src/components/Form/src/hooks/useAdvanced.ts

@@ -2,8 +2,8 @@ import type { ColEx } from '../types';
 import type { AdvanceState } from '../types/hooks';
 import { ComputedRef, getCurrentInstance, Ref, shallowReactive, computed, unref, watch } from 'vue';
 import type { FormProps, FormSchemaInner as FormSchema } from '../types/form';
-import { isBoolean, isFunction, isNumber, isObject } from '/@/utils/is';
-import { useBreakpoint } from '/@/hooks/event/useBreakpoint';
+import { isBoolean, isFunction, isNumber, isObject } from '@/utils/is';
+import { useBreakpoint } from '@/hooks/event/useBreakpoint';
 import { useDebounceFn } from '@vueuse/core';
 
 const BASIC_COL_LEN = 24;

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

@@ -1,4 +1,4 @@
-import type { ComponentType } from '../types/index';
+import type { ComponentType } from '../types';
 import { tryOnUnmounted } from '@vueuse/core';
 import { add, del } from '../componentMap';
 import type { Component } from 'vue';

+ 3 - 3
src/components/Form/src/hooks/useForm.ts

@@ -7,9 +7,9 @@ import type {
 import type { NamePath } from 'ant-design-vue/lib/form/interface';
 import type { DynamicProps } from '/#/utils';
 import { ref, onUnmounted, unref, nextTick, watch } from 'vue';
-import { isProdMode } from '/@/utils/env';
-import { error } from '/@/utils/log';
-import { getDynamicProps } from '/@/utils';
+import { isProdMode } from '@/utils/env';
+import { error } from '@/utils/log';
+import { getDynamicProps } from '@/utils';
 
 export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>;
 

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

@@ -1,5 +1,5 @@
 import type { InjectionKey } from 'vue';
-import { createContext, useContext } from '/@/hooks/core/useContext';
+import { createContext, useContext } from '@/hooks/core/useContext';
 
 export interface FormContextProps {
   resetAction: () => Promise<void>;

+ 4 - 4
src/components/Form/src/hooks/useFormEvents.ts

@@ -2,12 +2,12 @@ import type { ComputedRef, Ref } from 'vue';
 import type { FormProps, FormSchemaInner as FormSchema, FormActionType } from '../types/form';
 import type { NamePath } from 'ant-design-vue/lib/form/interface';
 import { unref, toRaw, nextTick } from 'vue';
-import { isArray, isFunction, isObject, isString, isDef, isNil } from '/@/utils/is';
-import { deepMerge } from '/@/utils';
+import { isArray, isFunction, isObject, isString, isDef, isNil } from '@/utils/is';
+import { deepMerge } from '@/utils';
 import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper';
-import { dateUtil } from '/@/utils/dateUtil';
+import { dateUtil } from '@/utils/dateUtil';
 import { cloneDeep, set, uniqBy, get } from 'lodash-es';
-import { error } from '/@/utils/log';
+import { error } from '@/utils/log';
 
 interface UseFormActionContext {
   emit: EmitType;

+ 2 - 2
src/components/Form/src/hooks/useFormValues.ts

@@ -1,5 +1,5 @@
-import { isArray, isFunction, isEmpty, isObject, isString, isNil } from '/@/utils/is';
-import { dateUtil } from '/@/utils/dateUtil';
+import { isArray, isFunction, isEmpty, isObject, isString, isNil } from '@/utils/is';
+import { dateUtil } from '@/utils/dateUtil';
 import { unref } from 'vue';
 import type { Ref, ComputedRef } from 'vue';
 import type { FormProps, FormSchemaInner as FormSchema } from '../types/form';

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

@@ -1,7 +1,7 @@
 import type { Ref } from 'vue';
 import { computed, unref } from 'vue';
 import type { FormProps, FormSchemaInner as FormSchema } from '../types/form';
-import { isNumber } from '/@/utils/is';
+import { isNumber } from '@/utils/is';
 
 export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<FormProps>) {
   return computed(() => {

+ 2 - 2
src/components/Form/src/props.ts

@@ -1,10 +1,10 @@
 import type { FieldMapToTime, FormSchema } from './types/form';
 import type { CSSProperties, PropType } from 'vue';
 import type { ColEx } from './types';
-import type { TableActionType } from '/@/components/Table';
+import type { TableActionType } from '@/components/Table';
 import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
 import type { RowProps } from 'ant-design-vue/lib/grid/Row';
-import { propTypes } from '/@/utils/propTypes';
+import { propTypes } from '@/utils/propTypes';
 
 export const basicProps = {
   model: {

+ 3 - 3
src/components/Form/src/types/form.ts

@@ -1,9 +1,9 @@
 import type { NamePath, RuleObject } from 'ant-design-vue/lib/form/interface';
 import type { VNode, CSSProperties } from 'vue';
-import type { ButtonProps as AntdButtonProps } from '/@/components/Button';
+import type { ButtonProps as AntdButtonProps } from '@/components/Button';
 import type { FormItem } from './formItem';
-import type { ColEx, ComponentType } from './index';
-import type { TableActionType } from '/@/components/Table/src/types/table';
+import type { ColEx, ComponentType } from './';
+import type { TableActionType } from '@/components/Table/src/types/table';
 import type { RowProps } from 'ant-design-vue/lib/grid/Row';
 
 export type FieldMapToTime = [string, [string, string], (string | [string, string])?][];

+ 56 - 69
src/components/Icon/Icon.vue

@@ -13,91 +13,78 @@
     :style="getWrapStyle"
   ></span>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { PropType } from 'vue';
-  import {
-    defineComponent,
-    ref,
-    watch,
-    onMounted,
-    nextTick,
-    unref,
-    computed,
-    CSSProperties,
-  } from 'vue';
+  import { ref, watch, onMounted, nextTick, unref, computed, CSSProperties } from 'vue';
   import SvgIcon from './src/SvgIcon.vue';
   import Iconify from '@purge-icons/generated';
-  import { isString } from '/@/utils/is';
-  import { propTypes } from '/@/utils/propTypes';
+  import { isString } from '@/utils/is';
+  import { propTypes } from '@/utils/propTypes';
 
   const SVG_END_WITH_FLAG = '|svg';
-  export default defineComponent({
-    name: 'Icon',
-    components: { SvgIcon },
-    props: {
-      // icon name
-      icon: propTypes.string,
-      // icon color
-      color: propTypes.string,
-      // icon size
-      size: {
-        type: [String, Number] as PropType<string | number>,
-        default: 16,
-      },
-      spin: propTypes.bool.def(false),
-      prefix: propTypes.string.def(''),
-    },
-    setup(props) {
-      const elRef = ref(null);
 
-      const isSvgIcon = computed(() => props.icon?.endsWith(SVG_END_WITH_FLAG));
-      const getSvgIcon = computed(() => props.icon.replace(SVG_END_WITH_FLAG, ''));
-      const getIconRef = computed(() => `${props.prefix ? props.prefix + ':' : ''}${props.icon}`);
+  defineOptions({ name: 'Icon' });
 
-      const update = async () => {
-        if (unref(isSvgIcon)) return;
+  const props = defineProps({
+    // icon name
+    icon: propTypes.string,
+    // icon color
+    color: propTypes.string,
+    // icon size
+    size: {
+      type: [String, Number] as PropType<string | number>,
+      default: 16,
+    },
+    spin: propTypes.bool.def(false),
+    prefix: propTypes.string.def(''),
+  });
 
-        const el: any = unref(elRef);
-        if (!el) return;
+  const elRef = ref(null);
 
-        await nextTick();
-        const icon = unref(getIconRef);
-        if (!icon) return;
+  const isSvgIcon = computed(() => props.icon?.endsWith(SVG_END_WITH_FLAG));
+  const getSvgIcon = computed(() => props.icon.replace(SVG_END_WITH_FLAG, ''));
+  const getIconRef = computed(() => `${props.prefix ? props.prefix + ':' : ''}${props.icon}`);
 
-        const svg = Iconify.renderSVG(icon, {});
-        if (svg) {
-          el.textContent = '';
-          el.appendChild(svg);
-        } else {
-          const span = document.createElement('span');
-          span.className = 'iconify';
-          span.dataset.icon = icon;
-          el.textContent = '';
-          el.appendChild(span);
-        }
-      };
+  const update = async () => {
+    if (unref(isSvgIcon)) return;
 
-      const getWrapStyle = computed((): CSSProperties => {
-        const { size, color } = props;
-        let fs = size;
-        if (isString(size)) {
-          fs = parseInt(size, 10);
-        }
+    const el: any = unref(elRef);
+    if (!el) return;
 
-        return {
-          fontSize: `${fs}px`,
-          color: color,
-          display: 'inline-flex',
-        };
-      });
+    await nextTick();
+    const icon = unref(getIconRef);
+    if (!icon) return;
 
-      watch(() => props.icon, update, { flush: 'post' });
+    const svg = Iconify.renderSVG(icon, {});
+    if (svg) {
+      el.textContent = '';
+      el.appendChild(svg);
+    } else {
+      const span = document.createElement('span');
+      span.className = 'iconify';
+      span.dataset.icon = icon;
+      el.textContent = '';
+      el.appendChild(span);
+    }
+  };
 
-      onMounted(update);
+  const getWrapStyle = computed((): CSSProperties => {
+    const { size, color } = props;
+    let fs = size;
+    if (isString(size)) {
+      fs = parseInt(size, 10);
+    }
 
-      return { elRef, getWrapStyle, isSvgIcon, getSvgIcon };
-    },
+    return {
+      fontSize: `${fs}px`,
+      color: color,
+      display: 'inline-flex',
+    };
   });
+
+  watch(() => props.icon, update, { flush: 'post' });
+
+  onMounted(update);
 </script>
 <style lang="less">
   .app-iconify {

+ 13 - 20
src/components/Icon/src/IconPicker.vue

@@ -1,5 +1,5 @@
 <template>
-  <a-input
+  <Input
     readonly
     :style="{ width }"
     :placeholder="t('component.icon.placeholder')"
@@ -8,7 +8,7 @@
     @click="triggerPopover"
   >
     <template #addonAfter>
-      <a-popover
+      <Popover
         placement="bottomLeft"
         trigger="click"
         v-model="visible"
@@ -16,7 +16,7 @@
       >
         <template #title>
           <div class="flex justify-between">
-            <a-input
+            <Input
               :placeholder="t('component.icon.search')"
               @change="debounceHandleSearchChange"
               allowClear
@@ -36,14 +36,13 @@
                   @click="handleClick(icon)"
                   :title="icon"
                 >
-                  <!-- <Icon :icon="icon" :prefix="prefix" /> -->
                   <SvgIcon v-if="isSvgMode" :name="icon" />
                   <Icon :icon="icon" v-else />
                 </li>
               </ul>
             </ScrollContainer>
             <div class="flex py-2 items-center justify-center" v-if="getTotal >= pageSize">
-              <a-pagination
+              <Pagination
                 showLessItems
                 size="small"
                 :pageSize="pageSize"
@@ -52,8 +51,8 @@
               />
             </div>
           </div>
-          <template v-else
-            ><div class="p-5"><a-empty /></div>
+          <template v-else>
+            <div class="p-5"><Empty /> </div>
           </template>
         </template>
 
@@ -70,30 +69,24 @@
             v-else
           />
         </div>
-      </a-popover>
+      </Popover>
     </template>
-  </a-input>
+  </Input>
 </template>
 <script lang="ts" setup>
   import { ref, watchEffect, watch } from 'vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { ScrollContainer } from '/@/components/Container';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { ScrollContainer } from '@/components/Container';
   import { Input, Popover, Pagination, Empty } from 'ant-design-vue';
   import Icon from '../Icon.vue';
   import SvgIcon from './SvgIcon.vue';
 
   import iconsData from '../data/icons.data';
-  import { usePagination } from '/@/hooks/web/usePagination';
+  import { usePagination } from '@/hooks/web/usePagination';
   import { useDebounceFn } from '@vueuse/core';
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useI18n } from '@/hooks/web/useI18n';
   import svgIcons from 'virtual:svg-icons-names';
-  import { copyText } from '/@/utils/copyTextToClipboard';
-
-  // 没有使用别名引入,是因为WebStorm当前版本还不能正确识别,会报unused警告
-  const AInput = Input;
-  const APopover = Popover;
-  const APagination = Pagination;
-  const AEmpty = Empty;
+  import { copyText } from '@/utils/copyTextToClipboard';
 
   function getIcons() {
     const prefix = iconsData.prefix;

+ 33 - 36
src/components/Icon/src/SvgIcon.vue

@@ -7,47 +7,44 @@
     <use :xlink:href="symbolId" />
   </svg>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { CSSProperties } from 'vue';
-  import { defineComponent, computed } from 'vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { computed } from 'vue';
+  import { useDesign } from '@/hooks/web/useDesign';
 
-  export default defineComponent({
-    name: 'SvgIcon',
-    props: {
-      prefix: {
-        type: String,
-        default: 'icon',
-      },
-      name: {
-        type: String,
-        required: true,
-      },
-      size: {
-        type: [Number, String],
-        default: 16,
-      },
-      spin: {
-        type: Boolean,
-        default: false,
-      },
-    },
-    setup(props) {
-      const { prefixCls } = useDesign('svg-icon');
-      const symbolId = computed(() => `#${props.prefix}-${props.name}`);
+  defineOptions({ name: 'SvgIcon' });
 
-      const getStyle = computed((): CSSProperties => {
-        const { size } = props;
-        let s = `${size}`;
-        s = `${s.replace('px', '')}px`;
-        return {
-          width: s,
-          height: s,
-        };
-      });
-      return { symbolId, prefixCls, getStyle };
+  const props = defineProps({
+    prefix: {
+      type: String,
+      default: 'icon',
+    },
+    name: {
+      type: String,
+      required: true,
+    },
+    size: {
+      type: [Number, String],
+      default: 16,
+    },
+    spin: {
+      type: Boolean,
+      default: false,
     },
   });
+
+  const { prefixCls } = useDesign('svg-icon');
+  const symbolId = computed(() => `#${props.prefix}-${props.name}`);
+
+  const getStyle = computed((): CSSProperties => {
+    const { size } = props;
+    let s = `${size}`;
+    s = `${s.replace('px', '')}px`;
+    return {
+      width: s,
+      height: s,
+    };
+  });
 </script>
 <style lang="less" scoped>
   @prefix-cls: ~'@{namespace}-svg-icon';

+ 29 - 31
src/components/Loading/src/Loading.vue

@@ -8,41 +8,39 @@
     <Spin v-bind="$attrs" :tip="tip" :size="size" :spinning="loading" />
   </section>
 </template>
-<script lang="ts">
-  import { PropType, defineComponent } from 'vue';
+<script lang="ts" setup>
+  import type { PropType } from 'vue';
   import { Spin } from 'ant-design-vue';
-  import { SizeEnum } from '/@/enums/sizeEnum';
+  import { SizeEnum } from '@/enums/sizeEnum';
 
-  export default defineComponent({
-    name: 'Loading',
-    components: { Spin },
-    props: {
-      tip: {
-        type: String as PropType<string>,
-        default: '',
-      },
-      size: {
-        type: String as PropType<SizeEnum>,
-        default: SizeEnum.LARGE,
-        validator: (v: SizeEnum): boolean => {
-          return [SizeEnum.DEFAULT, SizeEnum.SMALL, SizeEnum.LARGE].includes(v);
-        },
-      },
-      absolute: {
-        type: Boolean as PropType<boolean>,
-        default: false,
-      },
-      loading: {
-        type: Boolean as PropType<boolean>,
-        default: false,
-      },
-      background: {
-        type: String as PropType<string>,
-      },
-      theme: {
-        type: String as PropType<'dark' | 'light'>,
+  defineOptions({ name: 'Loading' });
+
+  defineProps({
+    tip: {
+      type: String as PropType<string>,
+      default: '',
+    },
+    size: {
+      type: String as PropType<SizeEnum>,
+      default: SizeEnum.LARGE,
+      validator: (v: SizeEnum): boolean => {
+        return [SizeEnum.DEFAULT, SizeEnum.SMALL, SizeEnum.LARGE].includes(v);
       },
     },
+    absolute: {
+      type: Boolean as PropType<boolean>,
+      default: false,
+    },
+    loading: {
+      type: Boolean as PropType<boolean>,
+      default: false,
+    },
+    background: {
+      type: String as PropType<string>,
+    },
+    theme: {
+      type: String as PropType<'dark' | 'light'>,
+    },
   });
 </script>
 <style lang="less" scoped>

+ 1 - 1
src/components/Loading/src/typing.ts

@@ -1,4 +1,4 @@
-import { SizeEnum } from '/@/enums/sizeEnum';
+import { SizeEnum } from '@/enums/sizeEnum';
 
 export interface LoadingProps {
   tip: string;

+ 1 - 1
src/components/Markdown/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import markDown from './src/Markdown.vue';
 import markDownViewer from './src/MarkdownViewer.vue';
 

+ 124 - 127
src/components/Markdown/src/Markdown.vue

@@ -1,10 +1,9 @@
 <template>
   <div ref="wrapRef"></div>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { Ref } from 'vue';
   import {
-    defineComponent,
     ref,
     unref,
     nextTick,
@@ -12,149 +11,147 @@
     watch,
     onBeforeUnmount,
     onDeactivated,
+    useAttrs,
   } from 'vue';
   import Vditor from 'vditor';
   import 'vditor/dist/index.css';
-  import { useLocale } from '/@/locales/useLocale';
+  import { useLocale } from '@/locales/useLocale';
   import { useModalContext } from '../../Modal';
-  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
+  import { useRootSetting } from '@/hooks/setting/useRootSetting';
   import { onMountedOrActivated } from '@vben/hooks';
   import { getTheme } from './getTheme';
 
   type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
 
-  export default defineComponent({
-    inheritAttrs: false,
-    props: {
-      height: { type: Number, default: 360 },
-      value: { type: String, default: '' },
-    },
-    emits: ['change', 'get', 'update:value'],
-    setup(props, { attrs, emit }) {
-      const wrapRef = ref(null);
-      const vditorRef = ref(null) as Ref<Vditor | null>;
-      const initedRef = ref(false);
+  defineOptions({ inheritAttrs: false });
 
-      const modalFn = useModalContext();
+  const props = defineProps({
+    height: { type: Number, default: 360 },
+    value: { type: String, default: '' },
+  });
 
-      const { getLocale } = useLocale();
-      const { getDarkMode } = useRootSetting();
-      const valueRef = ref(props.value || '');
+  const emit = defineEmits(['change', 'get', 'update:value']);
 
-      watch(
-        [() => getDarkMode.value, () => initedRef.value],
-        ([val, inited]) => {
-          if (!inited) {
-            return;
-          }
-          instance
-            .getVditor()
-            ?.setTheme(getTheme(val) as any, getTheme(val, 'content'), getTheme(val, 'code'));
-        },
-        {
-          immediate: true,
-          flush: 'post',
-        },
-      );
+  const attrs = useAttrs();
 
-      watch(
-        () => props.value,
-        (v) => {
-          if (v !== valueRef.value) {
-            instance.getVditor()?.setValue(v);
-          }
-          valueRef.value = v;
-        },
-      );
+  const wrapRef = ref(null);
+  const vditorRef = ref(null) as Ref<Vditor | null>;
+  const initedRef = ref(false);
 
-      const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => {
-        let lang: Lang;
-        switch (unref(getLocale)) {
-          case 'en':
-            lang = 'en_US';
-            break;
-          case 'ja':
-            lang = 'ja_JP';
-            break;
-          case 'ko':
-            lang = 'ko_KR';
-            break;
-          default:
-            lang = 'zh_CN';
-        }
-        return lang;
-      });
-      function init() {
-        const wrapEl = unref(wrapRef);
-        if (!wrapEl) return;
-        const bindValue = { ...attrs, ...props };
-        const insEditor = new Vditor(wrapEl, {
-          // 设置外观主题
-          theme: getTheme(getDarkMode.value) as any,
-          lang: unref(getCurrentLang),
-          mode: 'sv',
-          fullscreen: {
-            index: 520,
-          },
-          preview: {
-            theme: {
-              // 设置内容主题
-              current: getTheme(getDarkMode.value, 'content'),
-            },
-            hljs: {
-              // 设置代码块主题
-              style: getTheme(getDarkMode.value, 'code'),
-            },
-            actions: [],
-          },
-          input: (v) => {
-            valueRef.value = v;
-            emit('update:value', v);
-            emit('change', v);
-          },
-          after: () => {
-            nextTick(() => {
-              modalFn?.redoModalHeight?.();
-              insEditor.setValue(valueRef.value);
-              vditorRef.value = insEditor;
-              initedRef.value = true;
-              emit('get', instance);
-            });
-          },
-          blur: () => {
-            //unref(vditorRef)?.setValue(props.value);
-          },
-          ...bindValue,
-          cache: {
-            enable: false,
-          },
-        });
-      }
+  const modalFn = useModalContext();
 
-      const instance = {
-        getVditor: (): Vditor => vditorRef.value!,
-      };
+  const { getLocale } = useLocale();
+  const { getDarkMode } = useRootSetting();
+  const valueRef = ref(props.value || '');
 
-      function destroy() {
-        const vditorInstance = unref(vditorRef);
-        if (!vditorInstance) return;
-        try {
-          vditorInstance?.destroy?.();
-        } catch (error) {
-          //
-        }
-        vditorRef.value = null;
-        initedRef.value = false;
+  watch(
+    [() => getDarkMode.value, () => initedRef.value],
+    ([val, inited]) => {
+      if (!inited) {
+        return;
       }
+      instance
+        .getVditor()
+        ?.setTheme(getTheme(val) as any, getTheme(val, 'content'), getTheme(val, 'code'));
+    },
+    {
+      immediate: true,
+      flush: 'post',
+    },
+  );
 
-      onMountedOrActivated(init);
-
-      onBeforeUnmount(destroy);
-      onDeactivated(destroy);
-      return {
-        wrapRef,
-        ...instance,
-      };
+  watch(
+    () => props.value,
+    (v) => {
+      if (v !== valueRef.value) {
+        instance.getVditor()?.setValue(v);
+      }
+      valueRef.value = v;
     },
+  );
+
+  const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => {
+    let lang: Lang;
+    switch (unref(getLocale)) {
+      case 'en':
+        lang = 'en_US';
+        break;
+      case 'ja':
+        lang = 'ja_JP';
+        break;
+      case 'ko':
+        lang = 'ko_KR';
+        break;
+      default:
+        lang = 'zh_CN';
+    }
+    return lang;
   });
+  function init() {
+    const wrapEl = unref(wrapRef);
+    if (!wrapEl) return;
+    const bindValue = { ...attrs, ...props };
+    const insEditor = new Vditor(wrapEl, {
+      // 设置外观主题
+      theme: getTheme(getDarkMode.value) as any,
+      lang: unref(getCurrentLang),
+      mode: 'sv',
+      fullscreen: {
+        index: 520,
+      },
+      preview: {
+        theme: {
+          // 设置内容主题
+          current: getTheme(getDarkMode.value, 'content'),
+        },
+        hljs: {
+          // 设置代码块主题
+          style: getTheme(getDarkMode.value, 'code'),
+        },
+        actions: [],
+      },
+      input: (v) => {
+        valueRef.value = v;
+        emit('update:value', v);
+        emit('change', v);
+      },
+      after: () => {
+        nextTick(() => {
+          modalFn?.redoModalHeight?.();
+          insEditor.setValue(valueRef.value);
+          vditorRef.value = insEditor;
+          initedRef.value = true;
+          emit('get', instance);
+        });
+      },
+      blur: () => {
+        //unref(vditorRef)?.setValue(props.value);
+      },
+      ...bindValue,
+      cache: {
+        enable: false,
+      },
+    });
+  }
+
+  const instance = {
+    getVditor: (): Vditor => vditorRef.value!,
+  };
+
+  function destroy() {
+    const vditorInstance = unref(vditorRef);
+    if (!vditorInstance) return;
+    try {
+      vditorInstance?.destroy?.();
+    } catch (error) {
+      //
+    }
+    vditorRef.value = null;
+    initedRef.value = false;
+  }
+
+  onMountedOrActivated(init);
+
+  onBeforeUnmount(destroy);
+  onDeactivated(destroy);
 </script>

+ 1 - 1
src/components/Markdown/src/MarkdownViewer.vue

@@ -6,7 +6,7 @@
   import { onBeforeUnmount, onDeactivated, Ref, ref, unref, watch } from 'vue';
   import VditorPreview from 'vditor/dist/method.min';
   import { onMountedOrActivated } from '@vben/hooks';
-  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
+  import { useRootSetting } from '@/hooks/setting/useRootSetting';
   import { getTheme } from './getTheme';
 
   const props = defineProps({

+ 121 - 136
src/components/Menu/src/BasicMenu.vue

@@ -1,7 +1,7 @@
 <template>
   <Menu
-    :selectedKeys="selectedKeys"
-    :defaultSelectedKeys="defaultSelectedKeys"
+    :selectedKeys="menuState.selectedKeys"
+    :defaultSelectedKeys="menuState.defaultSelectedKeys"
     :mode="mode"
     :openKeys="getOpenKeys"
     :inlineIndent="inlineIndent"
@@ -17,147 +17,132 @@
     </template>
   </Menu>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { MenuState } from './types';
-  import { computed, defineComponent, unref, reactive, watch, toRefs, ref } from 'vue';
+  import { computed, unref, reactive, watch, toRefs, ref } from 'vue';
   import { Menu, MenuProps } from 'ant-design-vue';
   import BasicSubMenuItem from './components/BasicSubMenuItem.vue';
-  import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
+  import { MenuModeEnum, MenuTypeEnum } from '@/enums/menuEnum';
   import { useOpenKeys } from './useOpenKeys';
   import { RouteLocationNormalizedLoaded, useRouter } from 'vue-router';
-  import { isFunction } from '/@/utils/is';
+  import { isFunction } from '@/utils/is';
   import { basicProps } from './props';
-  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-  import { REDIRECT_NAME } from '/@/router/constant';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { getCurrentParentPath } from '/@/router/menus';
-  import { listenerRouteChange } from '/@/logics/mitt/routeChange';
-  import { getAllParentPath } from '/@/router/helper/menuHelper';
-
-  export default defineComponent({
-    name: 'BasicMenu',
-    components: {
-      Menu,
-      BasicSubMenuItem,
-    },
-    props: basicProps,
-    emits: ['menuClick'],
-    setup(props, { emit }) {
-      const isClickGo = ref(false);
-      const currentActiveMenu = ref('');
-
-      const menuState = reactive<MenuState>({
-        defaultSelectedKeys: [],
-        openKeys: [],
-        selectedKeys: [],
-        collapsedOpenKeys: [],
-      });
-
-      const { prefixCls } = useDesign('basic-menu');
-      const { items, mode, accordion } = toRefs(props);
-
-      const { getCollapsed, getTopMenuAlign, getSplit } = useMenuSetting();
-
-      const { currentRoute } = useRouter();
-
-      const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys(
-        menuState,
-        items,
-        mode as any,
-        accordion,
-      );
-
-      const getIsTopMenu = computed(() => {
-        const { type, mode } = props;
-
-        return (
-          (type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL) ||
-          (props.isHorizontal && unref(getSplit))
-        );
-      });
-
-      const getMenuClass = computed(() => {
-        const align = props.isHorizontal && unref(getSplit) ? 'start' : unref(getTopMenuAlign);
-        return [
-          prefixCls,
-          `justify-${align}`,
-          {
-            [`${prefixCls}__second`]: !props.isHorizontal && unref(getSplit),
-            [`${prefixCls}__sidebar-hor`]: unref(getIsTopMenu),
-          },
-        ];
-      });
-
-      const getInlineCollapseOptions = computed(() => {
-        const isInline = props.mode === MenuModeEnum.INLINE;
-
-        const inlineCollapseOptions: { inlineCollapsed?: boolean } = {};
-        if (isInline) {
-          inlineCollapseOptions.inlineCollapsed = props.mixSider ? false : unref(getCollapsed);
-        }
-        return inlineCollapseOptions;
-      });
-
-      listenerRouteChange((route) => {
-        if (route.name === REDIRECT_NAME) return;
-        handleMenuChange(route);
-        currentActiveMenu.value = route.meta?.currentActiveMenu as string;
-
-        if (unref(currentActiveMenu)) {
-          menuState.selectedKeys = [unref(currentActiveMenu)];
-          setOpenKeys(unref(currentActiveMenu));
-        }
-      });
-
-      !props.mixSider &&
-        watch(
-          () => props.items,
-          () => {
-            handleMenuChange();
-          },
-        );
-
-      const handleMenuClick: MenuProps['onClick'] = async ({ key }) => {
-        const { beforeClickFn } = props;
-        if (beforeClickFn && isFunction(beforeClickFn)) {
-          const flag = await beforeClickFn(key);
-          if (!flag) return;
-        }
-        emit('menuClick', key);
-
-        isClickGo.value = true;
-        menuState.selectedKeys = [key];
-      };
-
-      async function handleMenuChange(route?: RouteLocationNormalizedLoaded) {
-        if (unref(isClickGo)) {
-          isClickGo.value = false;
-          return;
-        }
-        const path =
-          (route || unref(currentRoute)).meta?.currentActiveMenu ||
-          (route || unref(currentRoute)).path;
-        setOpenKeys(path);
-        if (unref(currentActiveMenu)) return;
-        if (props.isHorizontal && unref(getSplit)) {
-          const parentPath = await getCurrentParentPath(path);
-          menuState.selectedKeys = [parentPath];
-        } else {
-          const parentPaths = await getAllParentPath(props.items, path);
-          menuState.selectedKeys = parentPaths;
-        }
-      }
-
-      return {
-        handleMenuClick,
-        getInlineCollapseOptions,
-        getMenuClass,
-        handleOpenChange,
-        getOpenKeys,
-        ...toRefs(menuState),
-      };
-    },
+  import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
+  import { REDIRECT_NAME } from '@/router/constant';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { getCurrentParentPath } from '@/router/menus';
+  import { listenerRouteChange } from '@/logics/mitt/routeChange';
+  import { getAllParentPath } from '@/router/helper/menuHelper';
+
+  defineOptions({ name: 'BasicMenu' });
+
+  const props = defineProps(basicProps);
+
+  const emit = defineEmits(['menuClick']);
+
+  const isClickGo = ref(false);
+  const currentActiveMenu = ref('');
+
+  const menuState = reactive<MenuState>({
+    defaultSelectedKeys: [],
+    openKeys: [],
+    selectedKeys: [],
+    collapsedOpenKeys: [],
   });
+
+  const { prefixCls } = useDesign('basic-menu');
+  const { items, mode, accordion } = toRefs(props);
+
+  const { getCollapsed, getTopMenuAlign, getSplit } = useMenuSetting();
+
+  const { currentRoute } = useRouter();
+
+  const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys(
+    menuState,
+    items,
+    mode as any,
+    accordion,
+  );
+
+  const getIsTopMenu = computed(() => {
+    const { type, mode } = props;
+
+    return (
+      (type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL) ||
+      (props.isHorizontal && unref(getSplit))
+    );
+  });
+
+  const getMenuClass = computed(() => {
+    const align = props.isHorizontal && unref(getSplit) ? 'start' : unref(getTopMenuAlign);
+    return [
+      prefixCls,
+      `justify-${align}`,
+      {
+        [`${prefixCls}__second`]: !props.isHorizontal && unref(getSplit),
+        [`${prefixCls}__sidebar-hor`]: unref(getIsTopMenu),
+      },
+    ];
+  });
+
+  const getInlineCollapseOptions = computed(() => {
+    const isInline = props.mode === MenuModeEnum.INLINE;
+
+    const inlineCollapseOptions: { inlineCollapsed?: boolean } = {};
+    if (isInline) {
+      inlineCollapseOptions.inlineCollapsed = props.mixSider ? false : unref(getCollapsed);
+    }
+    return inlineCollapseOptions;
+  });
+
+  listenerRouteChange((route) => {
+    if (route.name === REDIRECT_NAME) return;
+    handleMenuChange(route);
+    currentActiveMenu.value = route.meta?.currentActiveMenu as string;
+
+    if (unref(currentActiveMenu)) {
+      menuState.selectedKeys = [unref(currentActiveMenu)];
+      setOpenKeys(unref(currentActiveMenu));
+    }
+  });
+
+  !props.mixSider &&
+    watch(
+      () => props.items,
+      () => {
+        handleMenuChange();
+      },
+    );
+
+  const handleMenuClick: MenuProps['onClick'] = async ({ key }) => {
+    const { beforeClickFn } = props;
+    if (beforeClickFn && isFunction(beforeClickFn)) {
+      const flag = await beforeClickFn(key);
+      if (!flag) return;
+    }
+    emit('menuClick', key);
+
+    isClickGo.value = true;
+    menuState.selectedKeys = [key];
+  };
+
+  async function handleMenuChange(route?: RouteLocationNormalizedLoaded) {
+    if (unref(isClickGo)) {
+      isClickGo.value = false;
+      return;
+    }
+    const path =
+      (route || unref(currentRoute)).meta?.currentActiveMenu || (route || unref(currentRoute)).path;
+    setOpenKeys(path);
+    if (unref(currentActiveMenu)) return;
+    if (props.isHorizontal && unref(getSplit)) {
+      const parentPath = await getCurrentParentPath(path);
+      menuState.selectedKeys = [parentPath];
+    } else {
+      const parentPaths = await getAllParentPath(props.items, path);
+      menuState.selectedKeys = parentPaths;
+    }
+  }
 </script>
 <style lang="less">
   @import url('./index.less');

+ 6 - 13
src/components/Menu/src/components/BasicMenuItem.vue

@@ -1,21 +1,14 @@
 <template>
-  <MenuItem :key="item.path">
+  <Menu.Item :key="item.path">
     <MenuItemContent v-bind="$props" :item="item" />
-  </MenuItem>
+  </Menu.Item>
 </template>
-<script lang="ts">
-  import { defineComponent } from 'vue';
+<script lang="ts" setup>
   import { Menu } from 'ant-design-vue';
   import { itemProps } from '../props';
-
   import MenuItemContent from './MenuItemContent.vue';
 
-  export default defineComponent({
-    name: 'BasicMenuItem',
-    components: { MenuItem: Menu.Item, MenuItemContent },
-    props: itemProps,
-    setup() {
-      return {};
-    },
-  });
+  defineOptions({ name: 'BasicMenuItem' });
+
+  defineProps(itemProps);
 </script>

+ 17 - 33
src/components/Menu/src/components/BasicSubMenuItem.vue

@@ -1,6 +1,6 @@
 <template>
   <BasicMenuItem v-if="!menuHasChildren(item) && getShowMenu" v-bind="$props" />
-  <SubMenu
+  <Menu.SubMenu
     v-if="menuHasChildren(item) && getShowMenu"
     :class="[theme]"
     :key="`submenu-${item.path}`"
@@ -13,43 +13,27 @@
     <template v-for="childrenItem in item.children || []" :key="childrenItem.path">
       <BasicSubMenuItem v-bind="$props" :item="childrenItem" />
     </template>
-  </SubMenu>
+  </Menu.SubMenu>
 </template>
-<script lang="ts">
-  import type { Menu as MenuType } from '/@/router/types';
-  import { defineComponent, computed } from 'vue';
+<script lang="ts" setup>
+  import type { Menu as MenuType } from '@/router/types';
+  import { computed } from 'vue';
   import { Menu } from 'ant-design-vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
   import { itemProps } from '../props';
   import BasicMenuItem from './BasicMenuItem.vue';
   import MenuItemContent from './MenuItemContent.vue';
 
-  export default defineComponent({
-    name: 'BasicSubMenuItem',
-    isSubMenu: true,
-    components: {
-      BasicMenuItem,
-      SubMenu: Menu.SubMenu,
-      MenuItemContent,
-    },
-    props: itemProps,
-    setup(props) {
-      const { prefixCls } = useDesign('basic-menu-item');
+  defineOptions({ name: 'BasicSubMenuItem', isSubMenu: true });
 
-      const getShowMenu = computed(() => !props.item.meta?.hideMenu);
-      function menuHasChildren(menuTreeItem: MenuType): boolean {
-        return (
-          !menuTreeItem.meta?.hideChildrenInMenu &&
-          Reflect.has(menuTreeItem, 'children') &&
-          !!menuTreeItem.children &&
-          menuTreeItem.children.length > 0
-        );
-      }
-      return {
-        prefixCls,
-        menuHasChildren,
-        getShowMenu,
-      };
-    },
-  });
+  const props = defineProps(itemProps);
+
+  const getShowMenu = computed(() => !props.item.meta?.hideMenu);
+  function menuHasChildren(menuTreeItem: MenuType): boolean {
+    return (
+      !menuTreeItem.meta?.hideChildrenInMenu &&
+      Reflect.has(menuTreeItem, 'children') &&
+      !!menuTreeItem.children &&
+      menuTreeItem.children.length > 0
+    );
+  }
 </script>

+ 12 - 24
src/components/Menu/src/components/MenuItemContent.vue

@@ -5,33 +5,21 @@
     {{ getI18nName }}
   </span>
 </template>
-<script lang="ts">
-  import { computed, defineComponent } from 'vue';
+<script lang="ts" setup>
+  import { computed } from 'vue';
   import Icon from '@/components/Icon/Icon.vue';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useI18n } from '@/hooks/web/useI18n';
+  import { useDesign } from '@/hooks/web/useDesign';
   import { contentProps } from '../props';
 
-  const { t } = useI18n();
+  defineOptions({ name: 'MenuItemContent' });
+
+  const props = defineProps(contentProps);
 
-  export default defineComponent({
-    name: 'MenuItemContent',
-    components: {
-      Icon,
-    },
-    props: contentProps,
-    setup(props) {
-      const { prefixCls } = useDesign('basic-menu-item-content');
-      const getI18nName = computed(() => t(props.item?.name));
-      const getIcon = computed(() => (props.item?.img ? undefined : props.item?.icon));
-      const getImg = computed(() => props.item?.img);
+  const { t } = useI18n();
+  const { prefixCls } = useDesign('basic-menu-item-content');
 
-      return {
-        prefixCls,
-        getI18nName,
-        getIcon,
-        getImg,
-      };
-    },
-  });
+  const getI18nName = computed(() => t(props.item?.name));
+  const getIcon = computed(() => (props.item?.img ? undefined : props.item?.icon));
+  const getImg = computed(() => props.item?.img);
 </script>

+ 4 - 4
src/components/Menu/src/props.ts

@@ -1,9 +1,9 @@
-import type { Menu } from '/@/router/types';
+import type { Menu } from '@/router/types';
 import type { PropType } from 'vue';
 
-import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
-import { ThemeEnum } from '/@/enums/appEnum';
-import { propTypes } from '/@/utils/propTypes';
+import { MenuModeEnum, MenuTypeEnum } from '@/enums/menuEnum';
+import { ThemeEnum } from '@/enums/appEnum';
+import { propTypes } from '@/utils/propTypes';
 import type { Key } from './types';
 import type { MenuTheme } from 'ant-design-vue';
 import type { MenuMode } from 'ant-design-vue/lib/menu/src/interface';

+ 3 - 3
src/components/Menu/src/useOpenKeys.ts

@@ -1,11 +1,11 @@
-import { MenuModeEnum } from '/@/enums/menuEnum';
+import { MenuModeEnum } from '@/enums/menuEnum';
 import type { Menu as MenuType } from '/@/router/types';
 import type { MenuState, Key } from './types';
 import { computed, Ref, toRaw, unref } from 'vue';
 import { useTimeoutFn } from '@vben/hooks';
 import { uniq } from 'lodash-es';
-import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-import { getAllParentPath } from '/@/router/helper/menuHelper';
+import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
+import { getAllParentPath } from '@/router/helper/menuHelper';
 
 export function useOpenKeys(
   menuState: MenuState,

+ 1 - 1
src/components/Modal/index.ts

@@ -1,4 +1,4 @@
-import { withInstall } from '/@/utils';
+import { withInstall } from '@/utils';
 import './src/index.less';
 import basicModal from './src/BasicModal.vue';
 

+ 151 - 164
src/components/Modal/src/BasicModal.vue

@@ -48,11 +48,9 @@
     </template>
   </Modal>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { ModalProps, ModalMethods } from './typing';
-
   import {
-    defineComponent,
     computed,
     ref,
     watch,
@@ -61,183 +59,172 @@
     toRef,
     getCurrentInstance,
     nextTick,
+    useAttrs,
   } from 'vue';
   import Modal from './components/Modal';
   import ModalWrapper from './components/ModalWrapper.vue';
   import ModalClose from './components/ModalClose.vue';
   import ModalFooter from './components/ModalFooter.vue';
   import ModalHeader from './components/ModalHeader.vue';
-  import { isFunction } from '/@/utils/is';
-  import { deepMerge } from '/@/utils';
+  import { isFunction } from '@/utils/is';
+  import { deepMerge } from '@/utils';
   import { basicProps } from './props';
   import { useFullScreen } from './hooks/useModalFullScreen';
   import { omit } from 'lodash-es';
-  import { useDesign } from '/@/hooks/web/useDesign';
-
-  export default defineComponent({
-    name: 'BasicModal',
-    components: { Modal, ModalWrapper, ModalClose, ModalFooter, ModalHeader },
-    inheritAttrs: false,
-    props: basicProps,
-    emits: ['open-change', 'height-change', 'cancel', 'ok', 'register', 'update:open'],
-    setup(props, { emit, attrs }) {
-      const openRef = ref(false);
-      const propsRef = ref<Partial<ModalProps> | null>(null);
-      const modalWrapperRef = ref<any>(null);
-      const { prefixCls } = useDesign('basic-modal');
-
-      // modal   Bottom and top height
-      const extHeightRef = ref(0);
-      const modalMethods: ModalMethods = {
-        setModalProps,
-        emitOpen: undefined,
-        redoModalHeight: () => {
-          nextTick(() => {
-            if (unref(modalWrapperRef)) {
-              (unref(modalWrapperRef) as any).setModalHeight();
-            }
-          });
-        },
-      };
-
-      const instance = getCurrentInstance();
-      if (instance) {
-        emit('register', modalMethods, instance.uid);
-      }
-
-      // Custom title component: get title
-      const getMergeProps = computed((): Recordable => {
-        return {
-          ...props,
-          ...(unref(propsRef) as any),
-        };
-      });
-
-      const { handleFullScreen, getWrapClassName, fullScreenRef } = useFullScreen({
-        modalWrapperRef,
-        extHeightRef,
-        wrapClassName: toRef(getMergeProps.value, 'wrapClassName'),
+  import { useDesign } from '@/hooks/web/useDesign';
+
+  defineOptions({ name: 'BasicModal', inheritAttrs: false });
+
+  const props = defineProps(basicProps);
+
+  const emit = defineEmits([
+    'open-change',
+    'height-change',
+    'cancel',
+    'ok',
+    'register',
+    'update:open',
+  ]);
+
+  const attrs = useAttrs();
+  const openRef = ref(false);
+  const propsRef = ref<Partial<ModalProps> | null>(null);
+  const modalWrapperRef = ref<any>(null);
+  const { prefixCls } = useDesign('basic-modal');
+
+  // modal   Bottom and top height
+  const extHeightRef = ref(0);
+  const modalMethods: ModalMethods = {
+    setModalProps,
+    emitOpen: undefined,
+    redoModalHeight: () => {
+      nextTick(() => {
+        if (unref(modalWrapperRef)) {
+          (unref(modalWrapperRef) as any).setModalHeight();
+        }
       });
+    },
+  };
+
+  const instance = getCurrentInstance();
+  if (instance) {
+    emit('register', modalMethods, instance.uid);
+  }
+
+  // Custom title component: get title
+  const getMergeProps = computed((): Recordable => {
+    return {
+      ...props,
+      ...(unref(propsRef) as any),
+    };
+  });
 
-      // modal component does not need title and origin buttons
-      const getProps = computed((): Recordable => {
-        const opt = {
-          ...unref(getMergeProps),
-          open: unref(openRef),
-          okButtonProps: undefined,
-          cancelButtonProps: undefined,
-          title: undefined,
-        };
-        return {
-          ...opt,
-          wrapClassName: unref(getWrapClassName),
-        };
-      });
+  const { handleFullScreen, getWrapClassName, fullScreenRef } = useFullScreen({
+    modalWrapperRef,
+    extHeightRef,
+    wrapClassName: toRef(getMergeProps.value, 'wrapClassName'),
+  });
 
-      const getBindValue = computed((): Recordable => {
-        const attr = {
-          ...attrs,
-          ...unref(getMergeProps),
-          open: unref(openRef),
-        };
-        attr['wrapClassName'] =
-          `${attr?.['wrapClassName'] || ''} ${unref(getWrapClassName)}` + 'vben-basic-modal-wrap';
-        if (unref(fullScreenRef)) {
-          return omit(attr, ['height', 'title']);
-        }
-        return omit(attr, 'title');
-      });
+  // modal component does not need title and origin buttons
+  const getProps = computed((): Recordable => {
+    const opt = {
+      ...unref(getMergeProps),
+      open: unref(openRef),
+      okButtonProps: undefined,
+      cancelButtonProps: undefined,
+      title: undefined,
+    };
+    return {
+      ...opt,
+      wrapClassName: unref(getWrapClassName),
+    };
+  });
 
-      const getWrapperHeight = computed(() => {
-        if (unref(fullScreenRef)) return undefined;
-        return unref(getProps).height;
-      });
+  const getBindValue = computed((): Recordable => {
+    const attr = {
+      ...attrs,
+      ...unref(getMergeProps),
+      open: unref(openRef),
+    };
+    attr['wrapClassName'] =
+      `${attr?.['wrapClassName'] || ''} ${unref(getWrapClassName)}` + 'vben-basic-modal-wrap';
+    if (unref(fullScreenRef)) {
+      return omit(attr, ['height', 'title']);
+    }
+    return omit(attr, 'title');
+  });
 
-      watchEffect(() => {
-        openRef.value = !!props.open;
-        fullScreenRef.value = !!props.defaultFullscreen;
-      });
+  const getWrapperHeight = computed(() => {
+    if (unref(fullScreenRef)) return undefined;
+    return unref(getProps).height;
+  });
 
-      watch(
-        () => unref(openRef),
-        (v) => {
-          emit('open-change', v);
-          emit('update:open', v);
-          instance && modalMethods.emitOpen?.(v, instance.uid);
-          nextTick(() => {
-            if (props.scrollTop && v && unref(modalWrapperRef)) {
-              (unref(modalWrapperRef) as any).scrollTop();
-            }
-          });
-        },
-        {
-          immediate: false,
-        },
-      );
-
-      // 取消事件
-      async function handleCancel(e: Event) {
-        e?.stopPropagation();
-        // 过滤自定义关闭按钮的空白区域
-        if ((e.target as HTMLElement)?.classList?.contains(prefixCls + '-close--custom')) return;
-        if (props.closeFunc && isFunction(props.closeFunc)) {
-          const isClose: boolean = await props.closeFunc();
-          openRef.value = !isClose;
-          return;
-        }
+  watchEffect(() => {
+    openRef.value = !!props.open;
+    fullScreenRef.value = !!props.defaultFullscreen;
+  });
 
-        openRef.value = false;
-        emit('cancel', e);
-      }
-
-      /**
-       * @description: 设置modal参数
-       */
-      function setModalProps(props: Partial<ModalProps>): void {
-        // Keep the last setModalProps
-        propsRef.value = deepMerge(unref(propsRef) || ({} as any), props);
-        if (Reflect.has(props, 'open')) {
-          openRef.value = !!props.open;
-        }
-        if (Reflect.has(props, 'defaultFullscreen')) {
-          fullScreenRef.value = !!props.defaultFullscreen;
+  watch(
+    () => unref(openRef),
+    (v) => {
+      emit('open-change', v);
+      emit('update:open', v);
+      instance && modalMethods.emitOpen?.(v, instance.uid);
+      nextTick(() => {
+        if (props.scrollTop && v && unref(modalWrapperRef)) {
+          (unref(modalWrapperRef) as any).scrollTop();
         }
-      }
-
-      function handleOk(e: Event) {
-        emit('ok', e);
-      }
-
-      function handleHeightChange(height: string) {
-        emit('height-change', height);
-      }
-
-      function handleExtHeight(height: number) {
-        extHeightRef.value = height;
-      }
-
-      function handleTitleDbClick(e) {
-        if (!props.canFullscreen) return;
-        e.stopPropagation();
-        handleFullScreen(e);
-      }
-
-      return {
-        handleCancel,
-        getBindValue,
-        getProps,
-        handleFullScreen,
-        fullScreenRef,
-        getMergeProps,
-        handleOk,
-        openRef,
-        omit,
-        modalWrapperRef,
-        handleExtHeight,
-        handleHeightChange,
-        handleTitleDbClick,
-        getWrapperHeight,
-      };
+      });
     },
-  });
+    {
+      immediate: false,
+    },
+  );
+
+  // 取消事件
+  async function handleCancel(e: Event) {
+    e?.stopPropagation();
+    // 过滤自定义关闭按钮的空白区域
+    if ((e.target as HTMLElement)?.classList?.contains(prefixCls + '-close--custom')) return;
+    if (props.closeFunc && isFunction(props.closeFunc)) {
+      const isClose: boolean = await props.closeFunc();
+      openRef.value = !isClose;
+      return;
+    }
+
+    openRef.value = false;
+    emit('cancel', e);
+  }
+
+  /**
+   * @description: 设置modal参数
+   */
+  function setModalProps(props: Partial<ModalProps>): void {
+    // Keep the last setModalProps
+    propsRef.value = deepMerge(unref(propsRef) || ({} as any), props);
+    if (Reflect.has(props, 'open')) {
+      openRef.value = !!props.open;
+    }
+    if (Reflect.has(props, 'defaultFullscreen')) {
+      fullScreenRef.value = !!props.defaultFullscreen;
+    }
+  }
+
+  function handleOk(e: Event) {
+    emit('ok', e);
+  }
+
+  function handleHeightChange(height: string) {
+    emit('height-change', height);
+  }
+
+  function handleExtHeight(height: number) {
+    extHeightRef.value = height;
+  }
+
+  function handleTitleDbClick(e) {
+    if (!props.canFullscreen) return;
+    e.stopPropagation();
+    handleFullScreen(e);
+  }
 </script>

+ 1 - 1
src/components/Modal/src/components/Modal.tsx

@@ -3,7 +3,7 @@ import { defineComponent, toRefs, unref } from 'vue';
 import { basicProps } from '../props';
 import { useModalDragMove } from '../hooks/useModalDrag';
 import { useAttrs } from '@vben/hooks';
-import { extendSlots } from '/@/utils/helper/tsxHelper';
+import { extendSlots } from '@/utils/helper/tsxHelper';
 
 export default defineComponent({
   name: 'Modal',

+ 30 - 40
src/components/Modal/src/components/ModalClose.vue

@@ -13,54 +13,44 @@
     </Tooltip>
   </div>
 </template>
-<script lang="ts">
-  import { defineComponent, computed } from 'vue';
+<script lang="ts" setup>
+  import { computed } from 'vue';
   import { FullscreenExitOutlined, FullscreenOutlined, CloseOutlined } from '@ant-design/icons-vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
   import { Tooltip } from 'ant-design-vue';
-  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useDesign } from '@/hooks/web/useDesign';
+  import { useI18n } from '@/hooks/web/useI18n';
 
-  export default defineComponent({
-    name: 'ModalClose',
-    components: { Tooltip, FullscreenExitOutlined, FullscreenOutlined, CloseOutlined },
-    props: {
-      canFullscreen: { type: Boolean, default: true },
-      fullScreen: { type: Boolean },
-    },
-    emits: ['cancel', 'fullscreen'],
-    setup(props, { emit }) {
-      const { prefixCls } = useDesign('basic-modal-close');
-      const { t } = useI18n();
+  defineOptions({ name: 'ModalClose' });
 
-      const getClass = computed(() => {
-        return [
-          prefixCls,
-          `${prefixCls}--custom`,
-          {
-            [`${prefixCls}--can-full`]: props.canFullscreen,
-          },
-        ];
-      });
+  const props = defineProps({
+    canFullscreen: { type: Boolean, default: true },
+    fullScreen: { type: Boolean },
+  });
 
-      function handleCancel(e: Event) {
-        emit('cancel', e);
-      }
+  const emit = defineEmits(['cancel', 'fullscreen']);
 
-      function handleFullScreen(e: Event) {
-        e?.stopPropagation();
-        e?.preventDefault();
-        emit('fullscreen');
-      }
+  const { prefixCls } = useDesign('basic-modal-close');
+  const { t } = useI18n();
 
-      return {
-        t,
-        getClass,
-        prefixCls,
-        handleCancel,
-        handleFullScreen,
-      };
-    },
+  const getClass = computed(() => {
+    return [
+      prefixCls,
+      `${prefixCls}--custom`,
+      {
+        [`${prefixCls}--can-full`]: props.canFullscreen,
+      },
+    ];
   });
+
+  function handleCancel(e: Event) {
+    emit('cancel', e);
+  }
+
+  function handleFullScreen(e: Event) {
+    e?.stopPropagation();
+    e?.preventDefault();
+    emit('fullscreen');
+  }
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-basic-modal-close';

+ 12 - 17
src/components/Modal/src/components/ModalFooter.vue

@@ -17,25 +17,20 @@
     <slot name="appendFooter"></slot>
   </div>
 </template>
-<script lang="ts">
-  import { defineComponent } from 'vue';
-
+<script lang="ts" setup>
   import { basicProps } from '../props';
 
-  export default defineComponent({
-    name: 'BasicModalFooter',
-    props: basicProps,
-    emits: ['ok', 'cancel'],
-    setup(_, { emit }) {
-      function handleOk(e: Event) {
-        emit('ok', e);
-      }
+  defineOptions({ name: 'BasicModalFooter' });
+
+  defineProps(basicProps);
+
+  const emit = defineEmits(['ok', 'cancel']);
 
-      function handleCancel(e: Event) {
-        emit('cancel', e);
-      }
+  function handleOk(e: Event) {
+    emit('ok', e);
+  }
 
-      return { handleOk, handleCancel };
-    },
-  });
+  function handleCancel(e: Event) {
+    emit('cancel', e);
+  }
 </script>

+ 8 - 11
src/components/Modal/src/components/ModalHeader.vue

@@ -3,19 +3,16 @@
     {{ title }}
   </BasicTitle>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { PropType } from 'vue';
-  import { defineComponent } from 'vue';
-  import { BasicTitle } from '/@/components/Basic';
+  import { BasicTitle } from '@/components/Basic';
 
-  export default defineComponent({
-    name: 'BasicModalHeader',
-    components: { BasicTitle },
-    props: {
-      helpMessage: {
-        type: [String, Array] as PropType<string | string[]>,
-      },
-      title: { type: String },
+  defineOptions({ name: 'BasicModalHeader' });
+
+  defineProps({
+    helpMessage: {
+      type: [String, Array] as PropType<string | string[]>,
     },
+    title: { type: String },
   });
 </script>

+ 126 - 142
src/components/Modal/src/components/ModalWrapper.vue

@@ -5,26 +5,18 @@
     </div>
   </ScrollContainer>
 </template>
-<script lang="ts">
+<script lang="ts" setup>
   import type { CSSProperties } from 'vue';
-  import {
-    defineComponent,
-    computed,
-    ref,
-    watchEffect,
-    unref,
-    watch,
-    onMounted,
-    nextTick,
-    onUnmounted,
-  } from 'vue';
+  import { computed, ref, watchEffect, unref, watch, onMounted, nextTick, onUnmounted } from 'vue';
   import { useWindowSizeFn } from '@vben/hooks';
   import { type AnyFunction } from '@vben/types';
-  import { ScrollContainer } from '/@/components/Container';
+  import { ScrollContainer } from '@/components/Container';
   import { createModalContext } from '../hooks/useModalContext';
   import { useMutationObserver } from '@vueuse/core';
 
-  const props = {
+  defineOptions({ name: 'ModalWrapper', inheritAttrs: false });
+
+  const props = defineProps({
     loading: { type: Boolean },
     useWrapper: { type: Boolean, default: true },
     modalHeaderHeight: { type: Number, default: 57 },
@@ -35,136 +27,128 @@
     open: { type: Boolean },
     fullScreen: { type: Boolean },
     loadingTip: { type: String },
-  };
-
-  export default defineComponent({
-    name: 'ModalWrapper',
-    components: { ScrollContainer },
-    inheritAttrs: false,
-    props,
-    emits: ['height-change', 'ext-height'],
-    setup(props, { emit }) {
-      const wrapperRef = ref(null);
-      const spinRef = ref(null);
-      const realHeightRef = ref(0);
-      const minRealHeightRef = ref(0);
-
-      const realHeight = ref(0);
-
-      let stopElResizeFn: AnyFunction = () => {};
-
-      useWindowSizeFn(setModalHeight.bind(null));
-
-      useMutationObserver(
-        spinRef,
-        () => {
-          setModalHeight();
-        },
-        {
-          attributes: true,
-          subtree: true,
-        },
-      );
-
-      createModalContext({
-        redoModalHeight: setModalHeight,
-      });
-
-      const spinStyle = computed((): CSSProperties => {
-        return {
-          minHeight: `${props.minHeight}px`,
-          [props.fullScreen ? 'height' : 'maxHeight']: `${unref(realHeightRef)}px`,
-        };
-      });
-
-      watchEffect(() => {
-        props.useWrapper && setModalHeight();
-      });
-
-      watch(
-        () => props.fullScreen,
-        (v) => {
-          setModalHeight();
-          if (!v) {
-            realHeightRef.value = minRealHeightRef.value;
-          } else {
-            minRealHeightRef.value = realHeightRef.value;
-          }
-        },
-      );
-
-      onMounted(() => {
-        const { modalHeaderHeight, modalFooterHeight } = props;
-        emit('ext-height', modalHeaderHeight + modalFooterHeight);
-      });
-
-      onUnmounted(() => {
-        stopElResizeFn && stopElResizeFn();
-      });
-
-      async function scrollTop() {
-        nextTick(() => {
-          const wrapperRefDom = unref(wrapperRef);
-          if (!wrapperRefDom) return;
-          (wrapperRefDom as any)?.scrollTo?.(0);
-        });
-      }
+  });
 
-      async function setModalHeight() {
-        // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
-        // 加上这个,就必须在使用的时候传递父级的open
-        if (!props.open) return;
-        const wrapperRefDom = unref(wrapperRef);
-        if (!wrapperRefDom) return;
-
-        const bodyDom = (wrapperRefDom as any).$el.parentElement;
-        if (!bodyDom) return;
-        bodyDom.style.padding = '0';
-        await nextTick();
-
-        try {
-          const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement;
-          if (!modalDom) return;
-
-          const modalRect = getComputedStyle(modalDom as Element).top;
-          const modalTop = Number.parseInt(modalRect);
-          let maxHeight =
-            window.innerHeight -
-            modalTop * 2 +
-            (props.footerOffset! || 0) -
-            props.modalFooterHeight -
-            props.modalHeaderHeight;
-
-          // 距离顶部过进会出现滚动条
-          if (modalTop < 40) {
-            maxHeight -= 26;
-          }
-          await nextTick();
-          const spinEl: any = unref(spinRef);
-
-          if (!spinEl) return;
-          await nextTick();
-          // if (!realHeight) {
-          realHeight.value = spinEl.scrollHeight;
-          // }
-
-          if (props.fullScreen) {
-            realHeightRef.value =
-              window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 28;
-          } else {
-            realHeightRef.value = props.height
-              ? props.height
-              : realHeight.value > maxHeight
-              ? maxHeight
-              : realHeight.value;
-          }
-          emit('height-change', unref(realHeightRef));
-        } catch (error) {
-          console.log(error);
-        }
-      }
+  const emit = defineEmits(['height-change', 'ext-height']);
+
+  const wrapperRef = ref(null);
+  const spinRef = ref(null);
+  const realHeightRef = ref(0);
+  const minRealHeightRef = ref(0);
+  const realHeight = ref(0);
+
+  let stopElResizeFn: AnyFunction = () => {};
+
+  useWindowSizeFn(setModalHeight.bind(null));
+
+  useMutationObserver(
+    spinRef,
+    () => {
+      setModalHeight();
+    },
+    {
+      attributes: true,
+      subtree: true,
+    },
+  );
+
+  createModalContext({
+    redoModalHeight: setModalHeight,
+  });
 
-      return { wrapperRef, spinRef, spinStyle, scrollTop, setModalHeight, realHeight };
+  const spinStyle = computed((): CSSProperties => {
+    return {
+      minHeight: `${props.minHeight}px`,
+      [props.fullScreen ? 'height' : 'maxHeight']: `${unref(realHeightRef)}px`,
+    };
+  });
+
+  watchEffect(() => {
+    props.useWrapper && setModalHeight();
+  });
+
+  watch(
+    () => props.fullScreen,
+    (v) => {
+      setModalHeight();
+      if (!v) {
+        realHeightRef.value = minRealHeightRef.value;
+      } else {
+        minRealHeightRef.value = realHeightRef.value;
+      }
     },
+  );
+
+  onMounted(() => {
+    const { modalHeaderHeight, modalFooterHeight } = props;
+    emit('ext-height', modalHeaderHeight + modalFooterHeight);
   });
+
+  onUnmounted(() => {
+    stopElResizeFn && stopElResizeFn();
+  });
+
+  async function scrollTop() {
+    nextTick(() => {
+      const wrapperRefDom = unref(wrapperRef);
+      if (!wrapperRefDom) return;
+      (wrapperRefDom as any)?.scrollTo?.(0);
+    });
+  }
+
+  async function setModalHeight() {
+    // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
+    // 加上这个,就必须在使用的时候传递父级的open
+    if (!props.open) return;
+    const wrapperRefDom = unref(wrapperRef);
+    if (!wrapperRefDom) return;
+
+    const bodyDom = (wrapperRefDom as any).$el.parentElement;
+    if (!bodyDom) return;
+    bodyDom.style.padding = '0';
+    await nextTick();
+
+    try {
+      const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement;
+      if (!modalDom) return;
+
+      const modalRect = getComputedStyle(modalDom as Element).top;
+      const modalTop = Number.parseInt(modalRect);
+      let maxHeight =
+        window.innerHeight -
+        modalTop * 2 +
+        (props.footerOffset! || 0) -
+        props.modalFooterHeight -
+        props.modalHeaderHeight;
+
+      // 距离顶部过进会出现滚动条
+      if (modalTop < 40) {
+        maxHeight -= 26;
+      }
+      await nextTick();
+      const spinEl: any = unref(spinRef);
+
+      if (!spinEl) return;
+      await nextTick();
+      // if (!realHeight) {
+      realHeight.value = spinEl.scrollHeight;
+      // }
+
+      if (props.fullScreen) {
+        realHeightRef.value =
+          window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 28;
+      } else {
+        realHeightRef.value = props.height
+          ? props.height
+          : realHeight.value > maxHeight
+          ? maxHeight
+          : realHeight.value;
+      }
+      emit('height-change', unref(realHeightRef));
+    } catch (error) {
+      console.log(error);
+    }
+  }
+
+  defineExpose({ scrollTop });
 </script>

+ 3 - 3
src/components/Modal/src/hooks/useModal.ts

@@ -16,11 +16,11 @@ import {
   toRaw,
   computed,
 } from 'vue';
-import { isProdMode } from '/@/utils/env';
-import { isFunction } from '/@/utils/is';
+import { isProdMode } from '@/utils/env';
+import { isFunction } from '@/utils/is';
 import { isEqual } from 'lodash-es';
 import { tryOnUnmounted } from '@vueuse/core';
-import { error } from '/@/utils/log';
+import { error } from '@/utils/log';
 
 const dataTransfer = reactive<any>({});
 

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác