From fb234182d34c116591ec0e2232dcbee1a7baa423 Mon Sep 17 00:00:00 2001 From: daxpay Date: Fri, 31 Jul 2026 12:12:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(h5):=20=E6=96=B0=E5=A2=9E=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=85=A5=E5=8F=A3=E5=BC=95=E5=AF=BC=E9=A1=B5?= =?UTF-8?q?=E5=B9=B6=E6=8C=89UA=E5=88=86=E6=B5=81=E9=92=B1=E5=8C=85?= =?UTF-8?q?=E5=86=85=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增码牌 /m/:code 引导页(mobile/pc),消除浏览器直开404 - 引导页按UA分流:钱包内显示小程序暂不可用并高亮当前钱包图标 - 避免在微信内提示用微信扫码的矛盾,抽取 useMiniGuideEnv 统一处理 - 顺带统一视图文件命名(index.vue)与组件命名 --- src/mobile/router/index.ts | 2 +- src/mobile/router/modules.ts | 30 +++- .../views/{device-only.vue => DeviceOnly.vue} | 0 src/mobile/views/aggregate-mini/index.vue | 140 ++++++++++++++++++ src/mobile/views/aggregate/Entry.vue | 2 +- .../{unsupported.vue => Unsupported.vue} | 0 .../aggregate/alipay/{Index.vue => index.vue} | 0 .../components/AggregateResultCard.vue | 2 +- .../aggregate/douyin/{Index.vue => index.vue} | 0 .../union-pay/{Index.vue => index.vue} | 0 .../aggregate/wechat/{Index.vue => index.vue} | 0 .../views/cashier/{entry.vue => Entry.vue} | 0 src/mobile/views/cashier/index.vue | 24 --- src/mobile/views/code-pay-mini/index.vue | 140 ++++++++++++++++++ src/pc/router/index.ts | 36 +++-- .../views/{device-only.vue => DeviceOnly.vue} | 0 src/pc/views/aggregate-mini/index.vue | 138 +++++++++++++++++ .../views/aggregate/{Index.vue => index.vue} | 0 .../auth/wechat/{Index.vue => index.vue} | 0 src/pc/views/cashier/{Index.vue => index.vue} | 0 src/pc/views/code-pay-mini/index.vue | 138 +++++++++++++++++ .../views/code-pay/{Index.vue => index.vue} | 0 .../views/protocol/{Index.vue => index.vue} | 0 .../views/statement/{Index.vue => index.vue} | 0 src/shared/locales/en-US/aggregate.json | 4 + src/shared/locales/id-ID/aggregate.json | 4 + src/shared/locales/ja-JP/aggregate.json | 4 + src/shared/locales/ko-KR/aggregate.json | 4 + src/shared/locales/ms-MY/aggregate.json | 4 + src/shared/locales/th-TH/aggregate.json | 4 + src/shared/locales/vi-VN/aggregate.json | 4 + src/shared/locales/zh-CN/aggregate.json | 4 + src/shared/locales/zh-HK/aggregate.json | 4 + src/shared/locales/zh-TW/aggregate.json | 4 + src/shared/pay/use-mini-guide-env.ts | 65 ++++++++ src/shared/router/paths.ts | 12 +- 36 files changed, 722 insertions(+), 47 deletions(-) rename src/mobile/views/{device-only.vue => DeviceOnly.vue} (100%) create mode 100644 src/mobile/views/aggregate-mini/index.vue rename src/mobile/views/aggregate/{unsupported.vue => Unsupported.vue} (100%) rename src/mobile/views/aggregate/alipay/{Index.vue => index.vue} (100%) rename src/mobile/views/aggregate/douyin/{Index.vue => index.vue} (100%) rename src/mobile/views/aggregate/union-pay/{Index.vue => index.vue} (100%) rename src/mobile/views/aggregate/wechat/{Index.vue => index.vue} (100%) rename src/mobile/views/cashier/{entry.vue => Entry.vue} (100%) delete mode 100644 src/mobile/views/cashier/index.vue create mode 100644 src/mobile/views/code-pay-mini/index.vue rename src/pc/views/{device-only.vue => DeviceOnly.vue} (100%) create mode 100644 src/pc/views/aggregate-mini/index.vue rename src/pc/views/aggregate/{Index.vue => index.vue} (100%) rename src/pc/views/auth/wechat/{Index.vue => index.vue} (100%) rename src/pc/views/cashier/{Index.vue => index.vue} (100%) create mode 100644 src/pc/views/code-pay-mini/index.vue rename src/pc/views/code-pay/{Index.vue => index.vue} (100%) rename src/pc/views/protocol/{Index.vue => index.vue} (100%) rename src/pc/views/statement/{Index.vue => index.vue} (100%) create mode 100644 src/shared/pay/use-mini-guide-env.ts diff --git a/src/mobile/router/index.ts b/src/mobile/router/index.ts index ecb7f95..ccb8e66 100644 --- a/src/mobile/router/index.ts +++ b/src/mobile/router/index.ts @@ -19,7 +19,7 @@ routeStore.setRouters(constantRouter.concat(routeModuleList)) const pcOnlyStubs: RouteRecordRaw[] = otherDeviceExclusives('mobile').map(r => ({ path: r.path, name: `${r.name}__stub`, - component: () => import('@/mobile/views/device-only.vue'), + component: () => import('@/mobile/views/DeviceOnly.vue'), })) const router = createRouter({ diff --git a/src/mobile/router/modules.ts b/src/mobile/router/modules.ts index 4c56dcc..46740e3 100644 --- a/src/mobile/router/modules.ts +++ b/src/mobile/router/modules.ts @@ -37,7 +37,7 @@ const routeModuleList: Array = [ // 入口:UA 探测后 replace 到环境页 path: '', name: 'CashierEntry', - component: () => import('@/mobile/views/cashier/entry.vue'), + component: () => import('@/mobile/views/cashier/Entry.vue'), }, { // 环境页:clientEnv 白名单在页内校验(不缓存:收银台为一次性支付页,每次须重新探测与加载) @@ -66,31 +66,31 @@ const routeModuleList: Array = [ { path: 'unsupported', name: 'AggregateUnsupportedPage', - component: () => import('@/mobile/views/aggregate/unsupported.vue'), + component: () => import('@/mobile/views/aggregate/Unsupported.vue'), }, // 微信环境页 { path: 'wechat/:orderNo', name: 'AggregateWechatPage', - component: () => import('@/mobile/views/aggregate/wechat/Index.vue'), + component: () => import('@/mobile/views/aggregate/wechat/index.vue'), }, // 支付宝环境页 { path: 'alipay/:orderNo', name: 'AggregateAlipayPage', - component: () => import('@/mobile/views/aggregate/alipay/Index.vue'), + component: () => import('@/mobile/views/aggregate/alipay/index.vue'), }, // 云闪付环境页 { path: 'union-pay/:orderNo', name: 'AggregateUnionPage', - component: () => import('@/mobile/views/aggregate/union-pay/Index.vue'), + component: () => import('@/mobile/views/aggregate/union-pay/index.vue'), }, // 抖音环境页 { path: 'douyin/:orderNo', name: 'AggregateDouyinPage', - component: () => import('@/mobile/views/aggregate/douyin/Index.vue'), + component: () => import('@/mobile/views/aggregate/douyin/index.vue'), }, // 入口:UA 探测后 replace 到环境页(静态段已注册完毕,:orderNo 兜底匹配订单号) { @@ -100,6 +100,24 @@ const routeModuleList: Array = [ }, ], }, + // 聚合小程序引导页(跨端:浏览器直接打开 /am/:orderNo 时展示扫码提示,不发起支付) + { + path: RoutePath.AGGREGATE_MINI, + name: 'AggregateMiniGuide', + component: () => import('@/mobile/views/aggregate-mini/index.vue'), + meta: { + title: 'route.cashier', // 收银台 + }, + }, + // 码牌小程序引导页(跨端:浏览器直接打开 /m/:code 时展示扫码提示,不发起支付) + { + path: RoutePath.CODE_PAY_MINI, + name: 'CodePayMiniGuide', + component: () => import('@/mobile/views/code-pay-mini/index.vue'), + meta: { + title: 'route.codePay', // 码牌支付 + }, + }, // 码牌支付:入口 + 各宿主环境页 统一在 CodePay 父级下作为子路由 // 让 App.vue 顶层 transition key(matched[0].name)在 entry → 环境页跳转时保持不变(都是 CodePay), // 避免整页 remount 与 Entry 的 onBeforeMount router.replace 竞争导致白屏 diff --git a/src/mobile/views/device-only.vue b/src/mobile/views/DeviceOnly.vue similarity index 100% rename from src/mobile/views/device-only.vue rename to src/mobile/views/DeviceOnly.vue diff --git a/src/mobile/views/aggregate-mini/index.vue b/src/mobile/views/aggregate-mini/index.vue new file mode 100644 index 0000000..e6871f2 --- /dev/null +++ b/src/mobile/views/aggregate-mini/index.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/src/mobile/views/aggregate/Entry.vue b/src/mobile/views/aggregate/Entry.vue index b626c8b..8d36161 100644 --- a/src/mobile/views/aggregate/Entry.vue +++ b/src/mobile/views/aggregate/Entry.vue @@ -22,7 +22,7 @@ const ENV_ROUTE_NAME: Record = { // onBeforeMount 探测并 replace:挂载前跳走,避免与 App.vue 的 enter 动画 // 发生竞争(onMounted 跳转曾导致 /aggregate/unsupported 首次打开白屏、刷新才正常)。 -// 不用 setup 同步 replace,以免在当前导航未确认时触发新导航引发竞态(与 cashier/entry.vue 同源结论)。 +// 不用 setup 同步 replace,以免在当前导航未确认时触发新导航引发竞态(与 cashier/Entry.vue 同源结论)。 onBeforeMount(() => { const orderNo = route.params.orderNo as string if (!orderNo) { diff --git a/src/mobile/views/aggregate/unsupported.vue b/src/mobile/views/aggregate/Unsupported.vue similarity index 100% rename from src/mobile/views/aggregate/unsupported.vue rename to src/mobile/views/aggregate/Unsupported.vue diff --git a/src/mobile/views/aggregate/alipay/Index.vue b/src/mobile/views/aggregate/alipay/index.vue similarity index 100% rename from src/mobile/views/aggregate/alipay/Index.vue rename to src/mobile/views/aggregate/alipay/index.vue diff --git a/src/mobile/views/aggregate/components/AggregateResultCard.vue b/src/mobile/views/aggregate/components/AggregateResultCard.vue index 73f7e62..a8a0b07 100644 --- a/src/mobile/views/aggregate/components/AggregateResultCard.vue +++ b/src/mobile/views/aggregate/components/AggregateResultCard.vue @@ -10,7 +10,7 @@ /** * 聚合扫码 - 结果状态卡片 * 统一展示支付终态:成功 / 失败 / 关闭 / 过期 / 加载失败 - * 图标 + 颜色 + 标题 + 副提示,与 PC 端视觉语言对齐(见 pc/views/aggregate/Index.vue resultMeta) + * 图标 + 颜色 + 标题 + 副提示,与 PC 端视觉语言对齐(见 pc/views/aggregate/index.vue resultMeta) * 4 个聚合环境页共用;成功色优先继承父级 --agg-brand(深色已压亮) * * 成功态(state='paid')特殊处理: diff --git a/src/mobile/views/aggregate/douyin/Index.vue b/src/mobile/views/aggregate/douyin/index.vue similarity index 100% rename from src/mobile/views/aggregate/douyin/Index.vue rename to src/mobile/views/aggregate/douyin/index.vue diff --git a/src/mobile/views/aggregate/union-pay/Index.vue b/src/mobile/views/aggregate/union-pay/index.vue similarity index 100% rename from src/mobile/views/aggregate/union-pay/Index.vue rename to src/mobile/views/aggregate/union-pay/index.vue diff --git a/src/mobile/views/aggregate/wechat/Index.vue b/src/mobile/views/aggregate/wechat/index.vue similarity index 100% rename from src/mobile/views/aggregate/wechat/Index.vue rename to src/mobile/views/aggregate/wechat/index.vue diff --git a/src/mobile/views/cashier/entry.vue b/src/mobile/views/cashier/Entry.vue similarity index 100% rename from src/mobile/views/cashier/entry.vue rename to src/mobile/views/cashier/Entry.vue diff --git a/src/mobile/views/cashier/index.vue b/src/mobile/views/cashier/index.vue deleted file mode 100644 index 9c1a4ec..0000000 --- a/src/mobile/views/cashier/index.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - diff --git a/src/mobile/views/code-pay-mini/index.vue b/src/mobile/views/code-pay-mini/index.vue new file mode 100644 index 0000000..9719625 --- /dev/null +++ b/src/mobile/views/code-pay-mini/index.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/src/pc/router/index.ts b/src/pc/router/index.ts index fe8de52..78efce9 100644 --- a/src/pc/router/index.ts +++ b/src/pc/router/index.ts @@ -9,7 +9,7 @@ import { RoutePath } from '@/shared/router/paths' const mobileOnlyStubs: RouteRecordRaw[] = otherDeviceExclusives('pc').map(r => ({ path: r.path, name: `${r.name}__stub`, - component: () => import('@/pc/views/device-only.vue'), + component: () => import('@/pc/views/DeviceOnly.vue'), })) // PC 端路由树(独立于移动端,按需在此扩展业务路由,例如收银台 PC 版) @@ -24,7 +24,7 @@ const routes: RouteRecordRaw[] = [ { path: RoutePath.CASHIER, name: 'PcCashier', - component: () => import('@/pc/views/cashier/Index.vue'), + component: () => import('@/pc/views/cashier/index.vue'), meta: { title: 'route.cashier' }, // 收银台 }, // 聚合「非宿主」提示:须在 /aggregate/:orderNo 之前注册,避免 path 段 "unsupported" 被当成 orderNo 查单 @@ -38,59 +38,73 @@ const routes: RouteRecordRaw[] = [ { path: RoutePath.AGGREGATE, name: 'PcAggregate', - component: () => import('@/pc/views/aggregate/Index.vue'), + component: () => import('@/pc/views/aggregate/index.vue'), meta: { title: 'route.cashier' }, // 收银台 }, + // 聚合小程序引导页(跨端:浏览器直接打开 /am/:orderNo 时展示扫码提示,不发起支付) + { + path: RoutePath.AGGREGATE_MINI, + name: 'PcAggregateMini', + component: () => import('@/pc/views/aggregate-mini/index.vue'), + meta: { title: 'route.cashier' }, // 收银台 + }, + // 码牌小程序引导页(跨端:浏览器直接打开 /m/:code 时展示扫码提示,不发起支付) + { + path: RoutePath.CODE_PAY_MINI, + name: 'PcCodePayMini', + component: () => import('@/pc/views/code-pay-mini/index.vue'), + meta: { title: 'route.codePay' }, // 码牌支付 + }, // 商户对账单(PC 独占:移动端由注册表派生 device-only 存根) { path: RoutePath.MERCHANT_STATEMENT, name: 'MerchantStatement', - component: () => import('@/pc/views/statement/Index.vue'), + component: () => import('@/pc/views/statement/index.vue'), meta: { title: 'route.merchantStatement' }, // 商户对账单 }, // 协议展示页(跨端:与移动端同 path 各指各 view,链接可独立分享) { path: RoutePath.PROTOCOL, name: 'PcProtocol', - component: () => import('@/pc/views/protocol/Index.vue'), + component: () => import('@/pc/views/protocol/index.vue'), meta: { title: 'route.protocol' }, // 协议 }, // 微信认证落地页(跨端:与移动端同 path 各指各 view,PC 微信内置浏览器可访问) { path: RoutePath.AUTH_WECHAT, name: 'PcWechatAuth', - component: () => import('@/pc/views/auth/wechat/Index.vue'), + component: () => import('@/pc/views/auth/wechat/index.vue'), meta: { title: 'route.wechatAuth' }, // 微信认证 }, // 码牌支付:PC 仅展示扫码引导(静态段须在 /h/:code 之前) { path: RoutePath.CODE_PAY_WECHAT, name: 'PcCodePayWechat', - component: () => import('@/pc/views/code-pay/Index.vue'), + component: () => import('@/pc/views/code-pay/index.vue'), meta: { title: 'route.codePay' }, // 码牌支付 }, { path: RoutePath.CODE_PAY_ALIPAY, name: 'PcCodePayAlipay', - component: () => import('@/pc/views/code-pay/Index.vue'), + component: () => import('@/pc/views/code-pay/index.vue'), meta: { title: 'route.codePay' }, // 码牌支付 }, { path: RoutePath.CODE_PAY_UNION, name: 'PcCodePayUnion', - component: () => import('@/pc/views/code-pay/Index.vue'), + component: () => import('@/pc/views/code-pay/index.vue'), meta: { title: 'route.codePay' }, // 码牌支付 }, { path: RoutePath.CODE_PAY_DOUYIN, name: 'PcCodePayDouyin', - component: () => import('@/pc/views/code-pay/Index.vue'), + component: () => import('@/pc/views/code-pay/index.vue'), meta: { title: 'route.codePay' }, // 码牌支付 }, { path: RoutePath.CODE_PAY, name: 'PcCodePay', - component: () => import('@/pc/views/code-pay/Index.vue'), + component: () => import('@/pc/views/code-pay/index.vue'), meta: { title: 'route.codePay' }, // 码牌支付 }, ...mobileOnlyStubs, diff --git a/src/pc/views/device-only.vue b/src/pc/views/DeviceOnly.vue similarity index 100% rename from src/pc/views/device-only.vue rename to src/pc/views/DeviceOnly.vue diff --git a/src/pc/views/aggregate-mini/index.vue b/src/pc/views/aggregate-mini/index.vue new file mode 100644 index 0000000..1702468 --- /dev/null +++ b/src/pc/views/aggregate-mini/index.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/src/pc/views/aggregate/Index.vue b/src/pc/views/aggregate/index.vue similarity index 100% rename from src/pc/views/aggregate/Index.vue rename to src/pc/views/aggregate/index.vue diff --git a/src/pc/views/auth/wechat/Index.vue b/src/pc/views/auth/wechat/index.vue similarity index 100% rename from src/pc/views/auth/wechat/Index.vue rename to src/pc/views/auth/wechat/index.vue diff --git a/src/pc/views/cashier/Index.vue b/src/pc/views/cashier/index.vue similarity index 100% rename from src/pc/views/cashier/Index.vue rename to src/pc/views/cashier/index.vue diff --git a/src/pc/views/code-pay-mini/index.vue b/src/pc/views/code-pay-mini/index.vue new file mode 100644 index 0000000..70ebb4b --- /dev/null +++ b/src/pc/views/code-pay-mini/index.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/src/pc/views/code-pay/Index.vue b/src/pc/views/code-pay/index.vue similarity index 100% rename from src/pc/views/code-pay/Index.vue rename to src/pc/views/code-pay/index.vue diff --git a/src/pc/views/protocol/Index.vue b/src/pc/views/protocol/index.vue similarity index 100% rename from src/pc/views/protocol/Index.vue rename to src/pc/views/protocol/index.vue diff --git a/src/pc/views/statement/Index.vue b/src/pc/views/statement/index.vue similarity index 100% rename from src/pc/views/statement/Index.vue rename to src/pc/views/statement/index.vue diff --git a/src/shared/locales/en-US/aggregate.json b/src/shared/locales/en-US/aggregate.json index 75d5cc2..a2f8037 100644 --- a/src/shared/locales/en-US/aggregate.json +++ b/src/shared/locales/en-US/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "Scan the QR code to pay", "unsupportedTitle": "Open in a wallet app", "unsupportedDesc": "Please scan the QR code with WeChat, Alipay, UnionPay or Douyin", + "miniScanTitle": "Scan to Pay", + "miniScanDesc": "Please scan the QR code with WeChat, Alipay, etc. to complete payment", + "miniInWalletTitle": "Cashier mini-program unavailable", + "miniInWalletDesc": "The merchant may not have configured mini-program payment, or the mini-program hasn't been published. Please contact the merchant.", "useMobileScan": "Please scan with your phone to pay", "scanWithWallet": "Scan with WeChat, Alipay, UnionPay or Douyin to pay", "remainingTime": "Time remaining", diff --git a/src/shared/locales/id-ID/aggregate.json b/src/shared/locales/id-ID/aggregate.json index 8865985..449d132 100644 --- a/src/shared/locales/id-ID/aggregate.json +++ b/src/shared/locales/id-ID/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "Scan the QR code to pay", "unsupportedTitle": "Open in a wallet app", "unsupportedDesc": "Please scan the QR code with WeChat, Alipay, UnionPay or Douyin", + "miniScanTitle": "Pindai untuk Bayar", + "miniScanDesc": "Silakan pindai kode QR dengan WeChat, Alipay, dll. untuk menyelesaikan pembayaran", + "miniInWalletTitle": "Mini-program pembayaran tidak tersedia sementara", + "miniInWalletDesc": "Merchant mungkin belum mengonfigurasi pembayaran mini-program atau mini-program belum dipublikasikan. Silakan hubungi merchant.", "useMobileScan": "Please scan with your phone to pay", "scanWithWallet": "Pindai dengan WeChat, Alipay, UnionPay, atau Douyin untuk membayar", "remainingTime": "Sisa waktu bayar", diff --git a/src/shared/locales/ja-JP/aggregate.json b/src/shared/locales/ja-JP/aggregate.json index e67af39..bc5d988 100644 --- a/src/shared/locales/ja-JP/aggregate.json +++ b/src/shared/locales/ja-JP/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "QRコードをスキャンして支払ってください", "unsupportedTitle": "ウォレットでスキャンしてください", "unsupportedDesc": "WeChat、Alipay、銀聯またはDouyinでQRコードをスキャンしてください", + "miniScanTitle": "スキャンして支払い", + "miniScanDesc": "WeChat、AlipayなどでQRコードをスキャンして支払いを完了してください", + "miniInWalletTitle": "収納ミニプログラムは現在利用できません", + "miniInWalletDesc": "加盟店がミニプログラム決済を未設定、またはミニプログラムが未公開の可能性があります。加盟店にお問い合わせください。", "useMobileScan": "スマートフォンでスキャンして支払ってください", "scanWithWallet": "WeChat、Alipay、銀聯またはDouyinでスキャンして支払ってください", "remainingTime": "支払い残り時間", diff --git a/src/shared/locales/ko-KR/aggregate.json b/src/shared/locales/ko-KR/aggregate.json index 11024c1..8a1c36d 100644 --- a/src/shared/locales/ko-KR/aggregate.json +++ b/src/shared/locales/ko-KR/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "QR 코드를 스캔하여 결제하세요", "unsupportedTitle": "지갑 앱으로 스캔하세요", "unsupportedDesc": "위챗, 알리페이, 유니온페이 또는 도우인으로 QR 코드를 스캔하세요", + "miniScanTitle": "스캔하여 결제", + "miniScanDesc": "WeChat, Alipay 등으로 QR 코드를 스캔하여 결제를 완료해 주세요", + "miniInWalletTitle": "결제 미니프로그램을 일시적으로 사용할 수 없습니다", + "miniInWalletDesc": "가맹점이 미니프로그램 결제를 미설정했거나 미니프로그램이 미출시되었을 수 있습니다. 가맹점에 문의해 주세요.", "useMobileScan": "휴대폰으로 스캔하여 결제하세요", "scanWithWallet": "위챗, 알리페이, 유니온페이 또는 도우인으로 스캔하여 결제하세요", "remainingTime": "남은 결제 시간", diff --git a/src/shared/locales/ms-MY/aggregate.json b/src/shared/locales/ms-MY/aggregate.json index 37b032f..1f401ab 100644 --- a/src/shared/locales/ms-MY/aggregate.json +++ b/src/shared/locales/ms-MY/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "Scan the QR code to pay", "unsupportedTitle": "Open in a wallet app", "unsupportedDesc": "Please scan the QR code with WeChat, Alipay, UnionPay or Douyin", + "miniScanTitle": "Imbas untuk Bayar", + "miniScanDesc": "Sila imbas kod QR dengan WeChat, Alipay, dll. untuk menyelesaikan pembayaran", + "miniInWalletTitle": "Mini-program pembayaran tidak tersedia buat sementara waktu", + "miniInWalletDesc": "Pedagang mungkin belum mengkonfigurasi pembayaran mini-program atau mini-program belum diterbitkan. Sila hubungi pedagang.", "useMobileScan": "Please scan with your phone to pay", "scanWithWallet": "Imbas dengan WeChat, Alipay, UnionPay atau Douyin untuk bayar", "remainingTime": "Masa berbaki", diff --git a/src/shared/locales/th-TH/aggregate.json b/src/shared/locales/th-TH/aggregate.json index b37e9b5..533f946 100644 --- a/src/shared/locales/th-TH/aggregate.json +++ b/src/shared/locales/th-TH/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "Scan the QR code to pay", "unsupportedTitle": "Open in a wallet app", "unsupportedDesc": "Please scan the QR code with WeChat, Alipay, UnionPay or Douyin", + "miniScanTitle": "สแกนเพื่อชำระเงิน", + "miniScanDesc": "กรุณาสแกนคิวอาร์โค้ดด้วย WeChat, Alipay ฯลฯ เพื่อให้การชำระเงินเสร็จสมบูรณ์", + "miniInWalletTitle": "มินิโปรแกรมรับชำระไม่พร้อมใช้งานชั่วคราว", + "miniInWalletDesc": "อาจเป็นไปได้ว่าร้านค้ายังไม่ได้ตั้งค่าการชำระผ่านมินิโปรแกรมหรือมินิโปรแกรมยังไม่เผยแพร่ โปรดติดต่อร้านค้า", "useMobileScan": "Please scan with your phone to pay", "scanWithWallet": "สแกนด้วย WeChat, Alipay, UnionPay หรือ Douyin เพื่อชำระเงิน", "remainingTime": "เวลาที่เหลือ", diff --git a/src/shared/locales/vi-VN/aggregate.json b/src/shared/locales/vi-VN/aggregate.json index b773e03..4dddf9f 100644 --- a/src/shared/locales/vi-VN/aggregate.json +++ b/src/shared/locales/vi-VN/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "Scan the QR code to pay", "unsupportedTitle": "Open in a wallet app", "unsupportedDesc": "Please scan the QR code with WeChat, Alipay, UnionPay or Douyin", + "miniScanTitle": "Quét để thanh toán", + "miniScanDesc": "Vui lòng quét mã QR bằng WeChat, Alipay, v.v. để hoàn tất thanh toán", + "miniInWalletTitle": "Mini-program thanh toán tạm thời không khả dụng", + "miniInWalletDesc": "Có thể merchant chưa cấu hình thanh toán mini-program hoặc mini-program chưa được phát hành. Vui lòng liên hệ merchant.", "useMobileScan": "Please scan with your phone to pay", "scanWithWallet": "Quét bằng WeChat, Alipay, UnionPay hoặc Douyin để thanh toán", "remainingTime": "Thời gian còn lại", diff --git a/src/shared/locales/zh-CN/aggregate.json b/src/shared/locales/zh-CN/aggregate.json index 7621a10..7c6f072 100644 --- a/src/shared/locales/zh-CN/aggregate.json +++ b/src/shared/locales/zh-CN/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "请使用手机扫码完成支付", "unsupportedTitle": "请使用钱包扫码", "unsupportedDesc": "请使用微信、支付宝、云闪付或抖音扫描二维码完成支付", + "miniScanTitle": "请扫码支付", + "miniScanDesc": "请使用微信、支付宝等扫描二维码完成支付", + "miniInWalletTitle": "收款小程序暂不可用", + "miniInWalletDesc": "可能商户尚未配置小程序支付或小程序未发布,请联系商户处理", "useMobileScan": "请使用手机扫码支付", "scanWithWallet": "请使用微信、支付宝、云闪付或抖音扫一扫完成支付", "remainingTime": "剩余支付时间", diff --git a/src/shared/locales/zh-HK/aggregate.json b/src/shared/locales/zh-HK/aggregate.json index 661b1c9..c4c1849 100644 --- a/src/shared/locales/zh-HK/aggregate.json +++ b/src/shared/locales/zh-HK/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "請使用手機掃碼完成支付", "unsupportedTitle": "請使用錢包掃碼", "unsupportedDesc": "請使用微信、支付寶、雲閃付或抖音掃描二維碼完成支付", + "miniScanTitle": "請掃碼支付", + "miniScanDesc": "請用微信、支付寶等掃描二維碼完成付款", + "miniInWalletTitle": "收款小程式暫不可用", + "miniInWalletDesc": "可能商戶尚未設定小程式支付或小程式未發布,請聯絡商戶處理", "useMobileScan": "請使用手機掃碼支付", "scanWithWallet": "請使用微信、支付寶、雲閃付或抖音掃一掃完成支付", "remainingTime": "剩餘支付時間", diff --git a/src/shared/locales/zh-TW/aggregate.json b/src/shared/locales/zh-TW/aggregate.json index 6c59ce6..c25f1fd 100644 --- a/src/shared/locales/zh-TW/aggregate.json +++ b/src/shared/locales/zh-TW/aggregate.json @@ -24,6 +24,10 @@ "scanQr": "請使用手機掃碼完成支付", "unsupportedTitle": "請使用錢包掃碼", "unsupportedDesc": "請使用微信、支付寶、雲閃付或抖音掃描二維碼完成支付", + "miniScanTitle": "請掃碼支付", + "miniScanDesc": "請使用微信、支付寶等掃描 QR Code 完成支付", + "miniInWalletTitle": "收款小程式暫不可用", + "miniInWalletDesc": "可能商戶尚未設定小程式支付或小程式未發布,請聯絡商戶處理", "useMobileScan": "請使用手機掃碼支付", "scanWithWallet": "請使用微信、支付寶、雲閃付或抖音掃一掃完成支付", "remainingTime": "剩餘支付時間", diff --git a/src/shared/pay/use-mini-guide-env.ts b/src/shared/pay/use-mini-guide-env.ts new file mode 100644 index 0000000..483a147 --- /dev/null +++ b/src/shared/pay/use-mini-guide-env.ts @@ -0,0 +1,65 @@ +/** + * 小程序入口引导页(/m/:code、/am/:orderNo)的 UA 感知文案与图标 + * + * 钱包 App 内(微信/支付宝/云闪付/抖音)扫码本应由「普通链接二维码」规则拉起 + * cashier 小程序;若规则未配/未匹配/小程序未发布,会落到本 H5 引导页。此时再显示 + * "请用微信扫码"会自相矛盾(用户就在微信里),故按 UA 分流: + * - 钱包内:展示"收款小程序暂不可用"提示,并仅高亮当前钱包图标(聚焦) + * - 系统浏览器/PC:保持"请扫码支付"提示 + 四钱包图标 + * + * UA 一次扫描即定(同一会话不变),无需响应式。 + */ +import type { AggregateClientEnv } from '@/shared/utils/client-env' +import alipaySvg from '@/shared/assets/icons/channel/alipay.svg' +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' +import { + AGGREGATE_CLIENT_ENVS, + detectClientEnv, + isAggregateClientEnv, +} from '@/shared/utils/client-env' + +/** 钱包图标项(alt 用 aggregate.clientEnv.* 统一翻译) */ +export interface MiniGuideWalletIcon { + src: string + altKey: string +} + +/** 宿主环境 → 钱包图标 */ +const ENV_ICON_MAP: Record = { + wechat: { src: wechatSvg, altKey: 'aggregate.clientEnv.wechat' }, + alipay: { src: alipaySvg, altKey: 'aggregate.clientEnv.alipay' }, + union_pay: { src: unionPaySvg, altKey: 'aggregate.clientEnv.union' }, + douyin: { src: douyinSvg, altKey: 'aggregate.clientEnv.douyin' }, +} + +export interface MiniGuideEnv { + /** 是否在钱包 App 内(微信/支付宝/云闪付/抖音) */ + inWallet: boolean + /** 图标列表:钱包内仅当前钱包(高亮聚焦);系统浏览器为四钱包 */ + icons: MiniGuideWalletIcon[] + /** 标题 i18n key */ + titleKey: string + /** 描述 i18n key */ + descKey: string +} + +/** + * 探测当前 UA,返回引导页所需的文案 key 与图标列表 + */ +export function useMiniGuideEnv(): MiniGuideEnv { + const env = detectClientEnv() + const inWallet = isAggregateClientEnv(env) + // inWallet 为 true 时,env 已收窄为 AggregateClientEnv(type guard) + const icons = inWallet + ? [ENV_ICON_MAP[env]] + : AGGREGATE_CLIENT_ENVS.map(e => ENV_ICON_MAP[e]) + return { + inWallet, + icons, + // 钱包内:小程序未拉起专属文案;否则:通用扫码文案 + titleKey: inWallet ? 'aggregate.miniInWalletTitle' : 'aggregate.miniScanTitle', + descKey: inWallet ? 'aggregate.miniInWalletDesc' : 'aggregate.miniScanDesc', + } +} diff --git a/src/shared/router/paths.ts b/src/shared/router/paths.ts index 3c5cdb5..66b6519 100644 --- a/src/shared/router/paths.ts +++ b/src/shared/router/paths.ts @@ -44,9 +44,9 @@ export const RoutePath = { /** 聚合-不支持的宿主环境提示(Mobile + PC 注册用) */ AGGREGATE_UNSUPPORTED: '/aggregate/unsupported', /** - * 聚合小程序入口(跨端;linkForm=mini 预下单落地 URL 契约) - * 微信/支付宝扫码后由"普通链接二维码"规则拉起小程序(dax-pay-cashier); - * H5/PC 浏览器直接打开时展示扫码引导(不发起支付) + * 聚合小程序入口(跨端;预下单同时返回的 miniUrl 落地 URL 契约) + * 微信/支付宝扫码后由「普通链接二维码」规则拉起各自小程序; + * 浏览器直接打开时展示扫码引导提示(不发起支付) */ AGGREGATE_MINI: '/am/:orderNo', /** @@ -69,6 +69,12 @@ export const RoutePath = { CODE_PAY_UNION: '/h/union-pay/:code', /** 码牌支付-抖音端(Mobile 收款;PC 同入口扫码引导) */ CODE_PAY_DOUYIN: '/h/douyin/:code', + /** + * 码牌小程序入口(跨端;programType=mini_app 码牌落地 URL 契约) + * 微信/支付宝扫码后由「普通链接二维码」规则拉起小程序(dax-pay-cashier); + * H5/PC 浏览器直接打开时展示扫码引导(不发起支付)。path 与后端 CODE_MINI_PATH /m/{code} 一致 + */ + CODE_PAY_MINI: '/m/:code', /** 商户对账单(PC 独占) */ MERCHANT_STATEMENT: '/merchant/statement', /** 协议展示页(跨端:用户协议/隐私政策,链接可独立分享) */