diff --git a/common/js/util.js b/common/js/util.js index 9a0a87d..e0083dd 100644 --- a/common/js/util.js +++ b/common/js/util.js @@ -128,6 +128,144 @@ export const PAGE_KEY_MAP = { PAGE_WEBVIEW: '/pages_tool/webview/webview' }; +// ================== TabBar 高亮映射配置 ================== + +// TabBar 标识(使用各 Tab 根页面的 wap_url) +export const TAB_BAR_KEYS = { + HOME: '/pages/index/index', + CATEGORY: '/pages_goods/category', + MERCHANT: '/pages_promotion/merch/merchcategory', + CART: '/pages_goods/cart', + MEMBER: '/pages_tool/member/index' +}; + +// 明确不归属任何 TabBar 的独立页面:进入这些页面时 TabBar 全不亮 +export const NO_TAB_PAGES = new Set([ + // 登录/注册/找回密码 + '/pages_tool/login/login', + '/pages_tool/login/register', + '/pages_tool/login/find', + + // 支付/收银流程 + '/pages_tool/pay/index', + '/pages_tool/pay/wx_pay', + '/pages_tool/pay/cashier', + '/pages_tool/pay/result', + + // 订单独立流程页(详情/退款/物流/评价) + '/pages_order/payment', + '/pages_order/detail', + '/pages_order/detail_local_delivery', + '/pages_order/detail_pickup', + '/pages_order/detail_point', + '/pages_order/refund', + '/pages_order/refund_detail', + '/pages_order/refund_goods_select', + '/pages_order/refund_type_select', + '/pages_order/refund_batch', + '/pages_order/logistics', + '/pages_order/activist', + '/pages_order/order/evaluate', + '/pages_order/detail_virtual', + + // 表单 + '/pages_tool/form/form', + '/pages_tool/form/formdata', + + // 外部/特殊页面 + '/pages_tool/webview/webview', + '/pages_tool/ai-chat/index', + '/pages_tool/vr/index', + '/pages_tool/cases/index', + '/pages_tool/contact/contact', + '/pages_tool/weapp/order_shipping', + '/pages_tool/file-preview/file-preview', + + // 帮助/公告/文章详情 + '/pages_tool/help/detail', + '/pages_tool/notice/detail', + '/pages_tool/article/detail', + + // 介质材料 + '/pages_tool/seal/structure', + '/pages_tool/seal/medium/detail' +]); + +// 页面级 TabBar 精确归属映射(key: 页面路径, value: TabBar 根路径) +// 未在此映射中的页面,优先走 NO_TAB_PAGES 判断,其次走同分包回退逻辑 +export const PAGE_TAB_MAP = { + // 首页 + '/pages/index/index': TAB_BAR_KEYS.HOME, + '/pages/empty/index': TAB_BAR_KEYS.HOME, + + // 分类 + '/pages_goods/category': TAB_BAR_KEYS.CATEGORY, + '/pages_goods/list': TAB_BAR_KEYS.CATEGORY, + '/pages_goods/detail': TAB_BAR_KEYS.CATEGORY, + '/pages_tool/goods/search': TAB_BAR_KEYS.CATEGORY, + '/pages_tool/goods/brand': TAB_BAR_KEYS.CATEGORY, + '/pages_tool/goods/coupon': TAB_BAR_KEYS.CATEGORY, + '/pages_tool/goods/coupon_receive': TAB_BAR_KEYS.CATEGORY, + '/pages_tool/goods/evaluate': TAB_BAR_KEYS.CATEGORY, + '/pages_tool/goods/not_exist': TAB_BAR_KEYS.CATEGORY, + + // 入驻企业 + '/pages_promotion/merch/merchcategory': TAB_BAR_KEYS.MERCHANT, + '/pages_promotion/merch/detail': TAB_BAR_KEYS.MERCHANT, + + // 购物车 + '/pages_goods/cart': TAB_BAR_KEYS.CART, + + // 我的(会员中心及子页面) + '/pages_tool/member/index': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/info': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/info_edit': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/address': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/address_edit': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/account': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/account_edit': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/balance': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/balance_detail': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/point': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/point_detail': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/coupon': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/level': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/level_growth_rules': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/card': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/card_buy': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/card_log': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/card_agreement': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/invite_friends': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/collection': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/footprint': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/contact': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/modify_face': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/pay_password': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/apply_withdrawal': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/withdrawal': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/withdrawal_detail': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/cancellation': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/cancelstatus': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/cancelsuccess': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/cancelrefuse': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/assets': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/signin': TAB_BAR_KEYS.MEMBER, + '/pages_tool/member/bind_mobile': TAB_BAR_KEYS.MEMBER, + + // 我的频道下的其他功能页 + '/pages_order/list': TAB_BAR_KEYS.MEMBER, + '/pages_tool/recharge/list': TAB_BAR_KEYS.MEMBER, + '/pages_tool/recharge/order_list': TAB_BAR_KEYS.MEMBER, + + // 帮助/公告/文章列表属于首页频道 + '/pages_tool/help/list': TAB_BAR_KEYS.HOME, + '/pages_tool/notice/list': TAB_BAR_KEYS.HOME, + '/pages_tool/article/list': TAB_BAR_KEYS.HOME, + + // 文件列表(视业务可归首页,暂不归任何 Tab) + '/pages_tool/files/list': null +}; + /** * 根据 page_key + params 解析得到实际跳转URL * @param {string} page_key 页面语义常量,如 PAGE_GOODS_LIST @@ -366,9 +504,10 @@ export const isTabBarRootPage = (pagePath, tabBarList) => { * @param {string} currentPageRoute 当前页面路径 /pages_goods/category * @param {Object} tabBarList tabBar配置对象,用于动态判断 * @param {Object} packageEntryTab 追踪每个分包的入口Tab { 'pages_goods': '/pages_goods/category' } + * @param {Object} currentPageQuery 当前页面 query 参数,用于读取 from_tab 来源记忆 * @returns {boolean} 是否激活 */ -export const checkTabBarActive = (linkUrl, currentPageRoute, tabBarList, packageEntryTab) => { +export const checkTabBarActive = (linkUrl, currentPageRoute, tabBarList, packageEntryTab, currentPageQuery = {}) => { // 1) 归一化 linkUrl:统一前导 '/' + 子包路径适配 + 去除 query const normalizedLink = _normalizePath(linkUrl); const normalizedCurrent = _normalizePath(currentPageRoute); @@ -378,7 +517,10 @@ export const checkTabBarActive = (linkUrl, currentPageRoute, tabBarList, package // 2) 精确匹配:当前页面就是 linkUrl 指向的页面 if (normalizedLink === normalizedCurrent) return true; - // 3) 若传入 tabBarList,使用动态判断逻辑 + // 3) 独立流程页:不点亮任何 Tab + if (NO_TAB_PAGES.has(normalizedCurrent)) return false; + + // 4) 若传入 tabBarList,使用动态判断逻辑 if (tabBarList && tabBarList.list && Array.isArray(tabBarList.list)) { const tabUrls = tabBarList.list .filter(item => item.link && item.link.wap_url) @@ -387,13 +529,27 @@ export const checkTabBarActive = (linkUrl, currentPageRoute, tabBarList, package // 检查当前 linkUrl 是否是合法的 tab URL if (!tabUrls.includes(normalizedLink)) return false; - // 找出当前页面所属的 tab - const matchingTabUrl = _findMatchingTabUrl(currentPageRoute, tabBarList, packageEntryTab); + // 5) 页面级 Tab 精确绑定 + const mappedTabUrl = PAGE_TAB_MAP[normalizedCurrent]; + if (mappedTabUrl) { + return normalizedLink === _normalizePath(mappedTabUrl); + } + if (mappedTabUrl === null) return false; - // 当前页面若命中某个 tab,则只有该 tab 高亮 + // 6) 来源记忆兜底:从哪个 Tab 跳转过来,就保持那个 Tab 高亮 + const fromTab = currentPageQuery.from_tab; + if (fromTab) { + const normalizedFromTab = _normalizePath(fromTab); + if (tabUrls.includes(normalizedFromTab)) { + return normalizedLink === normalizedFromTab; + } + } + + // 7) 分包入口追踪:通过 updateCurrentRoute 写入的入口 tab + const matchingTabUrl = _findMatchingTabUrl(currentPageRoute, tabBarList, packageEntryTab); if (matchingTabUrl) return normalizedLink === matchingTabUrl; - // 4) 同分包回退:linkUrl 和当前页面在同一分包 → 高亮 + // 8) 同分包回退:linkUrl 和当前页面在同一分包 → 高亮 const linkPackage = _getPackageName(normalizedLink); const currentPackage = _getPackageName(normalizedCurrent); return linkPackage && currentPackage && linkPackage === currentPackage; diff --git a/components-diy/diy-bottom-nav.vue b/components-diy/diy-bottom-nav.vue index 124dd9d..9f61871 100644 --- a/components-diy/diy-bottom-nav.vue +++ b/components-diy/diy-bottom-nav.vue @@ -197,6 +197,7 @@ export default { }, redirectTo(link) { this.$emit('callback'); + const redirectLink = link ? { ...link } : link; if (link && link.wap_url) { const decodedUrl = decodeEntity(link.wap_url); @@ -209,9 +210,27 @@ export default { [packageName]: adaptedUrl.split('?')[0] }); } + + // 若目标页面不是 TabBar 根页面,追加 from_tab 来源参数, + // 用于非 Tab 页面的 TabBar 高亮记忆 + if (this.tabBarList && this.tabBarList.list) { + const tabUrls = this.tabBarList.list + .filter(item => item.link && item.link.wap_url) + .map(item => adaptSubpackageUrl(decodeEntity(item.link.wap_url)).split('?')[0]); + if (!tabUrls.includes(adaptedUrl.split('?')[0])) { + const currentPages = getCurrentPages(); + const currentPage = currentPages[currentPages.length - 1]; + const currentTab = currentPage && currentPage.route + ? tabUrls.find(tabUrl => checkTabBarActive(tabUrl, '/' + currentPage.route, this.tabBarList, this.packageEntryTab)) + : null; + if (currentTab) { + redirectLink.from_tab = currentTab; + } + } + } } - this.$util.diyRedirectTo(link); + this.$util.diyRedirectTo(redirectLink); }, verify(link) { if (link == null || link == '' || !link.wap_url) return false; @@ -222,11 +241,23 @@ export default { ? this._normalizeRoute(currentPage.route) : ''; + // 读取当前页面 query 参数(兼容小程序与 H5) + let currentPageQuery = {}; + if (currentPage) { + if (currentPage.options) { + currentPageQuery = currentPage.options; + } else if (currentPage.$page && currentPage.$page.options) { + currentPageQuery = currentPage.$page.options; + } else if (currentPage.$route && currentPage.$route.query) { + currentPageQuery = currentPage.$route.query; + } + } + if (link.wap_url === this.$util.INDEX_PAGE_URL && this.name === 'DIY_VIEW_INDEX') { return true; } - return checkTabBarActive(link.wap_url, currentPageRoute, this.tabBarList, this.packageEntryTab); + return checkTabBarActive(link.wap_url, currentPageRoute, this.tabBarList, this.packageEntryTab, currentPageQuery); } } };