Commit 81baf1d5c4606aab83c0e65397ce4b090c2e4e08

Authored by vben
1 parent 819127e8

perf: perf modal and drawer

CHANGELOG.zh_CN.md
@@ -18,12 +18,18 @@ @@ -18,12 +18,18 @@
18 18
19 - 缓存可以配置是否加密,默认生产环境开启 Aes 加密 19 - 缓存可以配置是否加密,默认生产环境开启 Aes 加密
20 - 新增标签页拖拽排序 20 - 新增标签页拖拽排序
  21 +- 新增 LayoutFooter.默认显示,可以在配置内关闭
  22 +
  23 +### ⚡ Performance Improvements
  24 +
  25 +- 优化`Modal`组件全屏动画不流畅问题
21 26
22 ### 🐛 Bug Fixes 27 ### 🐛 Bug Fixes
23 28
24 - 修复 tree 文本超出挡住操作按钮问题 29 - 修复 tree 文本超出挡住操作按钮问题
25 - 修复通过 useRedo 刷新页面参数丢失问题 30 - 修复通过 useRedo 刷新页面参数丢失问题
26 - 修复表单校验先设置在校验及控制台错误信息问题 31 - 修复表单校验先设置在校验及控制台错误信息问题
  32 +- 修复`modal`与`drawer`组件传递数组参数问题
27 33
28 ### 🎫 Chores 34 ### 🎫 Chores
29 35
src/components/Drawer/index.ts
1 -export { default as BasicDrawer } from './src/BasicDrawer'; 1 +import BasicDrawerLib from './src/BasicDrawer';
  2 +import { withInstall } from '../util';
2 3
3 -export { useDrawer, useDrawerInner } from './src/useDrawer';  
4 export * from './src/types'; 4 export * from './src/types';
  5 +export { useDrawer, useDrawerInner } from './src/useDrawer';
  6 +export const BasicDrawer = withInstall(BasicDrawerLib);
src/components/Drawer/src/BasicDrawer.tsx
1 import './index.less'; 1 import './index.less';
2 2
3 import type { DrawerInstance, DrawerProps } from './types'; 3 import type { DrawerInstance, DrawerProps } from './types';
  4 +import type { CSSProperties } from 'vue';
4 5
5 import { defineComponent, ref, computed, watchEffect, watch, unref, nextTick, toRaw } from 'vue'; 6 import { defineComponent, ref, computed, watchEffect, watch, unref, nextTick, toRaw } from 'vue';
6 import { Drawer, Row, Col, Button } from 'ant-design-vue'; 7 import { Drawer, Row, Col, Button } from 'ant-design-vue';
@@ -9,53 +10,96 @@ import { BasicTitle } from '/@/components/Basic'; @@ -9,53 +10,96 @@ import { BasicTitle } from '/@/components/Basic';
9 import { FullLoading } from '/@/components/Loading/index'; 10 import { FullLoading } from '/@/components/Loading/index';
10 import { LeftOutlined } from '@ant-design/icons-vue'; 11 import { LeftOutlined } from '@ant-design/icons-vue';
11 12
12 -import { basicProps } from './props'; 13 +import { useI18n } from '/@/hooks/web/useI18n';
13 14
14 import { getSlot } from '/@/utils/helper/tsxHelper'; 15 import { getSlot } from '/@/utils/helper/tsxHelper';
15 import { isFunction, isNumber } from '/@/utils/is'; 16 import { isFunction, isNumber } from '/@/utils/is';
16 -import { buildUUID } from '/@/utils/uuid';  
17 import { deepMerge } from '/@/utils'; 17 import { deepMerge } from '/@/utils';
18 -import { useI18n } from '/@/hooks/web/useI18n'; 18 +import { tryTsxEmit } from '/@/utils/helper/vueHelper';
  19 +
  20 +import { basicProps } from './props';
