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