支付宝上架

This commit is contained in:
2026-03-26 09:47:22 +08:00
parent 802aee59cb
commit 337a92d8c1
8 changed files with 222 additions and 40 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
// export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用
export const URL = "https://manager.fdzpower.com/api" //正式服务器
// export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
// export const URL = "http://192.168.5.58:8080" //本地调试
// export const URL = "http://192.168.5.108:8080" //本地调试
// export const URL = "http://127.0.0.1:8080" //本地调试
export const appid = "wx2165f0be356ae7a9" //微信小程序appid
+4 -1
View File
@@ -101,7 +101,9 @@ export default {
invalidQRCode: 'Invalid QR code',
scanFailed: 'Scan failed',
noticeTitle: 'Notice',
getLocationFailed: 'Location unavailable'
getLocationFailed: 'Location unavailable',
locationPermissionOffTip: 'Location permission is not enabled. Nearby devices cannot be found yet. Tap the button below to enable location services.',
enableLocation: 'Enable Location'
},
guide: {
@@ -147,6 +149,7 @@ export default {
autoChargeOvertime: 'Overtime will be charged automatically by hour',
useInDesignatedArea: 'Please use the device in designated area',
rentDepositFree: 'Rent Deposit-free',
rentNow: 'Rent Now',
wxPayScoreDesc: 'WeChat Pay Score | 550+ points enjoy',
checking: 'Checking',
deviceNoNotRecognized: 'Device number not recognized',
+4 -1
View File
@@ -101,7 +101,9 @@ export default {
invalidQRCode: 'Kode QR perangkat tidak valid',
scanFailed: 'Pemindaian gagal',
noticeTitle: 'Pemberitahuan',
getLocationFailed: 'Gagal mendapatkan lokasi, menampilkan peta default'
getLocationFailed: 'Gagal mendapatkan lokasi, menampilkan peta default',
locationPermissionOffTip: 'Izin lokasi belum diaktifkan. Sementara tidak dapat mencari perangkat terdekat. Jika ingin mencari perangkat terdekat, klik tombol di bawah untuk mengaktifkan lokasi.',
enableLocation: 'Aktifkan Lokasi'
},
guide: {
@@ -148,6 +150,7 @@ export default {
autoChargeOvertime: 'Melebihi waktu penggunaan akan dikenakan biaya per jam secara otomatis',
useInDesignatedArea: 'Harap gunakan perangkat di area yang ditentukan',
rentDepositFree: 'Sewa Tanpa Deposit',
rentNow: 'Sewa Sekarang',
wxPayScoreDesc: 'Skor Pembayaran WeChat | Nikmati dengan 550 poin atau lebih',
checking: 'Memeriksa',
deviceNoNotRecognized: 'Nomor perangkat tidak dikenali',
+5 -2
View File
@@ -100,7 +100,9 @@ export default {
invalidQRCode: '无效的设备二维码',
scanFailed: '扫码失败',
noticeTitle: '通知公告',
getLocationFailed: '获取位置失败,显示默认地图'
getLocationFailed: '获取位置失败,显示默认地图',
locationPermissionOffTip: '定位权限未打开,暂无法寻找附近设备。如需寻找附近设备,点击下方按钮开启定位。',
enableLocation: '开启定位'
},
guide: {
@@ -146,6 +148,7 @@ export default {
autoChargeOvertime: '超出使用时间将自动按小时计费',
useInDesignatedArea: '请在指定区域内使用设备',
rentDepositFree: '免押金租借',
rentNow: '立即租借',
wxPayScoreDesc: '微信支付分 | 550分以上优享',
checking: '检查中',
deviceNoNotRecognized: '未识别到设备编号',
@@ -571,7 +574,7 @@ export default {
},
join: {
title: '合作加盟',
title: '信息咨询',
cooperationTitle: '合作方式',
contactUs: '联系我们',
phone: '联系电话',
+1 -1
View File
@@ -585,7 +585,7 @@
if (isWechatMiniProgram.value) {
return t('device.rentDepositFree')
} else {
return '立即租借'
return t('device.rentNow')
}
}
+184 -16
View File
@@ -17,16 +17,11 @@
</view>
<!-- 内容区域 -->
<!-- #ifdef MP-ALIPAY -->
<view class="main-content" :style="{ paddingTop: (navBarHeight + noticeHeight) + 'px' }">
<!-- #endif -->
<!-- #ifndef MP-ALIPAY -->
<view class="main-content" :style="{ paddingTop: (statusBarHeight + navBarHeight + noticeHeight) + 'px' }">
<!-- #endif -->
<view class="main-content" :style="mainContentStyle">
<!-- 全屏地图组件 -->
<!-- 支付宝小程序使用专用组件 -->
<!-- #ifdef MP-ALIPAY -->
<MapComponentAlipay v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
<MapComponentAlipay v-if="!isLoading && userLocation && !locationPermissionDenied" ref="mapRef" :userLocation="userLocation"
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
:enableMarkers="true" :bannerImages="bannerImages"
:hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup" @relocate="handleRelocate"
@@ -35,7 +30,7 @@
<!-- #endif -->
<!-- 非支付宝小程序使用通用组件 -->
<!-- #ifndef MP-ALIPAY -->
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
<MapComponent v-if="!isLoading && userLocation && !locationPermissionDenied" ref="mapRef" :userLocation="userLocation"
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
:enableMarkers="true" :bannerImages="bannerImages"
:hideMapOverlays="showGuidePopup || showNoticePopup || showActivityPopup" @relocate="handleRelocate"
@@ -44,12 +39,26 @@
<!-- #endif -->
<!-- 地图加载状态 -->
<!-- #ifdef MP-ALIPAY -->
<view v-if="!userLocation" class="location-denied-placeholder">
<view class="denied-content">
<text class="denied-text">{{ $t('home.locationPermissionOffTip') }}</text>
<view class="denied-enable-btn" @click="handleEnableLocation">
<text class="denied-enable-btn-text">{{ $t('home.enableLocation') }}</text>
</view>
</view>
</view>
<!-- 支付宝端拒绝定位后直接展示提示不展示 common.loadingLocation -->
<!-- #endif -->
<!-- #ifndef MP-ALIPAY -->
<view v-if="isLoading || !userLocation" class="map-loading-placeholder">
<view class="loading-content">
<view class="loading-spinner"></view>
<text>{{ $t('common.loadingLocation') }}</text>
</view>
</view>
<!-- #endif -->
</view>
<!-- 底部操作栏附近设备 / 扫码使用 / 我的 -->
@@ -282,6 +291,7 @@
const filteredPositions = ref([])
const isExpanded = ref(false)
const isLoading = ref(false)
const locationPermissionDenied = ref(false) // MP-ALIPAY:定位权限拒绝后展示引导文案
const showPhoneAuthPopup = ref(false)
const pendingScan = ref(false) // 是否是扫码流程触发的手机号校验
const expectedUserPhone = ref('') // 当前登录态下绑定的手机号(用于支付宝一致性校验)
@@ -324,6 +334,16 @@
// #endif
})
// 主内容区域样式:不同端适配不同的 paddingTop
const mainContentStyle = computed(() => {
// #ifdef MP-ALIPAY
return { paddingTop: (navBarHeight.value + noticeHeight.value) + 'px' }
// #endif
// #ifndef MP-ALIPAY
return { paddingTop: (statusBarHeight.value + navBarHeight.value + noticeHeight.value) + 'px' }
// #endif
})
// 使用指南步骤
const guideSteps = ref([{
title: '扫码使用',
@@ -619,6 +639,7 @@
// 方法
const init = async () => {
locationPermissionDenied.value = false
isLoading.value = true
try {
// 清理旧版本的缓存键(兼容性处理)
@@ -651,6 +672,14 @@
} catch (error) {
console.error('初始化失败:', error)
// #ifdef MP-ALIPAY
if (isLocationPermissionDenied(error)) {
locationPermissionDenied.value = true
userLocation.value = null
positionList.value = []
filteredPositions.value = []
}
// #endif
// uni.showToast({
// title: t('home.getLocationFailed'),
// icon: 'none'
@@ -660,6 +689,12 @@
}
}
const isLocationPermissionDenied = (error) => {
const msg = String(error?.errMsg || error?.message || error || '')
// 覆盖常见文案:permission denied / auth deny / 拒绝 / 未授权
return /permission\s*denied|auth\s*deny|auth\s*denied|denied|拒绝|未授权|not\s*allowed|not\s*permitted/i.test(msg)
}
const getUserLocationAndAddress = async () => {
// 使用腾讯地图SDK获取位置(若失败抛出,由调用方统一处理)
const location = await getUserLocation()
@@ -719,6 +754,55 @@
return userLocation.value
}
const handleEnableLocation = async () => {
isLoading.value = true
try {
// #ifdef MP-ALIPAY
// 支付宝:用权限指引弹窗引导用户开启定位(showAuthGuide 在权限被拒后更可靠)
// 说明:调用后系统会弹出引导/授权界面;用户授权成功后再尝试获取定位。
try {
if (typeof my !== 'undefined' && my.showAuthGuide) {
await new Promise((resolve) => {
my.showAuthGuide({
authType: 'LBS',
success: () => resolve(true),
fail: () => resolve(false)
})
})
} else if (typeof my !== 'undefined' && my.authorize) {
// 兜底:如果 showAuthGuide 不可用,再尝试 authorize 触发授权
await new Promise((resolve) => {
my.authorize({
scope: 'scope.userLocation',
success: () => resolve(true),
fail: () => resolve(false)
})
})
}
} catch (_) {}
// #endif
// 重新触发定位授权/获取流程
await getUserLocationAndAddress()
await loadPositions()
// 成功拿到定位后,再隐藏权限提示
locationPermissionDenied.value = false
} catch (error) {
console.error('开启定位失败:', error)
// #ifdef MP-ALIPAY
if (isLocationPermissionDenied(error)) {
locationPermissionDenied.value = true // 保持在页面上提示,避免出现空白区
userLocation.value = null
positionList.value = []
filteredPositions.value = []
}
// #endif
} finally {
isLoading.value = false
}
}
const loadPositions = async () => {
try {
if (!userLocation.value || !userLocation.value.latitude || !userLocation.value.longitude) {
@@ -1118,6 +1202,39 @@
await doScan()
}
// 统一提取 deviceNo,兼容 URL、编码文本、纯设备号
const extractDeviceNoFromText = (rawText) => {
if (!rawText) return ''
const text = String(rawText).trim()
if (!text) return ''
const candidates = [text]
try {
const decoded = decodeURIComponent(text)
if (decoded && decoded !== text) {
candidates.push(decoded)
}
} catch (e) {}
for (const item of candidates) {
const fromQuery =
getQueryString(item, 'deviceNo') ||
getQueryString(item, 'deviceno')
if (fromQuery) {
return String(fromQuery).trim()
}
}
// 二维码内容本身就是设备号时,直接使用原文
for (const item of candidates) {
if (!item.includes('=') && !item.includes('&') && !item.includes('?')) {
return item
}
}
return ''
}
const processScanResult = async (scanResult) => {
try {
console.log('===== 处理扫码结果 =====');
@@ -1126,17 +1243,20 @@
console.log('result:', scanResult.result);
console.log('path:', scanResult.path);
let deviceNo;
let deviceNo = ''
if (scanResult.scanType == 'MANUAL') {
deviceNo = scanResult.result;
console.log('手动输入模式,设备号:', deviceNo);
deviceNo = extractDeviceNoFromText(scanResult.result)
console.log('手动输入模式,设备号:', deviceNo)
} else if (scanResult.scanType == 'QR_CODE') {
// 修复:移除多余的引号
deviceNo = getQueryString(scanResult.result, 'deviceNo');
console.log('二维码扫描模式,提取设备号:', deviceNo);
deviceNo =
extractDeviceNoFromText(scanResult.result) ||
extractDeviceNoFromText(scanResult.path)
console.log('二维码扫描模式,提取设备号:', deviceNo)
} else {
deviceNo = getQueryString(scanResult.path || scanResult.result, 'deviceNo');
console.log('其他模式,提取设备号:', deviceNo);
deviceNo =
extractDeviceNoFromText(scanResult.path) ||
extractDeviceNoFromText(scanResult.result)
console.log('其他模式,提取设备号:', deviceNo)
}
console.log('最终设备号:', deviceNo);
@@ -1986,6 +2106,54 @@
}
}
/* 支付宝:定位权限拒绝后的引导文案 */
.location-denied-placeholder {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 180rpx;
background: #f6f7fb;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
padding: 0 40rpx;
box-sizing: border-box;
}
.denied-content {
width: 100%;
background: #ffffff;
border-radius: 16rpx;
padding: 40rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
}
.denied-text {
display: block;
font-size: 28rpx;
color: #333;
line-height: 1.6;
}
.denied-enable-btn {
margin-top: 28rpx;
width: 100%;
height: 88rpx;
background: #3EAB64;
border-radius: 44rpx;
display: flex;
align-items: center;
justify-content: center;
}
.denied-enable-btn-text {
font-size: 32rpx;
font-weight: 700;
color: #ffffff;
}
/* 手机号授权弹窗 */
.phone-auth-popup {
position: fixed;
+19 -16
View File
@@ -63,7 +63,7 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { getQueryString } from '../../util/index.js';
import { Html5Qrcode } from 'html5-qrcode';
import { Html5Qrcode, Html5QrcodeSupportedFormats } from 'html5-qrcode';
const inputPopup = ref(null);
const manualDeviceNo = ref('');
@@ -75,6 +75,21 @@ const flashOn = ref(false);
let html5QrCode = null;
let isProcessing = false; //
//
const getScanConfig = () => ({
fps: 12,
qrbox: (viewfinderWidth, viewfinderHeight) => {
const minEdge = Math.min(viewfinderWidth, viewfinderHeight);
const size = Math.max(220, Math.floor(minEdge * 0.72));
return { width: size, height: size };
},
disableFlip: false,
formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE],
experimentalFeatures: {
useBarCodeDetectorIfSupported: true
}
});
//
const initScan = async () => {
try {
@@ -124,11 +139,7 @@ const startScanning = async () => {
console.log('html5QrCode.start 方法:', typeof html5QrCode.start);
//
const config = {
fps: 10, // 10
qrbox: 250, //
disableFlip: false
};
const config = getScanConfig();
console.log('扫描配置:', config);
console.log('准备调用 html5QrCode.start()...');
@@ -163,11 +174,7 @@ const startScanning = async () => {
// 使
console.log('尝试使用前置摄像头...');
try {
const config = {
fps: 10,
qrbox: 250,
disableFlip: false
};
const config = getScanConfig();
await html5QrCode.start(
{ facingMode: "user" },
@@ -190,11 +197,7 @@ const startScanning = async () => {
//
console.log('最后尝试:使用默认摄像头...');
try {
const config = {
fps: 10,
qrbox: 250,
disableFlip: false
};
const config = getScanConfig();
//
const cameras = await Html5Qrcode.getCameras();
+4 -2
View File
@@ -35,9 +35,9 @@
</swiper>
</view>
<!-- 默认图片当没有广告时显示 -->
<view class="banner-card" v-else @click="navigateTo('/pages/join/index')">
<!-- <view class="banner-card" v-else @click="navigateTo('/pages/join/index')">
<image class="banner-image" src="/static/userCenter_swiper.png" mode="aspectFill" lazy-load="true"></image>
</view>
</view> -->
<!-- <view class="section-title">常用服务</view> -->
<view class="list">
<view class="list-item" @click="handleQuickReturn">
@@ -97,6 +97,7 @@
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view> -->
<!-- #ifndef MP-ALIPAY -->
<view class="list-item" @click="navigateTo('/subPackages/other/join/index')">
<view class="left">
<image class="icon" src="/static/peopleInWork.png" mode="aspectFit" lazy-load="true"></image>
@@ -104,6 +105,7 @@
</view>
<uv-icon name="arrow-right" size="16" color="#c8c8c8"></uv-icon>
</view>
<!-- #endif -->
<view class="list-item" @click="navigateTo('/subPackages/user/setting/index')">
<view class="left">
<image class="icon" src="/static/setting.png" mode="aspectFit" lazy-load="true"></image>