19 21
20 const prefixCls = 'basic-drawer'; 22 const prefixCls = 'basic-drawer';
21 export default defineComponent({ 23 export default defineComponent({
22 - // inheritAttrs: false, 24 + inheritAttrs: false,
23 props: basicProps, 25 props: basicProps,
24 emits: ['visible-change', 'ok', 'close', 'register'], 26 emits: ['visible-change', 'ok', 'close', 'register'],
25 setup(props, { slots, emit, attrs }) { 27 setup(props, { slots, emit, attrs }) {
26 const scrollRef = ref<ElRef>(null); 28 const scrollRef = ref<ElRef>(null);
27 -  
28 const visibleRef = ref(false); 29 const visibleRef = ref(false);
29 - const propsRef = ref<Partial<DrawerProps> | null>(null); 30 + const propsRef = ref<Partial<Nullable<DrawerProps>>>(null);
30 31
31 const { t } = useI18n('component.drawer'); 32 const { t } = useI18n('component.drawer');
32 33
33 - const getMergeProps = computed((): any => {  
34 - return deepMerge(toRaw(props), unref(propsRef));  
35 - });  
36 -  
37 - const getProps = computed(() => {  
38 - const opt: any = {  
39 - placement: 'right',  
40 - ...attrs,  
41 - ...props,  
42 - ...(unref(propsRef) as any),  
43 - visible: unref(visibleRef),  
44 - };  
45 - opt.title = undefined; 34 + const getMergeProps = computed(
  35 + (): DrawerProps => {
  36 + return deepMerge(toRaw(props), unref(propsRef));
  37 + }
  38 + );
46 39
47 - if (opt.isDetail) {  
48 - if (!opt.width) {  
49 - opt.width = '100%';  
50 - }  
51 - opt.wrapClassName = opt.wrapClassName  
52 - ? `${opt.wrapClassName} ${prefixCls}__detail`  
53 - : `${prefixCls}__detail`;  
54 - if (!opt.getContainer) {  
55 - opt.getContainer = '.layout-content'; 40 + const getProps = computed(
  41 + (): DrawerProps => {
  42 + const opt = {
  43 + placement: 'right',
  44 + ...attrs,
  45 + ...unref(getMergeProps),
  46 + visible: unref(visibleRef),
  47 + };
  48 + opt.title = undefined;
  49 + const { isDetail, width, wrapClassName, getContainer } = opt;
  50 + if (isDetail) {
  51 + if (!width) {
  52 + opt.width = '100%';
  53 + }
  54 + const detailCls = `${prefixCls}__detail`;
  55 +
  56 + opt.wrapClassName = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls;
  57 +
  58 + if (!getContainer) {
  59 + // TODO type error?
  60 + opt.getContainer = '.layout-content' as any;
  61 + }
56 } 62 }
  63 + return opt as DrawerProps;
57 } 64 }
58 - return opt; 65 + );
  66 +
  67 + const getBindValues = computed(
  68 + (): DrawerProps => {
  69 + return {
  70 + ...attrs,
  71 + ...unref(getProps),
  72 + };
  73 + }
  74 + );
  75 +
  76 + // Custom implementation of the bottom button,
  77 + const getFooterHeight = computed(() => {
  78 + const { footerHeight, showFooter } = unref(getProps);
  79 +
  80 + if (showFooter && footerHeight) {
  81 + return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`;
  82 + }
  83 + return `0px`;
  84 + });
  85 +
  86 + const getScrollContentStyle = computed(
  87 + (): CSSProperties => {
  88 + const footerHeight = unref(getFooterHeight);
  89 + return {
  90 + position: 'relative',
  91 + height: `calc(100% - ${footerHeight})`,
  92 + overflow: 'auto',
  93 + padding: '16px',
  94 + paddingBottom: '30px',
  95 + };
  96 + }
  97 + );
  98 +
  99 + const getLoading = computed(() => {
  100 + return {
  101 + hidden: !unref(getProps).loading,
  102 + };
59 }); 103 });
60 104
61 watchEffect(() => { 105 watchEffect(() => {
@@ -74,22 +118,13 @@ export default defineComponent({ @@ -74,22 +118,13 @@ export default defineComponent({
74 } 118 }
75 ); 119 );
76 120
77 - // Custom implementation of the bottom button,  
78 - const getFooterHeight = computed(() => {  
79 - const { footerHeight, showFooter }: DrawerProps = unref(getProps);  
80 - if (showFooter && footerHeight) {  
81 - return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`;  
82 - }  
83 - return `0px`;  
84 - });  
85 -  
86 // Cancel event 121 // Cancel event
87 - async function onClose(e: any) { 122 + async function onClose(e: ChangeEvent) {
88 const { closeFunc } = unref(getProps); 123 const { closeFunc } = unref(getProps);
89 emit('close', e); 124 emit('close', e);
90 if (closeFunc && isFunction(closeFunc)) { 125 if (closeFunc && isFunction(closeFunc)) {
91 const res = await closeFunc(); 126 const res = await closeFunc();
92 - res && (visibleRef.value = false); 127 + visibleRef.value = !res;
93 return; 128 return;
94 } 129 }
95 visibleRef.value = false; 130 visibleRef.value = false;
@@ -98,12 +133,16 @@ export default defineComponent({ @@ -98,12 +133,16 @@ export default defineComponent({
98 function setDrawerProps(props: Partial<DrawerProps>): void { 133 function setDrawerProps(props: Partial<DrawerProps>): void {
99 // Keep the last setDrawerProps 134 // Keep the last setDrawerProps
100 propsRef.value = deepMerge(unref(propsRef) || {}, props); 135 propsRef.value = deepMerge(unref(propsRef) || {}, props);
  136 +
101 if (Reflect.has(props, 'visible')) { 137 if (Reflect.has(props, 'visible')) {
102 visibleRef.value = !!props.visible; 138 visibleRef.value = !!props.visible;
103 } 139 }
104 } 140 }
105 141
106 function renderFooter() { 142 function renderFooter() {
  143 + if (slots?.footer) {
  144 + return getSlot(slots, 'footer');
  145 + }
107 const { 146 const {
108 showCancelBtn, 147 showCancelBtn,
109 cancelButtonProps, 148 cancelButtonProps,
@@ -114,65 +153,64 @@ export default defineComponent({ @@ -114,65 +153,64 @@ export default defineComponent({
114 okButtonProps, 153 okButtonProps,
115 confirmLoading, 154 confirmLoading,
116 showFooter, 155 showFooter,
117 - }: DrawerProps = unref(getProps); 156 + } = unref(getProps);
  157 + if (!showFooter) {
  158 + return null;
  159 + }
118 160
119 return ( 161 return (
120 - getSlot(slots, 'footer') ||  
121 - (showFooter && (  
122 - <div class={`${prefixCls}__footer`}>  
123 - {getSlot(slots, 'insertFooter')}  
124 -  
125 - {showCancelBtn && (  
126 - <Button {...cancelButtonProps} onClick={onClose} class="mr-2">  
127 - {() => cancelText}  
128 - </Button>  
129 - )}  
130 - {getSlot(slots, 'centerFooter')}  
131 - {showOkBtn && (  
132 - <Button  
133 - type={okType}  
134 - onClick={() => {  
135 - emit('ok');  
136 - }}  
137 - {...okButtonProps}  
138 - loading={confirmLoading}  
139 - >  
140 - {() => okText}  
141 - </Button>  
142 - )}  
143 -  
144 - {getSlot(slots, 'appendFooter')}  
145 - </div>  
146 - )) 162 + <div class={`${prefixCls}__footer`}>
  163 + {getSlot(slots, 'insertFooter')}
  164 + {showCancelBtn && (
  165 + <Button {...cancelButtonProps} onClick={onClose} class="mr-2">
  166 + {() => cancelText}
  167 + </Button>
  168 + )}
  169 + {getSlot(slots, 'centerFooter')}
  170 + {showOkBtn && (
  171 + <Button
  172 + type={okType}
  173 + onClick={() => {
  174 + emit('ok');
  175 + }}
  176 + {...okButtonProps}
  177 + loading={confirmLoading}
  178 + >
  179 + {() => okText}
  180 + </Button>
  181 + )}
  182 + {getSlot(slots, 'appendFooter')}
  183 + </div>
147 ); 184 );
148 } 185 }
149 186
150 function renderHeader() { 187 function renderHeader() {
  188 + if (slots?.title) {
  189 + return getSlot(slots, 'title');
  190 + }
151 const { title } = unref(getMergeProps); 191 const { title } = unref(getMergeProps);
152 - return props.isDetail ? (  
153 - getSlot(slots, 'title') || (  
154 - <Row type="flex" align="middle" class={`${prefixCls}__detail-header`}>  
155 - {() => (  
156 - <>  
157 - {props.showDetailBack && (  
158 - <Button size="small" type="link" onClick={onClose}>  
159 - {() => <LeftOutlined />}  
160 - </Button>  
161 - )}  
162 -  
163 - {title && (  
164 - <Col style="flex:1" class={[`${prefixCls}__detail-title`, 'ellipsis', 'px-2']}>  
165 - {() => title}  
166 - </Col>  
167 - )}  
168 -  
169 - {getSlot(slots, 'titleToolbar')}  
170 - </>  
171 - )}  
172 - </Row>  
173 - )  
174 - ) : (  
175 - <BasicTitle>{() => title || getSlot(slots, 'title')}</BasicTitle> 192 +
  193 + if (!props.isDetail) {
  194 + return <BasicTitle>{() => title || getSlot(slots, 'title')}</BasicTitle>;
  195 + }
  196 + return (
  197 + <Row type="flex" align="middle" class={`${prefixCls}__detail-header`}>
  198 + {() => (
  199 + <>
  200 + {props.showDetailBack && (
  201 + <Button size="small" type="link" onClick={onClose}>
  202 + {() => <LeftOutlined />}
  203 + </Button>
  204 + )}
  205 + {title && (
  206 + <Col style="flex:1" class={[`${prefixCls}__detail-title`, 'ellipsis', 'px-2']}>
  207 + {() => title}
  208 + </Col>
  209 + )}
  210 + {getSlot(slots, 'titleToolbar')}
  211 + </>
  212 + )}
  213 + </Row>
176 ); 214 );
177 } 215 }
178 216
@@ -180,41 +218,20 @@ export default defineComponent({ @@ -180,41 +218,20 @@ export default defineComponent({
180 setDrawerProps: setDrawerProps, 218 setDrawerProps: setDrawerProps,
181 }; 219 };
182 220
183 - const uuid = buildUUID();  
184 - emit('register', drawerInstance, uuid); 221 + tryTsxEmit((instance) => {
  222 + emit('register', drawerInstance, instance.uid);
  223 + });
185 224
186 return () => { 225 return () => {
187 - const footerHeight = unref(getFooterHeight);  
188 return ( 226 return (
189 - <Drawer  
190 - class={prefixCls}  
191 - onClose={onClose}  
192 - {...{  
193 - ...attrs,  
194 - ...unref(getProps),  
195 - }}  
196 - > 227 + <Drawer class={prefixCls} onClose={onClose} {...unref(getBindValues)}>
197 {{ 228 {{
198 title: () => renderHeader(), 229 title: () => renderHeader(),
199 default: () => ( 230 default: () => (
200 <> 231 <>
201 - <div  
202 - ref={scrollRef}  
203 - {...attrs}  
204 - style={{  
205 - position: 'relative',  
206 - height: `calc(100% - ${footerHeight})`,  
207 - overflow: 'auto',  
208 - padding: '16px',  
209 - paddingBottom: '30px',  
210 - }}  
211 - >  
212 - <FullLoading  
213 - absolute  
214 - tip={t('loadingText')}  
215 - class={[!unref(getProps).loading ? 'hidden' : '']}  
216 - />  
217 - {getSlot(slots, 'default')} 232 + <div ref={scrollRef} style={unref(getScrollContentStyle)}>
  233 + <FullLoading absolute tip={t('loadingText')} class={unref(getLoading)} />
  234 + {getSlot(slots)}
218 </div> 235 </div>
219 {renderFooter()} 236 {renderFooter()}
220 </> 237 </>
src/components/Drawer/src/props.ts
1 import type { PropType } from 'vue'; 1 import type { PropType } from 'vue';
2 2
3 import { useI18n } from '/@/hooks/web/useI18n'; 3 import { useI18n } from '/@/hooks/web/useI18n';
  4 +import { propTypes } from '/@/utils/propTypes';
4 const { t } = useI18n('component.drawer'); 5 const { t } = useI18n('component.drawer');
5 6
6 export const footerProps = { 7 export const footerProps = {
7 - confirmLoading: Boolean as PropType<boolean>, 8 + confirmLoading: propTypes.bool,
8 /** 9 /**
9 * @description: Show close button 10 * @description: Show close button
10 */ 11 */
11 - showCancelBtn: {  
12 - type: Boolean as PropType<boolean>,  
13 - default: true,  
14 - }, 12 + showCancelBtn: propTypes.bool.def(true),
15 cancelButtonProps: Object as PropType<any>, 13 cancelButtonProps: Object as PropType<any>,
16 - cancelText: {  
17 - type: String as PropType<string>,  
18 - default: t('cancelText'),  
19 - }, 14 + cancelText: propTypes.string.def(t('cancelText')),
20 /** 15 /**
21 * @description: Show confirmation button 16 * @description: Show confirmation button
22 */ 17 */
23 - showOkBtn: {  
24 - type: Boolean as PropType<boolean>,  
25 - default: true,  
26 - },  
27 - okButtonProps: Object as PropType<any>,  
28 - okText: {  
29 - type: String as PropType<string>,  
30 - default: t('okText'),  
31 - },  
32 - okType: {  
33 - type: String as PropType<string>,  
34 - default: 'primary',  
35 - },  
36 - showFooter: {  
37 - type: Boolean as PropType<boolean>,  
38 - default: false,  
39 - }, 18 + showOkBtn: propTypes.bool.def(true),
  19 + okButtonProps: propTypes.any,
  20 + okText: propTypes.string.def(t('okText')),
  21 + okType: propTypes.string.def('primary'),
  22 + showFooter: propTypes.bool,
40 footerHeight: { 23 footerHeight: {
41 type: [String, Number] as PropType<string | number>, 24 type: [String, Number] as PropType<string | number>,
42 default: 60, 25 default: 60,
43 }, 26 },
44 }; 27 };
45 export const basicProps = { 28 export const basicProps = {
46 - isDetail: {  
47 - type: Boolean as PropType<boolean>,  
48 - default: false,  
49 - },  
50 - title: {  
51 - type: String as PropType<string>,  
52 - default: '',  
53 - },  
54 - showDetailBack: {  
55 - type: Boolean as PropType<boolean>,  
56 - default: true,  
57 - },  
58 - visible: {  
59 - type: Boolean as PropType<boolean>,  
60 - default: false,  
61 - },  
62 - loading: {  
63 - type: Boolean as PropType<boolean>,  
64 - default: false,  
65 - },  
66 - maskClosable: {  
67 - type: Boolean as PropType<boolean>,  
68 - default: true,  
69 - }, 29 + isDetail: propTypes.bool,
  30 + title: propTypes.string.def(''),
  31 + showDetailBack: propTypes.bool.def(true),
  32 + visible: propTypes.bool,
  33 + loading: propTypes.bool,
  34 + maskClosable: propTypes.bool.def(true),
70 getContainer: { 35 getContainer: {
71 type: [Object, String] as PropType<any>, 36 type: [Object, String] as PropType<any>,
72 }, 37 },
@@ -78,10 +43,7 @@ export const basicProps = { @@ -78,10 +43,7 @@ export const basicProps = {
78 type: [Function, Object] as PropType<any>, 43 type: [Function, Object] as PropType<any>,
79 default: null, 44 default: null,
80 }, 45 },
81 - triggerWindowResize: {  
82 - type: Boolean as PropType<boolean>,  
83 - default: false,  
84 - },  
85 - destroyOnClose: Boolean as PropType<boolean>, 46 + triggerWindowResize: propTypes.bool,
  47 + destroyOnClose: propTypes.bool,
86 ...footerProps, 48 ...footerProps,
87 }; 49 };
src/components/Drawer/src/types.ts
@@ -75,7 +75,7 @@ export interface DrawerProps extends DrawerFooterProps { @@ -75,7 +75,7 @@ export interface DrawerProps extends DrawerFooterProps {
75 * @type ScrollContainerOptions 75 * @type ScrollContainerOptions
76 */ 76 */
77 scrollOptions?: ScrollContainerOptions; 77 scrollOptions?: ScrollContainerOptions;
78 - closeFunc?: () => Promise<void>; 78 + closeFunc?: () => Promise<any>;
79 triggerWindowResize?: boolean; 79 triggerWindowResize?: boolean;
80 /** 80 /**
81 * Whether a close (x) button is visible on top right of the Drawer dialog or not. 81 * Whether a close (x) button is visible on top right of the Drawer dialog or not.
src/components/Drawer/src/useDrawer.ts
@@ -6,12 +6,15 @@ import type { @@ -6,12 +6,15 @@ import type {
6 UseDrawerInnerReturnType, 6 UseDrawerInnerReturnType,
7 } from './types'; 7 } from './types';
8 8
9 -import { ref, getCurrentInstance, onUnmounted, unref, reactive, watchEffect, nextTick } from 'vue'; 9 +import { ref, getCurrentInstance, unref, reactive, watchEffect, nextTick, toRaw } from 'vue';
10 10
11 import { isProdMode } from '/@/utils/env'; 11 import { isProdMode } from '/@/utils/env';
12 import { isFunction } from '/@/utils/is'; 12 import { isFunction } from '/@/utils/is';
  13 +import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
  14 +import { isEqual } from 'lodash-es';
13 15
14 const dataTransferRef = reactive<any>({}); 16 const dataTransferRef = reactive<any>({});
  17 +
15 /** 18 /**
16 * @description: Applicable to separate drawer and call outside 19 * @description: Applicable to separate drawer and call outside
17 */ 20 */
@@ -19,21 +22,23 @@ export function useDrawer(): UseDrawerReturnType { @@ -19,21 +22,23 @@ export function useDrawer(): UseDrawerReturnType {
19 if (!getCurrentInstance()) { 22 if (!getCurrentInstance()) {
20 throw new Error('Please put useDrawer function in the setup function!'); 23 throw new Error('Please put useDrawer function in the setup function!');
21 } 24 }
  25 +
22 const drawerRef = ref<DrawerInstance | null>(null); 26 const drawerRef = ref<DrawerInstance | null>(null);
23 - const loadedRef = ref<boolean | null>(false); 27 + const loadedRef = ref<Nullable<boolean>>(false);
24 const uidRef = ref<string>(''); 28 const uidRef = ref<string>('');
25 29
26 - function getDrawer(drawerInstance: DrawerInstance, uuid: string) {  
27 - uidRef.value = uuid; 30 + function register(drawerInstance: DrawerInstance, uuid: string) {
28 isProdMode() && 31 isProdMode() &&
29 - onUnmounted(() => { 32 + tryOnUnmounted(() => {
30 drawerRef.value = null; 33 drawerRef.value = null;
31 loadedRef.value = null; 34 loadedRef.value = null;
32 dataTransferRef[unref(uidRef)] = null; 35 dataTransferRef[unref(uidRef)] = null;
33 }); 36 });
  37 +
34 if (unref(loadedRef) && isProdMode() && drawerInstance === unref(drawerRef)) { 38 if (unref(loadedRef) && isProdMode() && drawerInstance === unref(drawerRef)) {
35 return; 39 return;
36 } 40 }
  41 + uidRef.value = uuid;
37 drawerRef.value = drawerInstance; 42 drawerRef.value = drawerInstance;
38 loadedRef.value = true; 43 loadedRef.value = true;
39 } 44 }
@@ -55,37 +60,46 @@ export function useDrawer(): UseDrawerReturnType { @@ -55,37 +60,46 @@ export function useDrawer(): UseDrawerReturnType {
55 getInstance().setDrawerProps({ 60 getInstance().setDrawerProps({
56 visible: visible, 61 visible: visible,
57 }); 62 });
58 - if (data) {  
59 - dataTransferRef[unref(uidRef)] = openOnSet  
60 - ? {  
61 - ...data,  
62 - __t__: Date.now(),  
63 - }  
64 - : data; 63 + if (!data) return;
  64 +
  65 + if (openOnSet) {
  66 + dataTransferRef[unref(uidRef)] = null;
  67 + dataTransferRef[unref(uidRef)] = data;
  68 + return;
  69 + }
  70 + const equal = isEqual(toRaw(dataTransferRef[unref(uidRef)]), data);
  71 + if (!equal) {
  72 + dataTransferRef[unref(uidRef)] = data;
65 } 73 }
66 }, 74 },
67 }; 75 };
68 76
69 - return [getDrawer, methods]; 77 + return [register, methods];
70 } 78 }
  79 +
71 export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => { 80 export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => {
72 - const drawerInstanceRef = ref<DrawerInstance | null>(null); 81 + const drawerInstanceRef = ref<Nullable<DrawerInstance>>(null);
73 const currentInstall = getCurrentInstance(); 82 const currentInstall = getCurrentInstance();
74 const uidRef = ref<string>(''); 83 const uidRef = ref<string>('');
75 84
76 if (!currentInstall) { 85 if (!currentInstall) {
77 - throw new Error('instance is undefined!'); 86 + throw new Error('useDrawerInner instance is undefined!');
78 } 87 }
79 88
80 const getInstance = () => { 89 const getInstance = () => {
81 const instance = unref(drawerInstanceRef); 90 const instance = unref(drawerInstanceRef);
82 if (!instance) { 91 if (!instance) {
83 - throw new Error('instance is undefined!'); 92 + throw new Error('useDrawerInner instance is undefined!');
84 } 93 }
85 return instance; 94 return instance;
86 }; 95 };
87 96
88 const register = (modalInstance: DrawerInstance, uuid: string) => { 97 const register = (modalInstance: DrawerInstance, uuid: string) => {
  98 + isProdMode() &&
  99 + tryOnUnmounted(() => {
  100 + drawerInstanceRef.value = null;
  101 + });
  102 +
89 uidRef.value = uuid; 103 uidRef.value = uuid;
90 drawerInstanceRef.value = modalInstance; 104 drawerInstanceRef.value = modalInstance;
91 currentInstall.emit('register', modalInstance); 105 currentInstall.emit('register', modalInstance);
src/components/Modal/index.ts
1 import './src/index.less'; 1 import './src/index.less';
2 -export { default as BasicModal } from './src/BasicModal';  
3 -export { default as Modal } from './src/Modal'; 2 +import BasicModalLib from './src/BasicModal';
  3 +import { withInstall } from '../util';
  4 +
  5 +export { useModalContext } from './src/useModalContext';
4 export { useModal, useModalInner } from './src/useModal'; 6 export { useModal, useModalInner } from './src/useModal';
5 export * from './src/types'; 7 export * from './src/types';
  8 +export const BasicModal = withInstall(BasicModalLib);
src/components/Modal/src/BasicModal.tsx
1 import type { ModalProps, ModalMethods } from './types'; 1 import type { ModalProps, ModalMethods } from './types';
2 2
3 -import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue'; 3 +import { defineComponent, computed, ref, watch, unref, watchEffect, toRef } from 'vue';
4 4
5 import Modal from './Modal'; 5 import Modal from './Modal';
6 import { Button } from '/@/components/Button'; 6 import { Button } from '/@/components/Button';
@@ -11,10 +11,10 @@ import { FullscreenExitOutlined, FullscreenOutlined, CloseOutlined } from &#39;@ant- @@ -11,10 +11,10 @@ import { FullscreenExitOutlined, FullscreenOutlined, CloseOutlined } from &#39;@ant-
11 import { getSlot, extendSlots } from '/@/utils/helper/tsxHelper'; 11 import { getSlot, extendSlots } from '/@/utils/helper/tsxHelper';
12 import { isFunction } from '/@/utils/is'; 12 import { isFunction } from '/@/utils/is';
13 import { deepMerge } from '/@/utils'; 13 import { deepMerge } from '/@/utils';
14 -import { buildUUID } from '/@/utils/uuid'; 14 +import { tryTsxEmit } from '/@/utils/helper/vueHelper';
15 15
16 import { basicProps } from './props'; 16 import { basicProps } from './props';
17 -// import { triggerWindowResize } from '@/utils/event/triggerWindowResizeEvent'; 17 +import { useFullScreen } from './useFullScreen';
18 export default defineComponent({ 18 export default defineComponent({
19 name: 'BasicModal', 19 name: 'BasicModal',
20 props: basicProps, 20 props: basicProps,
@@ -26,31 +26,41 @@ export default defineComponent({ @@ -26,31 +26,41 @@ export default defineComponent({
26 // modal Bottom and top height 26 // modal Bottom and top height
27 const extHeightRef = ref(0); 27 const extHeightRef = ref(0);
28 // Unexpanded height of the popup 28 // Unexpanded height of the popup
29 - const formerHeightRef = ref(0);  
30 - const fullScreenRef = ref(false);  
31 29
32 // Custom title component: get title 30 // Custom title component: get title
33 - const getMergeProps = computed(() => {  
34 - return {  
35 - ...props,  
36 - ...(unref(propsRef) as any),  
37 - }; 31 + const getMergeProps = computed(
  32 + (): ModalProps => {
  33 + return {
  34 + ...props,
  35 + ...(unref(propsRef) as any),
  36 + };
  37 + }
  38 + );
  39 +
  40 + const { handleFullScreen, getWrapClassName, fullScreenRef } = useFullScreen({
  41 + modalWrapperRef,
  42 + extHeightRef,
  43 + wrapClassName: toRef(getMergeProps.value, 'wrapClassName'),
38 }); 44 });
39 45
40 // modal component does not need title 46 // modal component does not need title
41 - const getProps = computed((): any => {  
42 - const opt = {  
43 - ...props,  
44 - ...((unref(propsRef) || {}) as any),  
45 - visible: unref(visibleRef),  
46 - title: undefined,  
47 - };  
48 - const { wrapClassName = '' } = opt;  
49 - const className = unref(fullScreenRef) ? `${wrapClassName} fullscreen-modal` : wrapClassName;  
50 - return {  
51 - ...opt,  
52 - wrapClassName: className,  
53 - }; 47 + const getProps = computed(
  48 + (): ModalProps => {
  49 + const opt = {
  50 + ...unref(getMergeProps),
  51 + visible: unref(visibleRef),
  52 + title: undefined,
  53 + };
  54 +
  55 + return {
  56 + ...opt,
  57 + wrapClassName: unref(getWrapClassName),
  58 + };
  59 + }
  60 + );
  61 +
  62 + const getModalBindValue = computed((): any => {
  63 + return { ...attrs, ...unref(getProps) };
54 }); 64 });
55 65
56 watchEffect(() => { 66 watchEffect(() => {
@@ -80,7 +90,35 @@ export default defineComponent({ @@ -80,7 +90,35 @@ export default defineComponent({
80 ); 90 );
81 } 91 }
82 92
  93 + // 取消事件
  94 + async function handleCancel(e: Event) {
  95 + e?.stopPropagation();
  96 +
  97 + if (props.closeFunc && isFunction(props.closeFunc)) {
  98 + const isClose: boolean = await props.closeFunc();
  99 + visibleRef.value = !isClose;
  100 + return;
  101 + }
  102 +
  103 + visibleRef.value = false;
  104 + emit('cancel');
  105 + }
  106 +
  107 + /**
  108 + * @description: 设置modal参数
  109 + */
  110 + function setModalProps(props: Partial<ModalProps>): void {
  111 + // Keep the last setModalProps
  112 + propsRef.value = deepMerge(unref(propsRef) || {}, props);
  113 + if (!Reflect.has(props, 'visible')) return;
  114 + visibleRef.value = !!props.visible;
  115 + }
  116 +
83 function renderContent() { 117 function renderContent() {
  118 + type OmitWrapperType = Omit<
  119 + ModalProps,
  120 + 'fullScreen' | 'modalFooterHeight' | 'visible' | 'loading'
  121 + >;
84 const { useWrapper, loading, wrapperProps } = unref(getProps); 122 const { useWrapper, loading, wrapperProps } = unref(getProps);
85 if (!useWrapper) return getSlot(slots); 123 if (!useWrapper) return getSlot(slots);
86 124
@@ -93,7 +131,7 @@ export default defineComponent({ @@ -93,7 +131,7 @@ export default defineComponent({
93 loading={loading} 131 loading={loading}
94 visible={unref(visibleRef)} 132 visible={unref(visibleRef)}
95 modalFooterHeight={showFooter} 133 modalFooterHeight={showFooter}
96 - {...wrapperProps} 134 + {...((wrapperProps as unknown) as OmitWrapperType)}
97 onGetExtHeight={(height: number) => { 135 onGetExtHeight={(height: number) => {
98 extHeightRef.value = height; 136 extHeightRef.value = height;
99 }} 137 }}
@@ -106,18 +144,6 @@ export default defineComponent({ @@ -106,18 +144,6 @@ export default defineComponent({
106 ); 144 );
107 } 145 }
108 146
109 - // 取消事件  
110 - async function handleCancel(e: Event) {  
111 - e && e.stopPropagation();  
112 - if (props.closeFunc && isFunction(props.closeFunc)) {  
113 - const isClose: boolean = await props.closeFunc();  
114 - visibleRef.value = !isClose;  
115 - return;  
116 - }  
117 - visibleRef.value = false;  
118 - emit('cancel');  
119 - }  
120 -  
121 // 底部按钮自定义实现, 147 // 底部按钮自定义实现,
122 function renderFooter() { 148 function renderFooter() {
123 const { 149 const {
@@ -162,64 +188,37 @@ export default defineComponent({ @@ -162,64 +188,37 @@ export default defineComponent({
162 */ 188 */
163 function renderClose() { 189 function renderClose() {
164 const { canFullscreen } = unref(getProps); 190 const { canFullscreen } = unref(getProps);
165 - if (!canFullscreen) {  
166 - return null;  
167 - } 191 +
  192 + const fullScreen = unref(fullScreenRef) ? (
  193 + <FullscreenExitOutlined role="full" onClick={handleFullScreen} />
  194 + ) : (
  195 + <FullscreenOutlined role="close" onClick={handleFullScreen} />
  196 + );
  197 +
  198 + const cls = [
  199 + 'custom-close-icon',
  200 + {
  201 + 'can-full': canFullscreen,
  202 + },
  203 + ];
  204 +
168 return ( 205 return (
169 - <div class="custom-close-icon">  
170 - {unref(fullScreenRef) ? (  
171 - <FullscreenExitOutlined role="full" onClick={handleFullScreen} />  
172 - ) : (  
173 - <FullscreenOutlined role="close" onClick={handleFullScreen} />  
174 - )} 206 + <div class={cls}>
  207 + {canFullscreen && fullScreen}
175 <CloseOutlined onClick={handleCancel} /> 208 <CloseOutlined onClick={handleCancel} />
176 </div> 209 </div>
177 ); 210 );
178 } 211 }
179 212
180 - function handleFullScreen(e: Event) {  
181 - e && e.stopPropagation();  
182 - fullScreenRef.value = !unref(fullScreenRef);  
183 -  
184 - const modalWrapper = unref(modalWrapperRef);  
185 - if (!modalWrapper) return;  
186 -  
187 - const wrapperEl = modalWrapper.$el as HTMLElement;  
188 - if (!wrapperEl) return;  
189 -  
190 - const modalWrapSpinEl = wrapperEl.querySelector('.ant-spin-nested-loading') as HTMLElement;  
191 - if (!modalWrapSpinEl) return;  
192 -  
193 - if (!unref(formerHeightRef) && unref(fullScreenRef)) {  
194 - formerHeightRef.value = modalWrapSpinEl.offsetHeight;  
195 - }  
196 -  
197 - if (unref(fullScreenRef)) {  
198 - modalWrapSpinEl.style.height = `${window.innerHeight - unref(extHeightRef)}px`;  
199 - } else {  
200 - modalWrapSpinEl.style.height = `${unref(formerHeightRef)}px`;  
201 - }  
202 - }  
203 -  
204 - /**  
205 - * @description: 设置modal参数  
206 - */  
207 - function setModalProps(props: Partial<ModalProps>): void {  
208 - // Keep the last setModalProps  
209 - propsRef.value = deepMerge(unref(propsRef) || {}, props);  
210 - if (!Reflect.has(props, 'visible')) return;  
211 - visibleRef.value = !!props.visible;  
212 - }  
213 -  
214 const modalMethods: ModalMethods = { 213 const modalMethods: ModalMethods = {
215 setModalProps, 214 setModalProps,
216 }; 215 };
217 216
218 - const uuid = buildUUID();  
219 - emit('register', modalMethods, uuid);  
220 - 217 + tryTsxEmit((instance) => {
  218 + emit('register', modalMethods, instance.uid);
  219 + });
221 return () => ( 220 return () => (
222 - <Modal onCancel={handleCancel} {...{ ...attrs, ...props, ...unref(getProps) }}> 221 + <Modal onCancel={handleCancel} {...unref(getModalBindValue)}>
223 {{ 222 {{
224 footer: () => renderFooter(), 223 footer: () => renderFooter(),
225 closeIcon: () => renderClose(), 224 closeIcon: () => renderClose(),
src/components/Modal/src/Modal.tsx
1 import { Modal } from 'ant-design-vue'; 1 import { Modal } from 'ant-design-vue';
2 -import { defineComponent, watchEffect } from 'vue'; 2 +import { defineComponent, toRefs } from 'vue';
3 import { basicProps } from './props'; 3 import { basicProps } from './props';
4 -import { useTimeoutFn } from '/@/hooks/core/useTimeout'; 4 +import { useModalDragMove } from './useModalDrag';
5 import { extendSlots } from '/@/utils/helper/tsxHelper'; 5 import { extendSlots } from '/@/utils/helper/tsxHelper';
6 6
7 export default defineComponent({ 7 export default defineComponent({
@@ -9,99 +9,12 @@ export default defineComponent({ @@ -9,99 +9,12 @@ export default defineComponent({
9 inheritAttrs: false, 9 inheritAttrs: false,
10 props: basicProps, 10 props: basicProps,
11 setup(props, { attrs, slots }) { 11 setup(props, { attrs, slots }) {
12 - const getStyle = (dom: any, attr: any) => {  
13 - return getComputedStyle(dom)[attr];  
14 - };  
15 - const drag = (wrap: any) => {  
16 - if (!wrap) return;  
17 - wrap.setAttribute('data-drag', props.draggable);  
18 - const dialogHeaderEl = wrap.querySelector('.ant-modal-header');  
19 - const dragDom = wrap.querySelector('.ant-modal');  
20 -  
21 - if (!dialogHeaderEl || !dragDom || !props.draggable) return;  
22 -  
23 - dialogHeaderEl.style.cursor = 'move';  
24 -  
25 - dialogHeaderEl.onmousedown = (e: any) => {  
26 - if (!e) return;  
27 - // 鼠标按下,计算当前元素距离可视区的距离  
28 - const disX = e.clientX;  
29 - const disY = e.clientY;  
30 - const screenWidth = document.body.clientWidth; // body当前宽度  
31 - const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取)  
32 -  
33 - const dragDomWidth = dragDom.offsetWidth; // 对话框宽度  
34 - const dragDomheight = dragDom.offsetHeight; // 对话框高度  
35 -  
36 - const minDragDomLeft = dragDom.offsetLeft;  
37 -  
38 - const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;  
39 - const minDragDomTop = dragDom.offsetTop;  
40 - const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;  
41 - // 获取到的值带px 正则匹配替换  
42 - const domLeft = getStyle(dragDom, 'left');  
43 - const domTop = getStyle(dragDom, 'top');  
44 - let styL = +domLeft;  
45 - let styT = +domTop;  
46 -  
47 - // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px  
48 - if (domLeft.includes('%')) {  
49 - styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100);  
50 - styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100);  
51 - } else {  
52 - styL = +domLeft.replace(/px/g, '');  
53 - styT = +domTop.replace(/px/g, '');  
54 - }  
55 -  
56 - document.onmousemove = function (e) {  
57 - // 通过事件委托,计算移动的距离  
58 - let left = e.clientX - disX;  
59 - let top = e.clientY - disY;  
60 -  
61 - // 边界处理  
62 - if (-left > minDragDomLeft) {  
63 - left = -minDragDomLeft;  
64 - } else if (left > maxDragDomLeft) {  
65 - left = maxDragDomLeft;  
66 - }  
67 -  
68 - if (-top > minDragDomTop) {  
69 - top = -minDragDomTop;  
70 - } else if (top > maxDragDomTop) {  
71 - top = maxDragDomTop;  
72 - }  
73 -  
74 - // 移动当前元素  
75 - dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;  
76 - };  
77 -  
78 - document.onmouseup = () => {  
79 - document.onmousemove = null;  
80 - document.onmouseup = null;  
81 - };  
82 - };  
83 - };  
84 -  
85 - const handleDrag = () => {  
86 - const dragWraps = document.querySelectorAll('.ant-modal-wrap');  
87 - for (const wrap of dragWraps as any) {  
88 - if (!wrap) continue;  
89 - const display = getStyle(wrap, 'display');  
90 - const draggable = wrap.getAttribute('data-drag');  
91 - if (display !== 'none') {  
92 - // 拖拽位置  
93 - (draggable === null || props.destroyOnClose) && drag(wrap);  
94 - }  
95 - }  
96 - }; 12 + const { visible, draggable, destroyOnClose } = toRefs(props);
97 13
98 - watchEffect(() => {  
99 - if (!props.visible) {  
100 - return;  
101 - }  
102 - useTimeoutFn(() => {  
103 - handleDrag();  
104 - }, 30); 14 + useModalDragMove({
  15 + visible,
  16 + destroyOnClose,
  17 + draggable,
105 }); 18 });
106 19
107 return () => { 20 return () => {
src/components/Modal/src/ModalWrapper.tsx
1 -import type { PropType } from 'vue';  
2 import type { ModalWrapperProps } from './types'; 1 import type { ModalWrapperProps } from './types';
  2 +import type { CSSProperties } from 'vue';
3 3
4 import { 4 import {
5 defineComponent, 5 defineComponent,
@@ -18,59 +18,44 @@ import { useWindowSizeFn } from &#39;/@/hooks/event/useWindowSizeFn&#39;; @@ -18,59 +18,44 @@ import { useWindowSizeFn } from &#39;/@/hooks/event/useWindowSizeFn&#39;;
18 18
19 import { getSlot } from '/@/utils/helper/tsxHelper'; 19 import { getSlot } from '/@/utils/helper/tsxHelper';
20 import { useElResize } from '/@/hooks/event/useElResize'; 20 import { useElResize } from '/@/hooks/event/useElResize';
21 -import { provideModal } from './provideModal'; 21 +import { propTypes } from '/@/utils/propTypes';
  22 +import { createModalContext } from './useModalContext';
22 23
23 export default defineComponent({ 24 export default defineComponent({
24 name: 'ModalWrapper', 25 name: 'ModalWrapper',
25 props: { 26 props: {
26 - loading: {  
27 - type: Boolean as PropType<boolean>,  
28 - default: false,  
29 - },  
30 - modalHeaderHeight: {  
31 - type: Number as PropType<number>,  
32 - default: 50,  
33 - },  
34 - modalFooterHeight: {  
35 - type: Number as PropType<number>,  
36 - default: 70,  
37 - },  
38 - minHeight: {  
39 - type: Number as PropType<number>,  
40 - default: 200,  
41 - },  
42 - footerOffset: {  
43 - type: Number as PropType<number>,  
44 - default: 0,  
45 - },  
46 - visible: {  
47 - type: Boolean as PropType<boolean>,  
48 - default: false,  
49 - },  
50 - fullScreen: {  
51 - type: Boolean as PropType<boolean>,  
52 - default: false,  
53 - }, 27 + loading: propTypes.bool,
  28 + modalHeaderHeight: propTypes.number.def(50),
  29 + modalFooterHeight: propTypes.number.def(54),
  30 + minHeight: propTypes.number.def(200),
  31 + footerOffset: propTypes.number.def(0),
  32 + visible: propTypes.bool,
  33 + fullScreen: propTypes.bool,
54 }, 34 },
55 emits: ['heightChange', 'getExtHeight'], 35 emits: ['heightChange', 'getExtHeight'],
56 setup(props: ModalWrapperProps, { slots, emit }) { 36 setup(props: ModalWrapperProps, { slots, emit }) {
57 - const wrapperRef = ref<HTMLElement | null>(null); 37 + const wrapperRef = ref<ElRef>(null);
58 const spinRef = ref<ComponentRef>(null); 38 const spinRef = ref<ComponentRef>(null);
59 const realHeightRef = ref(0); 39 const realHeightRef = ref(0);
60 - // 重试次数  
61 - // let tryCount = 0; 40 +
62 let stopElResizeFn: Fn = () => {}; 41 let stopElResizeFn: Fn = () => {};
63 42
64 - provideModal(setModalHeight); 43 + useWindowSizeFn(setModalHeight);
65 44
66 - const wrapStyle = computed(() => {  
67 - return {  
68 - minHeight: `${props.minHeight}px`,  
69 - height: `${unref(realHeightRef)}px`,  
70 - overflow: 'auto',  
71 - }; 45 + createModalContext({
  46 + redoModalHeight: setModalHeight,
72 }); 47 });
73 48
  49 + const wrapStyle = computed(
  50 + (): CSSProperties => {
  51 + return {
  52 + minHeight: `${props.minHeight}px`,
  53 + height: `${unref(realHeightRef)}px`,
  54 + overflow: 'auto',
  55 + };
  56 + }
  57 + );
  58 +
74 watchEffect(() => { 59 watchEffect(() => {
75 setModalHeight(); 60 setModalHeight();
76 }); 61 });
@@ -92,8 +77,6 @@ export default defineComponent({ @@ -92,8 +77,6 @@ export default defineComponent({
92 stopElResizeFn && stopElResizeFn(); 77 stopElResizeFn && stopElResizeFn();
93 }); 78 });
94 79
95 - useWindowSizeFn(setModalHeight);  
96 -  
97 async function setModalHeight() { 80 async function setModalHeight() {
98 // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度 81 // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
99 // 加上这个,就必须在使用的时候传递父级的visible 82 // 加上这个,就必须在使用的时候传递父级的visible
@@ -107,9 +90,8 @@ export default defineComponent({ @@ -107,9 +90,8 @@ export default defineComponent({
107 90
108 try { 91 try {
109 const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement; 92 const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement;
110 - if (!modalDom) {  
111 - return;  
112 - } 93 + if (!modalDom) return;
  94 +
113 const modalRect = getComputedStyle(modalDom).top; 95 const modalRect = getComputedStyle(modalDom).top;
114 const modalTop = Number.parseInt(modalRect); 96 const modalTop = Number.parseInt(modalRect);
115 let maxHeight = 97 let maxHeight =
@@ -135,11 +117,12 @@ export default defineComponent({ @@ -135,11 +117,12 @@ export default defineComponent({
135 117
136 if (props.fullScreen) { 118 if (props.fullScreen) {
137 realHeightRef.value = 119 realHeightRef.value =
138 - window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 6; 120 + window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight;
139 } else { 121 } else {
140 realHeightRef.value = realHeight > maxHeight ? maxHeight : realHeight + 16 + 30; 122 realHeightRef.value = realHeight > maxHeight ? maxHeight : realHeight + 16 + 30;
141 } 123 }
142 emit('heightChange', unref(realHeightRef)); 124 emit('heightChange', unref(realHeightRef));
  125 +
143 nextTick(() => { 126 nextTick(() => {
144 const el = spinEl.$el; 127 const el = spinEl.$el;
145 if (el) { 128 if (el) {
@@ -154,8 +137,10 @@ export default defineComponent({ @@ -154,8 +137,10 @@ export default defineComponent({
154 function listenElResize() { 137 function listenElResize() {
155 const wrapper = unref(wrapperRef); 138 const wrapper = unref(wrapperRef);
156 if (!wrapper) return; 139 if (!wrapper) return;
  140 +
157 const container = wrapper.querySelector('.ant-spin-container'); 141 const container = wrapper.querySelector('.ant-spin-container');
158 if (!container) return; 142 if (!container) return;
  143 +
159 const [start, stop] = useElResize(container, () => { 144 const [start, stop] = useElResize(container, () => {
160 setModalHeight(); 145 setModalHeight();
161 }); 146 });
src/components/Modal/src/index.less
@@ -9,6 +9,11 @@ @@ -9,6 +9,11 @@
9 bottom: 0 !important; 9 bottom: 0 !important;
10 left: 0 !important; 10 left: 0 !important;
11 width: 100% !important; 11 width: 100% !important;
  12 + height: 100%;
  13 +
  14 + &-content {
  15 + height: 100%;
  16 + }
12 } 17 }
13 } 18 }
14 19
@@ -35,8 +40,23 @@ @@ -35,8 +40,23 @@
35 height: 95%; 40 height: 95%;
36 align-items: center; 41 align-items: center;
37 42
38 - > * {  
39 - margin-left: 12px; 43 + > span {
  44 + margin-left: 48px;
  45 + font-size: 16px;
  46 + }
  47 +
  48 + &.can-full {
  49 + > span {
  50 + margin-left: 12px;
  51 + }
  52 + }
  53 +
  54 + &:not(.can-full) {
  55 + > span:nth-child(1) {
  56 + &:hover {
  57 + font-weight: 700;
  58 + }
  59 + }
40 } 60 }
41 61
42 & span:nth-child(1) { 62 & span:nth-child(1) {
@@ -76,7 +96,7 @@ @@ -76,7 +96,7 @@
76 } 96 }
77 97
78 &-footer { 98 &-footer {
79 - padding: 10px 26px 26px 16px; 99 + // padding: 10px 26px 26px 16px;
80 100
81 button + button { 101 button + button {
82 margin-left: 10px; 102 margin-left: 10px;
src/components/Modal/src/props.ts
@@ -2,66 +2,38 @@ import type { PropType } from &#39;vue&#39;; @@ -2,66 +2,38 @@ import type { PropType } from &#39;vue&#39;;
2 import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'; 2 import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
3 3
4 import { useI18n } from '/@/hooks/web/useI18n'; 4 import { useI18n } from '/@/hooks/web/useI18n';
  5 +import { propTypes } from '/@/utils/propTypes';
5 const { t } = useI18n('component.modal'); 6 const { t } = useI18n('component.modal');
6 7
7 export const modalProps = { 8 export const modalProps = {
8 - visible: Boolean as PropType<boolean>, 9 + visible: propTypes.bool,
9 // open drag 10 // open drag
10 - draggable: {  
11 - type: Boolean as PropType<boolean>,  
12 - default: true,  
13 - },  
14 - centered: {  
15 - type: Boolean as PropType<boolean>,  
16 - default: false,  
17 - },  
18 - cancelText: {  
19 - type: String as PropType<string>,  
20 - default: t('cancelText'),  
21 - },  
22 - okText: {  
23 - type: String as PropType<string>,  
24 - default: t('okText'),  
25 - }, 11 + draggable: propTypes.bool.def(true),
  12 + centered: propTypes.bool,
  13 + cancelText: propTypes.string.def(t('cancelText')),
  14 + okText: propTypes.string.def(t('okText')),
  15 +
26 closeFunc: Function as PropType<() => Promise<boolean>>, 16 closeFunc: Function as PropType<() => Promise<boolean>>,
27 }; 17 };
28 18
29 export const basicProps = Object.assign({}, modalProps, { 19 export const basicProps = Object.assign({}, modalProps, {
30 // Can it be full screen 20 // Can it be full screen
31 - canFullscreen: {  
32 - type: Boolean as PropType<boolean>,  
33 - default: true,  
34 - }, 21 + canFullscreen: propTypes.bool.def(true),
35 // After enabling the wrapper, the bottom can be increased in height 22 // After enabling the wrapper, the bottom can be increased in height
36 - wrapperFooterOffset: {  
37 - type: Number as PropType<number>,  
38 - default: 0,  
39 - }, 23 + wrapperFooterOffset: propTypes.number.def(0),
40 // Warm reminder message 24 // Warm reminder message
41 helpMessage: [String, Array] as PropType<string | string[]>, 25 helpMessage: [String, Array] as PropType<string | string[]>,
42 // Whether to setting wrapper 26 // Whether to setting wrapper
43 - useWrapper: {  
44 - type: Boolean as PropType<boolean>,  
45 - default: true,  
46 - },  
47 - loading: {  
48 - type: Boolean as PropType<boolean>,  
49 - default: false,  
50 - }, 27 + useWrapper: propTypes.bool.def(true),
  28 + loading: propTypes.bool,
51 /** 29 /**
52 * @description: Show close button 30 * @description: Show close button
53 */ 31 */
54 - showCancelBtn: {  
55 - type: Boolean as PropType<boolean>,  
56 - default: true,  
57 - }, 32 + showCancelBtn: propTypes.bool.def(true),
58 /** 33 /**
59 * @description: Show confirmation button 34 * @description: Show confirmation button
60 */ 35 */
61 - showOkBtn: {  
62 - type: Boolean as PropType<boolean>,  
63 - default: true,  
64 - }, 36 + showOkBtn: propTypes.bool.def(true),
65 37
66 wrapperProps: Object as PropType<any>, 38 wrapperProps: Object as PropType<any>,
67 39
src/components/Modal/src/provideModal.ts deleted 100644 → 0
1 -import { provide, inject } from 'vue';  
2 -  
3 -const key = Symbol('basic-modal');  
4 -  
5 -export function provideModal(redoHeight: Fn) {  
6 - provide(key, redoHeight);  
7 -}  
8 -  
9 -export function injectModal(): Fn {  
10 - return inject(key, () => {}) as Fn;  
11 -}  
src/components/Modal/src/types.ts
@@ -8,9 +8,11 @@ export interface ModalMethods { @@ -8,9 +8,11 @@ export interface ModalMethods {
8 } 8 }
9 9
10 export type RegisterFn = (modalMethods: ModalMethods, uuid?: string) => void; 10 export type RegisterFn = (modalMethods: ModalMethods, uuid?: string) => void;
  11 +
11 export interface ReturnMethods extends ModalMethods { 12 export interface ReturnMethods extends ModalMethods {
12 openModal: <T = any>(props?: boolean, data?: T, openOnSet?: boolean) => void; 13 openModal: <T = any>(props?: boolean, data?: T, openOnSet?: boolean) => void;
13 } 14 }
  15 +
14 export type UseModalReturnType = [RegisterFn, ReturnMethods]; 16 export type UseModalReturnType = [RegisterFn, ReturnMethods];
15 17
16 export interface ReturnInnerMethods extends ModalMethods { 18 export interface ReturnInnerMethods extends ModalMethods {
@@ -18,6 +20,7 @@ export interface ReturnInnerMethods extends ModalMethods { @@ -18,6 +20,7 @@ export interface ReturnInnerMethods extends ModalMethods {
18 changeLoading: (loading: boolean) => void; 20 changeLoading: (loading: boolean) => void;
19 changeOkLoading: (loading: boolean) => void; 21 changeOkLoading: (loading: boolean) => void;
20 } 22 }
  23 +
21 export type UseModalInnerReturnType = [RegisterFn, ReturnInnerMethods]; 24 export type UseModalInnerReturnType = [RegisterFn, ReturnInnerMethods];
22 25
23 export interface ModalProps { 26 export interface ModalProps {
src/components/Modal/src/useFullScreen.ts 0 → 100644
  1 +import { computed, Ref, ref, unref } from 'vue';
  2 +
  3 +export interface UseFullScreenContext {
  4 + wrapClassName: Ref<string | undefined>;
  5 + modalWrapperRef: Ref<ComponentRef>;
  6 + extHeightRef: Ref<number>;
  7 +}
  8 +
  9 +export function useFullScreen(context: UseFullScreenContext) {
  10 + const formerHeightRef = ref(0);
  11 + const fullScreenRef = ref(false);
  12 +
  13 + const getWrapClassName = computed(() => {
  14 + const clsName = unref(context.wrapClassName) || '';
  15 +
  16 + return unref(fullScreenRef) ? `fullscreen-modal ${clsName} ` : unref(clsName);
  17 + });
  18 +
  19 + function handleFullScreen(e: Event) {
  20 + e && e.stopPropagation();
  21 + fullScreenRef.value = !unref(fullScreenRef);
  22 +
  23 + const modalWrapper = unref(context.modalWrapperRef);
  24 +
  25 + if (!modalWrapper) return;
  26 +
  27 + const wrapperEl = modalWrapper.$el as HTMLElement;
  28 + if (!wrapperEl) return;
  29 + const modalWrapSpinEl = wrapperEl.querySelector('.ant-spin-nested-loading') as HTMLElement;
  30 +
  31 + if (!modalWrapSpinEl) return;
  32 +
  33 + if (!unref(formerHeightRef) && unref(fullScreenRef)) {
  34 + formerHeightRef.value = modalWrapSpinEl.offsetHeight;
  35 + }
  36 +
  37 + if (unref(fullScreenRef)) {
  38 + modalWrapSpinEl.style.height = `${window.innerHeight - unref(context.extHeightRef)}px`;
  39 + } else {
  40 + modalWrapSpinEl.style.height = `${unref(formerHeightRef)}px`;
  41 + }
  42 + }
  43 + return { getWrapClassName, handleFullScreen, fullScreenRef };
  44 +}
src/components/Modal/src/useModal.ts
@@ -5,9 +5,21 @@ import type { @@ -5,9 +5,21 @@ import type {
5 ReturnMethods, 5 ReturnMethods,
6 UseModalInnerReturnType, 6 UseModalInnerReturnType,
7 } from './types'; 7 } from './types';
8 -import { ref, onUnmounted, unref, getCurrentInstance, reactive, watchEffect, nextTick } from 'vue'; 8 +
  9 +import {
  10 + ref,
  11 + onUnmounted,
  12 + unref,
  13 + getCurrentInstance,
  14 + reactive,
  15 + watchEffect,
  16 + nextTick,
  17 + toRaw,
  18 +} from 'vue';
9 import { isProdMode } from '/@/utils/env'; 19 import { isProdMode } from '/@/utils/env';
10 import { isFunction } from '/@/utils/is'; 20 import { isFunction } from '/@/utils/is';
  21 +import { isEqual } from 'lodash-es';
  22 +import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
11 const dataTransferRef = reactive<any>({}); 23 const dataTransferRef = reactive<any>({});
12 24
13 /** 25 /**
@@ -20,6 +32,7 @@ export function useModal(): UseModalReturnType { @@ -20,6 +32,7 @@ export function useModal(): UseModalReturnType {
20 const modalRef = ref<Nullable<ModalMethods>>(null); 32 const modalRef = ref<Nullable<ModalMethods>>(null);
21 const loadedRef = ref<Nullable<boolean>>(false); 33 const loadedRef = ref<Nullable<boolean>>(false);
22 const uidRef = ref<string>(''); 34 const uidRef = ref<string>('');
  35 +
23 function register(modalMethod: ModalMethods, uuid: string) { 36 function register(modalMethod: ModalMethods, uuid: string) {
24 uidRef.value = uuid; 37 uidRef.value = uuid;
25 38
@@ -52,13 +65,16 @@ export function useModal(): UseModalReturnType { @@ -52,13 +65,16 @@ export function useModal(): UseModalReturnType {
52 visible: visible, 65 visible: visible,
53 }); 66 });
54 67
55 - if (data) {  
56 - dataTransferRef[unref(uidRef)] = openOnSet  
57 - ? {  
58 - ...data,  
59 - __t__: Date.now(),  
60 - }  
61 - : data; 68 + if (!data) return;
  69 +
  70 + if (openOnSet) {
  71 + dataTransferRef[unref(uidRef)] = null;
  72 + dataTransferRef[unref(uidRef)] = data;
  73 + return;
  74 + }
  75 + const equal = isEqual(toRaw(dataTransferRef[unref(uidRef)]), data);
  76 + if (!equal) {
  77 + dataTransferRef[unref(uidRef)] = data;
62 } 78 }
63 }, 79 },
64 }; 80 };
@@ -66,7 +82,7 @@ export function useModal(): UseModalReturnType { @@ -66,7 +82,7 @@ export function useModal(): UseModalReturnType {
66 } 82 }
67 83
68 export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => { 84 export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => {
69 - const modalInstanceRef = ref<ModalMethods | null>(null); 85 + const modalInstanceRef = ref<Nullable<ModalMethods>>(null);
70 const currentInstall = getCurrentInstance(); 86 const currentInstall = getCurrentInstance();
71 const uidRef = ref<string>(''); 87 const uidRef = ref<string>('');
72 88
@@ -83,6 +99,11 @@ export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType =&gt; { @@ -83,6 +99,11 @@ export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType =&gt; {
83 }; 99 };
84 100
85 const register = (modalInstance: ModalMethods, uuid: string) => { 101 const register = (modalInstance: ModalMethods, uuid: string) => {
  102 + isProdMode() &&
  103 + tryOnUnmounted(() => {
  104 + modalInstanceRef.value = null;
  105 + });
  106 +
86 uidRef.value = uuid; 107 uidRef.value = uuid;
87 modalInstanceRef.value = modalInstance; 108 modalInstanceRef.value = modalInstance;
88 currentInstall.emit('register', modalInstance); 109 currentInstall.emit('register', modalInstance);
src/components/Modal/src/useModalContext.ts 0 → 100644
  1 +import { InjectionKey } from 'vue';
  2 +import { createContext, useContext } from '/@/hooks/core/useContext';
  3 +
  4 +export interface ModalContextProps {
  5 + redoModalHeight: () => void;
  6 +}
  7 +
  8 +const modalContextInjectKey: InjectionKey<ModalContextProps> = Symbol();
  9 +
  10 +export function createModalContext(context: ModalContextProps) {
  11 + return createContext<ModalContextProps>(context, modalContextInjectKey);
  12 +}
  13 +
  14 +export function useModalContext() {
  15 + return useContext<ModalContextProps>(modalContextInjectKey);
  16 +}
src/components/Modal/src/useModalDrag.ts 0 → 100644
  1 +import { Ref, unref, watchEffect } from 'vue';
  2 +import { useTimeoutFn } from '/@/hooks/core/useTimeout';
  3 +
  4 +export interface UseModalDragMoveContext {
  5 + draggable: Ref<boolean>;
  6 + destroyOnClose: Ref<boolean | undefined> | undefined;
  7 + visible: Ref<boolean>;
  8 +}
  9 +
  10 +export function useModalDragMove(context: UseModalDragMoveContext) {
  11 + const getStyle = (dom: any, attr: any) => {
  12 + return getComputedStyle(dom)[attr];
  13 + };
  14 + const drag = (wrap: any) => {
  15 + if (!wrap) return;
  16 + wrap.setAttribute('data-drag', unref(context.draggable));
  17 + const dialogHeaderEl = wrap.querySelector('.ant-modal-header');
  18 + const dragDom = wrap.querySelector('.ant-modal');
  19 +
  20 + if (!dialogHeaderEl || !dragDom || !unref(context.draggable)) return;
  21 +
  22 + dialogHeaderEl.style.cursor = 'move';
  23 +
  24 + dialogHeaderEl.onmousedown = (e: any) => {
  25 + if (!e) return;
  26 + // 鼠标按下,计算当前元素距离可视区的距离
  27 + const disX = e.clientX;
  28 + const disY = e.clientY;
  29 + const screenWidth = document.body.clientWidth; // body当前宽度
  30 + const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取)
  31 +
  32 + const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
  33 + const dragDomheight = dragDom.offsetHeight; // 对话框高度
  34 +
  35 + const minDragDomLeft = dragDom.offsetLeft;
  36 +
  37 + const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
  38 + const minDragDomTop = dragDom.offsetTop;
  39 + const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;
  40 + // 获取到的值带px 正则匹配替换
  41 + const domLeft = getStyle(dragDom, 'left');
  42 + const domTop = getStyle(dragDom, 'top');
  43 + let styL = +domLeft;
  44 + let styT = +domTop;
  45 +
  46 + // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
  47 + if (domLeft.includes('%')) {
  48 + styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100);
  49 + styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100);
  50 + } else {
  51 + styL = +domLeft.replace(/px/g, '');
  52 + styT = +domTop.replace(/px/g, '');
  53 + }
  54 +
  55 + document.onmousemove = function (e) {
  56 + // 通过事件委托,计算移动的距离
  57 + let left = e.clientX - disX;
  58 + let top = e.clientY - disY;
  59 +
  60 + // 边界处理
  61 + if (-left > minDragDomLeft) {
  62 + left = -minDragDomLeft;
  63 + } else if (left > maxDragDomLeft) {
  64 + left = maxDragDomLeft;
  65 + }
  66 +
  67 + if (-top > minDragDomTop) {
  68 + top = -minDragDomTop;
  69 + } else if (top > maxDragDomTop) {
  70 + top = maxDragDomTop;
  71 + }
  72 +
  73 + // 移动当前元素
  74 + dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
  75 + };
  76 +
  77 + document.onmouseup = () => {
  78 + document.onmousemove = null;
  79 + document.onmouseup = null;
  80 + };
  81 + };
  82 + };
  83 +
  84 + const handleDrag = () => {
  85 + const dragWraps = document.querySelectorAll('.ant-modal-wrap');
  86 + for (const wrap of Array.from(dragWraps)) {
  87 + if (!wrap) continue;
  88 + const display = getStyle(wrap, 'display');
  89 + const draggable = wrap.getAttribute('data-drag');
  90 + if (display !== 'none') {
  91 + // 拖拽位置
  92 + if (draggable === null || unref(context.destroyOnClose)) {
  93 + drag(wrap);
  94 + }
  95 + }
  96 + }
  97 + };
  98 +
  99 + watchEffect(() => {
  100 + if (!unref(context.visible) || !unref(context.draggable)) {
  101 + return;
  102 + }
  103 + useTimeoutFn(() => {
  104 + handleDrag();
  105 + }, 30);
  106 + });
  107 +}
src/components/Scrollbar/src/Scrollbar.tsx
@@ -65,7 +65,7 @@ export default defineComponent({ @@ -65,7 +65,7 @@ export default defineComponent({
65 } 65 }
66 66
67 onMounted(() => { 67 onMounted(() => {
68 - tryTsxEmit((instance) => { 68 + tryTsxEmit<any>((instance) => {
69 instance.wrap = unref(wrapElRef); 69 instance.wrap = unref(wrapElRef);
70 }); 70 });
71 71
src/components/Table/src/hooks/useTableScroll.ts
1 import type { BasicTableProps } from '../types/table'; 1 import type { BasicTableProps } from '../types/table';
2 import { computed, Ref, onMounted, unref, ref, nextTick, ComputedRef, watch } from 'vue'; 2 import { computed, Ref, onMounted, unref, ref, nextTick, ComputedRef, watch } from 'vue';
3 3
4 -import { injectModal } from '/@/components/Modal/src/provideModal';  
5 -  
6 import { getViewportOffset } from '/@/utils/domUtils'; 4 import { getViewportOffset } from '/@/utils/domUtils';
7 import { isBoolean } from '/@/utils/is'; 5 import { isBoolean } from '/@/utils/is';
8 6
9 import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; 7 import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
10 import { useProps } from './useProps'; 8 import { useProps } from './useProps';
  9 +import { useModalContext } from '/@/components/Modal';
11 10
12 export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRef: Ref<any>) { 11 export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRef: Ref<any>) {
13 const { propsRef } = useProps(refProps); 12 const { propsRef } = useProps(refProps);
14 13
15 const tableHeightRef: Ref<number | null> = ref(null); 14 const tableHeightRef: Ref<number | null> = ref(null);
16 15
17 - const redoModalHeight = injectModal(); 16 + const modalFn = useModalContext();
18 17
19 watch( 18 watch(
20 () => unref(propsRef).canResize, 19 () => unref(propsRef).canResize,
@@ -93,7 +92,7 @@ export function useTableScroll(refProps: ComputedRef&lt;BasicTableProps&gt;, tableElRe @@ -93,7 +92,7 @@ export function useTableScroll(refProps: ComputedRef&lt;BasicTableProps&gt;, tableElRe
93 tableHeightRef.value = 92 tableHeightRef.value =
94 tableHeightRef.value! > maxHeight! ? (maxHeight as number) : tableHeightRef.value; 93 tableHeightRef.value! > maxHeight! ? (maxHeight as number) : tableHeightRef.value;
95 // 解决表格放modal内的时候,modal自适应高度计算问题 94 // 解决表格放modal内的时候,modal自适应高度计算问题
96 - redoModalHeight && redoModalHeight(); 95 + modalFn?.redoModalHeight?.();
97 }, 16); 96 }, 16);
98 } 97 }
99 98
src/components/Tree/src/BasicTree.tsx
1 import './index.less'; 1 import './index.less';
2 2
3 -import type { ReplaceFields, TreeItem, Keys, CheckKeys } from './types'; 3 +import type { ReplaceFields, TreeItem, Keys, CheckKeys, TreeActionType } from './types';
4 4
5 import { defineComponent, reactive, computed, unref, ref, watchEffect, CSSProperties } from 'vue'; 5 import { defineComponent, reactive, computed, unref, ref, watchEffect, CSSProperties } from 'vue';
6 import { Tree } from 'ant-design-vue'; 6 import { Tree } from 'ant-design-vue';
@@ -124,7 +124,6 @@ export default defineComponent({ @@ -124,7 +124,6 @@ export default defineComponent({
124 title: () => ( 124 title: () => (
125 <span class={`${prefixCls}-title`}> 125 <span class={`${prefixCls}-title`}>
126 <span class={`${prefixCls}__content`} style={unref(getContentStyle)}> 126 <span class={`${prefixCls}__content`} style={unref(getContentStyle)}>
127 - {' '}  
128 {titleField && anyItem[titleField]} 127 {titleField && anyItem[titleField]}
129 </span> 128 </span>
130 <span class={`${prefixCls}__actions`}> {renderAction(item)}</span> 129 <span class={`${prefixCls}__actions`}> {renderAction(item)}</span>
@@ -183,7 +182,7 @@ export default defineComponent({ @@ -183,7 +182,7 @@ export default defineComponent({
183 state.checkedKeys = props.checkedKeys; 182 state.checkedKeys = props.checkedKeys;
184 }); 183 });
185 184
186 - tryTsxEmit((currentInstance) => { 185 + tryTsxEmit<TreeActionType>((currentInstance) => {
187 currentInstance.setExpandedKeys = setExpandedKeys; 186 currentInstance.setExpandedKeys = setExpandedKeys;
188 currentInstance.getExpandedKeys = getExpandedKeys; 187 currentInstance.getExpandedKeys = getExpandedKeys;
189 currentInstance.setSelectedKeys = setSelectedKeys; 188 currentInstance.setSelectedKeys = setSelectedKeys;
src/components/Tree/src/useTree.ts
@@ -10,7 +10,7 @@ export function useTree( @@ -10,7 +10,7 @@ export function useTree(
10 getReplaceFields: ComputedRef<ReplaceFields> 10 getReplaceFields: ComputedRef<ReplaceFields>
11 ) { 11 ) {
12 // 更新节点 12 // 更新节点
13 - function updateNodeByKey(key: string, node: TreeItem, list: TreeItem[]) { 13 + function updateNodeByKey(key: string, node: TreeItem, list?: TreeItem[]) {
14 if (!key) return; 14 if (!key) return;
15 const treeData = list || unref(treeDataRef); 15 const treeData = list || unref(treeDataRef);
16 const { key: keyField, children: childrenField } = unref(getReplaceFields); 16 const { key: keyField, children: childrenField } = unref(getReplaceFields);
@@ -75,7 +75,7 @@ export function useTree( @@ -75,7 +75,7 @@ export function useTree(
75 } 75 }
76 76
77 // 删除节点 77 // 删除节点
78 - function deleteNodeByKey(key: string, list: TreeItem[]) { 78 + function deleteNodeByKey(key: string, list?: TreeItem[]) {
79 if (!key) return; 79 if (!key) return;
80 const treeData = list || unref(treeDataRef); 80 const treeData = list || unref(treeDataRef);
81 const { key: keyField, children: childrenField } = unref(getReplaceFields); 81 const { key: keyField, children: childrenField } = unref(getReplaceFields);
src/components/Verify/src/DragVerify.tsx
@@ -6,6 +6,7 @@ import { getSlot } from &#39;/@/utils/helper/tsxHelper&#39;; @@ -6,6 +6,7 @@ import { getSlot } from &#39;/@/utils/helper/tsxHelper&#39;;
6 import './DragVerify.less'; 6 import './DragVerify.less';
7 import { CheckOutlined, DoubleRightOutlined } from '@ant-design/icons-vue'; 7 import { CheckOutlined, DoubleRightOutlined } from '@ant-design/icons-vue';
8 import { tryTsxEmit } from '/@/utils/helper/vueHelper'; 8 import { tryTsxEmit } from '/@/utils/helper/vueHelper';
  9 +import type { DragVerifyActionType } from './types';
9 export default defineComponent({ 10 export default defineComponent({
10 name: 'BaseDargVerify', 11 name: 'BaseDargVerify',
11 props: basicProps, 12 props: basicProps,
@@ -210,7 +211,7 @@ export default defineComponent({ @@ -210,7 +211,7 @@ export default defineComponent({
210 contentEl.style.width = unref(getContentStyleRef).width; 211 contentEl.style.width = unref(getContentStyleRef).width;
211 } 212 }
212 213
213 - tryTsxEmit((instance) => { 214 + tryTsxEmit<DragVerifyActionType>((instance) => {
214 instance.resume = resume; 215 instance.resume = resume;
215 }); 216 });
216 217
src/hooks/setting/useRootSetting.ts
@@ -46,7 +46,7 @@ export function useRootSetting() { @@ -46,7 +46,7 @@ export function useRootSetting() {
46 unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED 46 unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED
47 ); 47 );
48 48
49 - function setRootSetting(setting: RootSetting) { 49 + function setRootSetting(setting: Partial<RootSetting>) {
50 appStore.commitProjectConfigState(setting); 50 appStore.commitProjectConfigState(setting);
51 } 51 }
52 52
src/utils/helper/vueHelper.ts
@@ -7,6 +7,7 @@ import { @@ -7,6 +7,7 @@ import {
7 onUnmounted, 7 onUnmounted,
8 nextTick, 8 nextTick,
9 reactive, 9 reactive,
  10 + ComponentInternalInstance,
10 } from 'vue'; 11 } from 'vue';
11 12
12 export function explicitComputed<T, S>(source: WatchSource<S>, fn: () => T) { 13 export function explicitComputed<T, S>(source: WatchSource<S>, fn: () => T) {
@@ -29,8 +30,10 @@ export function tryOnUnmounted(fn: () =&gt; Promise&lt;void&gt; | void) { @@ -29,8 +30,10 @@ export function tryOnUnmounted(fn: () =&gt; Promise&lt;void&gt; | void) {
29 getCurrentInstance() && onUnmounted(fn); 30 getCurrentInstance() && onUnmounted(fn);
30 } 31 }
31 32
32 -export function tryTsxEmit(fn: (_instance: any) => Promise<void> | void) {  
33 - const instance = getCurrentInstance(); 33 +export function tryTsxEmit<T extends any = ComponentInternalInstance>(
  34 + fn: (_instance: T) => Promise<void> | void
  35 +) {
  36 + const instance = getCurrentInstance() as any;
34 instance && fn.call(null, instance); 37 instance && fn.call(null, instance);
35 } 38 }
36 39