Sfoglia il codice sorgente

perf: perf modal and drawer

vben 4 anni fa
parent
commit
81baf1d5c4

+ 6 - 0
CHANGELOG.zh_CN.md

@@ -18,12 +18,18 @@
 
 - 缓存可以配置是否加密,默认生产环境开启 Aes 加密
 - 新增标签页拖拽排序
+- 新增 LayoutFooter.默认显示,可以在配置内关闭
+
+### ⚡ Performance Improvements
+
+- 优化`Modal`组件全屏动画不流畅问题
 
 ### 🐛 Bug Fixes
 
 - 修复 tree 文本超出挡住操作按钮问题
 - 修复通过 useRedo 刷新页面参数丢失问题
 - 修复表单校验先设置在校验及控制台错误信息问题
+- 修复`modal`与`drawer`组件传递数组参数问题
 
 ### 🎫 Chores
 

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

@@ -1,4 +1,6 @@
-export { default as BasicDrawer } from './src/BasicDrawer';
+import BasicDrawerLib from './src/BasicDrawer';
+import { withInstall } from '../util';
 
-export { useDrawer, useDrawerInner } from './src/useDrawer';
 export * from './src/types';
+export { useDrawer, useDrawerInner } from './src/useDrawer';
+export const BasicDrawer = withInstall(BasicDrawerLib);

+ 137 - 120
src/components/Drawer/src/BasicDrawer.tsx

@@ -1,6 +1,7 @@
 import './index.less';
 
 import type { DrawerInstance, DrawerProps } from './types';
+import type { CSSProperties } from 'vue';
 
 import { defineComponent, ref, computed, watchEffect, watch, unref, nextTick, toRaw } from 'vue';
 import { Drawer, Row, Col, Button } from 'ant-design-vue';
@@ -9,53 +10,96 @@ import { BasicTitle } from '/@/components/Basic';
 import { FullLoading } from '/@/components/Loading/index';
 import { LeftOutlined } from '@ant-design/icons-vue';
 
-import { basicProps } from './props';
+import { useI18n } from '/@/hooks/web/useI18n';
 
 import { getSlot } from '/@/utils/helper/tsxHelper';
 import { isFunction, isNumber } from '/@/utils/is';
-import { buildUUID } from '/@/utils/uuid';
 import { deepMerge } from '/@/utils';
