| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- import { defineStore } from "pinia";
- import { KeepAliveState } from "@/stores/interface";
- 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 => ({
- keepAliveName: [],
- keepAliveList: [],
- closeAliveList: []
- }),
- getters: {
- getKeepAliveList(): any[] {
- return this.keepAliveList;
- }
- },
- actions: {
- setKeepAliveList(keepAliveList: any) {
- this.keepAliveList = keepAliveList;
- console.log("getKeepAliveName routeItem setKeepAliveList :>> ", JSON.stringify(this.keepAliveList));
- console.log("getKeepAliveName routeItem setKeepAliveList :>> ", this.keepAliveList);
- },
- // Add KeepAliveName
- async addKeepAliveName(route: any) {
- !this.keepAliveName.includes(route.name) && this.keepAliveName.push(route.name);
- let routeItem = this.keepAliveList.find((item: any) => item.fullPath == route.fullPath);
- console.log("getKeepAliveName routeItem addKeepAliveName :>> ", JSON.stringify(this.keepAliveList));
- console.log("getKeepAliveName routeItem removeKeepAliveName closeAliveList:>> ", JSON.stringify(this.closeAliveList));
- if (!routeItem) {
- let closeItem = this.closeAliveList.find((item: any) => item.fullPath == route.fullPath);
- routeItem = {
- fullPath: route.fullPath,
- times: 0
- };
- if (closeItem) {
- routeItem.times = closeItem.times + 1;
- this.closeAliveList = this.closeAliveList.filter((item: any) => item.fullPath != route.fullPath);
- }
- this.keepAliveList.push(routeItem);
- // 检查缓存数量限制,如果超过限制则清理最旧的缓存
- this.cleanOldKeepAliveCache();
- }
- },
- // Remove KeepAliveName
- removeKeepAliveName(route: any) {
- this.keepAliveName = this.keepAliveName.filter(item => item !== route.name);
- let index = this.keepAliveList.findIndex(item => item.fullPath === route.fullPath);
- if (index > -1) {
- if (this.closeAliveList.every(item => item.fullPath !== route.fullPath)) {
- this.closeAliveList.push(this.keepAliveList[index]);
- }
- this.keepAliveList.splice(index, 1);
- // this.keepAliveList[index].times = this.keepAliveList[index].times + 1;
- if (route.needLock && Number(route.billid)) {
- UnLockBill({
- keyword: String(route.keyword),
- billid: Number(route.billid),
- billcode: String(route.billcode)
- }).catch(err => {
- console.warn("解锁失败:", route.keyword, route.billid, err);
- });
- }
- }
- console.log("getKeepAliveName routeItem removeKeepAliveName :>> ", index, JSON.stringify(this.keepAliveList));
- console.log("getKeepAliveName routeItem removeKeepAliveName :>> ", this.keepAliveList);
- console.log("getKeepAliveName routeItem keepAliveName :>> ", this.keepAliveName);
- },
- // Set KeepAliveName
- async setKeepAliveName(keepAliveName: string[] = []) {
- this.keepAliveName = keepAliveName;
- },
- async updateKeepAliveName(route: any) {
- // this.addKeepAliveName(route);
- console.log("updateKeepAliveName route :>> ", route, this.keepAliveList);
- this.keepAliveList.forEach((item: any) => {
- console.log("updateKeepAliveName item :>> ", item.fullPath, route.fullPath, item.fullPath == route.fullPath);
- if (item.fullPath == route.fullPath) {
- item.times++;
- }
- });
- },
- getKeepAliveName(name: string) {
- let routeItem = this.keepAliveList.find((item: any) => item.fullPath == name);
- if (!routeItem) {
- // routeItem = {
- // fullPath: name,
- // times: 0
- // };
- // this.keepAliveList.push(routeItem);
- return undefined;
- }
- 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 = {
- 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
- };
- 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);
- }
- const isEditToDetail =
- from.fullPath.includes("/edit") && to.fullPath.includes("/detail") && from.query?.id && from.meta?.needLock;
- const isSameBill = from.query?.code === to.query?.code;
- if (isEditToDetail && isSameBill) {
- UnLockBill({
- keyword: String(from.meta.billtype),
- billid: Number(from.query.id),
- billcode: String(from.query.code)
- }).catch(err => {
- console.warn("edit->detail 解锁失败:", err);
- });
- }
- let isReplace = false;
- if (tabsParams.path.indexOf("/edit?") > -1 || tabsParams.path.indexOf("/edit/") > -1) {
- let key = "/edit?";
- let name = "";
- let _path = tabsParams.path.replace(key, "/detail?");
- // let _path = from.fullPath;
- // 使用路由参数的地址,忽略查询参数后,查找相同地址
- let _path2 = tabsParams.path.replace("/edit/", "/detail/");
- let hasPath1 = to.fullPath.indexOf("/edit?") > -1;
- let hasPath2 = to.fullPath.indexOf("/edit/") > -1;
- let tabsMenuList = tabStore.tabsMenuList;
- console.log("tabsMenuList :>> ", JSON.stringify(tabsMenuList));
- for (let i = 0; i < tabsMenuList.length; i++) {
- if (
- (hasPath1 && tabsMenuList[i].path == _path) ||
- (hasPath2 && tabsMenuList[i].path.split("?")[0] == _path2.split("?")[0])
- ) {
- name = tabsMenuList[i].name;
- tabsMenuList[i] = tabsParams;
- isReplace = true;
- break;
- }
- }
- console.log("keilll name edit:>> ", name);
- tabStore.setTabs(tabsMenuList);
- isReplace && this.addKeepAliveName(to);
- isReplace && this.removeKeepAliveName(from);
- name && to.meta.isKeepAlive && this.updateKeepAliveName(to);
- // name && this.updateKeepAliveName(to);
- // to.meta.isKeepAlive && this.updateKeepAliveName(route);
- } else if (tabsParams.path.indexOf("/detail?") > -1 || tabsParams.path.indexOf("/detail/") > -1) {
- let key = "/detail?";
- let name = "";
- let _path = tabsParams.path.replace(key, "/edit?");
- // let _path = from.fullPath;
- // 使用路由参数的地址,忽略查询参数后,查找相同地址
- let _path2 = tabsParams.path.replace("/detail/", "/edit/");
- let hasPath1 = to.fullPath.indexOf("/detail?") > -1;
- let hasPath2 = to.fullPath.indexOf("/detail/") > -1;
- let tabsMenuList = tabStore.tabsMenuList;
- console.log("tabsMenuList :>> ", JSON.stringify(tabsMenuList));
- for (let i = 0; i < tabsMenuList.length; i++) {
- if (
- (hasPath1 &&
- (tabsMenuList[i].path == _path ||
- (tabsMenuList[i].path == from.fullPath && from.fullPath.indexOf("/copy?") > -1))) ||
- (hasPath2 && tabsMenuList[i].path.split("?")[0] == _path2.split("?")[0])
- ) {
- name = tabsMenuList[i].name;
- tabsMenuList[i] = tabsParams;
- isReplace = true;
- break;
- }
- }
- tabStore.setTabs(tabsMenuList);
- console.log("keilll name detail:>> ", name);
- isReplace && this.addKeepAliveName(to);
- isReplace && this.removeKeepAliveName(from);
- name && to.meta.isKeepAlive && this.updateKeepAliveName(to);
- // name && this.updateKeepAliveName(to);
- // to.meta.isKeepAlive && this.addKeepAliveName(to);
- }
- // }
- !isReplace && tabStore.addTabs(tabsParams);
- !isReplace && to.meta.isKeepAlive && this.addKeepAliveName(to);
- },
- async computedKeepAliveNamePro(to, from) {
- const tabStore = useTabsStore();
- const tabsMenuList = [...tabStore.tabsMenuList];
- let isReplace = false;
- // --- 生成 tab 参数 ---
- 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);
- }
- // --- 工具函数 ---
- const getBillCode = route => route?.query?.code || "";
- const getBillType = route => {
- const pathMatch = route?.fullPath?.match(/\/([a-zA-Z]+)\/(detail|edit|copy|index)/);
- return pathMatch ? pathMatch[1] : "";
- }; // 改为 meta 管理类型更可靠
- const isSameBill = (code1, type1, code2, type2) =>
- !!code1 && !!code2 && code1 === code2 && !!type1 && !!type2 && type1 === type2;
- const toBillCode = getBillCode(to);
- const fromBillCode = getBillCode(from);
- const toBillType = getBillType(to);
- const fromBillType = getBillType(from);
- // --- 查找 tab 工具函数 ---
- const findTabIndex = (tabType: "edit" | "detail" | "copy") => {
- return tabsMenuList.findIndex(item => {
- const itemBillCode = getBillCode(item);
- const itemBillType = getBillType(item);
- const isTypeMatch =
- (tabType === "edit" && item.path.includes("/edit")) ||
- (tabType === "detail" && item.path.includes("/detail")) ||
- (tabType === "copy" && item.path.includes("/copy"));
- return isSameBill(itemBillCode, itemBillType, toBillCode, toBillType) && isTypeMatch;
- });
- };
- // --- 替换 tab 并管理 keep-alive ---
- const replaceTab = (index: number) => {
- const oldTab = tabsMenuList[index];
- tabsMenuList[index] = tabsParams;
- tabStore.setTabs(tabsMenuList);
- if (oldTab?.name) {
- this.removeKeepAliveName(oldTab); // 移除旧缓存
- }
- if (to.meta.isKeepAlive) {
- this.addKeepAliveName(to);
- this.updateKeepAliveName(to);
- }
- isReplace = true;
- };
- // --- 解锁单据 ---
- const unlockBill = async route => {
- if (route?.meta?.needLock && route?.query?.id) {
- try {
- await UnLockBill({
- keyword: String(route.meta.billtype),
- billid: Number(route.query.id),
- billcode: String(route.query.code)
- });
- } catch (err) {
- console.warn("解锁单据失败:", err);
- }
- }
- };
- // --- 逻辑判断 ---
- const fromName = from?.name || "";
- // 情况1: 列表 -> 详情
- if ((!from || fromNameIncludes(from, "/index")) && toNameIncludes(to, "/detail") && toBillCode) {
- const editTabIndex = findTabIndex("edit");
- if (editTabIndex > -1) {
- await unlockBill(tabsMenuList[editTabIndex]);
- replaceTab(editTabIndex);
- }
- }
- // 情况2: 详情 -> 编辑
- if (
- fromName &&
- toNameIncludes(to, "/edit") &&
- fromNameIncludes(from, "/detail") &&
- isSameBill(toBillCode, toBillType, fromBillCode, fromBillType)
- ) {
- const detailTabIndex = findTabIndex("detail");
- if (detailTabIndex > -1) replaceTab(detailTabIndex);
- }
- // 情况3: 编辑 -> 详情
- if (
- fromName &&
- fromNameIncludes(from, "/edit") &&
- toNameIncludes(to, "/detail") &&
- isSameBill(toBillCode, toBillType, fromBillCode, fromBillType)
- ) {
- const editTabIndex = findTabIndex("edit");
- if (editTabIndex > -1) {
- await unlockBill(from); // 保证顺序
- replaceTab(editTabIndex);
- }
- }
- // 情况4: 列表 -> 编辑
- if ((!from || fromNameIncludes(from, "/index")) && toNameIncludes(to, "/edit") && toBillCode) {
- const detailTabIndex = findTabIndex("detail");
- if (detailTabIndex > -1) replaceTab(detailTabIndex);
- }
- // 情况5: 复制 -> 详情
- if (fromNameIncludes(from, "/copy") && toNameIncludes(to, "/detail") && to.query?.fromCopySave) {
- const copyTabIndex = tabsMenuList.findIndex(item => item.path === from.fullPath);
- if (copyTabIndex > -1) replaceTab(copyTabIndex);
- }
- // 默认添加 tab
- if (!isReplace) {
- tabStore.addTabs(tabsParams);
- if (to.meta.isKeepAlive) {
- this.addKeepAliveName(to);
- }
- }
- // --- 辅助函数: 判断 route.name 类型 ---
- function toNameIncludes(route, type: string) {
- return route?.fullPath?.toString().toLowerCase().includes(type);
- }
- function fromNameIncludes(route, type: string) {
- return route?.fullPath?.toString().toLowerCase().includes(type);
- }
- }
- }
- });
|