支付宝兼容
This commit is contained in:
+36
-7
@@ -91,7 +91,7 @@
|
||||
<!-- 底部操作区 -->
|
||||
<view class="footer">
|
||||
<view class="rent-button" :class="{ 'return-button': hasActiveOrder }"
|
||||
@click="handleRent(isWechatMiniProgram ? 'wx-score-pay' : 'wx-pay')">
|
||||
@click="handleRent">
|
||||
<text>{{ hasActiveOrder ? $t('order.returnDevice') : getRentButtonText() }}</text>
|
||||
</view>
|
||||
<!-- 微信支付分标识仅在微信小程序环境显示 -->
|
||||
@@ -176,6 +176,8 @@
|
||||
const phoneNumber = ref('')
|
||||
const showPhoneAuthPopup = ref(false)
|
||||
const isWechatMiniProgram = ref(false)
|
||||
const isAlipayMiniProgram = ref(false)
|
||||
const isH5 = ref(false)
|
||||
|
||||
// 生命周期 onLoad 钩子
|
||||
onLoad(async (options) => {
|
||||
@@ -193,13 +195,27 @@
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('device.deviceInfo')
|
||||
})
|
||||
// 检测当前运行环境
|
||||
// 检测当前运行环境:微信小程序 / 支付宝小程序 / H5
|
||||
// #ifdef MP-WEIXIN
|
||||
isWechatMiniProgram.value = true
|
||||
isAlipayMiniProgram.value = false
|
||||
isH5.value = false
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
isWechatMiniProgram.value = false
|
||||
isAlipayMiniProgram.value = true
|
||||
isH5.value = false
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
isWechatMiniProgram.value = false
|
||||
isAlipayMiniProgram.value = false
|
||||
isH5.value = true
|
||||
// #endif
|
||||
console.log('当前运行环境:', {
|
||||
isWechatMiniProgram: isWechatMiniProgram.value,
|
||||
isAlipayMiniProgram: isAlipayMiniProgram.value,
|
||||
isH5: isH5.value
|
||||
})
|
||||
await checkUserPhone()
|
||||
await fetchDeviceInfo()
|
||||
})
|
||||
@@ -437,7 +453,7 @@
|
||||
}
|
||||
|
||||
// 处理租借操作
|
||||
const handleRent = (payWay) => {
|
||||
const handleRent = () => {
|
||||
if (!isLoggedIn.value) {
|
||||
showLoginTip()
|
||||
return
|
||||
@@ -448,9 +464,22 @@
|
||||
showPhoneAuthPopup.value = true
|
||||
return
|
||||
}
|
||||
|
||||
// 提交订单
|
||||
submitRentOrder(payWay)
|
||||
|
||||
// 根据运行环境选择不同的租借/支付流程
|
||||
// 微信小程序:走微信支付分免押租借
|
||||
if (isWechatMiniProgram.value) {
|
||||
submitRentOrder('wx-score-pay')
|
||||
return
|
||||
}
|
||||
|
||||
// 支付宝小程序:走押金租借,后续在支付页内调起支付宝支付
|
||||
if (isAlipayMiniProgram.value) {
|
||||
submitRentOrder('wx-pay')
|
||||
return
|
||||
}
|
||||
|
||||
// H5 等其他环境:统一走押金租借,支付页内根据平台选择支付方式(Antom 等)
|
||||
submitRentOrder('wx-pay')
|
||||
}
|
||||
|
||||
// 获取价格单位文本
|
||||
@@ -603,7 +632,7 @@
|
||||
|
||||
// 跳转到订单支付页面
|
||||
uni.redirectTo({
|
||||
url: `/pages/order/payment?orderId=${order.orderId}&packagePrice=${packagePrice}&totalAmount=${totalAmount}&depositAmount=${deposit}${deviceInfo.value && deviceInfo.value.feeConfig ? '&feeConfig=' + encodeURIComponent(deviceInfo.value.feeConfig) : ''}`
|
||||
url: `/subPackages/order/payment?orderId=${order.orderId}&packagePrice=${packagePrice}&totalAmount=${totalAmount}&depositAmount=${deposit}${deviceInfo.value && deviceInfo.value.feeConfig ? '&feeConfig=' + encodeURIComponent(deviceInfo.value.feeConfig) : ''}`
|
||||
})
|
||||
|
||||
} else if (payWay == 'wx-score-pay') {
|
||||
|
||||
+192
-13
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<view class="container fullscreen">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||
<view class="custom-navbar" :style="navbarStyle">
|
||||
<view class="navbar-content" :style="{ height: navBarHeight + 'px' }">
|
||||
<text class="navbar-title">{{ $t('home.title') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 顶部信息区域(通知、招商等) -->
|
||||
<view class="top-info-section" :style="{ top: (statusBarHeight + navBarHeight) + 'px' }">
|
||||
<view class="top-info-section" :style="topInfoSectionStyle">
|
||||
<!-- 通知栏 -->
|
||||
<view class="notice-wrapper" v-if="noticeText" @click="openNoticePopup">
|
||||
<uv-notice-bar :text="noticeText" :speed="50" :show-icon="true" color="#07c160" bg-color="#E8F8EF"
|
||||
@@ -17,14 +17,31 @@
|
||||
</view>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<view class="main-content" :style="{ paddingTop: (navBarHeight + noticeHeight) + 'px' }">
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-ALIPAY -->
|
||||
<view class="main-content" :style="{ paddingTop: (statusBarHeight + navBarHeight + noticeHeight) + 'px' }">
|
||||
<!-- #endif -->
|
||||
<!-- 全屏地图组件 -->
|
||||
<!-- 支付宝小程序使用专用组件 -->
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<MapComponentAlipay v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
|
||||
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
|
||||
:enableMarkers="true" :bannerImages="bannerImages"
|
||||
:hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup" @relocate="handleRelocate"
|
||||
@scan="handleScan" @showList="showLocationList" @markerTap="selectPosition"
|
||||
@mapCenterChange="onMapCenterChange" @bannerClick="handleBannerClick" @guide="openGuidePopup" />
|
||||
<!-- #endif -->
|
||||
<!-- 非支付宝小程序使用通用组件 -->
|
||||
<!-- #ifndef MP-ALIPAY -->
|
||||
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
|
||||
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
|
||||
:enableMarkers="true" :bannerImages="bannerImages"
|
||||
:hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup" @relocate="handleRelocate"
|
||||
@scan="handleScan" @showList="showLocationList" @markerTap="selectPosition"
|
||||
@mapCenterChange="onMapCenterChange" @bannerClick="handleBannerClick" @guide="openGuidePopup" />
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- 地图加载状态 -->
|
||||
<view v-if="isLoading || !userLocation" class="map-loading-placeholder">
|
||||
@@ -79,7 +96,7 @@
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 手机号授权弹窗 -->
|
||||
<!-- 手机号校验/授权弹窗(扫码前校验) -->
|
||||
<view class="phone-auth-popup" v-if="showPhoneAuthPopup">
|
||||
<view class="popup-mask" @click.stop="showPhoneAuthPopup = false"></view>
|
||||
<view class="popup-content">
|
||||
@@ -90,9 +107,25 @@
|
||||
<view class="auth-desc">
|
||||
<text>{{ $t('auth.authDesc') }}</text>
|
||||
</view>
|
||||
<button class="auth-btn" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">
|
||||
<!-- 微信:获取手机号 code 并上报后端绑定 -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<button class="auth-btn" open-type="getPhoneNumber" @getphonenumber="onWxGetPhoneNumber">
|
||||
<text>{{ $t('auth.getPhoneNumber') }}</text>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- 支付宝:先授权 phoneNumber,再调用 my.getPhoneNumber,上报后端解密并校验一致性 -->
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<button
|
||||
class="auth-btn"
|
||||
open-type="getAuthorize"
|
||||
scope="phoneNumber"
|
||||
@getAuthorize="onAliAuthorizePhoneNumber"
|
||||
@error="onAliAuthorizePhoneNumberError"
|
||||
>
|
||||
<text>{{ $t('auth.getPhoneNumber') }}</text>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<view class="auth-cancel" @click="showPhoneAuthPopup = false">
|
||||
<text>{{ $t('auth.notNow') }}</text>
|
||||
</view>
|
||||
@@ -187,7 +220,10 @@
|
||||
} from 'vue'
|
||||
import {
|
||||
getQueryString,
|
||||
wxLogin
|
||||
wxLogin,
|
||||
getUserInfo,
|
||||
getUserPhoneNumber,
|
||||
getAlipayUserPhoneNumber
|
||||
} from '../../util/index.js'
|
||||
import {
|
||||
URL
|
||||
@@ -219,6 +255,9 @@
|
||||
// 同样需要使用相对路径引入组件
|
||||
// 注意:从 pages/index/ 目录访问 components/ 需要使用 ../../components/ 路径
|
||||
import MapComponent from '../../components/MapComponent.vue'
|
||||
// #ifdef MP-ALIPAY
|
||||
import MapComponentAlipay from '../../components/MapComponentAlipay.vue'
|
||||
// #endif
|
||||
import LocationListSheet from '../../components/LocationListSheet.vue'
|
||||
import {
|
||||
useI18n
|
||||
@@ -244,6 +283,8 @@
|
||||
const isExpanded = ref(false)
|
||||
const isLoading = ref(false)
|
||||
const showPhoneAuthPopup = ref(false)
|
||||
const pendingScan = ref(false) // 是否是扫码流程触发的手机号校验
|
||||
const expectedUserPhone = ref('') // 当前登录态下绑定的手机号(用于支付宝一致性校验)
|
||||
const isLocationInitialized = ref(false)
|
||||
const showLocationPopup = ref(false)
|
||||
const isRelocating = ref(false) // 防抖标志:是否正在重新定位
|
||||
@@ -259,6 +300,30 @@
|
||||
const navBarHeight = ref(44) // 默认导航栏内容高度
|
||||
const noticeHeight = ref(0) // 通知栏高度
|
||||
|
||||
// 导航栏样式:支付宝小程序不设置 paddingTop
|
||||
const navbarStyle = computed(() => {
|
||||
// #ifdef MP-ALIPAY
|
||||
// 支付宝小程序:不设置 paddingTop
|
||||
return { paddingTop: '0px' }
|
||||
// #endif
|
||||
// #ifndef MP-ALIPAY
|
||||
// 非支付宝小程序:设置 statusBarHeight
|
||||
return { paddingTop: statusBarHeight.value + 'px' }
|
||||
// #endif
|
||||
})
|
||||
|
||||
// 顶部信息区域样式:支付宝小程序使用 paddingTop,非支付宝小程序使用 top
|
||||
const topInfoSectionStyle = computed(() => {
|
||||
// #ifdef MP-ALIPAY
|
||||
// 支付宝小程序:使用 paddingTop
|
||||
return { top: ( navBarHeight.value) + 'px' }
|
||||
// #endif
|
||||
// #ifndef MP-ALIPAY
|
||||
// 非支付宝小程序:使用 top
|
||||
return { top: (statusBarHeight.value + navBarHeight.value) + 'px' }
|
||||
// #endif
|
||||
})
|
||||
|
||||
// 使用指南步骤
|
||||
const guideSteps = ref([{
|
||||
title: '扫码使用',
|
||||
@@ -474,11 +539,13 @@
|
||||
|
||||
// 距离格式化函数
|
||||
const formatDistance = (distanceInMeters) => {
|
||||
if (distanceInMeters < 1000) {
|
||||
return `${Math.round(distanceInMeters)}m`
|
||||
} else {
|
||||
return `${(distanceInMeters / 1000).toFixed(1)}km`
|
||||
}
|
||||
// 支付宝小程序等环境下,可能传入 String/BigInt/异常对象,导致 toFixed 不存在
|
||||
let meters = distanceInMeters
|
||||
if (typeof meters === 'bigint') meters = Number(meters)
|
||||
meters = Number(meters)
|
||||
if (!Number.isFinite(meters) || meters < 0) return ''
|
||||
if (meters < 1000) return `${Math.round(meters)}m`
|
||||
return `${(meters / 1000).toFixed(1)}km`
|
||||
}
|
||||
|
||||
|
||||
@@ -964,7 +1031,58 @@
|
||||
}
|
||||
}
|
||||
|
||||
const handleScan = async () => {
|
||||
const normalizePhone = (p) => {
|
||||
if (!p) return ''
|
||||
return String(p).replace(/\s+/g, '').replace(/^\+?86/, '')
|
||||
}
|
||||
|
||||
const isLoggedIn = () => {
|
||||
const token = uni.getStorageSync('token')
|
||||
return !!token
|
||||
}
|
||||
|
||||
const precheckBeforeScan = async () => {
|
||||
if (!isLoggedIn()) {
|
||||
redirectToLogin()
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
const userInfoRes = await getUserInfo()
|
||||
console.log('userInfoRes', userInfoRes.data.phone);
|
||||
|
||||
const phone = userInfoRes.data.phone || ''
|
||||
expectedUserPhone.value = phone
|
||||
console.log('expectedUserPhone', expectedUserPhone.value);
|
||||
|
||||
|
||||
// 没有手机号:弹窗引导获取/绑定
|
||||
if (!phone) {
|
||||
pendingScan.value = true
|
||||
showPhoneAuthPopup.value = true
|
||||
return false
|
||||
}
|
||||
|
||||
// // 支付宝:即使已有手机号,也要求扫码前做一次一致性校验(或命中缓存)
|
||||
// // #ifdef MP-ALIPAY
|
||||
// const cached = uni.getStorageSync('alipay_phone_verified')
|
||||
// const cachedPhone = cached && cached.phone ? cached.phone : ''
|
||||
// if (cachedPhone && normalizePhone(cachedPhone) === normalizePhone(phone)) {
|
||||
// return true
|
||||
// }
|
||||
// pendingScan.value = true
|
||||
// showPhoneAuthPopup.value = true
|
||||
// return false
|
||||
// // #endif
|
||||
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error('扫码前检查用户信息失败:', e)
|
||||
return true // 不阻断,避免影响主流程;后续租借仍会二次校验
|
||||
}
|
||||
}
|
||||
|
||||
const doScan = async () => {
|
||||
// #ifdef H5
|
||||
uni.navigateTo({
|
||||
url: '/pages/scan/index'
|
||||
@@ -987,6 +1105,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
const handleScan = async () => {
|
||||
const ok = await precheckBeforeScan()
|
||||
if (!ok) return
|
||||
await doScan()
|
||||
}
|
||||
|
||||
const processScanResult = async (scanResult) => {
|
||||
try {
|
||||
console.log('===== 处理扫码结果 =====');
|
||||
@@ -1162,12 +1286,67 @@
|
||||
showLocationPopup.value = false
|
||||
}
|
||||
|
||||
const onGetPhoneNumber = (e) => {
|
||||
if (e.detail.errMsg === 'getPhoneNumber:ok') {
|
||||
// 微信:绑定手机号后继续扫码
|
||||
const onWxGetPhoneNumber = async (e) => {
|
||||
try {
|
||||
if (!e || e.detail.errMsg !== 'getPhoneNumber:ok') {
|
||||
return
|
||||
}
|
||||
await getUserPhoneNumber(e.detail.code)
|
||||
showPhoneAuthPopup.value = false
|
||||
if (pendingScan.value) {
|
||||
pendingScan.value = false
|
||||
await doScan()
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('微信绑定手机号失败:', err)
|
||||
}
|
||||
}
|
||||
|
||||
// 支付宝:获取手机号(后端解密)并与 userInfo.phone 对比,一致才允许继续扫码
|
||||
const onAliAuthorizePhoneNumber = async (e) => {
|
||||
// #ifdef MP-ALIPAY
|
||||
try {
|
||||
console.log('[ALIPAY] getAuthorize(phoneNumber) event:', e)
|
||||
uni.showLoading({ title: t('common.processing') })
|
||||
const res = await getAlipayUserPhoneNumber()
|
||||
const aliPhone = res?.data?.phoneNumber || res?.data?.phone || res?.phoneNumber || ''
|
||||
if (!aliPhone) {
|
||||
throw new Error('未获取到手机号')
|
||||
}
|
||||
|
||||
const expected = expectedUserPhone.value
|
||||
if (expected && normalizePhone(aliPhone) !== normalizePhone(expected)) {
|
||||
uni.showModal({
|
||||
title: t('common.tips'),
|
||||
content: '当前支付宝授权手机号与账号绑定手机号不一致,无法扫码租借,请更换账号或联系管理员。',
|
||||
showCancel: false
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 缓存本次校验结果(避免每次扫码都弹)
|
||||
uni.setStorageSync('alipay_phone_verified', { phone: aliPhone, ts: Date.now() })
|
||||
|
||||
showPhoneAuthPopup.value = false
|
||||
if (pendingScan.value) {
|
||||
pendingScan.value = false
|
||||
await doScan()
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('支付宝手机号校验失败:', err)
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
const onAliAuthorizePhoneNumberError = (e) => {
|
||||
// #ifdef MP-ALIPAY
|
||||
console.error('支付宝手机号授权失败:', e)
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 使用指南弹窗控制
|
||||
const openPopup = () => {
|
||||
uni.navigateTo({
|
||||
|
||||
@@ -134,8 +134,13 @@
|
||||
}
|
||||
|
||||
const formatDistance = (meters) => {
|
||||
if (meters < 1000) return `${Math.round(meters)}m`
|
||||
return `${(meters / 1000).toFixed(1)}km`
|
||||
// 兼容支付宝小程序等环境:保证始终对 Number 调用 toFixed
|
||||
let m = meters
|
||||
if (typeof m === 'bigint') m = Number(m)
|
||||
m = Number(m)
|
||||
if (!Number.isFinite(m) || m < 0) return ''
|
||||
if (m < 1000) return `${Math.round(m)}m`
|
||||
return `${(m / 1000).toFixed(1)}km`
|
||||
}
|
||||
|
||||
const setTab = (name) => {
|
||||
|
||||
Reference in New Issue
Block a user