ソースを参照

fix: 商品页开门购物增加支付分授权流程

从微信直接扫码进入产品页时,点"开门购物"先预创建支付分订单,
按钮切换为"确认支付分授权",点击后调起 wxpayScoreUse 官方确认页,
确认后才开门。与首页扫码流程一致。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 2 週間 前
コミット
103b400a23
1 ファイル変更83 行追加11 行削除
  1. 83 11
      haha-mp/src/pages/products/products.vue

+ 83 - 11
haha-mp/src/pages/products/products.vue

@@ -106,7 +106,12 @@
       </view>
       <view class="bottom-actions">
         <view class="btn-back" @click="goBack">返回</view>
-        <view class="btn-open" @click="handleOpenDoor">开门购物</view>
+        <!-- 未授权时:开门购物(触发预创建) -->
+        <view v-if="!authReady" class="btn-open" @click="handleOpenDoor">开门购物</view>
+        <!-- 已准备好授权:确认支付分 -->
+        <view v-else class="btn-open btn-auth" @click="invokePayScore">
+          {{ authBusy ? '跳转中...' : '确认支付分授权' }}
+        </view>
       </view>
     </view>
   </view>
@@ -116,6 +121,7 @@
 import { ref, computed } from 'vue';
 import { onLoad } from '@dcloudio/uni-app';
 import { getDeviceProducts, scanDoor } from '@/api/device';
+import { preCreatePayscoreOrder } from '@/api/payscore';
 import { isLoggedIn } from '@/utils/auth';
 import { logger } from '@/utils/logger';
 import BrandSlogan from '@/components/BrandSlogan.vue';
@@ -132,6 +138,11 @@ const leftFloors = ref<FloorConfig[]>([]);
 const rightFloors = ref<FloorConfig[]>([]);
 const opening = ref(false);
 
+// 支付分授权状态
+const authReady = ref(false);
+const authBusy = ref(false);
+const authPackage = ref('');
+
 const activeDoor = ref<'left' | 'right'>('left');
 
 const hasRightDoor = computed(() => rightFloors.value.length > 0);
@@ -208,20 +219,83 @@ const handleOpenDoor = async () => {
   }
 
   opening.value = true;
+  uni.showLoading({ title: '准备中...', mask: true });
+
+  try {
+    // 预创建支付分订单
+    const result = await preCreatePayscoreOrder({ deviceId: deviceId.value });
+    uni.hideLoading();
+
+    if (!result.success || !result.package) {
+      opening.value = false;
+      uni.showToast({
+        title: result.errorMsg || '创建支付分订单失败',
+        icon: 'none',
+      });
+      return;
+    }
 
-  uni.showLoading({
-    title: '正在开门...',
-    mask: true
+    logger.log('[商品页] 支付分预创建成功');
+    authPackage.value = result.package;
+    authReady.value = true;
+  } catch (error: any) {
+    uni.hideLoading();
+    opening.value = false;
+    logger.error('[商品页] 预创建失败', error);
+    uni.showToast({
+      title: error?.message || '创建支付分订单失败',
+      icon: 'none',
+    });
+  }
+};
+
+/**
+ * 用户点击"确认支付分授权"按钮 → 调起微信官方确认页
+ */
+const invokePayScore = () => {
+  if (authBusy.value) return;
+  authBusy.value = true;
+
+  const pkg = authPackage.value;
+  if (!pkg) {
+    authBusy.value = false;
+    return;
+  }
+
+  wx.openBusinessView({
+    businessType: 'wxpayScoreUse',
+    extraData: {
+      package: pkg,
+    },
+    success: () => {
+      authBusy.value = false;
+      authReady.value = false;
+      logger.log('[商品页] 支付分确认成功,开门');
+      doOpenDoor();
+    },
+    fail: (err: any) => {
+      authBusy.value = false;
+      const errMsg = err?.errMsg || JSON.stringify(err);
+      logger.error('[商品页] openBusinessView fail:', errMsg);
+      if (!errMsg.includes('cancel')) {
+        uni.showModal({
+          title: '调起支付分失败',
+          content: errMsg,
+          showCancel: false,
+        });
+      }
+    },
   });
+};
+
+const doOpenDoor = async () => {
+  uni.showLoading({ title: '正在开门...', mask: true });
 
   try {
     const response = await scanDoor(deviceId.value);
 
     uni.hideLoading();
-    uni.showToast({
-      title: '开门成功',
-      icon: 'success'
-    });
+    uni.showToast({ title: '开门成功', icon: 'success' });
 
     uni.setStorageSync('currentDeviceId', response.deviceId);
     uni.setStorageSync('currentOutTradeNo', response.outTradeNo);
@@ -229,9 +303,7 @@ const handleOpenDoor = async () => {
     uni.removeStorageSync('shoppingPollingActive');
 
     setTimeout(() => {
-      uni.redirectTo({
-        url: '/pages/shopping/shopping'
-      });
+      uni.redirectTo({ url: '/pages/shopping/shopping' });
     }, 1000);
   } catch (error: any) {
     uni.hideLoading();