vben
2020-10-31 28f7f7bf7f3ae49759b44395f6b06c2c61359d04
提交 | 用户 | age
28f7f7 1 import type { DrawerInstance, DrawerProps } from './types';
V 2
2407b3 3 import { defineComponent, ref, computed, watchEffect, watch, unref, nextTick, toRaw } from 'vue';
28f7f7 4 import { Drawer, Row, Col, Button } from 'ant-design-vue';
V 5
2f6253 6 import { BasicTitle } from '/@/components/Basic';
7 import { FullLoading } from '/@/components/Loading/index';
28f7f7 8 import { LeftOutlined } from '@ant-design/icons-vue';
2f6253 9
10 import { basicProps } from './props';
28f7f7 11
V 12 import { getSlot } from '/@/utils/helper/tsxHelper';
2f6253 13 import { isFunction, isNumber } from '/@/utils/is';
14 import { buildUUID } from '/@/utils/uuid';
15 import { deepMerge } from '/@/utils';
28f7f7 16
2f6253 17 import './index.less';
18
19 const prefixCls = 'basic-drawer';
20 export default defineComponent({
21   // inheritAttrs: false,
22   props: basicProps,
23   emits: ['visible-change', 'ok', 'close', 'register'],
24   setup(props, { slots, emit, attrs }) {
25     const scrollRef = ref<any>(null);
26
27     const visibleRef = ref(false);
28     const propsRef = ref<Partial<DrawerProps> | null>(null);
29
30     const getMergeProps = computed((): any => {
31       return deepMerge(toRaw(props), unref(propsRef));
32     });
33
34     const getProps = computed(() => {
35       const opt: any = {
36         placement: 'right',
37         ...attrs,
38         ...props,
39         ...(unref(propsRef) as any),
40         visible: unref(visibleRef),
41       };
42       opt.title = undefined;
43
2628fb 44       if (opt.isDetail) {
2f6253 45         if (!opt.width) {
46           opt.width = '100%';
47         }
48         opt.wrapClassName = opt.wrapClassName
49           ? `${opt.wrapClassName} ${prefixCls}__detail`
50           : `${prefixCls}__detail`;
51         if (!opt.getContainer) {
52           opt.getContainer = `.default-layout__main`;
53         }
54       }
55       return opt;
56     });
2407b3 57
2f6253 58     watchEffect(() => {
59       visibleRef.value = props.visible;
60     });
2407b3 61
2f6253 62     watch(
63       () => visibleRef.value,
64       (visible) => {
65         nextTick(() => {
66           emit('visible-change', visible);
67         });
68       },
69       {
70         immediate: false,
71       }
72     );
2407b3 73
V 74     // 底部按钮自定义实现,
75     const getFooterHeight = computed(() => {
76       const { footerHeight, showFooter }: DrawerProps = unref(getProps);
77       if (showFooter && footerHeight) {
78         return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`;
79       }
80       return `0px`;
81     });
2f6253 82
83     // 取消事件
84     async function onClose(e: any) {
85       const { closeFunc } = unref(getProps);
86       emit('close', e);
87       if (closeFunc && isFunction(closeFunc)) {
88         const res = await closeFunc();
89         res && (visibleRef.value = false);
90         return;
91       }
92       visibleRef.value = false;
93     }
94
95     function setDrawerProps(props: Partial<DrawerProps>): void {
96       // 保留上一次的setDrawerProps
97       propsRef.value = deepMerge(unref(propsRef) || {}, props);
98       if (Reflect.has(props, 'visible')) {
99         visibleRef.value = !!props.visible;
100       }
101     }
102
103     function renderFooter() {
104       const {
105         showCancelBtn,
106         cancelButtonProps,
107         cancelText,
108         showOkBtn,
109         okType,
110         okText,
111         okButtonProps,
112         confirmLoading,
113         showFooter,
114       }: DrawerProps = unref(getProps);
115
116       return (
117         getSlot(slots, 'footer') ||
118         (showFooter && (
119           <div class={`${prefixCls}__footer`}>
120             {getSlot(slots, 'insertFooter')}
121
122             {showCancelBtn && (
123               <Button {...cancelButtonProps} onClick={onClose} class="mr-2">
124                 {() => cancelText}
125               </Button>
126             )}
127             {getSlot(slots, 'centerFooter')}
128             {showOkBtn && (
129               <Button
130                 type={okType}
131                 onClick={() => {
132                   emit('ok');
133                 }}
28f7f7 134                 {...okButtonProps}
V 135                 loading={confirmLoading}
2f6253 136               >
137                 {() => okText}
138               </Button>
139             )}
140
141             {getSlot(slots, 'appendFooter')}
142           </div>
143         ))
144       );
145     }
146
147     function renderHeader() {
148       const { title } = unref(getMergeProps);
2628fb 149       return props.isDetail ? (
2f6253 150         getSlot(slots, 'title') || (
151           <Row type="flex" align="middle" class={`${prefixCls}__detail-header`}>
152             {() => (
153               <>
154                 {props.showDetailBack && (
28f7f7 155                   <Button size="small" type="link" onClick={onClose}>
V 156                     {() => <LeftOutlined />}
157                   </Button>
2f6253 158                 )}
2407b3 159
2f6253 160                 {title && (
161                   <Col style="flex:1" class={[`${prefixCls}__detail-title`, 'ellipsis', 'px-2']}>
162                     {() => title}
163                   </Col>
164                 )}
2407b3 165
2f6253 166                 {getSlot(slots, 'titleToolbar')}
167               </>
168             )}
169           </Row>
170         )
171       ) : (
172         <BasicTitle>{() => title || getSlot(slots, 'title')}</BasicTitle>
173       );
174     }
175
176     const drawerInstance: DrawerInstance = {
177       setDrawerProps: setDrawerProps,
178     };
179
180     const uuid = buildUUID();
181     emit('register', drawerInstance, uuid);
182
183     return () => {
184       const footerHeight = unref(getFooterHeight);
185       return (
186         <Drawer
187           class={prefixCls}
188           onClose={onClose}
189           {...{
190             ...attrs,
191             ...unref(getProps),
192           }}
193         >
194           {{
195             title: () => renderHeader(),
196             default: () => (
197               <>
70fba7 198                 <div
V 199                   ref={scrollRef}
200                   {...attrs}
201                   style={{
2407b3 202                     position: 'relative',
88de82 203                     height: `calc(100% - ${footerHeight})`,
70fba7 204                     overflow: 'auto',
V 205                     padding: '16px',
206                     paddingBottom: '30px',
207                   }}
208                 >
2407b3 209                   <FullLoading
V 210                     absolute
211                     tip="加载中..."
212                     class={[!unref(getProps).loading ? 'hidden' : '']}
213                   />
70fba7 214                   {getSlot(slots, 'default')}
V 215                 </div>
2f6253 216                 {renderFooter()}
217               </>
218             ),
219           }}
220         </Drawer>
221       );
222     };
223   },
224 });