FramePage.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <!--
  2. * Copyright (c) 2013-Now https://jeesite.com All rights reserved.
  3. * No deletion without permission, or be held responsible to law.
  4. * @author Vben、ThinkGem
  5. -->
  6. <template>
  7. <div :class="prefixCls" :style="getWrapStyle">
  8. <Spin :spinning="loading" size="large" :style="getWrapStyle">
  9. <iframe
  10. :src="frameSrc"
  11. :class="`${prefixCls}__main ${props.frame?.name}`"
  12. ref="frameRef"
  13. @load="hideLoading"
  14. ></iframe>
  15. </Spin>
  16. </div>
  17. </template>
  18. <script lang="ts" setup>
  19. import type { CSSProperties } from 'vue';
  20. import type { AppRouteRecordRaw } from '@jeesite/core/router/types';
  21. import { ref, unref, computed, watch } from 'vue';
  22. import { Spin } from 'ant-design-vue';
  23. import { useWindowSizeFn } from '@jeesite/core/hooks/event/useWindowSizeFn';
  24. import { useDesign } from '@jeesite/core/hooks/web/useDesign';
  25. import { useLayoutHeight } from '@jeesite/core/layouts/default/content/useContentViewHeight';
  26. import { router } from '@jeesite/core/router';
  27. import { useGlobSetting } from '@jeesite/core/hooks/setting';
  28. const props = defineProps({
  29. frame: { type: Object as PropType<AppRouteRecordRaw> },
  30. query: { type: Object as PropType<Recordable> },
  31. fullHeight: { type: Boolean, default: false },
  32. });
  33. const loading = ref(true);
  34. const topRef = ref(50);
  35. const heightRef = ref(window.innerHeight);
  36. const frameRef = ref<HTMLFrameElement>();
  37. const { headerHeightRef } = useLayoutHeight();
  38. const { prefixCls } = useDesign('iframe-page');
  39. useWindowSizeFn(calcHeight, 150, { immediate: true });
  40. // const frameSrc = ref(props.frame?.meta?.frameSrc);
  41. const frameSrc = ref<string>();
  42. const { apiUrl } = useGlobSetting();
  43. function resolveFrameSrc(rawSrc: string): string {
  44. if (!rawSrc) return '';
  45. // If frameSrc is already a full URL (starts with http://, https://, or //), use it directly
  46. if (/^(https?:)?\/\//i.test(rawSrc)) {
  47. return rawSrc;
  48. }
  49. // If frameSrc is a relative path (starts with /) and we have an API URL configured,
  50. // resolve it against the API URL to avoid file:// protocol issues
  51. if (apiUrl && rawSrc.startsWith('/')) {
  52. // Remove trailing slash from apiUrl if present
  53. const base = apiUrl.replace(/\/+$/, '');
  54. return base + rawSrc;
  55. }
  56. return rawSrc;
  57. }
  58. watch(
  59. () => router.currentRoute.value.query,
  60. () => {
  61. // jee site iframe query
  62. let src = resolveFrameSrc(props.frame?.meta?.frameSrc || '');
  63. let search = window.location.search;
  64. if (search && search != '') {
  65. src += search;
  66. }
  67. const path = window.location.pathname.replace(/\/\//g, '/');
  68. if (!frameSrc.value || (frameSrc.value != src && src.indexOf(path) != -1)) {
  69. frameSrc.value = src;
  70. }
  71. },
  72. { immediate: true },
  73. );
  74. watch(
  75. () => router.currentRoute.value.name,
  76. () => {
  77. // jee site iframe refresh
  78. let params = router.currentRoute.value.params;
  79. if (params && params.path == props.frame?.path) {
  80. let src = resolveFrameSrc(props.frame?.meta?.frameSrc || '');
  81. src += src?.indexOf('?') != -1 ? '&' : '?';
  82. frameSrc.value = src + '__t' + new Date().getTime();
  83. }
  84. },
  85. );
  86. const padding = 35; // jee site default padding
  87. const getWrapStyle = computed((): CSSProperties => {
  88. return {
  89. height: `${unref(heightRef) - padding}px`,
  90. };
  91. });
  92. function calcHeight() {
  93. const iframe = unref(frameRef);
  94. if (!iframe) {
  95. return;
  96. }
  97. if (props.fullHeight) {
  98. const clientHeight = document.documentElement.clientHeight - 6;
  99. iframe.style.height = `${clientHeight}px`;
  100. return;
  101. }
  102. const top = headerHeightRef.value + padding;
  103. topRef.value = top;
  104. heightRef.value = window.innerHeight - top;
  105. const clientHeight = document.documentElement.clientHeight - top;
  106. iframe.style.height = `${clientHeight - padding}px`;
  107. }
  108. function hideLoading() {
  109. loading.value = false;
  110. calcHeight();
  111. }
  112. </script>
  113. <style lang="less">
  114. @prefix-cls: ~'jeesite-iframe-page';
  115. .@{prefix-cls} {
  116. .ant-spin-nested-loading {
  117. position: relative;
  118. height: 100%;
  119. .ant-spin-container {
  120. width: 100%;
  121. height: 100%;
  122. }
  123. }
  124. &__mask {
  125. position: absolute;
  126. top: 0;
  127. left: 0;
  128. width: 100%;
  129. height: 100%;
  130. }
  131. &__main {
  132. width: 100%;
  133. height: 100%;
  134. overflow: hidden;
  135. background-color: @component-background;
  136. border: 0;
  137. box-sizing: border-box;
  138. border-radius: 5px;
  139. }
  140. }
  141. </style>