|
@@ -0,0 +1,153 @@
|
|
|
+<template>
|
|
|
+ <div :class="getClass">
|
|
|
+ <PageHeader :ghost="ghost" v-bind="$attrs" ref="headerRef">
|
|
|
+ <template #default>
|
|
|
+ <template v-if="content">
|
|
|
+ {{ content }}
|
|
|
+ </template>
|
|
|
+ <slot name="headerContent" v-else />
|
|
|
+ </template>
|
|
|
+ <template #[item]="data" v-for="item in getHeaderSlots">
|
|
|
+ <slot :name="item" v-bind="data" />
|
|
|
+ </template>
|
|
|
+ </PageHeader>
|
|
|
+ <div :class="[`${prefixCls}-content`, $attrs.contentClass]" :style="getContentStyle">
|
|
|
+ <slot />
|
|
|
+ </div>
|
|
|
+ <PageFooter v-if="getShowFooter" ref="footerRef">
|
|
|
+ <template #left>
|
|
|
+ <slot name="leftFooter" />
|
|
|
+ </template>
|
|
|
+ <template #right>
|
|
|
+ <slot name="rightFooter" />
|
|
|
+ </template>
|
|
|
+ </PageFooter>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script lang="ts">
|
|
|
+ import type { CSSProperties, PropType } from 'vue';
|
|
|
+
|
|
|
+ import { defineComponent, computed, watch, nextTick, ref, unref } from 'vue';
|
|
|
+ import PageFooter from './PageFooter.vue';
|
|
|
+ import { usePageContext } from '/@/hooks/component/usePageContext';
|
|
|
+
|
|
|
+ import { useDesign } from '/@/hooks/web/useDesign';
|
|
|
+ import { propTypes } from '/@/utils/propTypes';
|
|
|
+ import { omit } from 'lodash-es';
|
|
|
+ import { PageHeader } from 'ant-design-vue';
|
|
|
+ export default defineComponent({
|
|
|
+ name: 'PageWrapper',
|
|
|
+ components: { PageFooter, PageHeader },
|
|
|
+ props: {
|
|
|
+ dense: propTypes.bool,
|
|
|
+ ghost: propTypes.bool,
|
|
|
+ content: propTypes.string,
|
|
|
+ contentStyle: {
|
|
|
+ type: Object as PropType<CSSProperties>,
|
|
|
+ },
|
|
|
+ contentBackgrond: propTypes.bool,
|
|
|
+ contentFullHeight: propTypes.bool,
|
|
|
+ },
|
|
|
+ setup(props, { slots }) {
|
|
|
+ const headerRef = ref<ComponentRef>(null);
|
|
|
+ const footerRef = ref<ComponentRef>(null);
|
|
|
+ const { prefixCls } = useDesign('page-wrapper');
|
|
|
+ const { contentHeight, setPageHeight, pageHeight } = usePageContext();
|
|
|
+
|
|
|
+ const getClass = computed(() => {
|
|
|
+ return [
|
|
|
+ prefixCls,
|
|
|
+ {
|
|
|
+ [`${prefixCls}--dense`]: props.dense,
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ });
|
|
|
+
|
|
|
+ const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);
|
|
|
+
|
|
|
+ const getHeaderSlots = computed(() => {
|
|
|
+ return Object.keys(omit(slots, 'default', 'leftFooter', 'rightFooter', 'headerContent'));
|
|
|
+ });
|
|
|
+
|
|
|
+ const getContentStyle = computed(
|
|
|
+ (): CSSProperties => {
|
|
|
+ const { contentBackgrond, contentFullHeight, contentStyle } = props;
|
|
|
+ const bg = contentBackgrond ? { backgroundColor: '#fff' } : {};
|
|
|
+ if (!contentFullHeight) {
|
|
|
+ return { ...bg, ...contentStyle };
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ ...bg,
|
|
|
+ ...contentStyle,
|
|
|
+ minHeight: `${unref(pageHeight)}px`,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => contentHeight?.value,
|
|
|
+ (height) => {
|
|
|
+ if (!props.contentFullHeight) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ nextTick(() => {
|
|
|
+ const footer = unref(footerRef);
|
|
|
+ const header = unref(headerRef);
|
|
|
+ let footetHeight = 0;
|
|
|
+ const footerEl = footer?.$el;
|
|
|
+ if (footerEl) {
|
|
|
+ footetHeight += footerEl?.offsetHeight ?? 0;
|
|
|
+ }
|
|
|
+ let headerHeight = 0;
|
|
|
+ const headerEl = header?.$el;
|
|
|
+ if (headerEl) {
|
|
|
+ headerHeight += headerEl?.offsetHeight ?? 0;
|
|
|
+ }
|
|
|
+ setPageHeight?.(height - footetHeight - headerHeight);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ {
|
|
|
+ immediate: true,
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ return {
|
|
|
+ getContentStyle,
|
|
|
+ footerRef,
|
|
|
+ headerRef,
|
|
|
+ getClass,
|
|
|
+ getHeaderSlots,
|
|
|
+ prefixCls,
|
|
|
+ getShowFooter,
|
|
|
+ pageHeight,
|
|
|
+ omit,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ });
|
|
|
+</script>
|
|
|
+<style lang="less">
|
|
|
+ @prefix-cls: ~'@{namespace}-page-wrapper';
|
|
|
+
|
|
|
+ .@{prefix-cls} {
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .ant-page-header {
|
|
|
+ padding: 12px 16px;
|
|
|
+
|
|
|
+ &:empty {
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-content {
|
|
|
+ // padding: 12px;
|
|
|
+ margin: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &--dense {
|
|
|
+ .@{prefix-cls}-content {
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|