Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a7c6c8e03 | |||
| 76bdcd1aba |
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
wxLogin,
|
alipayLogin,
|
||||||
getUserInfo
|
getUserInfo
|
||||||
} from './util/index'
|
} from './util/index'
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
// 保留方法但不调用
|
// 保留方法但不调用
|
||||||
async autoLogin() {
|
async autoLogin() {
|
||||||
try {
|
try {
|
||||||
const loginResult = await wxLogin()
|
const loginResult = await alipayLogin()
|
||||||
// await getUserInfo()
|
// await getUserInfo()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('自动登录失败:', error)
|
console.error('自动登录失败:', error)
|
||||||
|
|||||||
+63
-59
@@ -2,10 +2,20 @@
|
|||||||
<view class="map-container" :class="{ 'full-width': props.fullWidth }" :style="{ '--map-height': props.customHeight || '78vh' }">
|
<view class="map-container" :class="{ 'full-width': props.fullWidth }" :style="{ '--map-height': props.customHeight || '78vh' }">
|
||||||
<!-- 地图容器 -->
|
<!-- 地图容器 -->
|
||||||
<view class="map-wrapper">
|
<view class="map-wrapper">
|
||||||
<!-- 使用小程序原生地图组件 -->
|
<!-- 支付宝小程序地图组件:使用高德地图 -->
|
||||||
<map id="map" class="native-map" :longitude="mapCenter.longitude" :latitude="mapCenter.latitude"
|
<map id="map" class="native-map"
|
||||||
:markers="mapMarkers" :scale="mapZoom" :show-location="false" @regionchange="onMapRegionChange"
|
:longitude="mapCenter.longitude"
|
||||||
@markertap="onMapMarkerTap" @callouttap="onCalloutTap" @updated="onMapUpdated" @error="onMapError">
|
:latitude="mapCenter.latitude"
|
||||||
|
:markers="mapMarkers"
|
||||||
|
:scale="mapZoom"
|
||||||
|
:show-location="false"
|
||||||
|
@regionchange="onMapRegionChange"
|
||||||
|
@markertap="onMapMarkerTap"
|
||||||
|
@tap="onMapTap"
|
||||||
|
@updated="onMapUpdated"
|
||||||
|
@error="onMapError">
|
||||||
|
</map>
|
||||||
|
|
||||||
<!-- 覆盖在地图上的广告轮播(使用 cover-view 以兼容小程序原生组件层级) -->
|
<!-- 覆盖在地图上的广告轮播(使用 cover-view 以兼容小程序原生组件层级) -->
|
||||||
<cover-view class="index-swiper" v-if="!props.hideControls && !props.hideMapOverlays && currentBannerImage">
|
<cover-view class="index-swiper" v-if="!props.hideControls && !props.hideMapOverlays && currentBannerImage">
|
||||||
<cover-image :src="currentBannerImage" class="index-swiper-img" mode="aspectFill" @tap="handleBannerTap"></cover-image>
|
<cover-image :src="currentBannerImage" class="index-swiper-img" mode="aspectFill" @tap="handleBannerTap"></cover-image>
|
||||||
@@ -25,6 +35,7 @@
|
|||||||
<cover-image src="/static/location-icon.png" class="center-marker-icon"></cover-image>
|
<cover-image src="/static/location-icon.png" class="center-marker-icon"></cover-image>
|
||||||
</cover-view>
|
</cover-view>
|
||||||
|
|
||||||
|
<!-- 地图侧边控制按钮:重定位、客服中心、查看附近设备 -->
|
||||||
<cover-view class="map-side-controls" v-if="!props.hideControls && !props.hideMapOverlays">
|
<cover-view class="map-side-controls" v-if="!props.hideControls && !props.hideMapOverlays">
|
||||||
<cover-view class="side-btn locate" @tap="handleRelocate">
|
<cover-view class="side-btn locate" @tap="handleRelocate">
|
||||||
<cover-image class="side-icon" src="/static/location.png"></cover-image>
|
<cover-image class="side-icon" src="/static/location.png"></cover-image>
|
||||||
@@ -35,9 +46,7 @@
|
|||||||
<cover-view class="side-btn search" @tap="handleSearch">
|
<cover-view class="side-btn search" @tap="handleSearch">
|
||||||
<cover-image class="side-icon" src="/static/other_device.png"></cover-image>
|
<cover-image class="side-icon" src="/static/other_device.png"></cover-image>
|
||||||
</cover-view>
|
</cover-view>
|
||||||
|
|
||||||
</cover-view>
|
</cover-view>
|
||||||
</map>
|
|
||||||
|
|
||||||
<!-- 地图加载状态 -->
|
<!-- 地图加载状态 -->
|
||||||
<view class="map-loading" v-if="isLoading">
|
<view class="map-loading" v-if="isLoading">
|
||||||
@@ -245,6 +254,35 @@
|
|||||||
deep: true
|
deep: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 启动广告轮播
|
||||||
|
const startBannerRotation = () => {
|
||||||
|
// 如果只有一张或没有图片,不需要轮播
|
||||||
|
if (!props.bannerImages || props.bannerImages.length <= 1) {
|
||||||
|
console.log('图片数量不足,不启动轮播')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除旧的定时器
|
||||||
|
stopBannerRotation()
|
||||||
|
|
||||||
|
console.log('开始广告轮播定时器')
|
||||||
|
// 每3秒切换一次
|
||||||
|
bannerTimer = setInterval(() => {
|
||||||
|
const nextIndex = (currentBannerIndex.value + 1) % props.bannerImages.length
|
||||||
|
console.log('轮播切换:', currentBannerIndex.value, '->', nextIndex)
|
||||||
|
currentBannerIndex.value = nextIndex
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止广告轮播
|
||||||
|
const stopBannerRotation = () => {
|
||||||
|
if (bannerTimer) {
|
||||||
|
console.log('停止广告轮播')
|
||||||
|
clearInterval(bannerTimer)
|
||||||
|
bannerTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 监听广告图片变化,启动或停止轮播
|
// 监听广告图片变化,启动或停止轮播
|
||||||
watch(() => props.bannerImages, (newImages, oldImages) => {
|
watch(() => props.bannerImages, (newImages, oldImages) => {
|
||||||
console.log('广告图片变化:', newImages?.length, '张')
|
console.log('广告图片变化:', newImages?.length, '张')
|
||||||
@@ -270,25 +308,22 @@
|
|||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 地图区域变化事件(带防抖优化)
|
// 地图区域变化事件(支付宝小程序,带防抖优化)
|
||||||
const onMapRegionChange = (e) => {
|
const onMapRegionChange = (e) => {
|
||||||
|
if (!e) {
|
||||||
// 只处理结束事件
|
|
||||||
if (!e || e.type !== 'end') {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const causedBy = e.causedBy || e.detail?.causedBy
|
// 获取触发原因和中心位置
|
||||||
|
const causedBy = e.detail?.causedBy || e.causedBy
|
||||||
|
const centerLocation = e.detail?.centerLocation || e.centerLocation || e.detail?.location
|
||||||
|
|
||||||
if (causedBy === 'gesture' || causedBy === 'scale' || causedBy === 'drag'||causedBy==='update') {
|
if (causedBy === 'gesture' || causedBy === 'scale' || causedBy === 'drag' || causedBy === 'update') {
|
||||||
// 清除之前的定时器
|
// 清除之前的定时器
|
||||||
if (regionChangeTimer) {
|
if (regionChangeTimer) {
|
||||||
clearTimeout(regionChangeTimer)
|
clearTimeout(regionChangeTimer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接从事件对象中获取最新的中心点位置
|
|
||||||
const centerLocation = e.detail?.centerLocation || e.centerLocation
|
|
||||||
|
|
||||||
if (centerLocation && centerLocation.longitude && centerLocation.latitude) {
|
if (centerLocation && centerLocation.longitude && centerLocation.latitude) {
|
||||||
// 防抖:500ms后执行查询
|
// 防抖:500ms后执行查询
|
||||||
regionChangeTimer = setTimeout(() => {
|
regionChangeTimer = setTimeout(() => {
|
||||||
@@ -298,13 +333,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
mapCenter.value = newCenter;
|
mapCenter.value = newCenter;
|
||||||
|
|
||||||
|
|
||||||
// 触发父组件查询新位置的场地
|
// 触发父组件查询新位置的场地
|
||||||
emit('mapCenterChange', newCenter)
|
emit('mapCenterChange', newCenter)
|
||||||
}, 500)
|
}, 500)
|
||||||
} else {
|
} else {
|
||||||
// 兜底方案:如果事件中没有centerLocation,才使用API获取
|
// 兜底方案:使用API获取地图中心
|
||||||
regionChangeTimer = setTimeout(() => {
|
regionChangeTimer = setTimeout(() => {
|
||||||
if (mapContext.value) {
|
if (mapContext.value) {
|
||||||
mapContext.value.getCenterLocation({
|
mapContext.value.getCenterLocation({
|
||||||
@@ -328,12 +361,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记点点击事件
|
// 标记点点击事件(支付宝小程序)
|
||||||
const onMapMarkerTap = (e) => {
|
const onMapMarkerTap = (e) => {
|
||||||
const markerId = e.detail?.markerId || e.markerId
|
if (!e) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取markerId
|
||||||
|
const markerId = e.detail?.markerId || e.markerId || e.detail?.marker?.id
|
||||||
|
|
||||||
// 查找对应的场地位置信息
|
// 查找对应的场地位置信息
|
||||||
if (props.filteredPositions && props.filteredPositions.length > 0) {
|
if (props.filteredPositions && props.filteredPositions.length > 0 && markerId) {
|
||||||
const position = props.filteredPositions[markerId - 1]
|
const position = props.filteredPositions[markerId - 1]
|
||||||
if (position) {
|
if (position) {
|
||||||
emit('markerTap', position)
|
emit('markerTap', position)
|
||||||
@@ -341,14 +379,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记点气泡点击事件
|
// 地图点击事件(支付宝小程序)
|
||||||
const onCalloutTap = (e) => {
|
const onMapTap = (e) => {
|
||||||
const markerId = e.markerId
|
console.log('地图点击事件:', e)
|
||||||
const marker = mapMarkers.value.find(item => item.id === markerId)
|
|
||||||
|
|
||||||
if (marker && marker.position) {
|
|
||||||
emit('markerTap', marker.position)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 地图错误事件
|
// 地图错误事件
|
||||||
@@ -391,35 +424,6 @@ const handleSearch = () => {
|
|||||||
handleJoinTap()
|
handleJoinTap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动广告轮播
|
|
||||||
const startBannerRotation = () => {
|
|
||||||
// 如果只有一张或没有图片,不需要轮播
|
|
||||||
if (!props.bannerImages || props.bannerImages.length <= 1) {
|
|
||||||
console.log('图片数量不足,不启动轮播')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清除旧的定时器
|
|
||||||
stopBannerRotation()
|
|
||||||
|
|
||||||
console.log('开始广告轮播定时器')
|
|
||||||
// 每3秒切换一次
|
|
||||||
bannerTimer = setInterval(() => {
|
|
||||||
const nextIndex = (currentBannerIndex.value + 1) % props.bannerImages.length
|
|
||||||
console.log('轮播切换:', currentBannerIndex.value, '->', nextIndex)
|
|
||||||
currentBannerIndex.value = nextIndex
|
|
||||||
}, 3000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 停止广告轮播
|
|
||||||
const stopBannerRotation = () => {
|
|
||||||
if (bannerTimer) {
|
|
||||||
console.log('停止广告轮播')
|
|
||||||
clearInterval(bannerTimer)
|
|
||||||
bannerTimer = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleScan = () => {
|
const handleScan = () => {
|
||||||
emit('scan')
|
emit('scan')
|
||||||
}
|
}
|
||||||
@@ -595,7 +599,7 @@ const handleSearch = () => {
|
|||||||
// min-width: 160rpx;
|
// min-width: 160rpx;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
// height: 72rpx;
|
// height: 72rpx;
|
||||||
background: rgba(255, 255, 255, 0.96);
|
// background: rgba(255, 255, 255, 0.96);
|
||||||
border-radius: 36rpx;
|
border-radius: 36rpx;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|||||||
@@ -8,22 +8,22 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="header-right">
|
<view class="header-right">
|
||||||
<!-- 支付方式标识(移到头部右侧) -->
|
<!-- 支付方式标识(移到头部右侧) -->
|
||||||
<view class="payment-badge wx-score" v-if="order.payWay == 'wx_score_pay'">
|
<view class="payment-badge alipay-score" v-if="order.payWay == 'alipay_score_pay'">
|
||||||
<image src="/static/images/wxpayflag.png" mode="aspectFit" class="badge-icon"></image>
|
<image src="/static/images/alipay.svg" mode="aspectFit" class="badge-icon"></image>
|
||||||
<view class="badge-text">
|
<view class="badge-text">
|
||||||
<text>{{ $t('order.wxPayScore') }}</text>
|
<text>{{ $t('order.alipayScore') }}</text>
|
||||||
<text class="divider">|</text>
|
<text class="divider">|</text>
|
||||||
<text class="highlight">{{ $t('order.depositFree') }}</text>
|
<text class="highlight">{{ $t('order.depositFree') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="payment-badge whitelist" v-else-if="order.payWay == 'wx_global_pay'">
|
<view class="payment-badge whitelist" v-else-if="order.payWay == 'alipay_global_pay'">
|
||||||
<text class="badge-text">{{ $t('order.whitelistOrder') }}</text>
|
<text class="badge-text">{{ $t('order.whitelistOrder') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="payment-badge member" v-else-if="order.payWay == 'wx_member_pay'">
|
<view class="payment-badge member" v-else-if="order.payWay == 'alipay_member_pay'">
|
||||||
<text class="badge-text">{{ $t('order.memberOrder') }}</text>
|
<text class="badge-text">{{ $t('order.memberOrder') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="payment-badge deposit" v-else>
|
<view class="payment-badge deposit" v-else>
|
||||||
<text class="badge-text">{{ $t('order.wxPay') }}</text>
|
<text class="badge-text">{{ $t('order.alipayPay') }}</text>
|
||||||
<text class="divider">|</text>
|
<text class="divider">|</text>
|
||||||
<text class="badge-text">{{ $t('order.depositPay') }}</text>
|
<text class="badge-text">{{ $t('order.depositPay') }}</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
|
|
||||||
const emit = defineEmits(['pay', 'cancel', 'return-device', 'details']);
|
const emit = defineEmits(['pay', 'cancel', 'return-device', 'details']);
|
||||||
|
|
||||||
const rawStatus = computed(() => props.order.orderStatus ?? props.order.status);
|
const rawStatus = computed(() => props.order.orderStatus != null ? props.order.orderStatus : props.order.status);
|
||||||
const normalizedStatus = computed(() => {
|
const normalizedStatus = computed(() => {
|
||||||
const s = rawStatus.value;
|
const s = rawStatus.value;
|
||||||
switch (s) {
|
switch (s) {
|
||||||
@@ -272,8 +272,8 @@
|
|||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
&.wx-score {
|
&.alipay-score {
|
||||||
background: rgba(7, 193, 96, 0.08);
|
background: rgba(0, 122, 255, 0.08);
|
||||||
|
|
||||||
.badge-icon {
|
.badge-icon {
|
||||||
width: 32rpx;
|
width: 32rpx;
|
||||||
@@ -283,7 +283,7 @@
|
|||||||
|
|
||||||
.badge-text {
|
.badge-text {
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
color: #07c160;
|
color: #007AFF;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -76,21 +76,21 @@ export const getOrderByOrderNo = (orderNo) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过订单号获取支付分订单信息
|
// 通过订单号创建支付宝支付订单(芝麻信用免押)
|
||||||
export const getOrderByOrderNoScore = (orderNo) => {
|
export const getOrderByOrderNoScore = (orderNo) => {
|
||||||
console.log('通过订单号获取支付分订单信息', orderNo);
|
console.log('通过订单号创建支付宝支付订单(芝麻信用免押)', orderNo);
|
||||||
return request({
|
return request({
|
||||||
url: `/app/wx-payment/score/create/${orderNo}`,
|
url: `/app/ali-payment/create/${orderNo}`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
hideLoading: true
|
hideLoading: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过订单号获取支付分订单状态
|
// 通过订单号查询支付宝订单支付状态
|
||||||
export const getOrderByOrderNoScorePayStatus = (orderNo) => {
|
export const getOrderByOrderNoScorePayStatus = (orderNo) => {
|
||||||
console.log('通过订单号获取支付分订单状态', orderNo);
|
console.log('通过订单号查询支付宝订单支付状态', orderNo);
|
||||||
return request({
|
return request({
|
||||||
url: `/app/wx-payment/score/status/${orderNo}`,
|
url: `/app/ali-payment/status/${orderNo}`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
hideLoading: true
|
hideLoading: true
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ const request = (option) => {
|
|||||||
"Content-Type": option.headers && option.headers["Content-Type"] ? option.headers["Content-Type"] : (option.method && option.method.toUpperCase() === 'POST' ? 'application/json' : 'application/x-www-form-urlencoded'),
|
"Content-Type": option.headers && option.headers["Content-Type"] ? option.headers["Content-Type"] : (option.method && option.method.toUpperCase() === 'POST' ? 'application/json' : 'application/x-www-form-urlencoded'),
|
||||||
...option.headers,
|
...option.headers,
|
||||||
'appid': appid,
|
'appid': appid,
|
||||||
|
'platform': 'alipay', // 标识支付宝小程序平台
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
'Clientid': uni.getStorageSync('client_id')
|
||||||
},
|
},
|
||||||
|
|||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
// export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用
|
// export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用
|
||||||
// export const URL = "https://manager.fdzpower.com/api" //正式服务器
|
export const URL = "https://manager.fdzpower.com/api" //正式服务器
|
||||||
export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
// export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
||||||
// export const URL = "http://192.168.5.30:8080" //本地调试
|
// export const URL = "http://192.168.5.30:8080" //本地调试
|
||||||
// export const URL = "http://127.0.0.1:8080" //本地调试
|
// export const URL = "http://127.0.0.1:8080" //本地调试
|
||||||
|
|
||||||
export const appid = "wx2165f0be356ae7a9" //微信小程序appid
|
export const appid = "2021006117693332" //支付宝小程序appid
|
||||||
export const ZFBappid = "2021006117693332" //支付宝小程序appid
|
export const ZFBappid = "2021006117693332" //支付宝小程序appid(保留兼容)
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
# 支付宝支付接口文档
|
||||||
|
|
||||||
|
## 接口概述
|
||||||
|
本文档描述支付宝支付相关的API接口,包括创建支付订单和查询支付状态。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 创建支付宝支付订单
|
||||||
|
|
||||||
|
### 接口描述
|
||||||
|
创建支付宝支付订单,用于扫码预下单并返回二维码。
|
||||||
|
|
||||||
|
### 请求信息
|
||||||
|
|
||||||
|
#### 请求URL
|
||||||
|
```
|
||||||
|
GET /app/ali-payment/create/{orderNo}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 请求方式
|
||||||
|
`GET`
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
|
||||||
|
| 参数名 | 参数类型 | 是否必填 | 参数位置 | 参数说明 |
|
||||||
|
|--------|----------|----------|----------|----------|
|
||||||
|
| orderNo | String | 是 | Path | 订单号 |
|
||||||
|
|
||||||
|
#### 请求示例
|
||||||
|
```http
|
||||||
|
GET /app/ali-payment/create/ORD20231223001
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应信息
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
|
||||||
|
| 参数名 | 参数类型 | 参数说明 |
|
||||||
|
|--------|----------|----------|
|
||||||
|
| code | Integer | 响应状态码,200表示成功 |
|
||||||
|
| msg | String | 响应消息 |
|
||||||
|
| data | Object | 返回数据,包含支付宝支付相关信息 |
|
||||||
|
|
||||||
|
#### 响应示例
|
||||||
|
|
||||||
|
成功响应:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"msg": "操作成功",
|
||||||
|
"data": {
|
||||||
|
"qrCode": "https://qr.alipay.com/xxx",
|
||||||
|
"outTradeNo": "ORD20231223001",
|
||||||
|
"totalAmount": "99.00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
失败响应:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 500,
|
||||||
|
"msg": "订单不存在或已支付"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 错误码说明
|
||||||
|
|
||||||
|
| 错误码 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| 200 | 创建成功 |
|
||||||
|
| 400 | 参数错误,订单号不能为空 |
|
||||||
|
| 500 | 系统错误或订单状态异常 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 查询订单支付状态
|
||||||
|
|
||||||
|
### 接口描述
|
||||||
|
查询指定订单的支付状态。
|
||||||
|
|
||||||
|
### 请求信息
|
||||||
|
|
||||||
|
#### 请求URL
|
||||||
|
```
|
||||||
|
GET /app/ali-payment/status/{orderNo}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 请求方式
|
||||||
|
`GET`
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
|
||||||
|
| 参数名 | 参数类型 | 是否必填 | 参数位置 | 参数说明 |
|
||||||
|
|--------|----------|----------|----------|----------|
|
||||||
|
| orderNo | String | 是 | Path | 订单号 |
|
||||||
|
|
||||||
|
#### 请求示例
|
||||||
|
```http
|
||||||
|
GET /app/ali-payment/status/ORD20231223001
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应信息
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
|
||||||
|
| 参数名 | 参数类型 | 参数说明 |
|
||||||
|
|--------|----------|----------|
|
||||||
|
| code | Integer | 响应状态码,200表示成功 |
|
||||||
|
| msg | String | 响应消息 |
|
||||||
|
| data | Object | 订单支付状态信息 |
|
||||||
|
| data.tradeStatus | String | 交易状态(WAIT_BUYER_PAY-等待支付,TRADE_SUCCESS-支付成功,TRADE_CLOSED-交易关闭) |
|
||||||
|
| data.tradeNo | String | 支付宝交易号 |
|
||||||
|
| data.totalAmount | String | 订单金额 |
|
||||||
|
| data.buyerPayAmount | String | 买家实付金额 |
|
||||||
|
|
||||||
|
#### 响应示例
|
||||||
|
|
||||||
|
支付成功响应:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"msg": "操作成功",
|
||||||
|
"data": {
|
||||||
|
"tradeStatus": "TRADE_SUCCESS",
|
||||||
|
"tradeNo": "2023122322001234567890",
|
||||||
|
"outTradeNo": "ORD20231223001",
|
||||||
|
"totalAmount": "99.00",
|
||||||
|
"buyerPayAmount": "99.00",
|
||||||
|
"buyerLogonId": "158****5620"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
等待支付响应:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"msg": "操作成功",
|
||||||
|
"data": {
|
||||||
|
"tradeStatus": "WAIT_BUYER_PAY",
|
||||||
|
"outTradeNo": "ORD20231223001",
|
||||||
|
"totalAmount": "99.00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
失败响应:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 500,
|
||||||
|
"msg": "订单不存在"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 支付状态说明
|
||||||
|
|
||||||
|
| 状态码 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| WAIT_BUYER_PAY | 交易创建,等待买家付款 |
|
||||||
|
| TRADE_CLOSED | 未付款交易超时关闭,或支付完成后全额退款 |
|
||||||
|
| TRADE_SUCCESS | 交易支付成功 |
|
||||||
|
| TRADE_FINISHED | 交易结束,不可退款 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 公共说明
|
||||||
|
|
||||||
|
### 基础路径
|
||||||
|
```
|
||||||
|
http://your-domain.com/app/ali-payment
|
||||||
|
```
|
||||||
|
|
||||||
|
### 请求头
|
||||||
|
```
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
### 注意事项
|
||||||
|
|
||||||
|
1. **订单号格式**:订单号必须唯一,建议使用系统生成的订单编号
|
||||||
|
2. **幂等性**:同一订单号多次调用创建接口,返回相同的支付信息
|
||||||
|
3. **超时处理**:支付订单创建后,建议在15分钟内完成支付
|
||||||
|
4. **状态查询**:建议在支付完成后通过回调通知处理业务逻辑,状态查询接口用于补充查询
|
||||||
|
5. **安全性**:生产环境建议添加签名验证和请求频率限制
|
||||||
|
|
||||||
|
### 业务流程
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 用户发起租借 → 系统创建订单
|
||||||
|
2. 调用创建支付接口 → 返回支付二维码
|
||||||
|
3. 用户扫码支付 → 支付宝处理支付
|
||||||
|
4. 支付宝回调通知 → 系统更新订单状态
|
||||||
|
5. 前端轮询状态接口 → 确认支付结果
|
||||||
|
6. 支付成功 → 触发开锁逻辑
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 联系方式
|
||||||
|
|
||||||
|
如有问题,请联系技术支持团队。
|
||||||
|
|
||||||
|
**文档版本**:v1.0
|
||||||
|
**最后更新**:2025-12-23
|
||||||
|
**维护人员**:开发团队
|
||||||
|
|
||||||
+5
-6
@@ -97,7 +97,7 @@ export default {
|
|||||||
step1Title: 'Scan QR Code',
|
step1Title: 'Scan QR Code',
|
||||||
step1Desc: 'Find a device and scan its QR code',
|
step1Desc: 'Find a device and scan its QR code',
|
||||||
step2Title: 'No Deposit',
|
step2Title: 'No Deposit',
|
||||||
step2Desc: 'Rent with WeChat Pay Score, no deposit needed',
|
step2Desc: 'Rent with Sesame Credit, no deposit needed',
|
||||||
step3Title: 'Start Using',
|
step3Title: 'Start Using',
|
||||||
step3Desc: 'Device unlocks, take out the fan',
|
step3Desc: 'Device unlocks, take out the fan',
|
||||||
step4Title: 'Return',
|
step4Title: 'Return',
|
||||||
@@ -134,7 +134,7 @@ export default {
|
|||||||
autoChargeOvertime: 'Overtime will be charged automatically by hour',
|
autoChargeOvertime: 'Overtime will be charged automatically by hour',
|
||||||
useInDesignatedArea: 'Please use the device in designated area',
|
useInDesignatedArea: 'Please use the device in designated area',
|
||||||
rentDepositFree: 'Rent Deposit-free',
|
rentDepositFree: 'Rent Deposit-free',
|
||||||
wxPayScoreDesc: 'WeChat Pay Score | 550+ points enjoy',
|
alipayScoreDesc: 'Sesame Credit | 550+ points enjoy',
|
||||||
checking: 'Checking',
|
checking: 'Checking',
|
||||||
deviceNoNotRecognized: 'Device number not recognized',
|
deviceNoNotRecognized: 'Device number not recognized',
|
||||||
processFailed: 'Process failed, please try again later',
|
processFailed: 'Process failed, please try again later',
|
||||||
@@ -144,7 +144,7 @@ export default {
|
|||||||
rentSuccess: 'Rent successful',
|
rentSuccess: 'Rent successful',
|
||||||
rentFailedRetry: 'Rent failed, please retry',
|
rentFailedRetry: 'Rent failed, please retry',
|
||||||
getPayParamsFailed: 'Failed to get payment parameters',
|
getPayParamsFailed: 'Failed to get payment parameters',
|
||||||
payScoreFailedCancelled: 'Pay score call failed, order cancelled'
|
payScoreFailedCancelled: 'Credit payment failed, order cancelled'
|
||||||
},
|
},
|
||||||
|
|
||||||
order: {
|
order: {
|
||||||
@@ -190,11 +190,11 @@ export default {
|
|||||||
returnFailed: 'Return failed',
|
returnFailed: 'Return failed',
|
||||||
confirmCancel: 'Confirm to cancel order?',
|
confirmCancel: 'Confirm to cancel order?',
|
||||||
confirmReturn: 'Confirm to return device?',
|
confirmReturn: 'Confirm to return device?',
|
||||||
wxPayScore: 'WeChat Pay Score',
|
alipayScore: 'Sesame Credit',
|
||||||
|
alipayPay: 'Alipay',
|
||||||
depositFree: 'Deposit-free',
|
depositFree: 'Deposit-free',
|
||||||
whitelistOrder: 'Whitelist Order',
|
whitelistOrder: 'Whitelist Order',
|
||||||
memberOrder: 'Member Order',
|
memberOrder: 'Member Order',
|
||||||
wxPay: 'WeChat Pay',
|
|
||||||
depositPay: 'Deposit Pay',
|
depositPay: 'Deposit Pay',
|
||||||
paymentInProgress: 'Payment in Progress',
|
paymentInProgress: 'Payment in Progress',
|
||||||
paymentFailedRetry: 'Payment failed, please try again',
|
paymentFailedRetry: 'Payment failed, please try again',
|
||||||
@@ -318,7 +318,6 @@ export default {
|
|||||||
payment: {
|
payment: {
|
||||||
paymentAmount: 'Amount',
|
paymentAmount: 'Amount',
|
||||||
paymentMethod: 'Method',
|
paymentMethod: 'Method',
|
||||||
wechatPay: 'WeChat',
|
|
||||||
alipay: 'Alipay',
|
alipay: 'Alipay',
|
||||||
balance: 'Balance',
|
balance: 'Balance',
|
||||||
payNow: 'Pay',
|
payNow: 'Pay',
|
||||||
|
|||||||
+9
-8
@@ -60,7 +60,7 @@ export default {
|
|||||||
orders: '订单',
|
orders: '订单',
|
||||||
settings: '设置',
|
settings: '设置',
|
||||||
back: '返回',
|
back: '返回',
|
||||||
title: '风电者共享风扇&暖手充电宝'
|
title: '风电者共享风扇&暖手宝'
|
||||||
},
|
},
|
||||||
|
|
||||||
app: {
|
app: {
|
||||||
@@ -71,7 +71,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
home: {
|
home: {
|
||||||
title: '风电者共享风扇&暖手充电宝',
|
title: '风电者共享风扇&暖手宝',
|
||||||
nearbyDevices: '附近设备',
|
nearbyDevices: '附近设备',
|
||||||
scanToUse: '扫码使用',
|
scanToUse: '扫码使用',
|
||||||
personalCenter: '个人中心',
|
personalCenter: '个人中心',
|
||||||
@@ -97,7 +97,7 @@ export default {
|
|||||||
step1Title: '扫码使用',
|
step1Title: '扫码使用',
|
||||||
step1Desc: '找到附近设备,扫描设备上的二维码',
|
step1Desc: '找到附近设备,扫描设备上的二维码',
|
||||||
step2Title: '免押金支付',
|
step2Title: '免押金支付',
|
||||||
step2Desc: '无需支付押金,使用支付分免押即可完成租借',
|
step2Desc: '无需支付押金,使用芝麻信用免押即可完成租借',
|
||||||
step3Title: '开始使用',
|
step3Title: '开始使用',
|
||||||
step3Desc: '设备自动解锁,风扇弹出后取出即可开始使用',
|
step3Desc: '设备自动解锁,风扇弹出后取出即可开始使用',
|
||||||
step4Title: '归还设备',
|
step4Title: '归还设备',
|
||||||
@@ -134,7 +134,7 @@ export default {
|
|||||||
autoChargeOvertime: '超出使用时间将自动按小时计费',
|
autoChargeOvertime: '超出使用时间将自动按小时计费',
|
||||||
useInDesignatedArea: '请在指定区域内使用设备',
|
useInDesignatedArea: '请在指定区域内使用设备',
|
||||||
rentDepositFree: '免押金租借',
|
rentDepositFree: '免押金租借',
|
||||||
wxPayScoreDesc: '微信支付分 | 550分以上优享',
|
alipayScoreDesc: '芝麻信用免押 | 550分以上优享',
|
||||||
checking: '检查中',
|
checking: '检查中',
|
||||||
deviceNoNotRecognized: '未识别到设备编号',
|
deviceNoNotRecognized: '未识别到设备编号',
|
||||||
processFailed: '处理失败,请稍后重试',
|
processFailed: '处理失败,请稍后重试',
|
||||||
@@ -144,7 +144,7 @@ export default {
|
|||||||
rentSuccess: '租借成功',
|
rentSuccess: '租借成功',
|
||||||
rentFailedRetry: '租借失败,请重试',
|
rentFailedRetry: '租借失败,请重试',
|
||||||
getPayParamsFailed: '获取支付参数失败',
|
getPayParamsFailed: '获取支付参数失败',
|
||||||
payScoreFailedCancelled: '支付分调用失败,订单已取消'
|
payScoreFailedCancelled: '信用支付调用失败,订单已取消'
|
||||||
},
|
},
|
||||||
|
|
||||||
order: {
|
order: {
|
||||||
@@ -190,11 +190,11 @@ export default {
|
|||||||
returnFailed: '归还失败',
|
returnFailed: '归还失败',
|
||||||
confirmCancel: '确认取消订单?',
|
confirmCancel: '确认取消订单?',
|
||||||
confirmReturn: '确认归还设备?',
|
confirmReturn: '确认归还设备?',
|
||||||
wxPayScore: '微信支付分',
|
alipayScore: '芝麻信用免押',
|
||||||
depositFree: '免押租借',
|
depositFree: '免押租借',
|
||||||
whitelistOrder: '白名单订单',
|
whitelistOrder: '白名单订单',
|
||||||
memberOrder: '会员订单',
|
memberOrder: '会员订单',
|
||||||
wxPay: '微信支付',
|
alipayPay: '支付宝支付',
|
||||||
depositPay: '押金租借',
|
depositPay: '押金租借',
|
||||||
paymentInProgress: '支付中',
|
paymentInProgress: '支付中',
|
||||||
paymentFailedRetry: '支付失败,请重新支付',
|
paymentFailedRetry: '支付失败,请重新支付',
|
||||||
@@ -291,6 +291,7 @@ export default {
|
|||||||
getUserInfoSuccess: '获取用户信息成功',
|
getUserInfoSuccess: '获取用户信息成功',
|
||||||
getUserInfoFailed: '获取用户信息失败',
|
getUserInfoFailed: '获取用户信息失败',
|
||||||
pleaseUseInWechat: '请在微信小程序中使用此功能',
|
pleaseUseInWechat: '请在微信小程序中使用此功能',
|
||||||
|
pleaseUseInAlipay: '请在支付宝小程序中使用此功能',
|
||||||
agreeToTerms: '我已阅读并同意',
|
agreeToTerms: '我已阅读并同意',
|
||||||
pleaseAgreeToTerms: '请先阅读并同意《用户协议》和《隐私政策》',
|
pleaseAgreeToTerms: '请先阅读并同意《用户协议》和《隐私政策》',
|
||||||
loginSuccess: '登录成功',
|
loginSuccess: '登录成功',
|
||||||
@@ -318,7 +319,7 @@ export default {
|
|||||||
payment: {
|
payment: {
|
||||||
paymentAmount: '支付金额',
|
paymentAmount: '支付金额',
|
||||||
paymentMethod: '支付方式',
|
paymentMethod: '支付方式',
|
||||||
wechatPay: '微信支付',
|
alipayPay: '支付宝支付',
|
||||||
alipay: '支付宝',
|
alipay: '支付宝',
|
||||||
balance: '余额支付',
|
balance: '余额支付',
|
||||||
payNow: '立即支付',
|
payNow: '立即支付',
|
||||||
|
|||||||
+9
-19
@@ -43,36 +43,26 @@
|
|||||||
"ios" : {},
|
"ios" : {},
|
||||||
"sdkConfigs" : {
|
"sdkConfigs" : {
|
||||||
"maps" : {
|
"maps" : {
|
||||||
"amap" : {
|
"qqmap" : {
|
||||||
"appkey_ios" : "4c513a688938fd89b88b296e867f66ec",
|
"appkey_ios" : "RO5BZ-ECZ63-7US3C-RT5QW-TIDZE-2FF35",
|
||||||
"appkey_android" : "4c513a688938fd89b88b296e867f66ec"
|
"appkey_android" : "RO5BZ-ECZ63-7US3C-RT5QW-TIDZE-2FF35"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"quickapp" : {},
|
"quickapp" : {},
|
||||||
"mp-weixin" : {
|
|
||||||
"appid" : "wx2165f0be356ae7a9",
|
|
||||||
"setting" : {
|
|
||||||
"urlCheck" : false
|
|
||||||
},
|
|
||||||
"usingComponents" : true,
|
|
||||||
"permission" : {
|
|
||||||
"scope.getPhoneNumber" : {
|
|
||||||
"desc" : "您的手机号将用于登录和订单服务"
|
|
||||||
},
|
|
||||||
"scope.userLocation" : {
|
|
||||||
"desc" : "您的位置信息将用于获取附近的设备"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"requiredPrivateInfos" : [ "getLocation", "chooseLocation" ]
|
|
||||||
},
|
|
||||||
"mp-alipay" : {
|
"mp-alipay" : {
|
||||||
|
"component2": true,
|
||||||
"usingComponents" : true,
|
"usingComponents" : true,
|
||||||
"appid" : "2021006117693332",
|
"appid" : "2021006117693332",
|
||||||
"unipush" : {
|
"unipush" : {
|
||||||
"enable" : false
|
"enable" : false
|
||||||
|
},
|
||||||
|
"permission" : {
|
||||||
|
"scope.userLocation" : {
|
||||||
|
"desc" : "您的位置信息将用于获取附近的设备"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mp-baidu" : {
|
"mp-baidu" : {
|
||||||
|
|||||||
+20
-45
@@ -72,12 +72,12 @@
|
|||||||
<!-- 底部操作区 -->
|
<!-- 底部操作区 -->
|
||||||
<view class="footer">
|
<view class="footer">
|
||||||
<button class="rent-button" :class="{ 'return-button': hasActiveOrder }"
|
<button class="rent-button" :class="{ 'return-button': hasActiveOrder }"
|
||||||
@click="handleRent('wx-score-pay')">
|
@click="handleRent('alipay-score-pay')">
|
||||||
<text>{{ hasActiveOrder ? $t('order.returnDevice') : $t('device.rentDepositFree') }}</text>
|
<text>{{ hasActiveOrder ? $t('order.returnDevice') : $t('device.rentDepositFree') }}</text>
|
||||||
</button>
|
</button>
|
||||||
<view class="wechat-credit">
|
<view class="alipay-credit">
|
||||||
<image src="/static/images/wxpayflag.png" mode="aspectFit" class="wx-icon"></image>
|
<image src="/static/images/alipay.svg" mode="aspectFit" class="alipay-icon"></image>
|
||||||
<text class="credit-text">{{ $t('device.wxPayScoreDesc') }}</text>
|
<text class="credit-text">{{ $t('device.alipayScoreDesc') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
cancelOrder
|
cancelOrder
|
||||||
} from '@/config/api/order.js'
|
} from '@/config/api/order.js'
|
||||||
import {
|
import {
|
||||||
initiateWeChatScorePayment,
|
initiateAlipayPayment,
|
||||||
getUserInfo,
|
getUserInfo,
|
||||||
getUserPhoneNumber
|
getUserPhoneNumber
|
||||||
} from '@/util/index.js'
|
} from '@/util/index.js'
|
||||||
@@ -466,32 +466,8 @@
|
|||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: $t('common.processing')
|
title: $t('common.processing')
|
||||||
})
|
})
|
||||||
// --- 第一步:先请求订阅消息(必须在用户点击的同步上下文中)---
|
// --- 支付宝小程序不需要订阅消息,移除相关代码 ---
|
||||||
if (payWay === 'wx-score-pay') {
|
// 支付宝小程序使用消息推送,不需要订阅消息
|
||||||
console.log('准备请求订阅消息(在异步操作之前),时间:', new Date().toLocaleTimeString());
|
|
||||||
try {
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
uni.requestSubscribeMessage({
|
|
||||||
tmplIds: ['o7OMTIcHnFBR7mvsggxFtdt8FfIgSl-v0swVUefGx6w'],
|
|
||||||
success: (subscribeRes) => {
|
|
||||||
console.log('订阅消息success回调,时间:', new Date()
|
|
||||||
.toLocaleTimeString(), subscribeRes);
|
|
||||||
resolve(subscribeRes);
|
|
||||||
},
|
|
||||||
fail: (subscribeErr) => {
|
|
||||||
console.log('订阅消息fail回调,时间:', new Date().toLocaleTimeString(),
|
|
||||||
subscribeErr);
|
|
||||||
// 订阅失败不影响主流程
|
|
||||||
resolve(subscribeErr);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
console.log('订阅消息完成,时间:', new Date().toLocaleTimeString());
|
|
||||||
} catch (subscribeError) {
|
|
||||||
console.log('订阅消息异常', subscribeError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// --- 订阅消息请求完成 ---
|
|
||||||
|
|
||||||
console.log(deviceId.value);
|
console.log(deviceId.value);
|
||||||
// 调用设备租借接口
|
// 调用设备租借接口
|
||||||
@@ -504,7 +480,7 @@
|
|||||||
const order = rentResult.data
|
const order = rentResult.data
|
||||||
console.log('订单信息', order);
|
console.log('订单信息', order);
|
||||||
|
|
||||||
if (payWay == 'wx-pay') {
|
if (payWay == 'alipay-pay') {
|
||||||
// 当支付方式为押金支付时
|
// 当支付方式为押金支付时
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
const res = await getOrderByOrderNo(order.orderNo);
|
const res = await getOrderByOrderNo(order.orderNo);
|
||||||
@@ -519,29 +495,28 @@
|
|||||||
url: `/pages/order/payment?orderId=${order.orderId}&packagePrice=${packagePrice}&totalAmount=${totalAmount}&depositAmount=${deposit}${deviceInfo.value && deviceInfo.value.feeConfig ? '&feeConfig=' + encodeURIComponent(deviceInfo.value.feeConfig) : ''}`
|
url: `/pages/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') {
|
} else if (payWay == 'alipay-score-pay') {
|
||||||
// 当支付方式为支付分支付时
|
// 当支付方式为支付宝信用免押支付时
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
// 获取支付分所需参数
|
// 获取支付宝信用免押所需参数
|
||||||
const res = await getOrderByOrderNoScore(order.orderNo);
|
const res = await getOrderByOrderNoScore(order.orderNo);
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
|
|
||||||
if (res && res.code === 200) {
|
if (res && res.code === 200) {
|
||||||
try {
|
try {
|
||||||
// 调用微信支付分小程序
|
// 调用支付宝信用免押小程序
|
||||||
const payResult = await initiateWeChatScorePayment(res);
|
const payResult = await initiateAlipayPayment(res);
|
||||||
console.log('支付分调用结果', payResult);
|
console.log('支付宝信用免押调用结果', payResult);
|
||||||
// 成功则跳转到等待页面
|
// 成功则跳转到等待页面
|
||||||
if (payResult.errCode == '0' && payResult.extraData && Object.keys(payResult.extraData)
|
if (payResult && payResult.success !== false) {
|
||||||
.length > 0) {
|
console.log('支付宝信用免押授权成功,准备跳转到等待页,时间:', new Date().toLocaleTimeString());
|
||||||
console.log('支付分授权成功,准备跳转到等待页,时间:', new Date().toLocaleTimeString());
|
// 跳转到等待页面
|
||||||
// 跳转到等待页面(订阅消息已经在前面完成了)
|
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
url: `/pages/waiting/index?orderNo=${order.orderNo}&orderId=${order.orderId}&deviceId=${deviceId.value}`
|
url: `/pages/waiting/index?orderNo=${order.orderNo}&orderId=${order.orderId}&deviceId=${deviceId.value}`
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
console.log('支付分未完成授权或用户取消,extraData:', payResult.extraData);
|
console.log('支付宝信用免押未完成授权或用户取消:', payResult);
|
||||||
// 用户取消授权,需要取消订单
|
// 用户取消授权,需要取消订单
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
@@ -876,13 +851,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.wechat-credit {
|
.alipay-credit {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 16rpx;
|
margin-top: 16rpx;
|
||||||
|
|
||||||
.wx-icon {
|
.alipay-icon {
|
||||||
width: 48rpx;
|
width: 48rpx;
|
||||||
height: 38rpx;
|
height: 38rpx;
|
||||||
margin-right: 8rpx;
|
margin-right: 8rpx;
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
// 获取图片列表(支持字符串或数组)
|
// 获取图片列表(支持字符串或数组)
|
||||||
const getImageList = (item) => {
|
const getImageList = (item) => {
|
||||||
if (!item) return [];
|
if (!item) return [];
|
||||||
const pictureSource = item.pictureUrls ?? item.picturePath;
|
const pictureSource = item.pictureUrls != null ? item.pictureUrls : item.picturePath;
|
||||||
if (!pictureSource) return [];
|
if (!pictureSource) return [];
|
||||||
if (Array.isArray(pictureSource)) {
|
if (Array.isArray(pictureSource)) {
|
||||||
return pictureSource.filter(img => !!img);
|
return pictureSource.filter(img => !!img);
|
||||||
|
|||||||
+30
-25
@@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="container fullscreen">
|
<view class="container fullscreen">
|
||||||
<!-- 自定义导航栏 -->
|
<!-- 自定义导航栏 -->
|
||||||
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'rpx' }">
|
||||||
<view class="navbar-content" :style="{ height: navBarHeight + 'px' }">
|
<view class="navbar-content" :style="{ height: navBarHeight + 'rpx' }">
|
||||||
<text class="navbar-title">{{ $t('home.title') }}</text>
|
<text class="navbar-title">{{ $t('home.title') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 顶部信息区域(通知、招商等) -->
|
<!-- 顶部信息区域(通知、招商等) -->
|
||||||
<view class="top-info-section" :style="{ top: (statusBarHeight + navBarHeight) + 'px' }">
|
<view class="top-info-section" :style="{ top: (statusBarHeight + navBarHeight) + 'rpx' }">
|
||||||
<!-- 通知栏 -->
|
<!-- 通知栏 -->
|
||||||
<view class="notice-wrapper" v-if="noticeText" @click="openNoticePopup">
|
<view class="notice-wrapper" v-if="noticeText" @click="openNoticePopup">
|
||||||
<uv-notice-bar :text="noticeText" :speed="50" :show-icon="true" color="#07c160" bg-color="#E8F8EF"
|
<uv-notice-bar :text="noticeText" :speed="50" :show-icon="true" color="#07c160" bg-color="#E8F8EF"
|
||||||
@@ -17,13 +17,14 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<view class="main-content" :style="{ paddingTop: (statusBarHeight + navBarHeight + noticeHeight) + 'px' }">
|
<view class="main-content"
|
||||||
|
:style="{ paddingTop: (statusBarHeight + navBarHeight+navBarHeight + noticeHeight) + 'rpx' }">
|
||||||
<!-- 全屏地图组件 -->
|
<!-- 全屏地图组件 -->
|
||||||
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
|
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
|
||||||
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
|
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
|
||||||
:enableMarkers="true" :bannerImages="bannerImages"
|
:enableMarkers="true" :bannerImages="bannerImages"
|
||||||
:hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup"
|
:hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup" @relocate="handleRelocate"
|
||||||
@relocate="handleRelocate" @scan="handleScan" @showList="showLocationList" @markerTap="selectPosition"
|
@scan="handleScan" @showList="showLocationList" @markerTap="selectPosition"
|
||||||
@mapCenterChange="onMapCenterChange" @bannerClick="handleBannerClick" />
|
@mapCenterChange="onMapCenterChange" @bannerClick="handleBannerClick" />
|
||||||
|
|
||||||
<!-- 地图加载状态 -->
|
<!-- 地图加载状态 -->
|
||||||
@@ -187,7 +188,7 @@
|
|||||||
} from 'vue'
|
} from 'vue'
|
||||||
import {
|
import {
|
||||||
getQueryString,
|
getQueryString,
|
||||||
wxLogin
|
alipayLogin
|
||||||
} from '../../util/index.js'
|
} from '../../util/index.js'
|
||||||
import {
|
import {
|
||||||
URL
|
URL
|
||||||
@@ -218,12 +219,9 @@
|
|||||||
useI18n
|
useI18n
|
||||||
} from '../../utils/i18n.js'
|
} from '../../utils/i18n.js'
|
||||||
|
|
||||||
// 开启右上角分享菜单(仅 mp-weixin 有效)
|
// 支付宝小程序不支持分享菜单,移除相关代码
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-ALIPAY
|
||||||
wx.showShareMenu({
|
// 支付宝小程序分享功能通过页面配置实现
|
||||||
withShareTicket: true,
|
|
||||||
menus: ['shareAppMessage', 'shareTimeline']
|
|
||||||
})
|
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -260,7 +258,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '免押金支付',
|
title: '免押金支付',
|
||||||
desc: '无需支付押金,使用支付分免押即可完成租借'
|
desc: '无需支付押金,使用芝麻信用免押即可完成租借'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '开始使用',
|
title: '开始使用',
|
||||||
@@ -317,7 +315,7 @@
|
|||||||
'Content-Language': languageCode
|
'Content-Language': languageCode
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
type: 'wx_user_type' // 微信小程序用户端
|
type: 'zfb_user_type' // 支付宝小程序用户端
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -365,7 +363,7 @@
|
|||||||
'Content-Language': languageCode
|
'Content-Language': languageCode
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
appPlatform: 'wechat', // 微信平台
|
appPlatform: 'alipay', // 支付宝平台
|
||||||
appType: 'user' // 用户端
|
appType: 'user' // 用户端
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -394,7 +392,9 @@
|
|||||||
console.log('点击首页广告:', index, bannerImages.value[index])
|
console.log('点击首页广告:', index, bannerImages.value[index])
|
||||||
// 可以根据需要添加跳转逻辑
|
// 可以根据需要添加跳转逻辑
|
||||||
// 例如跳转到合作加盟页面
|
// 例如跳转到合作加盟页面
|
||||||
uni.navigateTo({ url: '/pages/join/index' })
|
uni.navigateTo({
|
||||||
|
url: '/pages/join/index'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询最近的活动
|
// 查询最近的活动
|
||||||
@@ -480,15 +480,13 @@
|
|||||||
const systemInfo = uni.getSystemInfoSync()
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
statusBarHeight.value = systemInfo.statusBarHeight || 0
|
statusBarHeight.value = systemInfo.statusBarHeight || 0
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-ALIPAY
|
||||||
// 获取胶囊按钮位置信息
|
// 支付宝小程序导航栏高度计算
|
||||||
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
navBarHeight.value = 44
|
||||||
// 计算导航栏内容高度:(胶囊底部坐标 - 状态栏高度) 确保与胶囊对齐
|
|
||||||
navBarHeight.value = (menuButtonInfo.top - systemInfo.statusBarHeight) * 2 + menuButtonInfo.height
|
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-ALIPAY
|
||||||
// 非微信小程序使用默认高度
|
// 其他平台使用默认高度
|
||||||
navBarHeight.value = 44
|
navBarHeight.value = 44
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
@@ -890,7 +888,11 @@
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
let deviceNo = getQueryString(scanResult.path, 'deviceNo')
|
// 兼容微信和支付宝小程序的扫码结果结构
|
||||||
|
// 微信小程序:scanResult.path
|
||||||
|
// 支付宝小程序:scanResult.result
|
||||||
|
const scanPath = scanResult.path || scanResult.result || ''
|
||||||
|
let deviceNo = getQueryString(scanPath, 'deviceNo')
|
||||||
|
|
||||||
if (!deviceNo) {
|
if (!deviceNo) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -1079,10 +1081,13 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
/* 支付宝小程序页面背景色通过外层 view 设置 */
|
||||||
.container {
|
.container {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
min-height: 100vh;
|
||||||
|
/* 支付宝小程序需要设置 min-height */
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<view class="p">Before using {{ brandName }}, please carefully read and fully understand all contents of this Agreement, especially the terms highlighted in bold (including but not limited to liability limitations, dispute resolution, applicable law, protection of minors, etc.). By clicking "Login/Use" or actually using the service, you are deemed to have read and agreed to be bound by this Agreement.</view>
|
<view class="p">Before using {{ brandName }}, please carefully read and fully understand all contents of this Agreement, especially the terms highlighted in bold (including but not limited to liability limitations, dispute resolution, applicable law, protection of minors, etc.). By clicking "Login/Use" or actually using the service, you are deemed to have read and agreed to be bound by this Agreement.</view>
|
||||||
|
|
||||||
<view class="h1">II. Account and Login</view>
|
<view class="h1">II. Account and Login</view>
|
||||||
<view class="p">2.1 You can log in and use this service through WeChat authorization. To complete deposit-free rental and order settlement, you agree that we conduct credit assessment and post-order settlement based on WeChat Payment Score.</view>
|
<view class="p">2.1 You can log in and use this service through Alipay authorization. To complete deposit-free rental and order settlement, you agree that we conduct credit assessment and post-order settlement based on Sesame Credit.</view>
|
||||||
<view class="p">2.2 You should ensure that the information provided is true, accurate, and complete, and update it in a timely manner. Any service restrictions, order abnormalities, or losses caused by untrue information or failure to update in time shall be borne by you.</view>
|
<view class="p">2.2 You should ensure that the information provided is true, accurate, and complete, and update it in a timely manner. Any service restrictions, order abnormalities, or losses caused by untrue information or failure to update in time shall be borne by you.</view>
|
||||||
<view class="p">2.3 You shall be responsible for all activities under the account, properly keep the device and account credentials, and shall not lend, rent, or otherwise provide them to others.</view>
|
<view class="p">2.3 You shall be responsible for all activities under the account, properly keep the device and account credentials, and shall not lend, rent, or otherwise provide them to others.</view>
|
||||||
|
|
||||||
@@ -20,10 +20,10 @@
|
|||||||
<view class="p">3.2 Usage specifications: Please use the device properly, avoid water ingress, dropping, unauthorized disassembly or modification; do not approach open flames and high-temperature environments; avoid outdoor use in rainy days; children should use under supervision.</view>
|
<view class="p">3.2 Usage specifications: Please use the device properly, avoid water ingress, dropping, unauthorized disassembly or modification; do not approach open flames and high-temperature environments; avoid outdoor use in rainy days; children should use under supervision.</view>
|
||||||
<view class="p">3.3 Prohibited behaviors: Using the device for illegal or improper purposes; affecting the normal operation of the device or system in any way; circumventing billing or return processes through abnormal means.</view>
|
<view class="p">3.3 Prohibited behaviors: Using the device for illegal or improper purposes; affecting the normal operation of the device or system in any way; circumventing billing or return processes through abnormal means.</view>
|
||||||
|
|
||||||
<view class="h1">IV. Billing and Settlement (Including WeChat Payment Score)</view>
|
<view class="h1">IV. Billing and Settlement (Including Sesame Credit)</view>
|
||||||
<view class="p"><text class="bold">4.1 Billing rules</text>: Subject to the real-time billing rules displayed in the mini program, which may include duration billing, capped prices, service fees, etc. Charges will be based on this after order generation.</view>
|
<view class="p"><text class="bold">4.1 Billing rules</text>: Subject to the real-time billing rules displayed in the mini program, which may include duration billing, capped prices, service fees, etc. Charges will be based on this after order generation.</view>
|
||||||
<view class="p"><text class="bold">4.2 WeChat Payment Score deposit-free</text>: If you activate and pass the credit assessment, you can enjoy deposit-free rental; if the assessment fails, pre-authorization or deposit may be required. Please refer to the page prompts for details.</view>
|
<view class="p"><text class="bold">4.2 Sesame Credit deposit-free</text>: If you activate and pass the credit assessment, you can enjoy deposit-free rental; if the assessment fails, pre-authorization or deposit may be required. Please refer to the page prompts for details.</view>
|
||||||
<view class="p">4.3 Settlement and deduction: After the order ends, we will complete the settlement based on actual usage and platform rules, and deduct through WeChat Payment Score/WeChat Pay.</view>
|
<view class="p">4.3 Settlement and deduction: After the order ends, we will complete the settlement based on actual usage and platform rules, and deduct through Sesame Credit/Alipay.</view>
|
||||||
<view class="p">4.4 Exceptions and disputes: If you have any objection to billing or settlement, please submit it through "My-Customer Service" within 48 hours after order completion; overdue submissions may affect processing results.</view>
|
<view class="p">4.4 Exceptions and disputes: If you have any objection to billing or settlement, please submit it through "My-Customer Service" within 48 hours after order completion; overdue submissions may affect processing results.</view>
|
||||||
|
|
||||||
<view class="h1">V. Device Return and Overdue Handling</view>
|
<view class="h1">V. Device Return and Overdue Handling</view>
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
<view class="p">9.2 You should be responsible for your own use. Any losses caused by your violation of this Agreement or improper storage and use of equipment shall be borne by you or compensated to relevant parties.</view>
|
<view class="p">9.2 You should be responsible for your own use. Any losses caused by your violation of this Agreement or improper storage and use of equipment shall be borne by you or compensated to relevant parties.</view>
|
||||||
|
|
||||||
<view class="h1">X. Privacy and Personal Information Protection</view>
|
<view class="h1">X. Privacy and Personal Information Protection</view>
|
||||||
<view class="p">10.1 We strictly handle your personal information in accordance with the Privacy Policy, including WeChat login information, mobile phone number (obtained after your authorization), device and order information, location and outlet information, etc.</view>
|
<view class="p">10.1 We strictly handle your personal information in accordance with the Privacy Policy, including Alipay login information, mobile phone number (obtained after your authorization), device and order information, location and outlet information, etc.</view>
|
||||||
<view class="p">10.2 For details, please refer to the Privacy Policy in this mini program.</view>
|
<view class="p">10.2 For details, please refer to the Privacy Policy in this mini program.</view>
|
||||||
|
|
||||||
<view class="h1">XI. Service Changes and Termination</view>
|
<view class="h1">XI. Service Changes and Termination</view>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<view class="p">在使用{{ brandName }}前,请您务必仔细阅读并充分理解本协议全部内容,尤其是以加粗方式提示的条款(包括但不限于责任限制、争议解决、适用法律、未成年人保护等)。您点击"登录/使用"或实际使用服务即视为您已阅读并同意受本协议约束。</view>
|
<view class="p">在使用{{ brandName }}前,请您务必仔细阅读并充分理解本协议全部内容,尤其是以加粗方式提示的条款(包括但不限于责任限制、争议解决、适用法律、未成年人保护等)。您点击"登录/使用"或实际使用服务即视为您已阅读并同意受本协议约束。</view>
|
||||||
|
|
||||||
<view class="h1">二、账号与登录</view>
|
<view class="h1">二、账号与登录</view>
|
||||||
<view class="p">2.1 您可通过微信授权登录使用本服务。为完成免押租借与订单结算,您同意我们基于微信支付分进行信用评估及订单后结等必要处理。</view>
|
<view class="p">2.1 您可通过支付宝授权登录使用本服务。为完成免押租借与订单结算,您同意我们基于芝麻信用进行信用评估及订单后结等必要处理。</view>
|
||||||
<view class="p">2.2 您应保证提供信息真实、准确、完整,并及时更新。因您提供的信息不真实或未及时更新导致的服务受限、订单异常或损失,由您自行承担。</view>
|
<view class="p">2.2 您应保证提供信息真实、准确、完整,并及时更新。因您提供的信息不真实或未及时更新导致的服务受限、订单异常或损失,由您自行承担。</view>
|
||||||
<view class="p">2.3 您应对账户下的全部行为负责,妥善保管设备与账户凭证,不得转借、出租或以其他方式提供给他人使用。</view>
|
<view class="p">2.3 您应对账户下的全部行为负责,妥善保管设备与账户凭证,不得转借、出租或以其他方式提供给他人使用。</view>
|
||||||
|
|
||||||
@@ -20,10 +20,10 @@
|
|||||||
<view class="p">3.2 使用规范:请合理使用设备,避免进水、摔落、私自拆卸或改装;请勿靠近明火与高温环境;室外雨天请避免使用;儿童应在监护下使用。</view>
|
<view class="p">3.2 使用规范:请合理使用设备,避免进水、摔落、私自拆卸或改装;请勿靠近明火与高温环境;室外雨天请避免使用;儿童应在监护下使用。</view>
|
||||||
<view class="p">3.3 禁止行为:将设备用于违法或不当用途;以任何方式影响设备或系统的正常运行;通过非正常手段规避计费或归还流程。</view>
|
<view class="p">3.3 禁止行为:将设备用于违法或不当用途;以任何方式影响设备或系统的正常运行;通过非正常手段规避计费或归还流程。</view>
|
||||||
|
|
||||||
<view class="h1">四、计费与结算(含微信支付分)</view>
|
<view class="h1">四、计费与结算(含芝麻信用)</view>
|
||||||
<view class="p"><text class="bold">4.1 计费规则</text>:以小程序展示的实时计费规则为准,可能包含时长计费、封顶价、服务费等。订单生成后将据此计费。</view>
|
<view class="p"><text class="bold">4.1 计费规则</text>:以小程序展示的实时计费规则为准,可能包含时长计费、封顶价、服务费等。订单生成后将据此计费。</view>
|
||||||
<view class="p"><text class="bold">4.2 微信支付分免押</text>:若您开通并通过信用评估,可享受免押租借;如评估未通过,可能需预授权或押金。具体以页面提示为准。</view>
|
<view class="p"><text class="bold">4.2 芝麻信用免押</text>:若您开通并通过信用评估,可享受免押租借;如评估未通过,可能需预授权或押金。具体以页面提示为准。</view>
|
||||||
<view class="p">4.3 结算与扣款:订单结束后,我们将基于实际使用情况与平台规则完成结算并通过微信支付分/微信支付进行扣款。</view>
|
<view class="p">4.3 结算与扣款:订单结束后,我们将基于实际使用情况与平台规则完成结算并通过芝麻信用/支付宝支付进行扣款。</view>
|
||||||
<view class="p">4.4 异常与争议:如对计费或结算有异议,请在订单完成后48小时内通过"我的-客服"提交;逾期可能影响处理结果。</view>
|
<view class="p">4.4 异常与争议:如对计费或结算有异议,请在订单完成后48小时内通过"我的-客服"提交;逾期可能影响处理结果。</view>
|
||||||
|
|
||||||
<view class="h1">五、设备归还与逾期处理</view>
|
<view class="h1">五、设备归还与逾期处理</view>
|
||||||
|
|||||||
@@ -16,18 +16,18 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="h1">II. Information We Collect</view>
|
<view class="h1">II. Information We Collect</view>
|
||||||
<view class="p">2.1 Account information: WeChat login identifier (such as openId/unionId), nickname and avatar (with your authorization), mobile phone number (obtained through WeChat after your authorization).</view>
|
<view class="p">2.1 Account information: Alipay login identifier (such as userId), nickname and avatar (with your authorization), mobile phone number (obtained through Alipay after your authorization).</view>
|
||||||
<view class="p">2.2 Order and device information: rental records, usage duration, fees, return points, device status, abnormal records, etc.</view>
|
<view class="p">2.2 Order and device information: rental records, usage duration, fees, return points, device status, abnormal records, etc.</view>
|
||||||
<view class="p">2.3 Location and outlet information: used to find nearby outlets and navigation after your authorization, and will not be obtained without authorization.</view>
|
<view class="p">2.3 Location and outlet information: used to find nearby outlets and navigation after your authorization, and will not be obtained without authorization.</view>
|
||||||
<view class="p">2.4 Log information: To ensure service security and stability, we may record operation logs, network requests, and error information.</view>
|
<view class="p">2.4 Log information: To ensure service security and stability, we may record operation logs, network requests, and error information.</view>
|
||||||
|
|
||||||
<view class="h1">III. Purpose of Information Use</view>
|
<view class="h1">III. Purpose of Information Use</view>
|
||||||
<view class="p">3.1 Provide core functions: identity verification, deposit-free rental (WeChat Payment Score assessment), order billing and settlement, customer service and after-sales.</view>
|
<view class="p">3.1 Provide core functions: identity verification, deposit-free rental (Sesame Credit assessment), order billing and settlement, customer service and after-sales.</view>
|
||||||
<view class="p">3.2 Security risk control: prevent fraud, violations and risk control; ensure system and device security.</view>
|
<view class="p">3.2 Security risk control: prevent fraud, violations and risk control; ensure system and device security.</view>
|
||||||
<view class="p">3.3 Product optimization: statistics and analysis to improve experience (conducted after de-identification/anonymization).</view>
|
<view class="p">3.3 Product optimization: statistics and analysis to improve experience (conducted after de-identification/anonymization).</view>
|
||||||
|
|
||||||
<view class="h1">IV. WeChat Payment Score and Payment</view>
|
<view class="h1">IV. Sesame Credit and Payment</view>
|
||||||
<view class="p">4.1 To implement deposit-free rental, we will conduct necessary data interaction with WeChat Payment Score (such as credit assessment results and order settlement). Related data processing follows the rules of WeChat Pay and WeChat Payment Score.</view>
|
<view class="p">4.1 To implement deposit-free rental, we will conduct necessary data interaction with Sesame Credit (such as credit assessment results and order settlement). Related data processing follows the rules of Alipay and Sesame Credit.</view>
|
||||||
<view class="p">4.2 If you fail the assessment, pre-authorization or deposit processing may be required, subject to page prompts.</view>
|
<view class="p">4.2 If you fail the assessment, pre-authorization or deposit processing may be required, subject to page prompts.</view>
|
||||||
|
|
||||||
<view class="h1">V. Sharing, Transfer and Public Disclosure</view>
|
<view class="h1">V. Sharing, Transfer and Public Disclosure</view>
|
||||||
|
|||||||
@@ -22,12 +22,12 @@
|
|||||||
<view class="p">2.4 日志信息:为保障服务安全与稳定,我们可能记录操作日志、网络请求与错误信息。</view>
|
<view class="p">2.4 日志信息:为保障服务安全与稳定,我们可能记录操作日志、网络请求与错误信息。</view>
|
||||||
|
|
||||||
<view class="h1">三、信息使用目的</view>
|
<view class="h1">三、信息使用目的</view>
|
||||||
<view class="p">3.1 提供核心功能:身份验证、免押租借(微信支付分评估)、订单计费结算、客服与售后。</view>
|
<view class="p">3.1 提供核心功能:身份验证、免押租借(芝麻信用评估)、订单计费结算、客服与售后。</view>
|
||||||
<view class="p">3.2 安全风控:防范欺诈、违规与风险控制;保障系统与设备安全。</view>
|
<view class="p">3.2 安全风控:防范欺诈、违规与风险控制;保障系统与设备安全。</view>
|
||||||
<view class="p">3.3 产品优化:统计与分析以改进体验(在去标识化/匿名化后进行)。</view>
|
<view class="p">3.3 产品优化:统计与分析以改进体验(在去标识化/匿名化后进行)。</view>
|
||||||
|
|
||||||
<view class="h1">四、微信支付分与支付</view>
|
<view class="h1">四、芝麻信用与支付</view>
|
||||||
<view class="p">4.1 为实现免押租借,我们将与微信支付分进行必要的数据交互(如信用评估结果、订单结算)。相关数据处理遵循微信支付与微信支付分的规则。</view>
|
<view class="p">4.1 为实现免押租借,我们将与芝麻信用进行必要的数据交互(如信用评估结果、订单结算)。相关数据处理遵循支付宝与芝麻信用的规则。</view>
|
||||||
<view class="p">4.2 如您未通过评估,可能需进行预授权或押金处理,以页面提示为准。</view>
|
<view class="p">4.2 如您未通过评估,可能需进行预授权或押金处理,以页面提示为准。</view>
|
||||||
|
|
||||||
<view class="h1">五、共享、转移与公开披露</view>
|
<view class="h1">五、共享、转移与公开披露</view>
|
||||||
|
|||||||
+17
-12
@@ -8,16 +8,16 @@
|
|||||||
<view class="title">{{ $t('auth.loginTitle') }}</view>
|
<view class="title">{{ $t('auth.loginTitle') }}</view>
|
||||||
<view class="subtitle">{{ $t('auth.loginDesc') }}</view>
|
<view class="subtitle">{{ $t('auth.loginDesc') }}</view>
|
||||||
|
|
||||||
<!-- 微信一键手机号快捷登录(推荐) -->
|
<!-- 支付宝一键手机号快捷登录(推荐) -->
|
||||||
<button v-if="!isAgreed" class="btn primary" @click="handleLoginClick">
|
<button v-if="!isAgreed" class="btn primary" @click="handleLoginClick">
|
||||||
{{ $t('auth.getPhoneNumber') }}
|
{{ $t('auth.getPhoneNumber') }}
|
||||||
</button>
|
</button>
|
||||||
<button v-else class="btn primary" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">
|
<button v-else class="btn primary" open-type="getAuthorize" scope="phoneNumber" @getAuthorize="onGetPhoneNumber">
|
||||||
{{ $t('auth.getPhoneNumber') }}
|
{{ $t('auth.getPhoneNumber') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- 仅微信登录(不授权手机号时使用) -->
|
<!-- 仅支付宝登录(不授权手机号时使用) -->
|
||||||
<!-- <button class="btn outline" @click="onWeChatLogin">仅微信登录</button> -->
|
<!-- <button class="btn outline" @click="onAlipayLogin">仅支付宝登录</button> -->
|
||||||
|
|
||||||
<view class="agreement-box">
|
<view class="agreement-box">
|
||||||
<checkbox-group @change="onAgreementChange">
|
<checkbox-group @change="onAgreementChange">
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { wxLogin, getUserPhoneNumber, getUserInfo } from '../../util/index.js'
|
import { alipayLogin, getUserPhoneNumber, getUserInfo } from '../../util/index.js'
|
||||||
import { useI18n } from '@/utils/i18n.js'
|
import { useI18n } from '@/utils/i18n.js'
|
||||||
|
|
||||||
const { t: $t } = useI18n()
|
const { t: $t } = useI18n()
|
||||||
@@ -113,12 +113,12 @@
|
|||||||
uni.reLaunch({ url: target })
|
uni.reLaunch({ url: target })
|
||||||
}
|
}
|
||||||
|
|
||||||
const onWeChatLogin = async () => {
|
const onAlipayLogin = async () => {
|
||||||
try {
|
try {
|
||||||
// 先检查是否同意协议
|
// 先检查是否同意协议
|
||||||
await checkAgreement()
|
await checkAgreement()
|
||||||
|
|
||||||
await wxLogin()
|
await alipayLogin()
|
||||||
uni.showToast({ title: $t('auth.loginSuccess'), icon: 'success' })
|
uni.showToast({ title: $t('auth.loginSuccess'), icon: 'success' })
|
||||||
await navigateAfterLogin()
|
await navigateAfterLogin()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -129,16 +129,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onGetPhoneNumber = async (e) => {
|
const onGetPhoneNumber = async (e) => {
|
||||||
if (!e || e.detail.errMsg !== 'getPhoneNumber:ok') {
|
// 支付宝获取手机号的回调处理
|
||||||
|
if (!e || !e.detail || !e.detail.response) {
|
||||||
uni.showToast({ title: $t('auth.phoneCancelled'), icon: 'none' })
|
uni.showToast({ title: $t('auth.phoneCancelled'), icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 先微信登录,获取 token
|
// 先支付宝登录,获取 token
|
||||||
await wxLogin()
|
await alipayLogin()
|
||||||
// 再用微信返回的临时 code 换取手机号
|
// 再用支付宝返回的授权码换取手机号
|
||||||
await getUserPhoneNumber(e.detail.code)
|
// 支付宝的授权码在 e.detail.response 中
|
||||||
|
const authCode = e.detail.response?.response?.code || e.detail.response?.code
|
||||||
|
if (authCode) {
|
||||||
|
await getUserPhoneNumber(authCode)
|
||||||
|
}
|
||||||
uni.showToast({ title: $t('auth.loginSuccess'), icon: 'success' })
|
uni.showToast({ title: $t('auth.loginSuccess'), icon: 'success' })
|
||||||
await navigateAfterLogin()
|
await navigateAfterLogin()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
+27
-55
@@ -9,7 +9,7 @@
|
|||||||
<view class="nickname">{{ userInfo.nickName || $t('user.clickToLogin') }}</view>
|
<view class="nickname">{{ userInfo.nickName || $t('user.clickToLogin') }}</view>
|
||||||
<view class="subtext">{{ userInfo.phone ? maskPhone(userInfo.phone) : $t('user.loginPrompt') }}</view>
|
<view class="subtext">{{ userInfo.phone ? maskPhone(userInfo.phone) : $t('user.loginPrompt') }}</view>
|
||||||
</view>
|
</view>
|
||||||
<uv-icon type="right" size="16" color="#999"></uv-icon>
|
<uv-icon name="arrow-right" size="16" color="#999"></uv-icon>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
<u-popup ref="authPopup" mode="center" border-radius="15" width="600rpx" @open="onPopupOpen" @close="onPopupClose">
|
<u-popup ref="authPopup" mode="center" border-radius="15" width="600rpx" @open="onPopupOpen" @close="onPopupClose">
|
||||||
<view class="auth-popup">
|
<view class="auth-popup">
|
||||||
<view class="auth-title">授权登录</view>
|
<view class="auth-title">授权登录</view>
|
||||||
<view class="auth-desc">获取您的微信头像、昵称等公开信息</view>
|
<view class="auth-desc">获取您的支付宝头像、昵称等公开信息</view>
|
||||||
<view class="auth-buttons">
|
<view class="auth-buttons">
|
||||||
<button class="cancel-btn" @click="closeAuthPopup">取消</button>
|
<button class="cancel-btn" @click="closeAuthPopup">取消</button>
|
||||||
<button class="confirm-btn" @click="getUserProfile">确定</button>
|
<button class="confirm-btn" @click="getUserProfile">确定</button>
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
} from '@dcloudio/uni-app';
|
} from '@dcloudio/uni-app';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
wxLogin,
|
alipayLogin,
|
||||||
getUserInfo
|
getUserInfo
|
||||||
} from '../../util/index.js';
|
} from '../../util/index.js';
|
||||||
import {
|
import {
|
||||||
@@ -184,7 +184,7 @@ import {
|
|||||||
'Content-Language': languageCode
|
'Content-Language': languageCode
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
appPlatform: 'wechat', // 微信平台
|
appPlatform: 'alipay', // 支付宝平台
|
||||||
appType: 'user' // 用户端
|
appType: 'user' // 用户端
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -267,11 +267,12 @@ import {
|
|||||||
|
|
||||||
// 初始化应用版本号(多端兼容,取可用信息)
|
// 初始化应用版本号(多端兼容,取可用信息)
|
||||||
const initVersion = () => {
|
const initVersion = () => {
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-ALIPAY
|
||||||
try {
|
try {
|
||||||
const info = wx.getAccountInfoSync && wx.getAccountInfoSync();
|
// 支付宝小程序获取版本号
|
||||||
if (info && info.miniProgram && info.miniProgram.version) {
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
appVersion.value = info.miniProgram.version;
|
if (systemInfo && systemInfo.version) {
|
||||||
|
appVersion.value = systemInfo.version;
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
// #endif
|
// #endif
|
||||||
@@ -368,12 +369,13 @@ import {
|
|||||||
redirectToLogin()
|
redirectToLogin()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-ALIPAY
|
||||||
getUserProfile()
|
// 支付宝小程序通过页面跳转处理用户资料
|
||||||
|
navigateTo('/pages/userProfile/index')
|
||||||
// #endif
|
// #endif
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-ALIPAY
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('auth.pleaseUseInWechat'),
|
title: $t('auth.pleaseUseInAlipay'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
// #endif
|
// #endif
|
||||||
@@ -446,65 +448,35 @@ import {
|
|||||||
// 这里可以添加弹窗关闭后的逻辑
|
// 这里可以添加弹窗关闭后的逻辑
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取微信用户个人信息
|
// 获取支付宝用户个人信息(已废弃,使用页面跳转方式)
|
||||||
const getUserProfile = () => {
|
const getUserProfile = () => {
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-ALIPAY
|
||||||
uni.showLoading({
|
// 支付宝小程序通过页面跳转处理用户资料
|
||||||
title: $t('common.getting'),
|
navigateTo('/pages/userProfile/index')
|
||||||
mask: true
|
|
||||||
});
|
|
||||||
|
|
||||||
wx.getUserProfile({
|
|
||||||
desc: '用于完善会员资料',
|
|
||||||
success: (res) => {
|
|
||||||
console.log('获取用户信息成功:', res);
|
|
||||||
updateUserInfo(res.userInfo);
|
|
||||||
uploadAvatarAndRefresh(res.userInfo);
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('获取用户信息失败:', err);
|
|
||||||
uni.showToast({
|
|
||||||
title: '获取用户信息失败',
|
|
||||||
icon: 'none'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
complete: () => {
|
|
||||||
uni.hideLoading();
|
|
||||||
closeAuthPopup();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-ALIPAY
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('auth.pleaseUseInWechat'),
|
title: $t('auth.pleaseUseInAlipay'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
closeAuthPopup();
|
closeAuthPopup();
|
||||||
// #endif
|
// #endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新用户信息
|
// 更新用户信息(支付宝小程序通过页面跳转处理)
|
||||||
const updateUserInfo = async (wxUserInfo) => {
|
const updateUserInfo = async (alipayUserInfo) => {
|
||||||
try {
|
try {
|
||||||
// 更新本地用户信息
|
// 更新本地用户信息
|
||||||
const updatedInfo = {
|
const updatedInfo = {
|
||||||
...userInfo.value,
|
...userInfo.value,
|
||||||
nickName: wxUserInfo.nickName,
|
nickName: alipayUserInfo.nickName,
|
||||||
avatar: wxUserInfo.avatarUrl
|
avatar: alipayUserInfo.avatarUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
userInfo.value = updatedInfo;
|
userInfo.value = updatedInfo;
|
||||||
uni.setStorageSync('userInfo', updatedInfo);
|
uni.setStorageSync('userInfo', updatedInfo);
|
||||||
|
|
||||||
// 这里可以添加调用后端API更新用户信息的代码
|
|
||||||
// const updateRes = await updateUserInfoApi({
|
|
||||||
// openId: openId.value,
|
|
||||||
// nickName: wxUserInfo.nickName,
|
|
||||||
// avatarUrl: wxUserInfo.avatarUrl,
|
|
||||||
// gender: wxUserInfo.gender
|
|
||||||
// });
|
|
||||||
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('user.updateSuccess'),
|
title: $t('user.updateSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
@@ -522,9 +494,9 @@ import {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 下载并上传头像,更新用户信息
|
// 下载并上传头像,更新用户信息
|
||||||
const uploadAvatarAndRefresh = async (wxUserInfo) => {
|
const uploadAvatarAndRefresh = async (alipayUserInfo) => {
|
||||||
try {
|
try {
|
||||||
const avatarUrl = wxUserInfo?.avatarUrl
|
const avatarUrl = alipayUserInfo?.avatarUrl
|
||||||
if (!avatarUrl) {
|
if (!avatarUrl) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '未获取到头像地址',
|
title: '未获取到头像地址',
|
||||||
@@ -532,7 +504,7 @@ import {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 下载微信头像为本地临时文件
|
// 下载支付宝头像为本地临时文件
|
||||||
const tempFilePath = await new Promise((resolve, reject) => {
|
const tempFilePath = await new Promise((resolve, reject) => {
|
||||||
uni.downloadFile({
|
uni.downloadFile({
|
||||||
url: avatarUrl,
|
url: avatarUrl,
|
||||||
|
|||||||
@@ -230,9 +230,9 @@
|
|||||||
// 获取支付方式文本
|
// 获取支付方式文本
|
||||||
const getPayWayText = () => {
|
const getPayWayText = () => {
|
||||||
const payWayMap = {
|
const payWayMap = {
|
||||||
'wx_score_pay': $t('order.depositFree'),
|
'alipay_score_pay': $t('order.depositFree'),
|
||||||
'wx_member_pay': $t('order.memberOrder'),
|
'alipay_member_pay': $t('order.memberOrder'),
|
||||||
'wx_pay': $t('order.depositPay')
|
'alipay_pay': $t('order.depositPay')
|
||||||
}
|
}
|
||||||
return payWayMap[orderInfo.value.payWay] || $t('order.depositFree')
|
return payWayMap[orderInfo.value.payWay] || $t('order.depositFree')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,9 +271,9 @@
|
|||||||
title: $t('common.processing')
|
title: $t('common.processing')
|
||||||
});
|
});
|
||||||
|
|
||||||
// 调用后端创建微信支付订单接口
|
// 调用后端创建支付宝支付订单接口
|
||||||
const res = await uni.request({
|
const res = await uni.request({
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/wx-payment/create/${order.orderNo}`,
|
url: `${URL || 'http://127.0.0.1:8080'}/app/alipay-payment/create/${order.orderNo}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
header: {
|
header: {
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
||||||
@@ -284,8 +284,9 @@
|
|||||||
if (res.statusCode === 200 && res.data.code === 200) {
|
if (res.statusCode === 200 && res.data.code === 200) {
|
||||||
const payParams = res.data.data;
|
const payParams = res.data.data;
|
||||||
|
|
||||||
// 调用微信支付
|
// 调用支付宝支付
|
||||||
await uni.requestPayment({
|
await uni.requestPayment({
|
||||||
|
provider: 'alipay',
|
||||||
...payParams,
|
...payParams,
|
||||||
success: async () => {
|
success: async () => {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
|
|||||||
@@ -246,9 +246,9 @@ export default {
|
|||||||
title: this.$t('common.processing')
|
title: this.$t('common.processing')
|
||||||
})
|
})
|
||||||
|
|
||||||
// 调用后端创建微信支付订单接口
|
// 调用后端创建支付宝支付订单接口
|
||||||
const res = await uni.request({
|
const res = await uni.request({
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/wx-payment/create/${this.orderInfo.orderNo}`,
|
url: `${URL || 'http://127.0.0.1:8080'}/app/alipay-payment/create/${this.orderInfo.orderNo}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
header: {
|
header: {
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
||||||
@@ -259,8 +259,9 @@ export default {
|
|||||||
if (res.statusCode === 200 && res.data.code === 200) {
|
if (res.statusCode === 200 && res.data.code === 200) {
|
||||||
const payParams = res.data.data
|
const payParams = res.data.data
|
||||||
|
|
||||||
// 调用微信支付
|
// 调用支付宝支付
|
||||||
await uni.requestPayment({
|
await uni.requestPayment({
|
||||||
|
provider: 'alipay',
|
||||||
...payParams,
|
...payParams,
|
||||||
success: async () => {
|
success: async () => {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -377,7 +378,7 @@ export default {
|
|||||||
async checkOrderStatus() {
|
async checkOrderStatus() {
|
||||||
try {
|
try {
|
||||||
const res = await uni.request({
|
const res = await uni.request({
|
||||||
url: `${URL || 'http://127.0.0.1:8080'}/app/wx-payment/status/${this.orderInfo.orderNo}`,
|
url: `${URL || 'http://127.0.0.1:8080'}/app/alipay-payment/status/${this.orderInfo.orderNo}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
header: {
|
header: {
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
||||||
|
|||||||
@@ -15,21 +15,21 @@
|
|||||||
|
|
||||||
<!-- 支付方式标识 -->
|
<!-- 支付方式标识 -->
|
||||||
<view class="device-right">
|
<view class="device-right">
|
||||||
<!-- 微信支付分标识 -->
|
<!-- 支付宝信用免押标识 -->
|
||||||
<view class="payment-badge wx-score" v-if="orderInfo.payWay == 'wx_score_pay'">
|
<view class="payment-badge alipay-score" v-if="orderInfo.payWay == 'alipay_score_pay'">
|
||||||
<image src="/static/images/wxpayflag.png" mode="aspectFit" class="badge-icon"></image>
|
<image src="/static/images/alipay.svg" mode="aspectFit" class="badge-icon"></image>
|
||||||
<view class="badge-text">
|
<view class="badge-text">
|
||||||
<text>{{ $t('order.wxPayScore') }}</text>
|
<text>{{ $t('order.alipayScore') }}</text>
|
||||||
<text class="divider">|</text>
|
<text class="divider">|</text>
|
||||||
<text class="highlight">{{ $t('order.depositFree') }}</text>
|
<text class="highlight">{{ $t('order.depositFree') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 会员订单标识 -->
|
<!-- 会员订单标识 -->
|
||||||
<view class="payment-badge member" v-else-if="orderInfo.payWay == 'wx_member_pay'">
|
<view class="payment-badge member" v-else-if="orderInfo.payWay == 'alipay_member_pay'">
|
||||||
<text class="badge-text">{{ $t('order.memberOrder') }}</text>
|
<text class="badge-text">{{ $t('order.memberOrder') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<!-- 微信支付(押金)标识 -->
|
<!-- 支付宝支付(押金)标识 -->
|
||||||
<view class="payment-badge deposit" v-else-if="orderInfo.payWay == 'wx_pay'">
|
<view class="payment-badge deposit" v-else-if="orderInfo.payWay == 'alipay_pay'">
|
||||||
<text class="badge-text">{{ $t('order.depositPay') }}</text>
|
<text class="badge-text">{{ $t('order.depositPay') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -322,7 +322,7 @@
|
|||||||
this.countdownTimer = null
|
this.countdownTimer = null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 解析开始时间字符串为时间戳(毫秒),兼容常见格式及 iOS/微信环境
|
// 解析开始时间字符串为时间戳(毫秒),兼容常见格式及 iOS/支付宝环境
|
||||||
parseStartTimeToMs(timeStr) {
|
parseStartTimeToMs(timeStr) {
|
||||||
if (!timeStr) return NaN
|
if (!timeStr) return NaN
|
||||||
if (typeof timeStr === 'number') {
|
if (typeof timeStr === 'number') {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
wxLogin,
|
alipayLogin,
|
||||||
} from '../../../util/index'
|
} from '../../../util/index'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
<view class="avatar-container">
|
<view class="avatar-container">
|
||||||
<image class="avatar" v-if="userInfo.avatar" :src="userInfo.avatar" mode="aspectFill"></image>
|
<image class="avatar" v-if="userInfo.avatar" :src="userInfo.avatar" mode="aspectFill"></image>
|
||||||
<image v-else class="avatar" src="@/static/head.png" mode="aspectFill"></image>
|
<image v-else class="avatar" src="@/static/head.png" mode="aspectFill"></image>
|
||||||
<!-- 覆盖在头像上的微信选择头像授权按钮,仅小程序生效 -->
|
<!-- 覆盖在头像上的支付宝选择头像授权按钮,仅小程序生效 -->
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
<!-- #ifdef MP-ALIPAY -->
|
||||||
<button class="avatar-choose-btn" open-type="chooseAvatar" @chooseavatar="onChooseAvatar"></button>
|
<button class="avatar-choose-btn" open-type="chooseAvatar" @chooseavatar="onChooseAvatar"></button>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
</view>
|
</view>
|
||||||
@@ -282,7 +282,7 @@ function maskPhone(phone) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 仅小程序端存在,此按钮覆盖在头像上捕获点击以触发选择头像 */
|
/* 仅小程序端存在,此按钮覆盖在头像上捕获点击以触发选择头像 */
|
||||||
/* #ifdef MP-WEIXIN */
|
/* #ifdef MP-ALIPAY */
|
||||||
.avatar-choose-btn {
|
.avatar-choose-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|||||||
+29
-27
@@ -10,12 +10,12 @@ import { getCommonByBrand } from "@/config/api/system"
|
|||||||
import { HELP_CONTENT } from "@/constants/help"
|
import { HELP_CONTENT } from "@/constants/help"
|
||||||
// import { GET_PHONE_NUMBER_URL } from "../config/url"
|
// import { GET_PHONE_NUMBER_URL } from "../config/url"
|
||||||
|
|
||||||
// 微信登录方法
|
// 支付宝登录方法
|
||||||
export const wxLogin = () => {
|
export const alipayLogin = () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// 1. 获取微信登录凭证
|
// 1. 获取支付宝登录凭证
|
||||||
uni.login({
|
uni.login({
|
||||||
provider: 'weixin',
|
provider: 'alipay',
|
||||||
success: async (loginRes) => {
|
success: async (loginRes) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -23,7 +23,7 @@ export const wxLogin = () => {
|
|||||||
// 2. 发送 code 到后端换取 token
|
// 2. 发送 code 到后端换取 token
|
||||||
const result = await login({
|
const result = await login({
|
||||||
code: loginRes.code,
|
code: loginRes.code,
|
||||||
appid: "wx2165f0be356ae7a9"
|
appid: "2021006117693332"
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result.code === 200) {
|
if (result.code === 200) {
|
||||||
@@ -42,7 +42,7 @@ export const wxLogin = () => {
|
|||||||
throw new Error(result.message || '登录失败')
|
throw new Error(result.message || '登录失败')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('获取微信登录凭证失败')
|
throw new Error('获取支付宝登录凭证失败')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ export const wxLogin = () => {
|
|||||||
},
|
},
|
||||||
fail: (error) => {
|
fail: (error) => {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '微信登录失败',
|
title: '支付宝登录失败',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
reject(error)
|
reject(error)
|
||||||
@@ -64,6 +64,9 @@ export const wxLogin = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 兼容旧代码,保留wxLogin别名
|
||||||
|
export const wxLogin = alipayLogin
|
||||||
|
|
||||||
// 检查登录状态
|
// 检查登录状态
|
||||||
// export const checkLogin = () => {
|
// export const checkLogin = () => {
|
||||||
// const token = uni.getStorageSync('token')
|
// const token = uni.getStorageSync('token')
|
||||||
@@ -104,7 +107,7 @@ export const getUserPhoneNumber = (code) => {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
code: code, // 微信获取手机号授权后的临时code
|
code: code, // 支付宝获取手机号授权后的临时code
|
||||||
appid: appid
|
appid: appid
|
||||||
},
|
},
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
@@ -137,34 +140,26 @@ export const getUserPhoneNumber = (code) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用微信支付分接口
|
// 调用支付宝支付接口
|
||||||
export const initiateWeChatScorePayment = (paymentData) => {
|
export const initiateAlipayPayment = (paymentData) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// 确保paymentData包含所需数据
|
// 确保paymentData包含所需数据
|
||||||
if (!paymentData || !paymentData.data || !paymentData.data.package) {
|
if (!paymentData || !paymentData.data) {
|
||||||
reject(new Error('支付参数不完整'));
|
reject(new Error('支付参数不完整'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用wx.openBusinessView打开微信支付分小程序
|
// 使用uni.requestPayment调用支付宝支付
|
||||||
wx.openBusinessView({
|
uni.requestPayment({
|
||||||
businessType: 'wxpayScoreUse',
|
provider: 'alipay',
|
||||||
extraData: {
|
orderInfo: paymentData.data.orderInfo || paymentData.data,
|
||||||
mch_id: paymentData.data.mch_id,
|
success: (res) => {
|
||||||
package: paymentData.data.package
|
resolve(res);
|
||||||
},
|
|
||||||
success: (businessRes) => {
|
|
||||||
// 根据返回结果判断是否完成支付
|
|
||||||
if (businessRes.errMsg === 'openBusinessView:ok') {
|
|
||||||
resolve(businessRes);
|
|
||||||
} else {
|
|
||||||
reject(new Error('支付流程未完成'));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
fail: (error) => {
|
fail: (error) => {
|
||||||
console.error('微信支付分小程序调用失败', error);
|
console.error('支付宝支付调用失败', error);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: error.errMsg || '支付分接口调用失败',
|
title: error.errMsg || '支付接口调用失败',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
reject(error);
|
reject(error);
|
||||||
@@ -173,7 +168,14 @@ export const initiateWeChatScorePayment = (paymentData) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 兼容旧代码,保留旧函数名
|
||||||
|
export const initiateWeChatScorePayment = initiateAlipayPayment
|
||||||
|
|
||||||
export const getQueryString = function(url, name) {
|
export const getQueryString = function(url, name) {
|
||||||
|
// 添加空值检查,兼容支付宝小程序
|
||||||
|
if (!url || typeof url !== 'string') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
var reg = new RegExp('(^|&|/?)' + name + '=([^&|/?]*)(&|/?|$)', 'i')
|
var reg = new RegExp('(^|&|/?)' + name + '=([^&|/?]*)(&|/?|$)', 'i')
|
||||||
var r = url.substr(1).match(reg)
|
var r = url.substr(1).match(reg)
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
|
|||||||
+614
-19
@@ -39,6 +39,287 @@ const getPermissionText = (key) => {
|
|||||||
// 腾讯地图Key
|
// 腾讯地图Key
|
||||||
const QQMAP_KEY = 'RO5BZ-ECZ63-7US3C-RT5QW-TIDZE-2FF35';
|
const QQMAP_KEY = 'RO5BZ-ECZ63-7US3C-RT5QW-TIDZE-2FF35';
|
||||||
|
|
||||||
|
// 高德地图配置(支付宝小程序专用)
|
||||||
|
const AMAP_KEY = 'a07af802ff0a04f012954ff4e69b36d0';
|
||||||
|
const AMAP_SECURITY_KEY = '119f36535ab42b8b2c857f29f9320b06';
|
||||||
|
const AMAP_BASE_URL = 'https://restapi.amap.com/v3';
|
||||||
|
const AMAP_PATH_PREFIX = '/v3';
|
||||||
|
|
||||||
|
// 运行环境标识(编译期指令)
|
||||||
|
const isAlipayEnv = (() => {
|
||||||
|
let flag = false;
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
flag = true;
|
||||||
|
// #endif
|
||||||
|
return flag;
|
||||||
|
})();
|
||||||
|
|
||||||
|
// 轻量级 MD5 实现(用于生成高德安全 sig)
|
||||||
|
function md5(string) {
|
||||||
|
function RotateLeft(lValue, iShiftBits) {
|
||||||
|
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
|
||||||
|
}
|
||||||
|
function AddUnsigned(lX, lY) {
|
||||||
|
const lX4 = lX & 0x40000000;
|
||||||
|
const lY4 = lY & 0x40000000;
|
||||||
|
const lX8 = lX & 0x80000000;
|
||||||
|
const lY8 = lY & 0x80000000;
|
||||||
|
const lResult = (lX & 0x3fffffff) + (lY & 0x3fffffff);
|
||||||
|
if (lX4 & lY4) {
|
||||||
|
return lResult ^ 0x80000000 ^ lX8 ^ lY8;
|
||||||
|
}
|
||||||
|
if (lX4 | lY4) {
|
||||||
|
if (lResult & 0x40000000) {
|
||||||
|
return lResult ^ 0xc0000000 ^ lX8 ^ lY8;
|
||||||
|
}
|
||||||
|
return lResult ^ 0x40000000 ^ lX8 ^ lY8;
|
||||||
|
}
|
||||||
|
return lResult ^ lX8 ^ lY8;
|
||||||
|
}
|
||||||
|
function F(x, y, z) { return (x & y) | (~x & z); }
|
||||||
|
function G(x, y, z) { return (x & z) | (y & ~z); }
|
||||||
|
function H(x, y, z) { return x ^ y ^ z; }
|
||||||
|
function I(x, y, z) { return y ^ (x | ~z); }
|
||||||
|
function FF(a, b, c, d, x, s, ac) {
|
||||||
|
a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
|
||||||
|
return AddUnsigned(RotateLeft(a, s), b);
|
||||||
|
}
|
||||||
|
function GG(a, b, c, d, x, s, ac) {
|
||||||
|
a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
|
||||||
|
return AddUnsigned(RotateLeft(a, s), b);
|
||||||
|
}
|
||||||
|
function HH(a, b, c, d, x, s, ac) {
|
||||||
|
a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
|
||||||
|
return AddUnsigned(RotateLeft(a, s), b);
|
||||||
|
}
|
||||||
|
function II(a, b, c, d, x, s, ac) {
|
||||||
|
a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
|
||||||
|
return AddUnsigned(RotateLeft(a, s), b);
|
||||||
|
}
|
||||||
|
function ConvertToWordArray(str) {
|
||||||
|
const lWordArray = [];
|
||||||
|
let lMessageLength = str.length;
|
||||||
|
let lNumberOfWordsTempOne = lMessageLength + 8;
|
||||||
|
const lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64;
|
||||||
|
const lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16;
|
||||||
|
let lBytePosition = 0;
|
||||||
|
let lByteCount = 0;
|
||||||
|
while (lByteCount < lMessageLength) {
|
||||||
|
const lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||||
|
lBytePosition = (lByteCount % 4) * 8;
|
||||||
|
lWordArray[lWordCount] = (lWordArray[lWordCount] || 0) | (str.charCodeAt(lByteCount) << lBytePosition);
|
||||||
|
lByteCount++;
|
||||||
|
}
|
||||||
|
const lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||||
|
lBytePosition = (lByteCount % 4) * 8;
|
||||||
|
lWordArray[lWordCount] = lWordArray[lWordCount] || 0;
|
||||||
|
lWordArray[lWordCount] |= 0x80 << lBytePosition;
|
||||||
|
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
|
||||||
|
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
|
||||||
|
return lWordArray;
|
||||||
|
}
|
||||||
|
function WordToHex(lValue) {
|
||||||
|
let WordToHexValue = '';
|
||||||
|
for (let lCount = 0; lCount <= 3; lCount++) {
|
||||||
|
const lByte = (lValue >>> (lCount * 8)) & 255;
|
||||||
|
const WordToHexValueTemp = '0' + lByte.toString(16);
|
||||||
|
WordToHexValue += WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2);
|
||||||
|
}
|
||||||
|
return WordToHexValue;
|
||||||
|
}
|
||||||
|
function Utf8Encode(str) {
|
||||||
|
str = str.replace(/\r\n/g, '\n');
|
||||||
|
let utftext = '';
|
||||||
|
for (let n = 0; n < str.length; n++) {
|
||||||
|
const c = str.charCodeAt(n);
|
||||||
|
if (c < 128) {
|
||||||
|
utftext += String.fromCharCode(c);
|
||||||
|
} else if (c > 127 && c < 2048) {
|
||||||
|
utftext += String.fromCharCode((c >> 6) | 192);
|
||||||
|
utftext += String.fromCharCode((c & 63) | 128);
|
||||||
|
} else {
|
||||||
|
utftext += String.fromCharCode((c >> 12) | 224);
|
||||||
|
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||||
|
utftext += String.fromCharCode((c & 63) | 128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return utftext;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = [];
|
||||||
|
let k, AA, BB, CC, DD, a, b, c, d;
|
||||||
|
const S11 = 7, S12 = 12, S13 = 17, S14 = 22;
|
||||||
|
const S21 = 5, S22 = 9, S23 = 14, S24 = 20;
|
||||||
|
const S31 = 4, S32 = 11, S33 = 16, S34 = 23;
|
||||||
|
const S41 = 6, S42 = 10, S43 = 15, S44 = 21;
|
||||||
|
|
||||||
|
string = Utf8Encode(String(string));
|
||||||
|
x = ConvertToWordArray(string);
|
||||||
|
a = 0x67452301;
|
||||||
|
b = 0xefcdab89;
|
||||||
|
c = 0x98badcfe;
|
||||||
|
d = 0x10325476;
|
||||||
|
|
||||||
|
for (k = 0; k < x.length; k += 16) {
|
||||||
|
AA = a; BB = b; CC = c; DD = d;
|
||||||
|
a = FF(a, b, c, d, x[k + 0], S11, 0xd76aa478);
|
||||||
|
d = FF(d, a, b, c, x[k + 1], S12, 0xe8c7b756);
|
||||||
|
c = FF(c, d, a, b, x[k + 2], S13, 0x242070db);
|
||||||
|
b = FF(b, c, d, a, x[k + 3], S14, 0xc1bdceee);
|
||||||
|
a = FF(a, b, c, d, x[k + 4], S11, 0xf57c0faf);
|
||||||
|
d = FF(d, a, b, c, x[k + 5], S12, 0x4787c62a);
|
||||||
|
c = FF(c, d, a, b, x[k + 6], S13, 0xa8304613);
|
||||||
|
b = FF(b, c, d, a, x[k + 7], S14, 0xfd469501);
|
||||||
|
a = FF(a, b, c, d, x[k + 8], S11, 0x698098d8);
|
||||||
|
d = FF(d, a, b, c, x[k + 9], S12, 0x8b44f7af);
|
||||||
|
c = FF(c, d, a, b, x[k + 10], S13, 0xffff5bb1);
|
||||||
|
b = FF(b, c, d, a, x[k + 11], S14, 0x895cd7be);
|
||||||
|
a = FF(a, b, c, d, x[k + 12], S11, 0x6b901122);
|
||||||
|
d = FF(d, a, b, c, x[k + 13], S12, 0xfd987193);
|
||||||
|
c = FF(c, d, a, b, x[k + 14], S13, 0xa679438e);
|
||||||
|
b = FF(b, c, d, a, x[k + 15], S14, 0x49b40821);
|
||||||
|
a = GG(a, b, c, d, x[k + 1], S21, 0xf61e2562);
|
||||||
|
d = GG(d, a, b, c, x[k + 6], S22, 0xc040b340);
|
||||||
|
c = GG(c, d, a, b, x[k + 11], S23, 0x265e5a51);
|
||||||
|
b = GG(b, c, d, a, x[k + 0], S24, 0xe9b6c7aa);
|
||||||
|
a = GG(a, b, c, d, x[k + 5], S21, 0xd62f105d);
|
||||||
|
d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
|
||||||
|
c = GG(c, d, a, b, x[k + 15], S23, 0xd8a1e681);
|
||||||
|
b = GG(b, c, d, a, x[k + 4], S24, 0xe7d3fbc8);
|
||||||
|
a = GG(a, b, c, d, x[k + 9], S21, 0x21e1cde6);
|
||||||
|
d = GG(d, a, b, c, x[k + 14], S22, 0xc33707d6);
|
||||||
|
c = GG(c, d, a, b, x[k + 3], S23, 0xf4d50d87);
|
||||||
|
b = GG(b, c, d, a, x[k + 8], S24, 0x455a14ed);
|
||||||
|
a = GG(a, b, c, d, x[k + 13], S21, 0xa9e3e905);
|
||||||
|
d = GG(d, a, b, c, x[k + 2], S22, 0xfcefa3f8);
|
||||||
|
c = GG(c, d, a, b, x[k + 7], S23, 0x676f02d9);
|
||||||
|
b = GG(b, c, d, a, x[k + 12], S24, 0x8d2a4c8a);
|
||||||
|
a = HH(a, b, c, d, x[k + 5], S31, 0xfffa3942);
|
||||||
|
d = HH(d, a, b, c, x[k + 8], S32, 0x8771f681);
|
||||||
|
c = HH(c, d, a, b, x[k + 11], S33, 0x6d9d6122);
|
||||||
|
b = HH(b, c, d, a, x[k + 14], S34, 0xfde5380c);
|
||||||
|
a = HH(a, b, c, d, x[k + 1], S31, 0xa4beea44);
|
||||||
|
d = HH(d, a, b, c, x[k + 4], S32, 0x4bdecfa9);
|
||||||
|
c = HH(c, d, a, b, x[k + 7], S33, 0xf6bb4b60);
|
||||||
|
b = HH(b, c, d, a, x[k + 10], S34, 0xbebfbc70);
|
||||||
|
a = HH(a, b, c, d, x[k + 13], S31, 0x289b7ec6);
|
||||||
|
d = HH(d, a, b, c, x[k + 0], S32, 0xeaa127fa);
|
||||||
|
c = HH(c, d, a, b, x[k + 3], S33, 0xd4ef3085);
|
||||||
|
b = HH(b, c, d, a, x[k + 6], S34, 0x4881d05);
|
||||||
|
a = HH(a, b, c, d, x[k + 9], S31, 0xd9d4d039);
|
||||||
|
d = HH(d, a, b, c, x[k + 12], S32, 0xe6db99e5);
|
||||||
|
c = HH(c, d, a, b, x[k + 15], S33, 0x1fa27cf8);
|
||||||
|
b = HH(b, c, d, a, x[k + 2], S34, 0xc4ac5665);
|
||||||
|
a = II(a, b, c, d, x[k + 0], S41, 0xf4292244);
|
||||||
|
d = II(d, a, b, c, x[k + 7], S42, 0x432aff97);
|
||||||
|
c = II(c, d, a, b, x[k + 14], S43, 0xab9423a7);
|
||||||
|
b = II(b, c, d, a, x[k + 5], S44, 0xfc93a039);
|
||||||
|
a = II(a, b, c, d, x[k + 12], S41, 0x655b59c3);
|
||||||
|
d = II(d, a, b, c, x[k + 3], S42, 0x8f0ccc92);
|
||||||
|
c = II(c, d, a, b, x[k + 10], S43, 0xffeff47d);
|
||||||
|
b = II(b, c, d, a, x[k + 1], S44, 0x85845dd1);
|
||||||
|
a = II(a, b, c, d, x[k + 8], S41, 0x6fa87e4f);
|
||||||
|
d = II(d, a, b, c, x[k + 15], S42, 0xfe2ce6e0);
|
||||||
|
c = II(c, d, a, b, x[k + 6], S43, 0xa3014314);
|
||||||
|
b = II(b, c, d, a, x[k + 13], S44, 0x4e0811a1);
|
||||||
|
a = II(a, b, c, d, x[k + 4], S41, 0xf7537e82);
|
||||||
|
d = II(d, a, b, c, x[k + 11], S42, 0xbd3af235);
|
||||||
|
c = II(c, d, a, b, x[k + 2], S43, 0x2ad7d2bb);
|
||||||
|
b = II(b, c, d, a, x[k + 9], S44, 0xeb86d391);
|
||||||
|
a = AddUnsigned(a, AA);
|
||||||
|
b = AddUnsigned(b, BB);
|
||||||
|
c = AddUnsigned(c, CC);
|
||||||
|
d = AddUnsigned(d, DD);
|
||||||
|
}
|
||||||
|
|
||||||
|
const temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d);
|
||||||
|
return temp.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将参数按字典序拼装为查询字符串
|
||||||
|
function buildSortedQuery(params) {
|
||||||
|
const sortedKeys = Object.keys(params || {}).sort();
|
||||||
|
return sortedKeys.map(key => `${key}=${params[key] !== undefined ? params[key] : ''}`).join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调试开关:如需打印签名原串和 sig,临时改为 true
|
||||||
|
const DEBUG_AMAP_SIG = false;
|
||||||
|
|
||||||
|
// 构造高德 API 签名(正确规则:参数字符串 + 私钥,不含路径)
|
||||||
|
function buildAmapSig(params) {
|
||||||
|
const query = buildSortedQuery(params);
|
||||||
|
const raw = `${query}${AMAP_SECURITY_KEY}`;
|
||||||
|
if (DEBUG_AMAP_SIG) {
|
||||||
|
console.log('[AMap Sig Debug] query:', query, 'raw:', raw, 'sig:', md5(raw));
|
||||||
|
}
|
||||||
|
return md5(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤掉 undefined / null 参数,避免签名与请求不一致
|
||||||
|
function sanitizeParams(obj = {}) {
|
||||||
|
const cleaned = {};
|
||||||
|
Object.keys(obj).forEach((k) => {
|
||||||
|
const v = obj[k];
|
||||||
|
if (v !== undefined && v !== null) {
|
||||||
|
cleaned[k] = v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return cleaned;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一的高德 API 请求
|
||||||
|
function requestAmap(path, params = {}) {
|
||||||
|
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
||||||
|
const baseParams = sanitizeParams({
|
||||||
|
key: AMAP_KEY,
|
||||||
|
...params
|
||||||
|
});
|
||||||
|
const sig = buildAmapSig(baseParams);
|
||||||
|
const queryParams = sanitizeParams({
|
||||||
|
...baseParams,
|
||||||
|
sig
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.request({
|
||||||
|
url: `${AMAP_BASE_URL}${normalizedPath}`,
|
||||||
|
method: 'GET',
|
||||||
|
data: queryParams,
|
||||||
|
success: (res) => {
|
||||||
|
if (res.data && res.data.status === '1') {
|
||||||
|
resolve(res.data);
|
||||||
|
} else {
|
||||||
|
reject(res.data || { message: 'AMap request failed' });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: reject
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 WGS84 转 GCJ02(支付宝 my.getLocation 返回 WGS84)
|
||||||
|
async function convertToGcj02(longitude, latitude) {
|
||||||
|
if (!isAlipayEnv) {
|
||||||
|
return { longitude, latitude };
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = await requestAmap('/assistant/coordinate/convert', {
|
||||||
|
locations: `${longitude},${latitude}`,
|
||||||
|
coordsys: 'gps' // gps 即 WGS84
|
||||||
|
});
|
||||||
|
const locStr = (data.locations || '').split(';')[0] || '';
|
||||||
|
const [lngStr, latStr] = locStr.split(',');
|
||||||
|
const lng = Number(lngStr);
|
||||||
|
const lat = Number(latStr);
|
||||||
|
if (!isNaN(lng) && !isNaN(lat)) {
|
||||||
|
return { longitude: lng, latitude: lat };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('坐标转换失败,使用原始坐标:', err);
|
||||||
|
}
|
||||||
|
return { longitude, latitude };
|
||||||
|
}
|
||||||
|
|
||||||
// 内联腾讯地图SDK核心代码
|
// 内联腾讯地图SDK核心代码
|
||||||
const QQMapWX = (function() {
|
const QQMapWX = (function() {
|
||||||
// 错误配置
|
// 错误配置
|
||||||
@@ -118,22 +399,55 @@ const QQMapWX = (function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!param.location) {
|
if (!param.location) {
|
||||||
|
// 微信小程序使用 wx.getLocation
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
wx.getLocation({
|
wx.getLocation({
|
||||||
type: 'gcj02',
|
type: 'gcj02',
|
||||||
success: locationsuccess,
|
success: locationsuccess,
|
||||||
fail: locationfail,
|
fail: locationfail,
|
||||||
complete: locationcomplete
|
complete: locationcomplete
|
||||||
});
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// 支付宝小程序使用 my.getLocation(不支持 type)
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
my.getLocation({
|
||||||
|
success: (res) => {
|
||||||
|
// 确保经纬度是数字类型
|
||||||
|
const result = {
|
||||||
|
...res,
|
||||||
|
longitude: Number(res.longitude),
|
||||||
|
latitude: Number(res.latitude)
|
||||||
|
};
|
||||||
|
locationsuccess(result);
|
||||||
|
},
|
||||||
|
fail: locationfail,
|
||||||
|
complete: locationcomplete
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// 其他平台使用 uni.getLocation
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
// #ifndef MP-ALIPAY
|
||||||
|
uni.getLocation({
|
||||||
|
type: 'gcj02',
|
||||||
|
success: locationsuccess,
|
||||||
|
fail: locationfail,
|
||||||
|
complete: locationcomplete
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
// #endif
|
||||||
} else if (that.checkLocation(param)) {
|
} else if (that.checkLocation(param)) {
|
||||||
const location = Utils.getLocationParam(param.location);
|
const location = Utils.getLocationParam(param.location);
|
||||||
locationsuccess(location);
|
locationsuccess(location);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 构造微信请求参数
|
// 构造腾讯地图API请求参数(跨平台兼容)
|
||||||
buildWxRequestConfig(param, options, feature) {
|
buildWxRequestConfig(param, options, feature) {
|
||||||
const that = this;
|
const that = this;
|
||||||
options.header = { "content-type": "application/json" };
|
// GET请求不需要设置content-type,uni.request会自动处理
|
||||||
|
options.header = options.header || {};
|
||||||
options.method = 'GET';
|
options.method = 'GET';
|
||||||
options.success = function (res) {
|
options.success = function (res) {
|
||||||
const data = res.data;
|
const data = res.data;
|
||||||
@@ -280,8 +594,10 @@ const QQMapWX = (function() {
|
|||||||
|
|
||||||
const locationsuccess = function (result) {
|
const locationsuccess = function (result) {
|
||||||
requestParam.location = result.latitude + ',' + result.longitude;
|
requestParam.location = result.latitude + ',' + result.longitude;
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// 调用腾讯地图API - 逆地理编码接口
|
||||||
url: URL_GET_GEOCODER,
|
// 使用 uni.request 跨平台API,在支付宝小程序中自动转换为 my.request
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
|
url: URL_GET_GEOCODER, // 腾讯地图API地址:https://apis.map.qq.com/ws/geocoder/v1/
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, 'reverseGeocoder'));
|
}, 'reverseGeocoder'));
|
||||||
};
|
};
|
||||||
@@ -323,8 +639,10 @@ const QQMapWX = (function() {
|
|||||||
|
|
||||||
const locationsuccess = function (result) {
|
const locationsuccess = function (result) {
|
||||||
requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance + "," + auto_extend + ")";
|
requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance + "," + auto_extend + ")";
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// 调用腾讯地图API - POI周边检索接口
|
||||||
url: URL_SEARCH,
|
// 使用 uni.request 跨平台API,在支付宝小程序中自动转换为 my.request
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
|
url: URL_SEARCH, // 腾讯地图API地址:https://apis.map.qq.com/ws/place/v1/search
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, 'search'));
|
}, 'search'));
|
||||||
};
|
};
|
||||||
@@ -368,15 +686,19 @@ const QQMapWX = (function() {
|
|||||||
if (options.location) {
|
if (options.location) {
|
||||||
const locationsuccess = function (result) {
|
const locationsuccess = function (result) {
|
||||||
requestParam.location = result.latitude + ',' + result.longitude;
|
requestParam.location = result.latitude + ',' + result.longitude;
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// 调用腾讯地图API - 地点搜索建议接口
|
||||||
url: URL_SUGGESTION,
|
// 使用 uni.request 跨平台API,在支付宝小程序中自动转换为 my.request
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
|
url: URL_SUGGESTION, // 腾讯地图API地址:https://apis.map.qq.com/ws/place/v1/suggestion
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, "suggest"));
|
}, "suggest"));
|
||||||
};
|
};
|
||||||
Utils.locationProcess(options, locationsuccess);
|
Utils.locationProcess(options, locationsuccess);
|
||||||
} else {
|
} else {
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// 调用腾讯地图API - 地点搜索建议接口(无位置信息)
|
||||||
url: URL_SUGGESTION,
|
// 使用 uni.request 跨平台API,在支付宝小程序中自动转换为 my.request
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
|
url: URL_SUGGESTION, // 腾讯地图API地址:https://apis.map.qq.com/ws/place/v1/suggestion
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, "suggest"));
|
}, "suggest"));
|
||||||
}
|
}
|
||||||
@@ -408,8 +730,10 @@ const QQMapWX = (function() {
|
|||||||
|
|
||||||
const locationsuccess = function (result) {
|
const locationsuccess = function (result) {
|
||||||
requestParam.from = result.latitude + ',' + result.longitude;
|
requestParam.from = result.latitude + ',' + result.longitude;
|
||||||
wx.request(Utils.buildWxRequestConfig(options, {
|
// 调用腾讯地图API - 距离计算接口
|
||||||
url: URL_DISTANCE,
|
// 使用 uni.request 跨平台API,在支付宝小程序中自动转换为 my.request
|
||||||
|
uni.request(Utils.buildWxRequestConfig(options, {
|
||||||
|
url: URL_DISTANCE, // 腾讯地图API地址:https://apis.map.qq.com/ws/distance/v1/
|
||||||
data: requestParam
|
data: requestParam
|
||||||
}, 'calculateDistance'));
|
}, 'calculateDistance'));
|
||||||
};
|
};
|
||||||
@@ -426,6 +750,10 @@ let qqmapInstance = null;
|
|||||||
|
|
||||||
// 初始化腾讯地图SDK
|
// 初始化腾讯地图SDK
|
||||||
function initQQMap() {
|
function initQQMap() {
|
||||||
|
if (isAlipayEnv) {
|
||||||
|
// 支付宝端改用高德地图服务
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (!qqmapInstance) {
|
if (!qqmapInstance) {
|
||||||
try {
|
try {
|
||||||
qqmapInstance = new QQMapWX({
|
qqmapInstance = new QQMapWX({
|
||||||
@@ -441,6 +769,9 @@ function initQQMap() {
|
|||||||
|
|
||||||
// 获取腾讯地图SDK实例
|
// 获取腾讯地图SDK实例
|
||||||
function getQQMapInstance() {
|
function getQQMapInstance() {
|
||||||
|
if (isAlipayEnv) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return qqmapInstance || initQQMap();
|
return qqmapInstance || initQQMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,8 +818,9 @@ function getUserLocation() {
|
|||||||
wx.getLocation({
|
wx.getLocation({
|
||||||
type: 'gcj02',
|
type: 'gcj02',
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
const longitude = parseFloat(res.longitude.toFixed(5));
|
// 确保经纬度是数字类型
|
||||||
const latitude = parseFloat(res.latitude.toFixed(5));
|
const longitude = parseFloat(Number(res.longitude).toFixed(5));
|
||||||
|
const latitude = parseFloat(Number(res.latitude).toFixed(5));
|
||||||
console.log('地址获取成功');
|
console.log('地址获取成功');
|
||||||
resolve({
|
resolve({
|
||||||
longitude,
|
longitude,
|
||||||
@@ -533,8 +865,9 @@ function getUserLocation() {
|
|||||||
wx.getLocation({
|
wx.getLocation({
|
||||||
type: 'gcj02',
|
type: 'gcj02',
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
const longitude = parseFloat(res.longitude.toFixed(5));
|
// 确保经纬度是数字类型
|
||||||
const latitude = parseFloat(res.latitude.toFixed(5));
|
const longitude = parseFloat(Number(res.longitude).toFixed(5));
|
||||||
|
const latitude = parseFloat(Number(res.latitude).toFixed(5));
|
||||||
console.log('地址获取成功');
|
console.log('地址获取成功');
|
||||||
resolve({
|
resolve({
|
||||||
longitude,
|
longitude,
|
||||||
@@ -550,13 +883,114 @@ function getUserLocation() {
|
|||||||
});
|
});
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// 非微信小程序平台:使用 uni.getLocation 做一个尽量兼容的兜底
|
// 支付宝小程序:使用 my.getLocation API,不支持 type 参数
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
// 支付宝小程序权限检查
|
||||||
|
my.getSetting({
|
||||||
|
success: (settingRes) => {
|
||||||
|
const authSetting = settingRes.authSetting || {};
|
||||||
|
const hasLocationAuth = Object.prototype.hasOwnProperty.call(authSetting, 'location');
|
||||||
|
const locationAuth = authSetting['location'];
|
||||||
|
|
||||||
|
// 已明确拒绝定位
|
||||||
|
if (locationAuth === false) {
|
||||||
|
my.showModal({
|
||||||
|
title: getPermissionText('locationTitle'),
|
||||||
|
content: getPermissionText('locationNeed'),
|
||||||
|
confirmText: getPermissionText('goToSettings'),
|
||||||
|
cancelText: getPermissionText('later'),
|
||||||
|
success: (modalRes) => {
|
||||||
|
if (modalRes.confirm) {
|
||||||
|
my.openSetting({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
reject({
|
||||||
|
code: 'LOCATION_DENIED',
|
||||||
|
errMsg: 'user denied location permission'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const doGetLocation = () => {
|
||||||
|
// 支付宝小程序使用 my.getLocation,不支持 type 参数
|
||||||
|
my.getLocation({
|
||||||
|
success: (res) => {
|
||||||
|
// 支付宝小程序返回的经纬度可能是字符串,需要先转换为数字
|
||||||
|
// 注意:支付宝返回的是 WGS84 坐标系,如需 GCJ02 需要转换
|
||||||
|
const longitude = parseFloat(Number(res.longitude).toFixed(5));
|
||||||
|
const latitude = parseFloat(Number(res.latitude).toFixed(5));
|
||||||
|
console.log('支付宝地址获取成功');
|
||||||
|
resolve({
|
||||||
|
longitude,
|
||||||
|
latitude
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail: (error) => {
|
||||||
|
console.error('获取位置失败:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 未显式授权时,主动申请一次权限
|
||||||
|
if (!hasLocationAuth || locationAuth === undefined) {
|
||||||
|
my.authorize({
|
||||||
|
scope: 'scope.userLocation',
|
||||||
|
success: () => {
|
||||||
|
doGetLocation();
|
||||||
|
},
|
||||||
|
fail: (authErr) => {
|
||||||
|
console.error('定位授权失败:', authErr);
|
||||||
|
my.showModal({
|
||||||
|
title: getPermissionText('locationTitle'),
|
||||||
|
content: getPermissionText('locationDenied'),
|
||||||
|
confirmText: getPermissionText('gotIt'),
|
||||||
|
showCancel: false
|
||||||
|
});
|
||||||
|
reject({
|
||||||
|
code: 'LOCATION_AUTH_FAIL',
|
||||||
|
errMsg: authErr.errorMessage || 'authorize location fail'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 已授权,直接获取定位
|
||||||
|
doGetLocation();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.warn('获取授权设置失败,直接尝试定位:', err);
|
||||||
|
// 支付宝小程序使用 my.getLocation,不支持 type 参数
|
||||||
|
my.getLocation({
|
||||||
|
success: (res) => {
|
||||||
|
// 支付宝小程序返回的经纬度可能是字符串,需要先转换为数字
|
||||||
|
const longitude = parseFloat(Number(res.longitude).toFixed(5));
|
||||||
|
const latitude = parseFloat(Number(res.latitude).toFixed(5));
|
||||||
|
console.log('支付宝地址获取成功');
|
||||||
|
resolve({
|
||||||
|
longitude,
|
||||||
|
latitude
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail: (error) => {
|
||||||
|
console.error('获取位置失败:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// 其他非微信、非支付宝小程序平台
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-WEIXIN
|
||||||
|
// #ifndef MP-ALIPAY
|
||||||
uni.getLocation({
|
uni.getLocation({
|
||||||
type: 'gcj02',
|
type: 'gcj02',
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
const longitude = parseFloat(res.longitude.toFixed(5));
|
// 确保经纬度是数字类型
|
||||||
const latitude = parseFloat(res.latitude.toFixed(5));
|
const longitude = parseFloat(Number(res.longitude).toFixed(5));
|
||||||
|
const latitude = parseFloat(Number(res.latitude).toFixed(5));
|
||||||
console.log('地址获取成功');
|
console.log('地址获取成功');
|
||||||
resolve({
|
resolve({
|
||||||
longitude,
|
longitude,
|
||||||
@@ -569,12 +1003,46 @@ function getUserLocation() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// #endif
|
// #endif
|
||||||
|
// #endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 逆地理编码 - 根据经纬度获取地址信息
|
// 逆地理编码 - 根据经纬度获取地址信息
|
||||||
function getRegeo(longitude, latitude) {
|
function getRegeo(longitude, latitude) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
// 支付宝端使用高德逆地理编码
|
||||||
|
if (isAlipayEnv) {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const gcj = await convertToGcj02(longitude, latitude);
|
||||||
|
const data = await requestAmap('/geocode/regeo', {
|
||||||
|
location: `${gcj.longitude},${gcj.latitude}`,
|
||||||
|
extensions: 'all',
|
||||||
|
batch: 'false'
|
||||||
|
});
|
||||||
|
const info = data.regeocode || {};
|
||||||
|
const comp = info.addressComponent || {};
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
formatted_address: info.formatted_address || '',
|
||||||
|
addressComponent: {
|
||||||
|
city: comp.city || comp.province || '',
|
||||||
|
district: comp.district || '',
|
||||||
|
province: comp.province || '',
|
||||||
|
street: comp.streetNumber?.street || comp.street || '',
|
||||||
|
street_number: comp.streetNumber?.number || comp.streetNumber?.street_number || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('高德逆地理编码失败:', error);
|
||||||
|
reject({ success: false, message: error.message || '逆地理编码失败' });
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const qqmap = getQQMapInstance();
|
const qqmap = getQQMapInstance();
|
||||||
if (!qqmap) {
|
if (!qqmap) {
|
||||||
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
||||||
@@ -614,6 +1082,45 @@ function getRegeo(longitude, latitude) {
|
|||||||
// 搜索周边POI
|
// 搜索周边POI
|
||||||
function getPoiAround(longitude, latitude, keyword = '', radius = 1000) {
|
function getPoiAround(longitude, latitude, keyword = '', radius = 1000) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
// 支付宝端使用高德周边搜索
|
||||||
|
if (isAlipayEnv) {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const gcj = await convertToGcj02(longitude, latitude);
|
||||||
|
const data = await requestAmap('/place/around', {
|
||||||
|
location: `${gcj.longitude},${gcj.latitude}`,
|
||||||
|
keywords: keyword,
|
||||||
|
radius,
|
||||||
|
offset: 20,
|
||||||
|
page: 1,
|
||||||
|
extensions: 'base',
|
||||||
|
sortrule: 'distance'
|
||||||
|
});
|
||||||
|
const pois = data.pois || [];
|
||||||
|
const normalized = pois.map((item, idx) => ({
|
||||||
|
id: item.id || idx + 1,
|
||||||
|
title: item.name || '',
|
||||||
|
latitude: Number(item.location?.split(',')[1] || item.location?.lat || 0),
|
||||||
|
longitude: Number(item.location?.split(',')[0] || item.location?.lng || 0),
|
||||||
|
address: item.address || '',
|
||||||
|
category: item.type || '',
|
||||||
|
tel: item.tel || '',
|
||||||
|
city: item.cityname || '',
|
||||||
|
district: item.adname || '',
|
||||||
|
province: item.pname || ''
|
||||||
|
}));
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
data: normalized
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('高德周边搜索失败:', error);
|
||||||
|
reject({ success: false, message: error.message || '搜索POI失败' });
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const qqmap = getQQMapInstance();
|
const qqmap = getQQMapInstance();
|
||||||
if (!qqmap) {
|
if (!qqmap) {
|
||||||
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
||||||
@@ -645,6 +1152,63 @@ function getPoiAround(longitude, latitude, keyword = '', radius = 1000) {
|
|||||||
// 计算距离(异步)
|
// 计算距离(异步)
|
||||||
function calculateDistance(from, to) {
|
function calculateDistance(from, to) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
// 支付宝端使用高德距离测量接口
|
||||||
|
if (isAlipayEnv) {
|
||||||
|
// to 支持数组
|
||||||
|
const targets = Array.isArray(to) ? to : [to];
|
||||||
|
if (!targets.length) {
|
||||||
|
reject({ success: false, message: '缺少目标坐标' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const doRequest = async (originPoint) => {
|
||||||
|
if (!originPoint || originPoint.longitude === undefined || originPoint.latitude === undefined) {
|
||||||
|
reject({ success: false, message: '缺少起点坐标' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const originGcj = await convertToGcj02(originPoint.longitude || originPoint.lng, originPoint.latitude || originPoint.lat);
|
||||||
|
const convertedTargets = await Promise.all(targets.map(async (item) => {
|
||||||
|
const lng = item.longitude || item.lng;
|
||||||
|
const lat = item.latitude || item.lat;
|
||||||
|
const res = await convertToGcj02(lng, lat);
|
||||||
|
return `${res.longitude},${res.latitude}`;
|
||||||
|
}));
|
||||||
|
const origins = convertedTargets.join('|');
|
||||||
|
const destination = `${originGcj.longitude},${originGcj.latitude}`;
|
||||||
|
const data = await requestAmap('/distance', {
|
||||||
|
origins,
|
||||||
|
destination,
|
||||||
|
type: 3 // 3:步行距离
|
||||||
|
});
|
||||||
|
const results = data.results || [];
|
||||||
|
const distance = results.map(r => Number(r.distance || 0));
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
data: distance
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('高德距离计算失败:', error);
|
||||||
|
reject({ success: false, message: error.message || '计算距离失败' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (from && typeof from === 'object') {
|
||||||
|
doRequest(from);
|
||||||
|
} else {
|
||||||
|
// 未传入起点时,使用用户当前定位
|
||||||
|
getUserLocation().then(loc => {
|
||||||
|
doRequest({
|
||||||
|
longitude: loc.longitude,
|
||||||
|
latitude: loc.latitude
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
reject({ success: false, message: err.message || '获取起点位置失败' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const qqmap = getQQMapInstance();
|
const qqmap = getQQMapInstance();
|
||||||
if (!qqmap) {
|
if (!qqmap) {
|
||||||
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
||||||
@@ -685,6 +1249,37 @@ function calculateDistanceSync(lat1, lng1, lat2, lng2) {
|
|||||||
// 关键词提示
|
// 关键词提示
|
||||||
function getSuggestion(keyword, region = '全国') {
|
function getSuggestion(keyword, region = '全国') {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
// 支付宝端使用高德输入提示
|
||||||
|
if (isAlipayEnv) {
|
||||||
|
requestAmap('/assistant/inputtips', {
|
||||||
|
keywords: keyword,
|
||||||
|
city: region === '全国' ? undefined : region,
|
||||||
|
datatype: 'all'
|
||||||
|
}).then((data) => {
|
||||||
|
const tips = data.tips || [];
|
||||||
|
const normalized = tips.map((item, idx) => ({
|
||||||
|
id: item.id || idx + 1,
|
||||||
|
title: item.name || '',
|
||||||
|
adcode: item.adcode || '',
|
||||||
|
address: item.address || '',
|
||||||
|
category: item.type || '',
|
||||||
|
city: item.city || '',
|
||||||
|
district: item.district || '',
|
||||||
|
latitude: item.location ? Number(item.location.split(',')[1]) : null,
|
||||||
|
longitude: item.location ? Number(item.location.split(',')[0]) : null,
|
||||||
|
province: item.province || ''
|
||||||
|
}));
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
data: normalized
|
||||||
|
});
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('高德关键词提示失败:', error);
|
||||||
|
reject({ success: false, message: error.message || '关键词提示失败' });
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const qqmap = getQQMapInstance();
|
const qqmap = getQQMapInstance();
|
||||||
if (!qqmap) {
|
if (!qqmap) {
|
||||||
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
reject({ success: false, message: '腾讯地图SDK未初始化' });
|
||||||
|
|||||||
+12
-3
@@ -248,8 +248,10 @@ class OrderMonitor {
|
|||||||
// 导出单例实例
|
// 导出单例实例
|
||||||
export const orderMonitor = new OrderMonitor()
|
export const orderMonitor = new OrderMonitor()
|
||||||
|
|
||||||
// 监听页面切换事件
|
// 监听页面切换事件(仅微信小程序支持)
|
||||||
uni.onAppRoute((route) => {
|
// #ifdef MP-WEIXIN
|
||||||
|
if (typeof uni.onAppRoute === 'function') {
|
||||||
|
uni.onAppRoute((route) => {
|
||||||
const pagePath = route.path || ''
|
const pagePath = route.path || ''
|
||||||
const pageSegments = pagePath.split('/')
|
const pageSegments = pagePath.split('/')
|
||||||
const pageName = pageSegments[pageSegments.length - 1]
|
const pageName = pageSegments[pageSegments.length - 1]
|
||||||
@@ -258,7 +260,14 @@ uni.onAppRoute((route) => {
|
|||||||
orderMonitor.setActivePage(pageName || null)
|
orderMonitor.setActivePage(pageName || null)
|
||||||
|
|
||||||
console.log('页面切换:', pagePath, '当前活跃页面:', pageName)
|
console.log('页面切换:', pagePath, '当前活跃页面:', pageName)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
// 支付宝小程序不支持 onAppRoute,通过页面生命周期手动设置
|
||||||
|
// 各个页面需要在 onShow 中调用 orderMonitor.setActivePage()
|
||||||
|
// #endif
|
||||||
|
|
||||||
// 页面加载时自动恢复监控上次的活跃订单(如果有)
|
// 页面加载时自动恢复监控上次的活跃订单(如果有)
|
||||||
const initOrderMonitor = () => {
|
const initOrderMonitor = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user