97 lines
3.3 KiB
Vue
97 lines
3.3 KiB
Vue
<script setup>
|
||
/**
|
||
* 主包壳页面:主页 / 权益 / 我的 三块面板同屏共存,底部 Tab 栏只渲染一次
|
||
* ---------------------------------------------------------------------------
|
||
* 扫码入口:二维码指向本页并带商家 id(`merchant_id` / `scene` / `q` 三种来源都认),
|
||
* 进来自动切到权益 Tab 再打开商家详情 —— 取值见 utils/nav.js 的 pickMerchantId / handleEntry。
|
||
*/
|
||
import { nextTick, onMounted, ref } from "vue";
|
||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||
import { TABS } from "@/constant";
|
||
import {
|
||
consumePendingMerchant,
|
||
consumePendingTab,
|
||
goDetail,
|
||
pickMerchantId,
|
||
registerTabController,
|
||
setPendingMerchant,
|
||
setTabQuery,
|
||
} from "@/utils/nav";
|
||
import HomePanel from "@/views/home/index.vue";
|
||
import BenefitPanel from "@/views/benefit/index.vue";
|
||
import MinePanel from "@/views/mine/index.vue";
|
||
|
||
const active = ref("home");
|
||
const homeRef = ref(null);
|
||
const benefitRef = ref(null);
|
||
const mineRef = ref(null);
|
||
|
||
const panelRefs = { home: homeRef, benefit: benefitRef, mine: mineRef };
|
||
|
||
/** 面板按需刷新(切到它、或页面 onShow 时) */
|
||
const showPanel = (key) => panelRefs[key]?.value?.onPanelShow?.();
|
||
|
||
/**
|
||
* 切 Tab 的唯一入口:Tab 栏点击、页面内 switchTabTo(key, query)、登录回跳都汇到这里。
|
||
* query 用 nav 的内存透传(如 `?seg=mine`),由目标面板 onPanelShow 消费。
|
||
*/
|
||
const goTab = (key, query = "") => {
|
||
if (!TABS.some((t) => t.key === key)) return;
|
||
setTabQuery(query);
|
||
active.value = key;
|
||
showPanel(key);
|
||
};
|
||
|
||
/** Tab 控制器是否已就绪(onShow 可能早于 onMounted,未就绪时不消费扫码参数) */
|
||
let shellReady = false;
|
||
|
||
/**
|
||
* 扫码进店:先切权益 Tab 再打开商家详情。
|
||
* 顺序不能反 —— 先切 Tab,「详情返回」才会落在权益页而不是主页。
|
||
*/
|
||
const runEntry = () => {
|
||
if (!shellReady) return;
|
||
const id = consumePendingMerchant();
|
||
if (!id) return;
|
||
goTab("benefit");
|
||
nextTick(() => setTimeout(() => goDetail(id), 0));
|
||
};
|
||
|
||
onLoad((options) => {
|
||
setPendingMerchant(pickMerchantId(options));
|
||
});
|
||
|
||
onMounted(() => {
|
||
// 面板的 onMounted 早于本页 onMounted,此时 ref 已就绪
|
||
registerTabController({ go: goTab, getActive: () => active.value });
|
||
// 从子页 / 登录页切过来:nav 里可能压着待切 Tab(登录回跳、reLaunch 冷启)
|
||
const pending = consumePendingTab();
|
||
goTab(pending?.key || active.value, pending?.query || "");
|
||
shellReady = true;
|
||
runEntry();
|
||
});
|
||
|
||
onShow(() => {
|
||
// 从板块列表 / 详情 / 登录页等返回:让当前面板按需刷新(各家内部有幂等守卫)
|
||
showPanel(active.value);
|
||
runEntry();
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<view class="relative h-screen w-full overflow-hidden">
|
||
<!-- 三块面板叠放同屏,靠 visibility 切换:见 script 头部的说明 -->
|
||
<view :class="['absolute inset-0', active === 'home' ? 'visible' : 'invisible']">
|
||
<HomePanel ref="homeRef" />
|
||
</view>
|
||
<view :class="['absolute inset-0', active === 'benefit' ? 'visible' : 'invisible']">
|
||
<BenefitPanel ref="benefitRef" />
|
||
</view>
|
||
<view :class="['absolute inset-0', active === 'mine' ? 'visible' : 'invisible']">
|
||
<MinePanel ref="mineRef" />
|
||
</view>
|
||
|
||
<AppTabBar :active="active" @change="goTab" />
|
||
</view>
|
||
</template>
|