瀏覽代碼

1、修复keep-alive因key不一样,导致重新加载问题
2、优化keepalive的computedKeepAliveName方法,避免极端情况出现上锁解锁数量不一致问题
3、列表页增加/index用于识别

MY 3 周之前
父節點
當前提交
5c51f22e37

+ 6 - 5
JLHWEB/src/layouts/components/Main/index.vue

@@ -9,8 +9,10 @@
     <!-- {{ JSON.stringify(keepAliveList) }} -->
     <router-view v-slot="{ Component, route }">
       <keep-alive>
-        <component :is="Component" :key="getRouteKey(route)" />
+        <component v-if="route.meta.isKeepAlive" :is="Component" :key="getRouteKey(route)" />
       </keep-alive>
+      <!-- 非缓存页面直接渲染,不包在 keep-alive 中 -->
+      <component v-if="!route.meta.isKeepAlive" :is="Component" :key="getRouteKey(route)" />
     </router-view>
   </el-main>
   <el-footer v-if="footer">
@@ -98,11 +100,10 @@ const getRouteKey = (route: any) => {
   // const keepAliveStore1 = useKeepAliveStore();
   let routeItem = keepAliveStore.getKeepAliveName(route.fullPath);
   console.log("getKeepAliveName routeItem getRouteKey:>> ", routeItem, route.fullPath);
-  if (routeItem) {
-    return routeItem.fullPath + "_" + routeItem.times;
-  } else {
-    return route.fullPath;
+  if (!routeItem) {
+    routeItem = keepAliveStore.closeAliveList.find(item => item.fullPath === route.fullPath);
   }
+  return routeItem ? `${routeItem.fullPath}_${routeItem.times}` : route.fullPath;
 };
 
 const tabsRef = ref();

+ 1 - 1
JLHWEB/src/routers/modules/bednetQtuoteRouter.ts

@@ -4,7 +4,7 @@ import type { Menu } from "@/typings/global";
  */
 export const bednetQtuoteRouter: Menu.MenuOptions[] = [
   {
-    path: "/bednetQuote",
+    path: "/bednetQuote/index",
     name: "bednetQuote",
     component: "/quote/bednetQuote/index",
     meta: {

+ 2 - 2
JLHWEB/src/routers/modules/erpApiRouter.ts

@@ -18,7 +18,7 @@ export const erpApiRouter: Menu.MenuOptions[] = [
     },
     children: [
       {
-        path: "/erpapi/mattressInterface",
+        path: "/erpapi/mattressInterface/index",
         name: "mattressInterface",
         component: "/erpapi/mattressInterface/index",
         meta: {
@@ -176,7 +176,7 @@ export const erpApiRouter: Menu.MenuOptions[] = [
               isHide: true,
               isFull: false,
               isAffix: false,
-              isKeepAlive: false,
+              isKeepAlive: true,
               funid: 71,
               activeMenu: "/erpapi/bednetInterface"
             }

+ 1 - 1
JLHWEB/src/routers/modules/mattressQtuoteRouter.ts

@@ -4,7 +4,7 @@ import type { Menu } from "@/typings/global";
  */
 export const mattressQtuoteRouter: Menu.MenuOptions[] = [
   {
-    path: "/mattressQuote",
+    path: "/mattressQuote/index",
     name: "mattressQuote",
     component: "/quote/mattressQuote/index",
     meta: {

+ 1 - 1
JLHWEB/src/routers/modules/softbedQuoteRouter.ts

@@ -4,7 +4,7 @@ import type { Menu } from "@/typings/global";
  */
 export const softbedQuoteRouter: Menu.MenuOptions[] = [
   {
-    path: "/softbedQuote",
+    path: "/softbedQuote/index",
     name: "softbedQuote",
     component: "/quote/softbedQuote/index",
     meta: {

+ 4 - 0
JLHWEB/src/stores/interface/index.ts

@@ -223,6 +223,10 @@ export interface TabsMenuProps {
   name: string;
   close: boolean;
   query?: any;
+  keyword?: string;
+  billid?: number;
+  billcode?: string;
+  needLock?: boolean;
 }
 
 /* TabsState */

+ 260 - 0
JLHWEB/src/stores/modules/keepAlive.ts

@@ -4,6 +4,8 @@ import { cloneDeep } from "lodash-es";
 import { useTabsStore } from "@/stores/modules/tabs";
 import { LockBill, UnLockBill } from "@/api/modules/common";
 
+// 最大缓存页面数量限制
+const MAX_KEEP_ALIVE_COUNT = 10;
 export const useKeepAliveStore = defineStore({
   id: "geeker-keepAlive",
   state: (): KeepAliveState => ({
@@ -42,6 +44,9 @@ export const useKeepAliveStore = defineStore({
           this.closeAliveList = this.closeAliveList.filter((item: any) => item.fullPath != route.fullPath);
         }
         this.keepAliveList.push(routeItem);
+
+        // 检查缓存数量限制,如果超过限制则清理最旧的缓存
+        this.cleanOldKeepAliveCache();
       }
     },
     // Remove KeepAliveName
@@ -96,7 +101,70 @@ export const useKeepAliveStore = defineStore({
       }
       return routeItem;
     },
+    // 清理过期的 keepAlive 缓存
+    cleanOldKeepAliveCache() {
+      if (this.keepAliveList.length <= MAX_KEEP_ALIVE_COUNT) {
+        return;
+      }
+
+      const tabStore = useTabsStore();
+      // 过滤出编辑页,跳过不清理
+      const editPages = this.keepAliveList.filter(item => {
+        const tab = tabStore.tabsMenuList.find(tabItem => tabItem.path === item.fullPath);
+        return tab && (tab.path.includes("/edit?") || tab.path.includes("/edit/"));
+      });
+
+      // 计算可清理的缓存数量(总数减去编辑页数量)
+      const availableToClean = this.keepAliveList.length - editPages.length;
+      const maxCleanable = MAX_KEEP_ALIVE_COUNT - editPages.length;
+
+      // 如果非编辑页数量在限制范围内,不需要清理
+      if (availableToClean <= maxCleanable) {
+        console.log(`非编辑页缓存数量 (${availableToClean}) 在限制范围内,跳过清理`);
+        return;
+      }
+      console.log(
+        `keepAlive 缓存数量 (${this.keepAliveList.length}) 超过限制,编辑页: ${editPages.length},开始清理非编辑页缓存`
+      );
+
+      // 获取非编辑页缓存进行清理
+      const nonEditPages = this.keepAliveList.filter(item => {
+        const tab = tabStore.tabsMenuList.find(tabItem => tabItem.path === item.fullPath);
+        return !tab || (!tab.path.includes("/edit?") && !tab.path.includes("/edit/"));
+      });
+
+      // 按访问次数排序,优先清理访问次数少的缓存
+      const sortedCache = nonEditPages.sort((a, b) => a.times - b.times);
+
+      // 需要清理的数量
+      const removeCount = availableToClean - maxCleanable;
+      const toRemove = sortedCache.slice(0, removeCount);
+
+      // 清理 keepAliveName 和 keepAliveList
+      toRemove.forEach(item => {
+        console.log(`清理 keepAlive 缓存: ${item.fullPath} (访问次数: ${item.times})`);
+
+        // 从 keepAliveList 中移除
+        const index = this.keepAliveList.findIndex(cacheItem => cacheItem.fullPath === item.fullPath);
+        if (index > -1) {
+          this.keepAliveList.splice(index, 1);
+        }
+
+        // 从 keepAliveName 中移除对应的组件名
+        const tab = tabStore.tabsMenuList.find(tabItem => tabItem.path === item.fullPath);
+        if (tab && tab.name) {
+          const nameIndex = this.keepAliveName.indexOf(tab.name);
+          if (nameIndex > -1) {
+            this.keepAliveName.splice(nameIndex, 1);
+          }
+        }
+      });
+
+      console.log(`keepAlive 缓存清理完成,当前缓存数量: ${this.keepAliveList.length}`);
+    },
     computedKeepAliveName(to, from) {
+      this.computedKeepAliveNamePro(to, from);
+      return;
       const tabStore = useTabsStore();
 
       const tabsParams = {
@@ -193,6 +261,198 @@ export const useKeepAliveStore = defineStore({
       // }
       !isReplace && tabStore.addTabs(tabsParams);
       !isReplace && to.meta.isKeepAlive && this.addKeepAliveName(to);
+    },
+    computedKeepAliveNamePro(to, from) {
+      const tabStore = useTabsStore();
+
+      const tabsParams = {
+        icon: to.meta.icon as string,
+        title: to.meta.title as string,
+        path: to.fullPath,
+        fullPath: to.fullPath,
+        name: to.name as string,
+        close: !to.meta.isAffix,
+        query: to.query
+      };
+
+      // 如果需要锁定单据,添加锁定相关参数
+      if (to.meta.needLock && Number(to.query.id)) {
+        tabsParams["needLock"] = to.meta.needLock;
+        tabsParams["keyword"] = String(to.meta.billtype);
+        tabsParams["billid"] = Number(to.query.id);
+        tabsParams["billcode"] = String(to.query.code);
+      }
+
+      let isReplace = false;
+      const tabsMenuList = [...tabStore.tabsMenuList];
+
+      // 判断是否为同一单据的单据编码
+      const getBillCode = route => {
+        return route?.query?.code || "";
+      };
+      const toBillCode = getBillCode(to);
+      const fromBillCode = getBillCode(from);
+
+      // 情况1: 列表页跳转到详情页 (/list -> /detail)
+      const isListToDetail =
+        (!from || from.fullPath.includes("/index")) && (to.fullPath.includes("/detail?") || to.fullPath.includes("/detail/"));
+
+      if (isListToDetail && toBillCode) {
+        // 查找是否有相同单据的编辑页
+        const editTabIndex = tabsMenuList.findIndex(item => {
+          const itemBillCode = getBillCode(item);
+          return itemBillCode === toBillCode && (item.path.includes("/edit?") || item.path.includes("/edit/"));
+        });
+
+        if (editTabIndex > -1) {
+          // 保存被替换的编辑页信息,用于解锁
+          const oldEditTab = tabsMenuList[editTabIndex];
+
+          // 替换编辑页为详情页
+          console.log("列表页->详情页: 替换编辑页", oldEditTab.path, "=>", to.fullPath);
+          tabsMenuList[editTabIndex] = tabsParams;
+          tabStore.setTabs(tabsMenuList);
+
+          // 如果被替换的编辑页需要锁定,解锁单据
+          if (oldEditTab.needLock && oldEditTab.billid) {
+            UnLockBill({
+              keyword: oldEditTab.keyword,
+              billid: oldEditTab.billid,
+              billcode: oldEditTab.billcode
+            }).catch(err => {
+              console.warn("替换编辑页时解锁失败:", err);
+            });
+          }
+
+          isReplace = true;
+          to.meta.isKeepAlive && this.addKeepAliveName(to);
+          to.meta.isKeepAlive && this.updateKeepAliveName(to);
+        }
+      }
+
+      // 情况2: 详情页跳转到编辑页 (/detail -> /edit)
+      const isDetailToEdit =
+        from &&
+        (from.fullPath.includes("/detail?") || from.fullPath.includes("/detail/")) &&
+        (to.fullPath.includes("/edit?") || to.fullPath.includes("/edit/")) &&
+        toBillCode &&
+        fromBillCode &&
+        toBillCode === fromBillCode;
+
+      if (isDetailToEdit) {
+        // 查找是否有相同单据的详情页
+        const detailTabIndex = tabsMenuList.findIndex(item => {
+          const itemBillCode = getBillCode(item);
+          const isDetailTab = item.path.includes("/detail?") || item.path.includes("/detail/");
+          console.log("检查tab:", {
+            itemPath: item.path,
+            itemBillCode,
+            toBillCode,
+            isDetailTab,
+            match: itemBillCode === toBillCode && isDetailTab
+          });
+          return itemBillCode === toBillCode && isDetailTab;
+        });
+
+        console.log("找到的详情页索引:", detailTabIndex);
+        if (detailTabIndex > -1) {
+          // 替换详情页为编辑页
+          console.log("详情页->编辑页: 替换详情页", tabsMenuList[detailTabIndex].path, "=>", to.fullPath);
+          tabsMenuList[detailTabIndex] = tabsParams;
+          tabStore.setTabs(tabsMenuList);
+          isReplace = true;
+          to.meta.isKeepAlive && this.addKeepAliveName(to);
+          to.meta.isKeepAlive && this.updateKeepAliveName(to);
+        }
+      }
+
+      // 情况3: 编辑页跳转到详情页 (/edit -> /detail),需要解锁单据
+      const isEditToDetailPro =
+        from &&
+        (from.fullPath.includes("/edit?") || from.fullPath.includes("/edit/")) &&
+        (to.fullPath.includes("/detail?") || to.fullPath.includes("/detail/")) &&
+        toBillCode &&
+        fromBillCode &&
+        toBillCode === fromBillCode;
+
+      if (isEditToDetailPro) {
+        console.log("编辑页->详情页: 解锁单据", fromBillCode);
+        // 查找是否有相同单据的编辑页
+        const editTabIndex = tabsMenuList.findIndex(item => {
+          const itemBillCode = getBillCode(item);
+          const isEditTab = item.path.includes("/edit?") || item.path.includes("/edit/");
+          console.log("检查tab:", {
+            itemPath: item.path,
+            itemBillCode,
+            fromBillCode,
+            isEditTab,
+            match: itemBillCode === fromBillCode && isEditTab
+          });
+          return itemBillCode === fromBillCode && isEditTab;
+        });
+
+        console.log("找到的编辑页索引:", editTabIndex);
+        if (editTabIndex > -1) {
+          // 替换编辑页为详情页
+          console.log("编辑页->详情页: 替换编辑页", tabsMenuList[editTabIndex].path, "=>", to.fullPath);
+          tabsMenuList[editTabIndex] = tabsParams;
+          tabStore.setTabs(tabsMenuList);
+
+          // 关键修复:移除编辑页的 keepAlive 缓存,确保下次进入编辑页会触发加锁
+          this.removeKeepAliveName(from);
+
+          if (from.meta?.needLock && from.query?.id) {
+            // 解锁单据
+            UnLockBill({
+              keyword: String(from.meta.billtype),
+              billid: Number(from.query.id),
+              billcode: String(from.query.code)
+            }).catch(err => {
+              console.warn("edit->detail 解锁失败:", err);
+            });
+          }
+
+          isReplace = true;
+          to.meta.isKeepAlive && this.addKeepAliveName(to);
+          to.meta.isKeepAlive && this.updateKeepAliveName(to);
+        }
+      }
+
+      // 情况4: 列表页跳转到编辑页 (/list -> /edit),需要替换相同单据的详情页
+      const isListToEdit =
+        (!from || from.fullPath.includes("/index")) && (to.fullPath.includes("/edit?") || to.fullPath.includes("/edit/"));
+      if (isListToEdit && toBillCode) {
+        // 查找是否有相同单据的详情页
+        const detailTabIndex = tabsMenuList.findIndex(item => {
+          const itemBillCode = getBillCode(item);
+          const isDetailTab = item.path.includes("/detail?") || item.path.includes("/detail/");
+          console.log("检查tab:", {
+            itemPath: item.path,
+            itemBillCode,
+            toBillCode,
+            isDetailTab,
+            match: itemBillCode === toBillCode && isDetailTab
+          });
+          return itemBillCode === toBillCode && isDetailTab;
+        });
+
+        console.log("找到的详情页索引:", detailTabIndex);
+        if (detailTabIndex > -1) {
+          // 替换详情页为编辑页
+          console.log("列表页->编辑页: 替换详情页", tabsMenuList[detailTabIndex].path, "=>", to.fullPath);
+          tabsMenuList[detailTabIndex] = tabsParams;
+          tabStore.setTabs(tabsMenuList);
+          isReplace = true;
+          to.meta.isKeepAlive && this.addKeepAliveName(to);
+          to.meta.isKeepAlive && this.updateKeepAliveName(to);
+        }
+      }
+
+      // 如果没有发生替换,则正常添加tab
+      if (!isReplace) {
+        tabStore.addTabs(tabsParams);
+        to.meta.isKeepAlive && this.addKeepAliveName(to);
+      }
     }
   }
 });

+ 5 - 4
JLHWEB/src/views/quote/softbedQuote/detail.vue

@@ -287,13 +287,12 @@ const orderDefaultAction = [
     clickFunc: item => {
       if (route.path.indexOf("/new") > -1) {
         tabRemove(route.fullPath);
-        pageRefresh({ name: "softbedQuoteEdit" });
       } else {
         // router.replace(
         //   `/softbedQuote/detail?id=${LjDetailRef.value._mainData.softbed_id}&code=${LjDetailRef.value._mainData.softbed_code}`
         // );
         pageRefresh({
-          name: "softbedQuoteEdit",
+          name: "softbedQuoteDetail",
           params: {
             id: LjDetailRef.value._mainData.softbed_id,
             code: LjDetailRef.value._mainData.softbed_code
@@ -468,11 +467,13 @@ const funcAfterMound = async (data: any) => {
 
   if (orderStatus.value != "new") {
     initParams.value.billid = Number(route.query.id);
+    detail_getData(initParams.value);
   }
+};
 
-  detail_getData(initParams.value);
+onMounted(() => {
   GetSoftBedFormulaMapper();
-};
+});
 
 // 返回绑定的事件
 const tableEvents = {};

+ 0 - 8
JLHWEB/src/views/quote/softbedQuote/hooks/index.tsx

@@ -1689,14 +1689,6 @@ export const useHooks = (t?: any) => {
     }
   };
 
-  /**
-   * 打开部件配置弹窗
-   */
-  const onOpenEditFormulaDialog = async () => {
-    const { _mainData } = state.LjDetailRef;
-    console.log("sadfasdfasfasdfasfda");
-  };
-
   return {
     ...toRefs(state),
     columns,