fix(aggregate): 合并 unsupported 至 Aggregate 父级修复首屏白屏

Entry.vue 从 /aggregate/:orderNo 跳转 /aggregate/unsupported 是跨顶层路由跳转,
触发 App.vue transition mode=out-in 整页 remount Layout, 与 onBeforeMount 内
router.replace 竞争导致 unsupported 页首次打开白屏、刷新才正常。

将 AggregateUnsupported 合并到 Aggregate 父级下作为 'unsupported' 子路由,
与 :orderNo 同父级 (对齐 cashier entry/envPage 模式), transition key 不再变化,
Layout 不 remount。URL 契约不变。

- paths.ts: 新增 AGGREGATE_GROUP='/aggregate' (PC 仍用 AGGREGATE)
- modules.ts: unsupported 子路由须在 :orderNo 前, 避免被当 orderNo 吞掉
- Entry.vue: 跳转目标 name 改为子路由 AggregateUnsupportedPage
- unsupported.vue: 组件名改为 AggregateUnsupportedPage, 消除与父路由名同名隐患
This commit is contained in:
bootx
2026-07-20 13:06:27 +08:00
parent 015f13258f
commit da824892c2
4 changed files with 31 additions and 21 deletions

View File

@@ -100,30 +100,27 @@ const routeModuleList: Array<RouteRecordRaw> = [
},
],
},
// 聚合扫码:入口 + 非宿主提示 统一在 Aggregate 父级下,避免跨顶层路由跳转
// 触发 App.vue <transition mode="out-in"> 整页 remount Layout 与 Entry.vue 的
// onBeforeMount router.replace 竞争(曾导致 /aggregate/unsupported 首次白屏、刷新才正常)
// 注:环境页 wechat/alipay/union-pay/douyin 仍为独立顶层路由(仅宿主内访问,无此问题)
{
path: RoutePath.AGGREGATE_UNSUPPORTED,
name: 'AggregateUnsupported',
component: Layout,
meta: { title: '聚合支付' },
children: [
{
path: '',
name: 'AggregateUnsupportedPage',
component: () => import('@/mobile/views/aggregate/unsupported.vue'),
},
],
},
// 聚合扫码入口(预下单落地 URL 契约 /aggregate/:orderNo
{
path: RoutePath.AGGREGATE,
path: RoutePath.AGGREGATE_GROUP,
name: 'Aggregate',
component: Layout,
meta: {
title: '聚合支付',
},
children: [
// 非宿主提示:静态 path 段,须在 :orderNo 之前注册,避免 'unsupported' 被当 orderNo 吞掉
{
path: '',
path: 'unsupported',
name: 'AggregateUnsupportedPage',
component: () => import('@/mobile/views/aggregate/unsupported.vue'),
},
// 入口UA 探测后 replace 到环境页
{
path: ':orderNo',
name: 'AggregateEntry',
component: () => import('@/mobile/views/aggregate/Entry.vue'),
},

View File

@@ -3,7 +3,7 @@
* 聚合扫码入口UA 探测后 replace 到分环境页
* 对外契约 URL 仍为 /aggregate/:orderNo
*/
import { onMounted } from 'vue'
import { onBeforeMount } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { detectAggregateClientEnv } from '@/shared/utils/client-env'
@@ -20,16 +20,20 @@ const ENV_ROUTE_NAME: Record<string, string> = {
douyin: 'AggregateDouyin',
}
onMounted(() => {
// onBeforeMount 探测并 replace挂载前跳走避免与 App.vue <transition mode="out-in" appear> 的 enter 动画
// 发生竞争onMounted 跳转曾导致 /aggregate/unsupported 首次打开白屏、刷新才正常)。
// 不用 setup 同步 replace以免在当前导航未确认时触发新导航引发竞态与 cashier/entry.vue 同源结论)。
onBeforeMount(() => {
const orderNo = route.params.orderNo as string
if (!orderNo) {
return
}
const clientEnv = detectAggregateClientEnv()
if (!clientEnv) {
// 非宿主:提示页
// 非宿主:提示页AggregateUnsupportedPage 与本入口同属 Aggregate 父级,
// 避免跨顶层路由跳转触发 App.vue transition 整页 remount
router.replace({
name: 'AggregateUnsupported',
name: 'AggregateUnsupportedPage',
query: { orderNo },
})
return

View File

@@ -10,7 +10,7 @@ import douyinSvg from '@/shared/assets/icons/channel/douyin.svg'
import unionPaySvg from '@/shared/assets/icons/channel/union_pay.svg'
import wechatSvg from '@/shared/assets/icons/channel/wechat.svg'
defineOptions({ name: 'AggregateUnsupported' })
defineOptions({ name: 'AggregateUnsupportedPage' })
const { t } = useI18n()
const route = useRoute()

View File

@@ -31,6 +31,15 @@ export const RoutePath = {
* MobileUA 探测后 replace 到环境页PC单页处理
*/
AGGREGATE: '/aggregate/:orderNo',
/**
* 聚合扫码父级分组(仅 Mobile 路由注册用)
* Mobile 把入口 + unsupported 提示合并到此父级下作为子路由,让 App.vue
* 顶层 transition keymatched[0].name在 entry → unsupported 跳转时保持
* 不变,避免整页 remount 与 onBeforeMount 内 router.replace 竞争导致白屏。
* URL 契约不变,仍是 /aggregate/:orderNo 与 /aggregate/unsupported。
* PC 仍用 AGGREGATE/aggregate/:orderNo作为单层路由。
*/
AGGREGATE_GROUP: '/aggregate',
/** 聚合-微信环境页Mobile */
AGGREGATE_WECHAT: '/aggregate/wechat/:orderNo',
/** 聚合-支付宝环境页Mobile */