新增前端vue
This commit is contained in:
9
web-vue/packages/core/layouts/iframe/FrameBlank.vue
Normal file
9
web-vue/packages/core/layouts/iframe/FrameBlank.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'FrameBlank',
|
||||
});
|
||||
</script>
|
||||
138
web-vue/packages/core/layouts/iframe/FramePage.vue
Normal file
138
web-vue/packages/core/layouts/iframe/FramePage.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<!--
|
||||
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
* @author Vben、ThinkGem
|
||||
-->
|
||||
<template>
|
||||
<div :class="prefixCls" :style="getWrapStyle">
|
||||
<Spin :spinning="loading" size="large" :style="getWrapStyle">
|
||||
<iframe
|
||||
:src="frameSrc"
|
||||
:class="`${prefixCls}__main ${props.frame?.name}`"
|
||||
ref="frameRef"
|
||||
@load="hideLoading"
|
||||
></iframe>
|
||||
</Spin>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { CSSProperties } from 'vue';
|
||||
import type { AppRouteRecordRaw } from '@jeesite/core/router/types';
|
||||
import { ref, unref, computed, watch } from 'vue';
|
||||
import { Spin } from 'ant-design-vue';
|
||||
import { useWindowSizeFn } from '@jeesite/core/hooks/event/useWindowSizeFn';
|
||||
import { useDesign } from '@jeesite/core/hooks/web/useDesign';
|
||||
import { useLayoutHeight } from '@jeesite/core/layouts/default/content/useContentViewHeight';
|
||||
import { router } from '@jeesite/core/router';
|
||||
|
||||
const props = defineProps({
|
||||
frame: { type: Object as PropType<AppRouteRecordRaw> },
|
||||
query: { type: Object as PropType<Recordable> },
|
||||
fullHeight: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
const loading = ref(true);
|
||||
const topRef = ref(50);
|
||||
const heightRef = ref(window.innerHeight);
|
||||
const frameRef = ref<HTMLFrameElement>();
|
||||
const { headerHeightRef } = useLayoutHeight();
|
||||
|
||||
const { prefixCls } = useDesign('iframe-page');
|
||||
useWindowSizeFn(calcHeight, 150, { immediate: true });
|
||||
|
||||
// const frameSrc = ref(props.frame?.meta?.frameSrc);
|
||||
const frameSrc = ref<string>();
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value.query,
|
||||
() => {
|
||||
// jee site iframe query
|
||||
let src = props.frame?.meta?.frameSrc || '';
|
||||
let search = window.location.search;
|
||||
if (search && search != '') {
|
||||
src += search;
|
||||
}
|
||||
const path = window.location.pathname.replace(/\/\//g, '/');
|
||||
if (!frameSrc.value || (frameSrc.value != src && src.indexOf(path) != -1)) {
|
||||
frameSrc.value = src;
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value.name,
|
||||
() => {
|
||||
// jee site iframe refresh
|
||||
let params = router.currentRoute.value.params;
|
||||
if (params && params.path == props.frame?.path) {
|
||||
let src = props.frame?.meta?.frameSrc;
|
||||
src += src?.indexOf('?') != -1 ? '&' : '?';
|
||||
frameSrc.value = src + '__t' + new Date().getTime();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const padding = 13; // jee site default padding
|
||||
|
||||
const getWrapStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
height: `${unref(heightRef) - padding}px`,
|
||||
};
|
||||
});
|
||||
|
||||
function calcHeight() {
|
||||
const iframe = unref(frameRef);
|
||||
if (!iframe) {
|
||||
return;
|
||||
}
|
||||
if (props.fullHeight) {
|
||||
const clientHeight = document.documentElement.clientHeight - 6;
|
||||
iframe.style.height = `${clientHeight}px`;
|
||||
return;
|
||||
}
|
||||
const top = headerHeightRef.value + padding;
|
||||
topRef.value = top;
|
||||
heightRef.value = window.innerHeight - top;
|
||||
const clientHeight = document.documentElement.clientHeight - top;
|
||||
iframe.style.height = `${clientHeight - padding}px`;
|
||||
}
|
||||
|
||||
function hideLoading() {
|
||||
loading.value = false;
|
||||
calcHeight();
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'jeesite-iframe-page';
|
||||
|
||||
.@{prefix-cls} {
|
||||
.ant-spin-nested-loading {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
.ant-spin-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: @component-background;
|
||||
border: 0;
|
||||
box-sizing: border-box;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
24
web-vue/packages/core/layouts/iframe/FrameSimple.vue
Normal file
24
web-vue/packages/core/layouts/iframe/FrameSimple.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<div v-if="showFrame">
|
||||
<template v-for="frame in getFramePages" :key="frame.path">
|
||||
<template v-if="frame.meta.frameSrc && showIframe(frame)">
|
||||
<FramePage :frame="frame" :fullHeight="true" />
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, unref } from 'vue';
|
||||
import FramePage from '@jeesite/core/layouts/iframe/FramePage.vue';
|
||||
import { useFrameKeepAlive } from '@jeesite/core/layouts/iframe/useFrameKeepAlive';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FrameSimple',
|
||||
components: { FramePage },
|
||||
setup() {
|
||||
const { getFramePages, hasRenderFrame, showIframe } = useFrameKeepAlive();
|
||||
const showFrame = computed(() => unref(getFramePages).length > 0);
|
||||
return { getFramePages, hasRenderFrame, showIframe, showFrame };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
25
web-vue/packages/core/layouts/iframe/index.vue
Normal file
25
web-vue/packages/core/layouts/iframe/index.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div v-if="showFrame">
|
||||
<template v-for="frame in getFramePages" :key="frame.path">
|
||||
<FramePage v-if="frame.meta.frameSrc && hasRenderFrame(frame.name)" v-show="showIframe(frame)" :frame="frame" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, unref, computed } from 'vue';
|
||||
import FramePage from '@jeesite/core/layouts/iframe/FramePage.vue';
|
||||
|
||||
import { useFrameKeepAlive } from './useFrameKeepAlive';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FrameLayout',
|
||||
components: { FramePage },
|
||||
setup() {
|
||||
const { getFramePages, hasRenderFrame, showIframe } = useFrameKeepAlive();
|
||||
|
||||
const showFrame = computed(() => unref(getFramePages).length > 0);
|
||||
|
||||
return { getFramePages, hasRenderFrame, showIframe, showFrame };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
105
web-vue/packages/core/layouts/iframe/useFrameKeepAlive.ts
Normal file
105
web-vue/packages/core/layouts/iframe/useFrameKeepAlive.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import type { AppRouteRecordRaw } from '@jeesite/core/router/types';
|
||||
|
||||
import { computed, toRaw, ref, unref } from 'vue';
|
||||
|
||||
import { useMultipleTabStore } from '@jeesite/core/store/modules/multipleTab';
|
||||
|
||||
import { uniqBy } from 'lodash-es';
|
||||
|
||||
import { useMultipleTabSetting } from '@jeesite/core/hooks/setting/useMultipleTabSetting';
|
||||
import { useFullContent } from '@jeesite/core/hooks/web/useFullContent';
|
||||
|
||||
import { RouteRecordRaw, useRouter } from 'vue-router';
|
||||
import { LAYOUT, IFRAME_BLANK } from '@jeesite/core/router/constant';
|
||||
import { router } from '@jeesite/core/router';
|
||||
|
||||
const framePages = ref<AppRouteRecordRaw[]>();
|
||||
const tempFramePages = ref<AppRouteRecordRaw[]>();
|
||||
|
||||
export function useFrameKeepAlive() {
|
||||
const router = useRouter();
|
||||
const { currentRoute } = router;
|
||||
const { getShowMultipleTab } = useMultipleTabSetting();
|
||||
const { getFullContent } = useFullContent();
|
||||
const tabStore = useMultipleTabStore();
|
||||
|
||||
const getFramePages = computed(() => {
|
||||
if (!unref(framePages.value)) {
|
||||
framePages.value = getAllFramePages(toRaw(router.getRoutes()) as AppRouteRecordRaw[]);
|
||||
}
|
||||
return [...(framePages.value || []), ...(tempFramePages.value || [])];
|
||||
});
|
||||
|
||||
const getOpenTabList = computed((): string[] => {
|
||||
return tabStore.getTabList.reduce((prev: string[], next) => {
|
||||
if (next.meta && Reflect.has(next.meta, 'frameSrc')) {
|
||||
prev.push(next.name as string);
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
});
|
||||
|
||||
function getAllFramePages(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] {
|
||||
let res: AppRouteRecordRaw[] = [];
|
||||
for (const route of routes) {
|
||||
const { meta: { frameSrc } = {}, children } = route;
|
||||
if (frameSrc && !route.name.startsWith('JeeSite')) {
|
||||
res.push(route);
|
||||
}
|
||||
if (children && children.length) {
|
||||
res.push(...getAllFramePages(children));
|
||||
}
|
||||
}
|
||||
res = uniqBy(res, 'name');
|
||||
return (res || []) as AppRouteRecordRaw[];
|
||||
}
|
||||
|
||||
function showIframe(item: AppRouteRecordRaw) {
|
||||
return item.name === unref(currentRoute).name;
|
||||
}
|
||||
|
||||
function hasRenderFrame(name: string) {
|
||||
if (!unref(getShowMultipleTab) || unref(getFullContent)) {
|
||||
return router.currentRoute.value.name === name;
|
||||
}
|
||||
return unref(getOpenTabList).includes(name);
|
||||
}
|
||||
|
||||
return { hasRenderFrame, getFramePages, showIframe, getAllFramePages };
|
||||
}
|
||||
|
||||
export function initFramePage() {
|
||||
tempFramePages.value = JSON.parse(sessionStorage.getItem('temp-frame-pages') || '[]');
|
||||
tempFramePages.value?.forEach((r) => addFramePage(r, false));
|
||||
return addFramePage;
|
||||
}
|
||||
|
||||
function addFramePage(route: AppRouteRecordRaw, store = true) {
|
||||
if (store) {
|
||||
let array = tempFramePages.value || [];
|
||||
if (array.length > 10) {
|
||||
array = array.slice(-10);
|
||||
}
|
||||
for (let i = array.length - 1; i >= 0; i--) {
|
||||
if (array[i].name === route.name) {
|
||||
array.splice(i, 1);
|
||||
}
|
||||
}
|
||||
const currentRoute = router.currentRoute.value;
|
||||
route.meta.currentActiveMenu = currentRoute.meta.currentActiveMenu || currentRoute.path;
|
||||
array.push(route);
|
||||
tempFramePages.value = array;
|
||||
sessionStorage.setItem('temp-frame-pages', JSON.stringify(array));
|
||||
}
|
||||
router.addRoute({
|
||||
component: LAYOUT,
|
||||
meta: { single: true, affix: false },
|
||||
name: `${route.name}Parent`,
|
||||
children: [
|
||||
{
|
||||
component: IFRAME_BLANK,
|
||||
...route,
|
||||
},
|
||||
],
|
||||
} as unknown as RouteRecordRaw);
|
||||
}
|
||||
Reference in New Issue
Block a user