From d13be3580f7f093c678d9152badbfa86317f4d7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E8=BF=9B?= Date: Sat, 7 Nov 2026 21:57:26 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BB=B6=E6=9C=9F=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E5=9C=A8=E5=BE=AE=E4=BF=A1=E5=86=85=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E6=8B=89=E8=B5=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 微信支付下单带 app_type;拿到 pay_config 后与套餐购买一样拉起微信支付,继续支付同样处理 - 微信内打开时支付方式默认微信;取消支付保留同一请求号,再次确认不重复建单 --- api/modules/packageSilence.js | 6 +++++- pages/silence-extension/silence-extension.vue | 13 ++++++++----- pages/silence-orders/detail.vue | 5 +++-- tests/silence.test.mjs | 1 + utils/silence-payment.js | 6 +++++- utils/silence.js | 7 ++++--- 6 files changed, 26 insertions(+), 12 deletions(-) diff --git a/api/modules/packageSilence.js b/api/modules/packageSilence.js index ebb2e4b..46abf0f 100644 --- a/api/modules/packageSilence.js +++ b/api/modules/packageSilence.js @@ -1,4 +1,5 @@ import request from '@/utils/request.js'; +import { APP_TYPE } from '@/utils/env.js'; // 实名即生效套餐沉默期 H5 接口(后端 Iteration/8-11,/api/c/v1/package-silence)。 // 资格、试算、下单关闭默认错误提示,由页面按沉默期错误码给出客户能看懂的文案。 @@ -24,10 +25,13 @@ export const packageSilenceApi = { }, createOrder({ package_usage_id, days, payment_method, request_id }) { + const data = { package_usage_id, days, payment_method, request_id }; + // 微信支付带上应用类型:后端在微信内直接下 JSAPI 单,返回 pay_config 拉起支付 + if (payment_method === 'wechat') data.app_type = APP_TYPE; return request({ url: `${BASE}/orders`, method: 'POST', - data: { package_usage_id, days, payment_method, request_id }, + data, showError: false }); }, diff --git a/pages/silence-extension/silence-extension.vue b/pages/silence-extension/silence-extension.vue index eaf045e..29f370d 100644 --- a/pages/silence-extension/silence-extension.vue +++ b/pages/silence-extension/silence-extension.vue @@ -155,6 +155,7 @@ )); const showToast = (title) => uni.showToast({ title, icon: 'none', duration: 2500 }); + const isInWechatBrowser = () => typeof navigator !== 'undefined' && /micromessenger/i.test(navigator.userAgent); const loadEligibility = async () => { loading.value = true; @@ -166,7 +167,7 @@ assetApi.getInfo(userStore.state.identifier).catch(() => null) ]); eligibility.value = data; - paymentOptions.value = getSilencePaymentOptions(info?.allowed_payment_methods); + paymentOptions.value = getSilencePaymentOptions(info?.allowed_payment_methods, isInWechatBrowser()); if (!paymentOptions.value.some((option) => option.value === paymentMethod.value)) { paymentMethod.value = paymentOptions.value[0]?.value || ''; } @@ -248,15 +249,17 @@ request_id: requestIds.get(days, paymentMethod.value) }); lastOrderId.value = order?.id || 0; - if (!order?.qr_content) { + if (!order?.qr_content && !order?.pay_config) { showToast('订单已创建,请在"我的延期订单"中继续支付'); openOrders(); return; } - await openSilencePayment(order, SILENCE_REFRESH_TARGET.EXTENSION); + const result = await openSilencePayment(order, SILENCE_REFRESH_TARGET.EXTENSION); + // 微信内直接支付完成:立即查订单结果(不经过支付页回跳) + if (result?.paid) await checkLastOrder(); } catch (error) { - // 网络异常时后端可能已建单:保留 request_id,客户再次点击会拿到同一笔订单。 - if (!error?.paymentResultUnknown) requestIds.reset(); + // 网络异常时后端可能已建单、取消微信支付时订单仍待支付:保留 request_id,客户再次点击会拿到同一笔订单。 + if (!error?.paymentResultUnknown && !error?.cancelled) requestIds.reset(); showToast(getSilenceErrorMessage(error, '下单失败,请稍后重试')); if (Number(error?.code) === 1271) await loadEligibility(); } finally { diff --git a/pages/silence-orders/detail.vue b/pages/silence-orders/detail.vue index 3004463..ec7fd1a 100644 --- a/pages/silence-orders/detail.vue +++ b/pages/silence-orders/detail.vue @@ -52,7 +52,7 @@ ]; }); - const canContinuePay = computed(() => order.value?.status === 'pending_payment' && !!order.value?.qr_content); + const canContinuePay = computed(() => order.value?.status === 'pending_payment' && (!!order.value?.qr_content || !!order.value?.pay_config)); const canCancel = computed(() => order.value?.status === 'pending_payment'); const cancelling = ref(false); @@ -91,7 +91,8 @@ const continuePay = async () => { try { - await openSilencePayment(order.value, SILENCE_REFRESH_TARGET.ORDER_DETAIL); + const result = await openSilencePayment(order.value, SILENCE_REFRESH_TARGET.ORDER_DETAIL); + if (result?.paid) await load(); } catch (error) { uni.showToast({ title: error?.message || '拉起支付失败', icon: 'none' }); } diff --git a/tests/silence.test.mjs b/tests/silence.test.mjs index 07b6d50..9236d47 100644 --- a/tests/silence.test.mjs +++ b/tests/silence.test.mjs @@ -19,6 +19,7 @@ test('延期支付方式只取 wechat、alipay 与资产允许方式的交集, assert.deepEqual(getSilencePaymentOptions(['wechat', 'wallet', 'alipay']).map((item) => item.value), ['alipay', 'wechat']); assert.deepEqual(getSilencePaymentOptions(['wallet']), []); assert.deepEqual(getSilencePaymentOptions(undefined), []); + assert.deepEqual(getSilencePaymentOptions(['alipay', 'wechat'], true).map((item) => item.value), ['wechat', 'alipay']); }); test('延期天数校验:整数且在 min~max 内', () => { diff --git a/utils/silence-payment.js b/utils/silence-payment.js index 339b8bc..fcf4884 100644 --- a/utils/silence-payment.js +++ b/utils/silence-payment.js @@ -1,4 +1,4 @@ -import { markPendingPaymentRefresh, openAlipayPayment } from '@/utils/payment.js'; +import { isValidWechatPayConfig, markPendingPaymentRefresh, openAlipayPayment, wechatH5Pay } from '@/utils/payment.js'; import { isPaymentLink } from '@/utils/silence.js'; export const SILENCE_REFRESH_TARGET = { @@ -19,6 +19,10 @@ const isInWechat = () => typeof navigator !== 'undefined' && /micromessenger/i.t * 在微信外且为链接时直接跳转;其余情况进入延期支付页展示二维码与链接。 */ export const openSilencePayment = (order, refreshTarget) => { + // 微信内直接支付(JSAPI):与套餐购买一致,用 pay_config 拉起微信支付 + if (order?.pay_config && isValidWechatPayConfig(order.pay_config)) { + return wechatH5Pay(order.pay_config).then(() => ({ paid: true })); + } const content = String(order?.qr_content || '').trim(); if (!content) return Promise.reject(new Error('支付内容为空')); diff --git a/utils/silence.js b/utils/silence.js index b2ebacd..73523f9 100644 --- a/utils/silence.js +++ b/utils/silence.js @@ -67,10 +67,11 @@ export const getSilenceErrorMessage = (error, fallback = '操作失败,请稍 export const isSilenceFeatureDisabled = (error) => Number(error?.code) === 1274; -/** 延期可用支付方式:资产允许的支付方式与 wechat、alipay 取交集,支付宝优先 */ -export const getSilencePaymentOptions = (allowedMethods) => { +/** 延期可用支付方式:资产允许的支付方式与 wechat、alipay 取交集;微信内打开时微信优先,否则支付宝优先 */ +export const getSilencePaymentOptions = (allowedMethods, preferWechat = false) => { const allowed = Array.isArray(allowedMethods) ? allowedMethods : []; - return SILENCE_PAYMENT_METHODS + const order = preferWechat ? ['wechat', 'alipay'] : SILENCE_PAYMENT_METHODS; + return order .filter((method) => allowed.includes(method)) .map((value) => ({ value, label: SILENCE_PAYMENT_LABELS[value] })); };