Bladeren bron

[Fix 0000] 修复可配置首页open self导致的子应用未卸载问题

houzekong 4 dagen geleden
bovenliggende
commit
4e311cb668

+ 4 - 2
src/views/vent/home/configurable/components/ModuleBD.vue

@@ -52,7 +52,7 @@
   import { defineEmits, computed, watch } from 'vue';
   import { useInitModule } from '../hooks/useInit';
   import { getFormattedText } from '../hooks/helper';
-  import { openWindow } from '/@/utils';
+  import { useRedirect } from '../hooks/useRedirect';
   // import { ModuleProps } from '../types';
 
   const props = defineProps<{
@@ -69,6 +69,8 @@
   }>();
   const emit = defineEmits(['close', 'select']);
 
+  const redirect = useRedirect();
+
   const { header } = props.moduleData;
 
   const { selectedDeviceID, selectedDevice, options, init } = useInitModule(props.deviceType, props.moduleData);
@@ -114,7 +116,7 @@
   function redirectTo() {
     const { to } = props.moduleData;
     if (!to) return;
-    openWindow(to, { target: '_self' });
+    redirect(to);
   }
 
   watch(

+ 4 - 2
src/views/vent/home/configurable/components/ModuleCommon.vue

@@ -29,8 +29,8 @@
   // import ModuleBottom from './original/moduleBottom.vue';
   import { computed, ref } from 'vue';
   import ventBox1 from '/@/components/vent/ventBox1.vue';
-  import { openWindow } from '/@/utils';
   import { getFormattedText } from '../hooks/helper';
+  import { useRedirect } from '../hooks/useRedirect';
   // import { ModuleProps } from '../types';
 
   const props = defineProps<{
@@ -51,6 +51,8 @@
   const { header } = props.moduleData;
   const selectedData = ref();
 
+  const redirect = useRedirect();
+
   const style = computed(() => {
     const size = props.showStyle.size;
     const position = props.showStyle.position;
@@ -73,7 +75,7 @@
   function redirectTo() {
     const { to } = props.moduleData;
     if (!to) return;
-    openWindow(getFormattedText(selectedData.value, to), { target: '_self' });
+    redirect(getFormattedText(selectedData.value, to));
   }
 </script>
 <style lang="less" scoped>

+ 4 - 2
src/views/vent/home/configurable/components/ModuleEnhanced.vue

@@ -22,8 +22,8 @@
   import ModuleRight from './enhanced/moduleRight.vue';
   import ModuleBottom from './enhanced/moduleBottom.vue';
   import { computed, ref } from 'vue';
-  import { openWindow } from '/@/utils';
   import { getFormattedText } from '../hooks/helper';
+  import { useRedirect } from '../hooks/useRedirect';
   // import { ModuleProps } from '../types';
 
   const props = defineProps<{
@@ -43,6 +43,8 @@
   const { header } = props.moduleData;
   const selectedData = ref();
 
+  const redirect = useRedirect();
+
   const style = computed(() => {
     const size = props.showStyle.size;
     const position = props.showStyle.position;
@@ -67,6 +69,6 @@
   function redirectTo() {
     const { to } = props.moduleData;
     if (!to) return;
-    openWindow(getFormattedText(selectedData.value, to), { target: '_self' });
+    redirect(getFormattedText(selectedData.value, to));
   }
 </script>

+ 4 - 2
src/views/vent/home/configurable/components/ModuleMine.vue

@@ -36,7 +36,7 @@
   import { defineEmits, computed, watch } from 'vue';
   import { useInitModule } from '../hooks/useInit';
   import { getFormattedText } from '../hooks/helper';
-  import { openWindow } from '/@/utils';
+  import { useRedirect } from '../hooks/useRedirect';
 
   // 定义组件接收的属性
   const props = defineProps<{
@@ -55,6 +55,8 @@
   // 初始化模块相关的下拉、选中项等
   const { selectedDeviceID, selectedDevice, options, init } = useInitModule(props.deviceType, props.moduleData);
 
+  const redirect = useRedirect();
+
   // 计算样式(宽高+定位)
   const style = computed(() => {
     const size = props.showStyle.size;
@@ -97,7 +99,7 @@
   function redirectTo() {
     const { to } = props.moduleData;
     if (!to) return;
-    openWindow(to, { target: '_self' });
+    redirect(to);
   }
 
   // 监听数据变化,初始化

+ 4 - 2
src/views/vent/home/configurable/components/ModuleOriginal.vue

@@ -14,8 +14,8 @@
   import ModuleRight from './original/moduleRight.vue';
   import ModuleBottom from './original/moduleBottom.vue';
   import { computed, ref } from 'vue';
-  import { openWindow } from '/@/utils';
   import { getFormattedText } from '../hooks/helper';
+  import { useRedirect } from '../hooks/useRedirect';
   // import { ModuleProps } from '../types';
 
   const props = defineProps<{
@@ -35,6 +35,8 @@
   const { header } = props.moduleData;
   const selectedData = ref();
 
+  const redirect = useRedirect();
+
   const style = computed(() => {
     const size = props.showStyle.size;
     const position = props.showStyle.position;
@@ -59,6 +61,6 @@
   function redirectTo() {
     const { to } = props.moduleData;
     if (!to) return;
-    openWindow(getFormattedText(selectedData.value, to), { target: '_self' });
+    redirect(getFormattedText(selectedData.value, to));
   }
 </script>

+ 63 - 0
src/views/vent/home/configurable/hooks/useRedirect.ts

@@ -0,0 +1,63 @@
+import type { Router } from 'vue-router';
+import { useRouter } from 'vue-router';
+import { openWindow } from '/@/utils';
+import { PAGE_NOT_FOUND_NAME } from '/@/router/constant';
+
+/**
+ * 解析跳转地址,可以按站内路由跳转时返回路由地址,否则返回 null
+ * 1. 完整链接(如 http://当前域名:端口/ventilate/warn/home)且地址与当前地址一致:去掉地址部分,取 /ventilate/warn/home
+ * 2. 站内路由(如 /ventilate/warn/home):直接返回
+ * 3. 其他情况(外部链接、非同源链接、未注册的路由等):返回 null,由调用方按原有逻辑跳转
+ * @param to 配置的跳转地址
+ * @param router 路由实例
+ */
+export function resolveRoutePath(to: unknown, router: Router): string | null {
+  if (typeof to !== 'string') return null;
+  const value = to.trim();
+  if (!value) return null;
+
+  let path: string;
+  if (value.startsWith('/') && !value.startsWith('//')) {
+    // 站内路由
+    path = value;
+  } else {
+    // 完整链接或相对链接:解析后与当前地址同源,才认为可以在当前应用内跳转
+    let url: URL;
+    try {
+      url = new URL(value, window.location.href);
+    } catch {
+      return null;
+    }
+    if (url.origin !== window.location.origin) return null;
+    path = `${url.pathname}${url.search}${url.hash}`;
+  }
+
+  // 只对已注册的路由做路由跳转,避免把同源的非单页应用地址也带进来
+  try {
+    const resolved = router.resolve(path);
+    const isRoute = resolved.matched.length > 0 && resolved.matched.every((r) => r.name !== PAGE_NOT_FOUND_NAME);
+    return isRoute ? path : null;
+  } catch {
+    return null;
+  }
+}
+
+/**
+ * 首页模块标题跳转:
+ * 站内路由使用 router.push 跳转,其余地址保持原有 openWindow 逻辑
+ */
+export function useRedirect() {
+  const router = useRouter();
+
+  return function redirect(to: unknown) {
+    if (typeof to !== 'string' || !to) return;
+    const path = resolveRoutePath(to, router);
+    if (path) {
+      console.log('debug push');
+      router.push(path);
+      return;
+    }
+    console.log('debug open');
+    openWindow(to, { target: '_self' });
+  };
+}