-import { useI18n } from '/@/hooks/web/useI18n';
+import { tryTsxEmit } from '/@/utils/helper/vueHelper';
+
+import { basicProps } from './props';
 
 const prefixCls = 'basic-drawer';
 export default defineComponent({
-  // inheritAttrs: false,
+  inheritAttrs: false,
   props: basicProps,
   emits: ['visible-change', 'ok', 'close', 'register'],
   setup(props, { slots, emit, attrs }) {
     const scrollRef = ref<ElRef>(null);
-
     const visibleRef = ref(false);
-    const propsRef = ref<Partial<DrawerProps> | null>(null);
+    const propsRef = ref<Partial<Nullable<DrawerProps>>>(null);
 
     const { t } = useI18n('component.drawer');
 
-    const getMergeProps = computed((): any => {
-      return deepMerge(toRaw(props), unref(propsRef));
-    });
-
-    const getProps = computed(() => {
-      const opt: any = {
-        placement: 'right',
-        ...attrs,
-        ...props,
-        ...(unref(propsRef) as any),
-        visible: unref(visibleRef),
-      };
-      opt.title = undefined;
+    const getMergeProps = computed(
+      (): DrawerProps => {
+        return deepMerge(toRaw(props), unref(propsRef));
+      }
+    );
 
-      if (opt.isDetail) {
-        if (!opt.width) {
-          opt.width = '100%';
-        }
-        opt.wrapClassName = opt.wrapClassName
-          ? `${opt.wrapClassName} ${prefixCls}__detail`
-          : `${prefixCls}__detail`;
-        if (!opt.getContainer) {
-          opt.getContainer = '.layout-content';
+    const getProps = computed(
+      (): DrawerProps => {
+        const opt = {
+          placement: 'right',
+          ...attrs,
+          ...unref(getMergeProps),
+          visible: unref(visibleRef),
+        };
+        opt.title = undefined;
+        const { isDetail, width, wrapClassName, getContainer } = opt;
+        if (isDetail) {
+          if (!width) {
+            opt.width = '100%';
+          }
+          const detailCls = `${prefixCls}__detail`;
+
+          opt.wrapClassName = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls;
+
+          if (!getContainer) {
+            // TODO type error?
+            opt.getContainer = '.layout-content' as any;
+          }
         }
+        return opt as DrawerProps;
       }
-      return opt;
+    );
+
+    const getBindValues = computed(
+      (): DrawerProps => {
+        return {
+          ...attrs,
+          ...unref(getProps),
+        };
+      }
+    );
+
+    // 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`;
+    });
+
+    const getScrollContentStyle = computed(
+      (): CSSProperties => {
+        const footerHeight = unref(getFooterHeight);
+        return {
+          position: 'relative',
+          height: `calc(100% - ${footerHeight})`,
+          overflow: 'auto',
+          padding: '16px',
+          paddingBottom: '30px',
+        };
+      }
+    );
+
+    const getLoading = computed(() => {
+      return {
+        hidden: !unref(getProps).loading,
+      };
     });
 
     watchEffect(() => {
@@ -74,22 +118,13 @@ export default defineComponent({
       }
     );
 
-    // Custom implementation of the bottom button,
-    const getFooterHeight = computed(() => {
-      const { footerHeight, showFooter }: DrawerProps = unref(getProps);
-      if (showFooter && footerHeight) {
-        return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`;
-      }
-      return `0px`;
-    });
-
     // Cancel event
-    async function onClose(e: any) {
+    async function onClose(e: ChangeEvent) {
       const { closeFunc } = unref(getProps);
       emit('close', e);
       if (closeFunc && isFunction(closeFunc)) {
         const res = await closeFunc();
-        res && (visibleRef.value = false);
+        visibleRef.value = !res;
         return;
       }
       visibleRef.value = false;
@@ -98,12 +133,16 @@ export default defineComponent({
     function setDrawerProps(props: Partial<DrawerProps>): void {
       // Keep the last setDrawerProps
       propsRef.value = deepMerge(unref(propsRef) || {}, props);
+
       if (Reflect.has(props, 'visible')) {
         visibleRef.value = !!props.visible;
       }
     }
 
     function renderFooter() {
+      if (slots?.footer) {
+        return getSlot(slots, 'footer');
+      }
       const {
         showCancelBtn,
         cancelButtonProps,
@@ -114,65 +153,64 @@ export default defineComponent({
         okButtonProps,
         confirmLoading,
         showFooter,
-      }: DrawerProps = unref(getProps);
+      } = unref(getProps);
+      if (!showFooter) {
+        return null;
+      }
 
       return (
-        getSlot(slots, 'footer') ||
-        (showFooter && (
-          <div class={`${prefixCls}__footer`}>
-            {getSlot(slots, 'insertFooter')}
-
-            {showCancelBtn && (
-              <Button {...cancelButtonProps} onClick={onClose} class="mr-2">
-                {() => cancelText}
-              </Button>
-            )}
-            {getSlot(slots, 'centerFooter')}
-            {showOkBtn && (
-              <Button
-                type={okType}
-                onClick={() => {
-                  emit('ok');
-                }}
-                {...okButtonProps}
-                loading={confirmLoading}
-              >
-                {() => okText}
-              </Button>
-            )}
-
-            {getSlot(slots, 'appendFooter')}
-          </div>
-        ))
+        <div class={`${prefixCls}__footer`}>
+          {getSlot(slots, 'insertFooter')}
+          {showCancelBtn && (
+            <Button {...cancelButtonProps} onClick={onClose} class="mr-2">
+              {() => cancelText}
+            </Button>
+          )}
+          {getSlot(slots, 'centerFooter')}
+          {showOkBtn && (
+            <Button
+              type={okType}
+              onClick={() => {
+                emit('ok');
+              }}
+              {...okButtonProps}
+              loading={confirmLoading}
+            >
+              {() => okText}
+            </Button>
+          )}
+          {getSlot(slots, 'appendFooter')}
+        </div>
       );
     }
 
     function renderHeader() {
+      if (slots?.title) {
+        return getSlot(slots, 'title');
+      }
       const { title } = unref(getMergeProps);
-      return props.isDetail ? (
-        getSlot(slots, 'title') || (
-          <Row type="flex" align="middle" class={`${prefixCls}__detail-header`}>
-            {() => (
-              <>
-                {props.showDetailBack && (
-                  <Button size="small" type="link" onClick={onClose}>
-                    {() => <LeftOutlined />}
-                  </Button>
-                )}
-
-                {title && (
-                  <Col style="flex:1" class={[`${prefixCls}__detail-title`, 'ellipsis', 'px-2']}>
-                    {() => title}
-                  </Col>
-                )}
-
-                {getSlot(slots, 'titleToolbar')}
-              </>
-            )}
-          </Row>
-        )
-      ) : (
-        <BasicTitle>{() => title || getSlot(slots, 'title')}</BasicTitle>
+
+      if (!props.isDetail) {
+        return <BasicTitle>{() => title || getSlot(slots, 'title')}</BasicTitle>;
+      }
+      return (
+        <Row type="flex" align="middle" class={`${prefixCls}__detail-header`}>
+          {() => (
+            <>
+              {props.showDetailBack && (
+                <Button size="small" type="link" onClick={onClose}>
+                  {() => <LeftOutlined />}
+                </Button>
+              )}
+              {title && (
+                <Col style="flex:1" class={[`${prefixCls}__detail-title`, 'ellipsis', 'px-2']}>
+                  {() => title}
+                </Col>
+              )}
+              {getSlot(slots, 'titleToolbar')}
+            </>
+          )}
+        </Row>
       );
     }
 
@@ -180,41 +218,20 @@ export default defineComponent({
       setDrawerProps: setDrawerProps,
     };
 
-    const uuid = buildUUID();
-    emit('register', drawerInstance, uuid);
+    tryTsxEmit((instance) => {
+      emit('register', drawerInstance, instance.uid);
+    });
 
     return () => {
-      const footerHeight = unref(getFooterHeight);
       return (
-        <Drawer
-          class={prefixCls}
-          onClose={onClose}
-          {...{
-            ...attrs,
-            ...unref(getProps),
-          }}
-        >
+        <Drawer class={prefixCls} onClose={onClose} {...unref(getBindValues)}>
           {{
             title: () => renderHeader(),
             default: () => (
               <>
-                <div
-                  ref={scrollRef}
-                  {...attrs}
-                  style={{
-                    position: 'relative',
-                    height: `calc(100% - ${footerHeight})`,
-                    overflow: 'auto',
-                    padding: '16px',
-                    paddingBottom: '30px',
-                  }}
-                >
-                  <FullLoading
-                    absolute
-                    tip={t('loadingText')}
-                    class={[!unref(getProps).loading ? 'hidden' : '']}
-                  />
-                  {getSlot(slots, 'default')}
+                <div ref={scrollRef} style={unref(getScrollContentStyle)}>
+                  <FullLoading absolute tip={t('loadingText')} class={unref(getLoading)} />
+                  {getSlot(slots)}
                 </div>
                 {renderFooter()}
               </>

+ 17 - 55
src/components/Drawer/src/props.ts

@@ -1,72 +1,37 @@
 import type { PropType } from 'vue';
 
 import { useI18n } from '/@/hooks/web/useI18n';
+import { propTypes } from '/@/utils/propTypes';
 const { t } = useI18n('component.drawer');
 
 export const footerProps = {
-  confirmLoading: Boolean as PropType<boolean>,
+  confirmLoading: propTypes.bool,
   /**
    * @description: Show close button
    */
-  showCancelBtn: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
+  showCancelBtn: propTypes.bool.def(true),
   cancelButtonProps: Object as PropType<any>,
-  cancelText: {
-    type: String as PropType<string>,
-    default: t('cancelText'),
-  },
+  cancelText: propTypes.string.def(t('cancelText')),
   /**
    * @description: Show confirmation button
    */
-  showOkBtn: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
-  okButtonProps: Object as PropType<any>,
-  okText: {
-    type: String as PropType<string>,
-    default: t('okText'),
-  },
-  okType: {
-    type: String as PropType<string>,
-    default: 'primary',
-  },
-  showFooter: {
-    type: Boolean as PropType<boolean>,
-    default: false,
-  },
+  showOkBtn: propTypes.bool.def(true),
+  okButtonProps: propTypes.any,
+  okText: propTypes.string.def(t('okText')),
+  okType: propTypes.string.def('primary'),
+  showFooter: propTypes.bool,
   footerHeight: {
     type: [String, Number] as PropType<string | number>,
     default: 60,
   },
 };
 export const basicProps = {
-  isDetail: {
-    type: Boolean as PropType<boolean>,
-    default: false,
-  },
-  title: {
-    type: String as PropType<string>,
-    default: '',
-  },
-  showDetailBack: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
-  visible: {
-    type: Boolean as PropType<boolean>,
-    default: false,
-  },
-  loading: {
-    type: Boolean as PropType<boolean>,
-    default: false,
-  },
-  maskClosable: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
+  isDetail: propTypes.bool,
+  title: propTypes.string.def(''),
+  showDetailBack: propTypes.bool.def(true),
+  visible: propTypes.bool,
+  loading: propTypes.bool,
+  maskClosable: propTypes.bool.def(true),
   getContainer: {
     type: [Object, String] as PropType<any>,
   },
@@ -78,10 +43,7 @@ export const basicProps = {
     type: [Function, Object] as PropType<any>,
     default: null,
   },
-  triggerWindowResize: {
-    type: Boolean as PropType<boolean>,
-    default: false,
-  },
-  destroyOnClose: Boolean as PropType<boolean>,
+  triggerWindowResize: propTypes.bool,
+  destroyOnClose: propTypes.bool,
   ...footerProps,
 };

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

@@ -75,7 +75,7 @@ export interface DrawerProps extends DrawerFooterProps {
    * @type ScrollContainerOptions
    */
   scrollOptions?: ScrollContainerOptions;
-  closeFunc?: () => Promise<void>;
+  closeFunc?: () => Promise<any>;
   triggerWindowResize?: boolean;
   /**
    * Whether a close (x) button is visible on top right of the Drawer dialog or not.

+ 30 - 16
src/components/Drawer/src/useDrawer.ts

@@ -6,12 +6,15 @@ import type {
   UseDrawerInnerReturnType,
 } from './types';
 
-import { ref, getCurrentInstance, onUnmounted, unref, reactive, watchEffect, nextTick } from 'vue';
+import { ref, getCurrentInstance, unref, reactive, watchEffect, nextTick, toRaw } from 'vue';
 
 import { isProdMode } from '/@/utils/env';
 import { isFunction } from '/@/utils/is';
+import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
+import { isEqual } from 'lodash-es';
 
 const dataTransferRef = reactive<any>({});
+
 /**
  * @description: Applicable to separate drawer and call outside
  */
@@ -19,21 +22,23 @@ export function useDrawer(): UseDrawerReturnType {
   if (!getCurrentInstance()) {
     throw new Error('Please put useDrawer function in the setup function!');
   }
+
   const drawerRef = ref<DrawerInstance | null>(null);
-  const loadedRef = ref<boolean | null>(false);
+  const loadedRef = ref<Nullable<boolean>>(false);
   const uidRef = ref<string>('');
 
-  function getDrawer(drawerInstance: DrawerInstance, uuid: string) {
-    uidRef.value = uuid;
+  function register(drawerInstance: DrawerInstance, uuid: string) {
     isProdMode() &&
-      onUnmounted(() => {
+      tryOnUnmounted(() => {
         drawerRef.value = null;
         loadedRef.value = null;
         dataTransferRef[unref(uidRef)] = null;
       });
+
     if (unref(loadedRef) && isProdMode() && drawerInstance === unref(drawerRef)) {
       return;
     }
+    uidRef.value = uuid;
     drawerRef.value = drawerInstance;
     loadedRef.value = true;
   }
@@ -55,37 +60,46 @@ export function useDrawer(): UseDrawerReturnType {
       getInstance().setDrawerProps({
         visible: visible,
       });
-      if (data) {
-        dataTransferRef[unref(uidRef)] = openOnSet
-          ? {
-              ...data,
-              __t__: Date.now(),
-            }
-          : data;
+      if (!data) return;
+
+      if (openOnSet) {
+        dataTransferRef[unref(uidRef)] = null;
+        dataTransferRef[unref(uidRef)] = data;
+        return;
+      }
+      const equal = isEqual(toRaw(dataTransferRef[unref(uidRef)]), data);
+      if (!equal) {
+        dataTransferRef[unref(uidRef)] = data;
       }
     },
   };
 
-  return [getDrawer, methods];
+  return [register, methods];
 }
+
 export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => {
-  const drawerInstanceRef = ref<DrawerInstance | null>(null);
+  const drawerInstanceRef = ref<Nullable<DrawerInstance>>(null);
   const currentInstall = getCurrentInstance();
   const uidRef = ref<string>('');
 
   if (!currentInstall) {
-    throw new Error('instance is undefined!');
+    throw new Error('useDrawerInner instance is undefined!');
   }
 
   const getInstance = () => {
     const instance = unref(drawerInstanceRef);
     if (!instance) {
-      throw new Error('instance is undefined!');
+      throw new Error('useDrawerInner instance is undefined!');
     }
     return instance;
   };
 
   const register = (modalInstance: DrawerInstance, uuid: string) => {
+    isProdMode() &&
+      tryOnUnmounted(() => {
+        drawerInstanceRef.value = null;
+      });
+
     uidRef.value = uuid;
     drawerInstanceRef.value = modalInstance;
     currentInstall.emit('register', modalInstance);

+ 5 - 2
src/components/Modal/index.ts

@@ -1,5 +1,8 @@
 import './src/index.less';
-export { default as BasicModal } from './src/BasicModal';
-export { default as Modal } from './src/Modal';
+import BasicModalLib from './src/BasicModal';
+import { withInstall } from '../util';
+
+export { useModalContext } from './src/useModalContext';
 export { useModal, useModalInner } from './src/useModal';
 export * from './src/types';
+export const BasicModal = withInstall(BasicModalLib);

+ 82 - 83
src/components/Modal/src/BasicModal.tsx

@@ -1,6 +1,6 @@
 import type { ModalProps, ModalMethods } from './types';
 
-import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue';
+import { defineComponent, computed, ref, watch, unref, watchEffect, toRef } from 'vue';
 
 import Modal from './Modal';
 import { Button } from '/@/components/Button';
@@ -11,10 +11,10 @@ import { FullscreenExitOutlined, FullscreenOutlined, CloseOutlined } from '@ant-
 import { getSlot, extendSlots } from '/@/utils/helper/tsxHelper';
 import { isFunction } from '/@/utils/is';
 import { deepMerge } from '/@/utils';
-import { buildUUID } from '/@/utils/uuid';
+import { tryTsxEmit } from '/@/utils/helper/vueHelper';
 
 import { basicProps } from './props';
-// import { triggerWindowResize } from '@/utils/event/triggerWindowResizeEvent';
+import { useFullScreen } from './useFullScreen';
 export default defineComponent({
   name: 'BasicModal',
   props: basicProps,
@@ -26,31 +26,41 @@ export default defineComponent({
     // modal   Bottom and top height
     const extHeightRef = ref(0);
     // Unexpanded height of the popup
-    const formerHeightRef = ref(0);
-    const fullScreenRef = ref(false);
 
     // Custom title component: get title
-    const getMergeProps = computed(() => {
-      return {
-        ...props,
-        ...(unref(propsRef) as any),
-      };
+    const getMergeProps = computed(
+      (): ModalProps => {
+        return {
+          ...props,
+          ...(unref(propsRef) as any),
+        };
+      }
+    );
+
+    const { handleFullScreen, getWrapClassName, fullScreenRef } = useFullScreen({
+      modalWrapperRef,
+      extHeightRef,
+      wrapClassName: toRef(getMergeProps.value, 'wrapClassName'),
     });
 
     // modal component does not need title
-    const getProps = computed((): any => {
-      const opt = {
-        ...props,
-        ...((unref(propsRef) || {}) as any),
-        visible: unref(visibleRef),
-        title: undefined,
-      };
-      const { wrapClassName = '' } = opt;
-      const className = unref(fullScreenRef) ? `${wrapClassName} fullscreen-modal` : wrapClassName;
-      return {
-        ...opt,
-        wrapClassName: className,
-      };
+    const getProps = computed(
+      (): ModalProps => {
+        const opt = {
+          ...unref(getMergeProps),
+          visible: unref(visibleRef),
+          title: undefined,
+        };
+
+        return {
+          ...opt,
+          wrapClassName: unref(getWrapClassName),
+        };
+      }
+    );
+
+    const getModalBindValue = computed((): any => {
+      return { ...attrs, ...unref(getProps) };
     });
 
     watchEffect(() => {
@@ -80,7 +90,35 @@ export default defineComponent({
       );
     }
 
+    // 取消事件
+    async function handleCancel(e: Event) {
+      e?.stopPropagation();
+
+      if (props.closeFunc && isFunction(props.closeFunc)) {
+        const isClose: boolean = await props.closeFunc();
+        visibleRef.value = !isClose;
+        return;
+      }
+
+      visibleRef.value = false;
+      emit('cancel');
+    }
+
+    /**
+     * @description: 设置modal参数
+     */
+    function setModalProps(props: Partial<ModalProps>): void {
+      // Keep the last setModalProps
+      propsRef.value = deepMerge(unref(propsRef) || {}, props);
+      if (!Reflect.has(props, 'visible')) return;
+      visibleRef.value = !!props.visible;
+    }
+
     function renderContent() {
+      type OmitWrapperType = Omit<
+        ModalProps,
+        'fullScreen' | 'modalFooterHeight' | 'visible' | 'loading'
+      >;
       const { useWrapper, loading, wrapperProps } = unref(getProps);
       if (!useWrapper) return getSlot(slots);
 
@@ -93,7 +131,7 @@ export default defineComponent({
           loading={loading}
           visible={unref(visibleRef)}
           modalFooterHeight={showFooter}
-          {...wrapperProps}
+          {...((wrapperProps as unknown) as OmitWrapperType)}
           onGetExtHeight={(height: number) => {
             extHeightRef.value = height;
           }}
@@ -106,18 +144,6 @@ export default defineComponent({
       );
     }
 
-    // 取消事件
-    async function handleCancel(e: Event) {
-      e && e.stopPropagation();
-      if (props.closeFunc && isFunction(props.closeFunc)) {
-        const isClose: boolean = await props.closeFunc();
-        visibleRef.value = !isClose;
-        return;
-      }
-      visibleRef.value = false;
-      emit('cancel');
-    }
-
     // 底部按钮自定义实现,
     function renderFooter() {
       const {
@@ -162,64 +188,37 @@ export default defineComponent({
      */
     function renderClose() {
       const { canFullscreen } = unref(getProps);
-      if (!canFullscreen) {
-        return null;
-      }
+
+      const fullScreen = unref(fullScreenRef) ? (
+        <FullscreenExitOutlined role="full" onClick={handleFullScreen} />
+      ) : (
+        <FullscreenOutlined role="close" onClick={handleFullScreen} />
+      );
+
+      const cls = [
+        'custom-close-icon',
+        {
+          'can-full': canFullscreen,
+        },
+      ];
+
       return (
-        <div class="custom-close-icon">
-          {unref(fullScreenRef) ? (
-            <FullscreenExitOutlined role="full" onClick={handleFullScreen} />
-          ) : (
-            <FullscreenOutlined role="close" onClick={handleFullScreen} />
-          )}
+        <div class={cls}>
+          {canFullscreen && fullScreen}
           <CloseOutlined onClick={handleCancel} />
         </div>
       );
     }
 
-    function handleFullScreen(e: Event) {
-      e && e.stopPropagation();
-      fullScreenRef.value = !unref(fullScreenRef);
-
-      const modalWrapper = unref(modalWrapperRef);
-      if (!modalWrapper) return;
-
-      const wrapperEl = modalWrapper.$el as HTMLElement;
-      if (!wrapperEl) return;
-
-      const modalWrapSpinEl = wrapperEl.querySelector('.ant-spin-nested-loading') as HTMLElement;
-      if (!modalWrapSpinEl) return;
-
-      if (!unref(formerHeightRef) && unref(fullScreenRef)) {
-        formerHeightRef.value = modalWrapSpinEl.offsetHeight;
-      }
-
-      if (unref(fullScreenRef)) {
-        modalWrapSpinEl.style.height = `${window.innerHeight - unref(extHeightRef)}px`;
-      } else {
-        modalWrapSpinEl.style.height = `${unref(formerHeightRef)}px`;
-      }
-    }
-
-    /**
-     * @description: 设置modal参数
-     */
-    function setModalProps(props: Partial<ModalProps>): void {
-      // Keep the last setModalProps
-      propsRef.value = deepMerge(unref(propsRef) || {}, props);
-      if (!Reflect.has(props, 'visible')) return;
-      visibleRef.value = !!props.visible;
-    }
-
     const modalMethods: ModalMethods = {
       setModalProps,
     };
 
-    const uuid = buildUUID();
-    emit('register', modalMethods, uuid);
-
+    tryTsxEmit((instance) => {
+      emit('register', modalMethods, instance.uid);
+    });
     return () => (
-      <Modal onCancel={handleCancel} {...{ ...attrs, ...props, ...unref(getProps) }}>
+      <Modal onCancel={handleCancel} {...unref(getModalBindValue)}>
         {{
           footer: () => renderFooter(),
           closeIcon: () => renderClose(),

+ 7 - 94
src/components/Modal/src/Modal.tsx

@@ -1,7 +1,7 @@
 import { Modal } from 'ant-design-vue';
-import { defineComponent, watchEffect } from 'vue';
+import { defineComponent, toRefs } from 'vue';
 import { basicProps } from './props';
-import { useTimeoutFn } from '/@/hooks/core/useTimeout';
+import { useModalDragMove } from './useModalDrag';
 import { extendSlots } from '/@/utils/helper/tsxHelper';
 
 export default defineComponent({
@@ -9,99 +9,12 @@ export default defineComponent({
   inheritAttrs: false,
   props: basicProps,
   setup(props, { attrs, slots }) {
-    const getStyle = (dom: any, attr: any) => {
-      return getComputedStyle(dom)[attr];
-    };
-    const drag = (wrap: any) => {
-      if (!wrap) return;
-      wrap.setAttribute('data-drag', props.draggable);
-      const dialogHeaderEl = wrap.querySelector('.ant-modal-header');
-      const dragDom = wrap.querySelector('.ant-modal');
-
-      if (!dialogHeaderEl || !dragDom || !props.draggable) return;
-
-      dialogHeaderEl.style.cursor = 'move';
-
-      dialogHeaderEl.onmousedown = (e: any) => {
-        if (!e) return;
-        // 鼠标按下,计算当前元素距离可视区的距离
-        const disX = e.clientX;
-        const disY = e.clientY;
-        const screenWidth = document.body.clientWidth; // body当前宽度
-        const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取)
-
-        const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
-        const dragDomheight = dragDom.offsetHeight; // 对话框高度
-
-        const minDragDomLeft = dragDom.offsetLeft;
-
-        const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
-        const minDragDomTop = dragDom.offsetTop;
-        const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;
-        // 获取到的值带px 正则匹配替换
-        const domLeft = getStyle(dragDom, 'left');
-        const domTop = getStyle(dragDom, 'top');
-        let styL = +domLeft;
-        let styT = +domTop;
-
-        // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
-        if (domLeft.includes('%')) {
-          styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100);
-          styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100);
-        } else {
-          styL = +domLeft.replace(/px/g, '');
-          styT = +domTop.replace(/px/g, '');
-        }
-
-        document.onmousemove = function (e) {
-          // 通过事件委托,计算移动的距离
-          let left = e.clientX - disX;
-          let top = e.clientY - disY;
-
-          // 边界处理
-          if (-left > minDragDomLeft) {
-            left = -minDragDomLeft;
-          } else if (left > maxDragDomLeft) {
-            left = maxDragDomLeft;
-          }
-
-          if (-top > minDragDomTop) {
-            top = -minDragDomTop;
-          } else if (top > maxDragDomTop) {
-            top = maxDragDomTop;
-          }
-
-          // 移动当前元素
-          dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
-        };
-
-        document.onmouseup = () => {
-          document.onmousemove = null;
-          document.onmouseup = null;
-        };
-      };
-    };
-
-    const handleDrag = () => {
-      const dragWraps = document.querySelectorAll('.ant-modal-wrap');
-      for (const wrap of dragWraps as any) {
-        if (!wrap) continue;
-        const display = getStyle(wrap, 'display');
-        const draggable = wrap.getAttribute('data-drag');
-        if (display !== 'none') {
-          // 拖拽位置
-          (draggable === null || props.destroyOnClose) && drag(wrap);
-        }
-      }
-    };
+    const { visible, draggable, destroyOnClose } = toRefs(props);
 
-    watchEffect(() => {
-      if (!props.visible) {
-        return;
-      }
-      useTimeoutFn(() => {
-        handleDrag();
-      }, 30);
+    useModalDragMove({
+      visible,
+      destroyOnClose,
+      draggable,
     });
 
     return () => {

+ 31 - 46
src/components/Modal/src/ModalWrapper.tsx

@@ -1,5 +1,5 @@
-import type { PropType } from 'vue';
 import type { ModalWrapperProps } from './types';
+import type { CSSProperties } from 'vue';
 
 import {
   defineComponent,
@@ -18,59 +18,44 @@ import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
 
 import { getSlot } from '/@/utils/helper/tsxHelper';
 import { useElResize } from '/@/hooks/event/useElResize';
-import { provideModal } from './provideModal';
+import { propTypes } from '/@/utils/propTypes';
+import { createModalContext } from './useModalContext';
 
 export default defineComponent({
   name: 'ModalWrapper',
   props: {
-    loading: {
-      type: Boolean as PropType<boolean>,
-      default: false,
-    },
-    modalHeaderHeight: {
-      type: Number as PropType<number>,
-      default: 50,
-    },
-    modalFooterHeight: {
-      type: Number as PropType<number>,
-      default: 70,
-    },
-    minHeight: {
-      type: Number as PropType<number>,
-      default: 200,
-    },
-    footerOffset: {
-      type: Number as PropType<number>,
-      default: 0,
-    },
-    visible: {
-      type: Boolean as PropType<boolean>,
-      default: false,
-    },
-    fullScreen: {
-      type: Boolean as PropType<boolean>,
-      default: false,
-    },
+    loading: propTypes.bool,
+    modalHeaderHeight: propTypes.number.def(50),
+    modalFooterHeight: propTypes.number.def(54),
+    minHeight: propTypes.number.def(200),
+    footerOffset: propTypes.number.def(0),
+    visible: propTypes.bool,
+    fullScreen: propTypes.bool,
   },
   emits: ['heightChange', 'getExtHeight'],
   setup(props: ModalWrapperProps, { slots, emit }) {
-    const wrapperRef = ref<HTMLElement | null>(null);
+    const wrapperRef = ref<ElRef>(null);
     const spinRef = ref<ComponentRef>(null);
     const realHeightRef = ref(0);
-    // 重试次数
-    // let tryCount = 0;
+
     let stopElResizeFn: Fn = () => {};
 
-    provideModal(setModalHeight);
+    useWindowSizeFn(setModalHeight);
 
-    const wrapStyle = computed(() => {
-      return {
-        minHeight: `${props.minHeight}px`,
-        height: `${unref(realHeightRef)}px`,
-        overflow: 'auto',
-      };
+    createModalContext({
+      redoModalHeight: setModalHeight,
     });
 
+    const wrapStyle = computed(
+      (): CSSProperties => {
+        return {
+          minHeight: `${props.minHeight}px`,
+          height: `${unref(realHeightRef)}px`,
+          overflow: 'auto',
+        };
+      }
+    );
+
     watchEffect(() => {
       setModalHeight();
     });
@@ -92,8 +77,6 @@ export default defineComponent({
       stopElResizeFn && stopElResizeFn();
     });
 
-    useWindowSizeFn(setModalHeight);
-
     async function setModalHeight() {
       // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
       // 加上这个,就必须在使用的时候传递父级的visible
@@ -107,9 +90,8 @@ export default defineComponent({
 
       try {
         const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement;
-        if (!modalDom) {
-          return;
-        }
+        if (!modalDom) return;
+
         const modalRect = getComputedStyle(modalDom).top;
         const modalTop = Number.parseInt(modalRect);
         let maxHeight =
@@ -135,11 +117,12 @@ export default defineComponent({
 
         if (props.fullScreen) {
           realHeightRef.value =
-            window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 6;
+            window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight;
         } else {
           realHeightRef.value = realHeight > maxHeight ? maxHeight : realHeight + 16 + 30;
         }
         emit('heightChange', unref(realHeightRef));
+
         nextTick(() => {
           const el = spinEl.$el;
           if (el) {
@@ -154,8 +137,10 @@ export default defineComponent({
     function listenElResize() {
       const wrapper = unref(wrapperRef);
       if (!wrapper) return;
+
       const container = wrapper.querySelector('.ant-spin-container');
       if (!container) return;
+
       const [start, stop] = useElResize(container, () => {
         setModalHeight();
       });

+ 23 - 3
src/components/Modal/src/index.less

@@ -9,6 +9,11 @@
     bottom: 0 !important;
     left: 0 !important;
     width: 100% !important;
+    height: 100%;
+
+    &-content {
+      height: 100%;
+    }
   }
 }
 
@@ -35,8 +40,23 @@
     height: 95%;
     align-items: center;
 
-    > * {
-      margin-left: 12px;
+    > span {
+      margin-left: 48px;
+      font-size: 16px;
+    }
+
+    &.can-full {
+      > span {
+        margin-left: 12px;
+      }
+    }
+
+    &:not(.can-full) {
+      > span:nth-child(1) {
+        &:hover {
+          font-weight: 700;
+        }
+      }
     }
 
     & span:nth-child(1) {
@@ -76,7 +96,7 @@
   }
 
   &-footer {
-    padding: 10px 26px 26px 16px;
+    // padding: 10px 26px 26px 16px;
 
     button + button {
       margin-left: 10px;

+ 13 - 41
src/components/Modal/src/props.ts

@@ -2,66 +2,38 @@ import type { PropType } from 'vue';
 import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
 
 import { useI18n } from '/@/hooks/web/useI18n';
+import { propTypes } from '/@/utils/propTypes';
 const { t } = useI18n('component.modal');
 
 export const modalProps = {
-  visible: Boolean as PropType<boolean>,
+  visible: propTypes.bool,
   // open drag
-  draggable: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
-  centered: {
-    type: Boolean as PropType<boolean>,
-    default: false,
-  },
-  cancelText: {
-    type: String as PropType<string>,
-    default: t('cancelText'),
-  },
-  okText: {
-    type: String as PropType<string>,
-    default: t('okText'),
-  },
+  draggable: propTypes.bool.def(true),
+  centered: propTypes.bool,
+  cancelText: propTypes.string.def(t('cancelText')),
+  okText: propTypes.string.def(t('okText')),
+
   closeFunc: Function as PropType<() => Promise<boolean>>,
 };
 
 export const basicProps = Object.assign({}, modalProps, {
   // Can it be full screen
-  canFullscreen: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
+  canFullscreen: propTypes.bool.def(true),
   // After enabling the wrapper, the bottom can be increased in height
-  wrapperFooterOffset: {
-    type: Number as PropType<number>,
-    default: 0,
-  },
+  wrapperFooterOffset: propTypes.number.def(0),
   // Warm reminder message
   helpMessage: [String, Array] as PropType<string | string[]>,
   // Whether to setting wrapper
-  useWrapper: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
-  loading: {
-    type: Boolean as PropType<boolean>,
-    default: false,
-  },
+  useWrapper: propTypes.bool.def(true),
+  loading: propTypes.bool,
   /**
    * @description: Show close button
    */
-  showCancelBtn: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
+  showCancelBtn: propTypes.bool.def(true),
   /**
    * @description: Show confirmation button
    */
-  showOkBtn: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
+  showOkBtn: propTypes.bool.def(true),
 
   wrapperProps: Object as PropType<any>,
 

+ 0 - 11
src/components/Modal/src/provideModal.ts

@@ -1,11 +0,0 @@
-import { provide, inject } from 'vue';
-
-const key = Symbol('basic-modal');
-
-export function provideModal(redoHeight: Fn) {
-  provide(key, redoHeight);
-}
-
-export function injectModal(): Fn {
-  return inject(key, () => {}) as Fn;
-}

+ 3 - 0
src/components/Modal/src/types.ts

@@ -8,9 +8,11 @@ export interface ModalMethods {
 }
 
 export type RegisterFn = (modalMethods: ModalMethods, uuid?: string) => void;
+
 export interface ReturnMethods extends ModalMethods {
   openModal: <T = any>(props?: boolean, data?: T, openOnSet?: boolean) => void;
 }
+
 export type UseModalReturnType = [RegisterFn, ReturnMethods];
 
 export interface ReturnInnerMethods extends ModalMethods {
@@ -18,6 +20,7 @@ export interface ReturnInnerMethods extends ModalMethods {
   changeLoading: (loading: boolean) => void;
   changeOkLoading: (loading: boolean) => void;
 }
+
 export type UseModalInnerReturnType = [RegisterFn, ReturnInnerMethods];
 
 export interface ModalProps {

+ 44 - 0
src/components/Modal/src/useFullScreen.ts

@@ -0,0 +1,44 @@
+import { computed, Ref, ref, unref } from 'vue';
+
+export interface UseFullScreenContext {
+  wrapClassName: Ref<string | undefined>;
+  modalWrapperRef: Ref<ComponentRef>;
+  extHeightRef: Ref<number>;
+}
+
+export function useFullScreen(context: UseFullScreenContext) {
+  const formerHeightRef = ref(0);
+  const fullScreenRef = ref(false);
+
+  const getWrapClassName = computed(() => {
+    const clsName = unref(context.wrapClassName) || '';
+
+    return unref(fullScreenRef) ? `fullscreen-modal ${clsName} ` : unref(clsName);
+  });
+
+  function handleFullScreen(e: Event) {
+    e && e.stopPropagation();
+    fullScreenRef.value = !unref(fullScreenRef);
+
+    const modalWrapper = unref(context.modalWrapperRef);
+
+    if (!modalWrapper) return;
+
+    const wrapperEl = modalWrapper.$el as HTMLElement;
+    if (!wrapperEl) return;
+    const modalWrapSpinEl = wrapperEl.querySelector('.ant-spin-nested-loading') as HTMLElement;
+
+    if (!modalWrapSpinEl) return;
+
+    if (!unref(formerHeightRef) && unref(fullScreenRef)) {
+      formerHeightRef.value = modalWrapSpinEl.offsetHeight;
+    }
+
+    if (unref(fullScreenRef)) {
+      modalWrapSpinEl.style.height = `${window.innerHeight - unref(context.extHeightRef)}px`;
+    } else {
+      modalWrapSpinEl.style.height = `${unref(formerHeightRef)}px`;
+    }
+  }
+  return { getWrapClassName, handleFullScreen, fullScreenRef };
+}

+ 30 - 9
src/components/Modal/src/useModal.ts

@@ -5,9 +5,21 @@ import type {
   ReturnMethods,
   UseModalInnerReturnType,
 } from './types';
-import { ref, onUnmounted, unref, getCurrentInstance, reactive, watchEffect, nextTick } from 'vue';
+
+import {
+  ref,
+  onUnmounted,
+  unref,
+  getCurrentInstance,
+  reactive,
+  watchEffect,
+  nextTick,
+  toRaw,
+} from 'vue';
 import { isProdMode } from '/@/utils/env';
 import { isFunction } from '/@/utils/is';
+import { isEqual } from 'lodash-es';
+import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
 const dataTransferRef = reactive<any>({});
 
 /**
@@ -20,6 +32,7 @@ export function useModal(): UseModalReturnType {
   const modalRef = ref<Nullable<ModalMethods>>(null);
   const loadedRef = ref<Nullable<boolean>>(false);
   const uidRef = ref<string>('');
+
   function register(modalMethod: ModalMethods, uuid: string) {
     uidRef.value = uuid;
 
@@ -52,13 +65,16 @@ export function useModal(): UseModalReturnType {
         visible: visible,
       });
 
-      if (data) {
-        dataTransferRef[unref(uidRef)] = openOnSet
-          ? {
-              ...data,
-              __t__: Date.now(),
-            }
-          : data;
+      if (!data) return;
+
+      if (openOnSet) {
+        dataTransferRef[unref(uidRef)] = null;
+        dataTransferRef[unref(uidRef)] = data;
+        return;
+      }
+      const equal = isEqual(toRaw(dataTransferRef[unref(uidRef)]), data);
+      if (!equal) {
+        dataTransferRef[unref(uidRef)] = data;
       }
     },
   };
@@ -66,7 +82,7 @@ export function useModal(): UseModalReturnType {
 }
 
 export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => {
-  const modalInstanceRef = ref<ModalMethods | null>(null);
+  const modalInstanceRef = ref<Nullable<ModalMethods>>(null);
   const currentInstall = getCurrentInstance();
   const uidRef = ref<string>('');
 
@@ -83,6 +99,11 @@ export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => {
   };
 
   const register = (modalInstance: ModalMethods, uuid: string) => {
+    isProdMode() &&
+      tryOnUnmounted(() => {
+        modalInstanceRef.value = null;
+      });
+
     uidRef.value = uuid;
     modalInstanceRef.value = modalInstance;
     currentInstall.emit('register', modalInstance);

+ 16 - 0
src/components/Modal/src/useModalContext.ts

@@ -0,0 +1,16 @@
+import { InjectionKey } from 'vue';
+import { createContext, useContext } from '/@/hooks/core/useContext';
+
+export interface ModalContextProps {
+  redoModalHeight: () => void;
+}
+
+const modalContextInjectKey: InjectionKey<ModalContextProps> = Symbol();
+
+export function createModalContext(context: ModalContextProps) {
+  return createContext<ModalContextProps>(context, modalContextInjectKey);
+}
+
+export function useModalContext() {
+  return useContext<ModalContextProps>(modalContextInjectKey);
+}

+ 107 - 0
src/components/Modal/src/useModalDrag.ts

@@ -0,0 +1,107 @@
+import { Ref, unref, watchEffect } from 'vue';
+import { useTimeoutFn } from '/@/hooks/core/useTimeout';
+
+export interface UseModalDragMoveContext {
+  draggable: Ref<boolean>;
+  destroyOnClose: Ref<boolean | undefined> | undefined;
+  visible: Ref<boolean>;
+}
+
+export function useModalDragMove(context: UseModalDragMoveContext) {
+  const getStyle = (dom: any, attr: any) => {
+    return getComputedStyle(dom)[attr];
+  };
+  const drag = (wrap: any) => {
+    if (!wrap) return;
+    wrap.setAttribute('data-drag', unref(context.draggable));
+    const dialogHeaderEl = wrap.querySelector('.ant-modal-header');
+    const dragDom = wrap.querySelector('.ant-modal');
+
+    if (!dialogHeaderEl || !dragDom || !unref(context.draggable)) return;
+
+    dialogHeaderEl.style.cursor = 'move';
+
+    dialogHeaderEl.onmousedown = (e: any) => {
+      if (!e) return;
+      // 鼠标按下,计算当前元素距离可视区的距离
+      const disX = e.clientX;
+      const disY = e.clientY;
+      const screenWidth = document.body.clientWidth; // body当前宽度
+      const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取)
+
+      const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
+      const dragDomheight = dragDom.offsetHeight; // 对话框高度
+
+      const minDragDomLeft = dragDom.offsetLeft;
+
+      const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
+      const minDragDomTop = dragDom.offsetTop;
+      const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;
+      // 获取到的值带px 正则匹配替换
+      const domLeft = getStyle(dragDom, 'left');
+      const domTop = getStyle(dragDom, 'top');
+      let styL = +domLeft;
+      let styT = +domTop;
+
+      // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
+      if (domLeft.includes('%')) {
+        styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100);
+        styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100);
+      } else {
+        styL = +domLeft.replace(/px/g, '');
+        styT = +domTop.replace(/px/g, '');
+      }
+
+      document.onmousemove = function (e) {
+        // 通过事件委托,计算移动的距离
+        let left = e.clientX - disX;
+        let top = e.clientY - disY;
+
+        // 边界处理
+        if (-left > minDragDomLeft) {
+          left = -minDragDomLeft;
+        } else if (left > maxDragDomLeft) {
+          left = maxDragDomLeft;
+        }
+
+        if (-top > minDragDomTop) {
+          top = -minDragDomTop;
+        } else if (top > maxDragDomTop) {
+          top = maxDragDomTop;
+        }
+
+        // 移动当前元素
+        dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
+      };
+
+      document.onmouseup = () => {
+        document.onmousemove = null;
+        document.onmouseup = null;
+      };
+    };
+  };
+
+  const handleDrag = () => {
+    const dragWraps = document.querySelectorAll('.ant-modal-wrap');
+    for (const wrap of Array.from(dragWraps)) {
+      if (!wrap) continue;
+      const display = getStyle(wrap, 'display');
+      const draggable = wrap.getAttribute('data-drag');
+      if (display !== 'none') {
+        // 拖拽位置
+        if (draggable === null || unref(context.destroyOnClose)) {
+          drag(wrap);
+        }
+      }
+    }
+  };
+
+  watchEffect(() => {
+    if (!unref(context.visible) || !unref(context.draggable)) {
+      return;
+    }
+    useTimeoutFn(() => {
+      handleDrag();
+    }, 30);
+  });
+}

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

@@ -65,7 +65,7 @@ export default defineComponent({
     }
 
     onMounted(() => {
-      tryTsxEmit((instance) => {
+      tryTsxEmit<any>((instance) => {
         instance.wrap = unref(wrapElRef);
       });
 

+ 3 - 4
src/components/Table/src/hooks/useTableScroll.ts

@@ -1,20 +1,19 @@
 import type { BasicTableProps } from '../types/table';
 import { computed, Ref, onMounted, unref, ref, nextTick, ComputedRef, watch } from 'vue';
 
-import { injectModal } from '/@/components/Modal/src/provideModal';
-
 import { getViewportOffset } from '/@/utils/domUtils';
 import { isBoolean } from '/@/utils/is';
 
 import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
 import { useProps } from './useProps';
+import { useModalContext } from '/@/components/Modal';
 
 export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRef: Ref<any>) {
   const { propsRef } = useProps(refProps);
 
   const tableHeightRef: Ref<number | null> = ref(null);
 
-  const redoModalHeight = injectModal();
+  const modalFn = useModalContext();
 
   watch(
     () => unref(propsRef).canResize,
@@ -93,7 +92,7 @@ export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRe
       tableHeightRef.value =
         tableHeightRef.value! > maxHeight! ? (maxHeight as number) : tableHeightRef.value;
       //  解决表格放modal内的时候,modal自适应高度计算问题
-      redoModalHeight && redoModalHeight();
+      modalFn?.redoModalHeight?.();
     }, 16);
   }
 

+ 2 - 3
src/components/Tree/src/BasicTree.tsx

@@ -1,6 +1,6 @@
 import './index.less';
 
-import type { ReplaceFields, TreeItem, Keys, CheckKeys } from './types';
+import type { ReplaceFields, TreeItem, Keys, CheckKeys, TreeActionType } from './types';
 
 import { defineComponent, reactive, computed, unref, ref, watchEffect, CSSProperties } from 'vue';
 import { Tree } from 'ant-design-vue';
@@ -124,7 +124,6 @@ export default defineComponent({
               title: () => (
                 <span class={`${prefixCls}-title`}>
                   <span class={`${prefixCls}__content`} style={unref(getContentStyle)}>
-                    {' '}
                     {titleField && anyItem[titleField]}
                   </span>
                   <span class={`${prefixCls}__actions`}> {renderAction(item)}</span>
@@ -183,7 +182,7 @@ export default defineComponent({
       state.checkedKeys = props.checkedKeys;
     });
 
-    tryTsxEmit((currentInstance) => {
+    tryTsxEmit<TreeActionType>((currentInstance) => {
       currentInstance.setExpandedKeys = setExpandedKeys;
       currentInstance.getExpandedKeys = getExpandedKeys;
       currentInstance.setSelectedKeys = setSelectedKeys;

+ 2 - 2
src/components/Tree/src/useTree.ts

@@ -10,7 +10,7 @@ export function useTree(
   getReplaceFields: ComputedRef<ReplaceFields>
 ) {
   // 更新节点
-  function updateNodeByKey(key: string, node: TreeItem, list: TreeItem[]) {
+  function updateNodeByKey(key: string, node: TreeItem, list?: TreeItem[]) {
     if (!key) return;
     const treeData = list || unref(treeDataRef);
     const { key: keyField, children: childrenField } = unref(getReplaceFields);
@@ -75,7 +75,7 @@ export function useTree(
   }
 
   // 删除节点
-  function deleteNodeByKey(key: string, list: TreeItem[]) {
+  function deleteNodeByKey(key: string, list?: TreeItem[]) {
     if (!key) return;
     const treeData = list || unref(treeDataRef);
     const { key: keyField, children: childrenField } = unref(getReplaceFields);

+ 2 - 1
src/components/Verify/src/DragVerify.tsx

@@ -6,6 +6,7 @@ import { getSlot } from '/@/utils/helper/tsxHelper';
 import './DragVerify.less';
 import { CheckOutlined, DoubleRightOutlined } from '@ant-design/icons-vue';
 import { tryTsxEmit } from '/@/utils/helper/vueHelper';
+import type { DragVerifyActionType } from './types';
 export default defineComponent({
   name: 'BaseDargVerify',
   props: basicProps,
@@ -210,7 +211,7 @@ export default defineComponent({
       contentEl.style.width = unref(getContentStyleRef).width;
     }
 
-    tryTsxEmit((instance) => {
+    tryTsxEmit<DragVerifyActionType>((instance) => {
       instance.resume = resume;
     });
 

+ 1 - 1
src/hooks/setting/useRootSetting.ts

@@ -46,7 +46,7 @@ export function useRootSetting() {
     unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED
   );
 
-  function setRootSetting(setting: RootSetting) {
+  function setRootSetting(setting: Partial<RootSetting>) {
     appStore.commitProjectConfigState(setting);
   }
 

+ 5 - 2
src/utils/helper/vueHelper.ts

@@ -7,6 +7,7 @@ import {
   onUnmounted,
   nextTick,
   reactive,
+  ComponentInternalInstance,
 } from 'vue';
 
 export function explicitComputed<T, S>(source: WatchSource<S>, fn: () => T) {
@@ -29,8 +30,10 @@ export function tryOnUnmounted(fn: () => Promise<void> | void) {
   getCurrentInstance() && onUnmounted(fn);
 }
 
-export function tryTsxEmit(fn: (_instance: any) => Promise<void> | void) {
-  const instance = getCurrentInstance();
+export function tryTsxEmit<T extends any = ComponentInternalInstance>(
+  fn: (_instance: T) => Promise<void> | void
+) {
+  const instance = getCurrentInstance() as any;
   instance && fn.call(null, instance);
 }