|
@@ -106,7 +106,12 @@
|
|
|
</view>
|
|
</view>
|
|
|
<view class="bottom-actions">
|
|
<view class="bottom-actions">
|
|
|
<view class="btn-back" @click="goBack">返回</view>
|
|
<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>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
@@ -116,6 +121,7 @@
|
|
|
import { ref, computed } from 'vue';
|
|
import { ref, computed } from 'vue';
|
|
|
import { onLoad } from '@dcloudio/uni-app';
|
|
import { onLoad } from '@dcloudio/uni-app';
|
|
|
import { getDeviceProducts, scanDoor } from '@/api/device';
|
|
import { getDeviceProducts, scanDoor } from '@/api/device';
|
|
|
|
|
+import { preCreatePayscoreOrder } from '@/api/payscore';
|
|
|
import { isLoggedIn } from '@/utils/auth';
|
|
import { isLoggedIn } from '@/utils/auth';
|
|
|
import { logger } from '@/utils/logger';
|
|
import { logger } from '@/utils/logger';
|
|
|
import BrandSlogan from '@/components/BrandSlogan.vue';
|
|
import BrandSlogan from '@/components/BrandSlogan.vue';
|
|
@@ -132,6 +138,11 @@ const leftFloors = ref<FloorConfig[]>([]);
|
|
|
const rightFloors = ref<FloorConfig[]>([]);
|
|
const rightFloors = ref<FloorConfig[]>([]);
|
|
|
const opening = ref(false);
|
|
const opening = ref(false);
|
|
|
|
|
|
|
|
|
|
+// 支付分授权状态
|
|
|
|
|
+const authReady = ref(false);
|
|
|
|
|
+const authBusy = ref(false);
|
|
|
|
|
+const authPackage = ref('');
|
|
|
|
|
+
|
|
|
const activeDoor = ref<'left' | 'right'>('left');
|
|
const activeDoor = ref<'left' | 'right'>('left');
|
|
|
|
|
|
|
|
const hasRightDoor = computed(() => rightFloors.value.length > 0);
|
|
const hasRightDoor = computed(() => rightFloors.value.length > 0);
|
|
@@ -208,20 +219,83 @@ const handleOpenDoor = async () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
opening.value = true;
|
|
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 {
|
|
try {
|
|
|
const response = await scanDoor(deviceId.value);
|
|
const response = await scanDoor(deviceId.value);
|
|
|
|
|
|
|
|
uni.hideLoading();
|
|
uni.hideLoading();
|
|
|
- uni.showToast({
|
|
|
|
|
- title: '开门成功',
|
|
|
|
|
- icon: 'success'
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ uni.showToast({ title: '开门成功', icon: 'success' });
|
|
|
|
|
|
|
|
uni.setStorageSync('currentDeviceId', response.deviceId);
|
|
uni.setStorageSync('currentDeviceId', response.deviceId);
|
|
|
uni.setStorageSync('currentOutTradeNo', response.outTradeNo);
|
|
uni.setStorageSync('currentOutTradeNo', response.outTradeNo);
|
|
@@ -229,9 +303,7 @@ const handleOpenDoor = async () => {
|
|
|
uni.removeStorageSync('shoppingPollingActive');
|
|
uni.removeStorageSync('shoppingPollingActive');
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
- uni.redirectTo({
|
|
|
|
|
- url: '/pages/shopping/shopping'
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ uni.redirectTo({ url: '/pages/shopping/shopping' });
|
|
|
}, 1000);
|
|
}, 1000);
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
uni.hideLoading();
|
|
uni.hideLoading();
|