IOS 微信扫码ios:scanQRCode:the permission value is offline verifying
这个修改应该能解决 iOS 设备上的扫码问题。记得在页面销毁时可以考虑清除 localStorage 中的 URL(如果需要的话)。我直接上个代码,请大家品尝一下,有需要的自己复制相关的部分即可,不用全复制。在所有需要使用 URL 的地方都使用 getConfigUrl 函数。解决了 iOS 设备上 wx.config 可能失败的问题。在 iOS 设备上首次进入时保存初始 URL。Android
·
解决方案:
添加了 getConfigUrl 函数来统一处理 URL 获取逻辑
在 iOS 设备上首次进入时保存初始 URL
在所有需要使用 URL 的地方都使用 getConfigUrl 函数
保持了 URL 解码处理
这样修改后:
iOS 设备会使用保存的初始 URL
Android 设备会使用当前 URL
解决了 iOS 设备上 wx.config 可能失败的问题
保持了跨页面的一致性
这个修改应该能解决 iOS 设备上的扫码问题。记得在页面销毁时可以考虑清除 localStorage 中的 URL(如果需要的话)。
我直接上个代码,请大家品尝一下,有需要的自己复制相关的部分即可,不用全复制。
<template>
<div class="admin-verify-container">
<van-nav-bar
title="核销管理"
left-text="退出"
right-text="刷新"
@click-left="handleLogout"
@click-right="refreshData"
/>
<div class="actions-bar">
<van-button type="primary" icon="scan" block @click="startScan">
扫码核销
</van-button>
</div>
<div class="verify-list-title">
<h3>今日核销记录 ({{ verifyRecords.length }})</h3>
</div>
<div class="verify-list">
<van-empty v-if="verifyRecords.length === 0" description="暂无核销记录" />
<van-cell-group v-else inset>
<van-cell
v-for="record in verifyRecords"
:key="record.id"
:title="record.orderNo"
:label="`${record.amount}元 | ${record.auditDate}`"
>
<template #right-icon>
<van-tag type="success">已核销</van-tag>
</template>
</van-cell>
</van-cell-group>
</div>
<!-- 核销确认对话框 -->
<van-dialog
v-model:show="showVerifyDialog"
title="确认核销"
show-cancel-button
@confirm="handleVerify"
@cancel="cancelVerify"
>
<p class="dialog-content">
是否确认核销该订单?
<br />
订单号:{{ scannedOrderId }}
</p>
</van-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from "vue";
import { useRouter } from "vue-router";
import {
showToast,
showDialog,
NavBar as VanNavBar,
Button as VanButton,
Empty as VanEmpty,
CellGroup as VanCellGroup,
Cell as VanCell,
Tag as VanTag,
Dialog as VanDialog
} from "vant";
import "vant/es/nav-bar/style";
import "vant/es/button/style";
import "vant/es/empty/style";
import "vant/es/cell/style";
import "vant/es/cell-group/style";
import "vant/es/tag/style";
import "vant/es/dialog/style";
import "vant/es/toast/style";
import adminHttp, {
getAdminToken,
removeAdminToken
} from "@/utils/http/adminHttp";
// 删除TypeScript接口声明
interface VerifyRecord {
id: number;
orderNo: string;
amount: number;
time: string;
auditDate: string;
}
// 定义API响应接口
interface ApiResponse<T = any> {
code: number;
msg: string;
data?: T;
rows?: T;
}
const router = useRouter();
const verifyRecords = ref<VerifyRecord[]>([]);
const loading = ref(false);
const showScanResult = ref(false);
const scanResult = ref<VerifyRecord | null>(null);
const verifying = ref(false);
const scannedOrderId = ref("");
const showVerifyDialog = ref(false);
// 日期相关的计算属性
const dateRange = computed(() => {
const today = new Date();
// 设置为当天的起始时间 (00:00:00.000)
const startDate = new Date(today);
startDate.setHours(0, 0, 0, 0);
// 设置为当天的结束时间 (23:59:59.999)
const endDate = new Date(today);
endDate.setHours(23, 59, 59, 999);
// 格式化日期为后端所需格式 yyyy-MM-dd HH:mm:ss
const formatDate = (date: Date): string => {
const pad = (num: number): string => String(num).padStart(2, "0");
const year = date.getFullYear();
const month = pad(date.getMonth() + 1);
const day = pad(date.getDate());
const hours = pad(date.getHours());
const minutes = pad(date.getMinutes());
const seconds = pad(date.getSeconds());
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
return {
orderDateStart: formatDate(startDate),
orderDateEnd: formatDate(endDate)
};
});
// 检查登录状态
const checkAdminLogin = () => {
const adminToken = getAdminToken();
if (!adminToken) {
showToast("请先登录");
router.replace("/admin/login");
return false;
}
return true;
};
// 获取核销记录
const fetchVerifyRecords = async () => {
if (!checkAdminLogin()) return;
loading.value = true;
try {
// 使用计算属性中的日期范围
const { orderDateStart, orderDateEnd } = dateRange.value;
const response = await adminHttp.request<ApiResponse<VerifyRecord[]>>({
url: "/vae/order/list",
method: "GET",
params: {
status: 2,
type: 1,
orderDateStart,
orderDateEnd
},
headers: {
Authorization: `Bearer ${getAdminToken()}`
}
});
if (response.code === 200 && response.rows) {
verifyRecords.value = response.rows;
} else {
showToast({
message: response.msg || "获取记录失败",
type: "fail"
});
}
} catch (error) {
console.error("获取核销记录失败:", error);
showToast({
message: "获取记录失败,请稍后再试",
type: "fail"
});
} finally {
loading.value = false;
}
};
// 刷新数据
const refreshData = () => {
fetchVerifyRecords();
};
// 1. 添加错误重试机制
let retryCount = 0;
const maxRetries = 3;
const initWithRetry = async () => {
try {
await initWxConfig();
} catch (error) {
if (retryCount < maxRetries) {
retryCount++;
console.log(`第 ${retryCount} 次重试初始化`);
setTimeout(initWithRetry, 1000);
}
}
};
// 2. 在调用扫码前再次检查配置
const checkWxReady = () => {
return new Promise((resolve) => {
if (typeof (window as any).wx !== "undefined") {
(window as any).wx.ready(() => {
resolve(true);
});
} else {
resolve(false);
}
});
};
// 添加 getConfigUrl 函数
const getConfigUrl = () => {
let u = window.navigator.userAgent;
let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
let url = '';
if (isiOS) {
// iOS 需要使用进入页面的初始 URL
url = window.localStorage.getItem('_iosWXConfig_') || window.location.href.split('#')[0];
} else {
// 安卓使用当前 URL
url = window.location.href.split('#')[0];
}
return url;
};
// 修改 startScan 方法中获取 URL 的部分
const startScan = async () => {
if (!checkAdminLogin()) return;
try {
// 使用 getConfigUrl 获取正确的 URL
const currentUrl = decodeURIComponent(getConfigUrl());
console.log("当前URL:", currentUrl);
// 如果是 iOS 设备,保存初始 URL
if (!!window.navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) {
window.localStorage.setItem('_iosWXConfig_', currentUrl);
}
// 获取微信配置参数
const response = await adminHttp.request<ApiResponse>({
url: "/app/auth/jsSign",
method: "POST",
data: {
url: currentUrl
}
});
if (response.code !== 200 || !response.data) {
showToast("获取配置失败");
return;
}
console.log("获取到的微信配置:", response.data);
// 配置微信JSSDK
(window as any).wx.config({
debug: false,
appId: response.data.appId,
timestamp: response.data.timestamp,
nonceStr: response.data.nonceStr,
signature: response.data.signature,
jsApiList: ["scanQRCode"]
});
// 等待配置就绪后再调用扫码
(window as any).wx.ready(() => {
console.log("微信JSSDK配置就绪,开始调用扫码");
callWxScan();
});
// 配置错误处理
(window as any).wx.error((res: any) => {
console.error("微信JSSDK配置失败", {
error: res,
url: currentUrl,
config: response.data
});
showToast("初始化失败,请重试");
});
} catch (error) {
console.error("初始化微信配置错误", error);
showToast("配置失败,请重试");
}
};
// 将实际的扫码调用抽离为独立方法
const callWxScan = () => {
if (typeof (window as any).wx === "undefined") {
showToast("微信环境未初始化");
return;
}
(window as any).wx.scanQRCode({
needResult: 1,
scanType: ["qrCode"],
success: function (res: any) {
console.log("扫码成功", res);
handleScanResult(res.resultStr);
},
fail: function (error: any) {
console.error("扫码失败详情:", {
error,
stack: error?.stack,
message: error?.message
});
showToast("扫码失败,请重试");
},
cancel: function () {
console.log("用户取消扫码");
showToast("已取消扫码");
},
complete: function (res: any) {
console.log("扫码完成状态:", res);
}
});
};
// 处理扫码结果
const handleScanResult = async (result: string) => {
if (!result) {
showToast("无效的二维码");
return;
}
// 保存扫描到的订单ID
scannedOrderId.value = result;
// 添加调试信息
showToast(`扫描到订单号: ${result}`);
// 显示确认对话框
showVerifyDialog.value = true;
};
// 核销方法
const handleVerify = async () => {
// 添加调试信息
// showToast(`正在核销订单: ${scannedOrderId.value}`);
const response = await adminHttp.request<ApiResponse>({
url: `/vae/order/audit/${scannedOrderId.value}`,
method: "GET"
});
if (response.code === 200) {
refreshData();
showToast({
message: "核销成功",
type: "success"
});
// 重置状态
showVerifyDialog.value = false;
scannedOrderId.value = "";
showScanResult.value = false;
// 刷新页面
location.reload();
} else {
showToast({
message: response.msg || "核销失败",
type: "fail"
});
}
};
// 取消核销
const cancelVerify = () => {
showVerifyDialog.value = false;
scannedOrderId.value = "";
};
// 退出登录
const handleLogout = () => {
showDialog({
title: "确认退出",
message: "是否确认退出管理系统?",
showCancelButton: true,
confirmButtonText: "确认",
cancelButtonText: "取消",
confirmButtonColor: "#ff6b00"
})
.then(() => {
// 清除管理员token
removeAdminToken();
// 跳转到登录页
router.replace("/admin/login");
})
.catch(() => {
// 用户取消,不做操作
});
};
// 修改 initWxConfig 方法中获取 URL 的部分
const initWxConfig = async () => {
if (typeof (window as any).wx === "undefined") {
console.warn("未检测到微信环境");
return;
}
try {
// 使用 getConfigUrl 获取正确的 URL
const currentUrl = decodeURIComponent(getConfigUrl());
console.log("当前URL:", currentUrl);
// 如果是 iOS 设备,保存初始 URL
if (!!window.navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) {
window.localStorage.setItem('_iosWXConfig_', currentUrl);
}
// 获取微信配置参数
const response = await adminHttp.request<ApiResponse>({
url: "/app/auth/jsSign",
method: "POST",
data: {
url: currentUrl
}
});
console.log("签名请求结果:", response);
if (response.code === 200 && response.data) {
console.log("获取到的微信配置:", response.data);
// 配置微信JSSDK
(window as any).wx.config({
debug: false, // 临时开启调试模式,排查问题后记得关闭
appId: response.data.appId,
timestamp: response.data.timestamp,
nonceStr: response.data.nonceStr,
signature: response.data.signature,
jsApiList: ["scanQRCode"],
openTagList: ["wx-open-launch-weapp"] // 如果需要的话添加
});
(window as any).wx.ready(function () {
console.log("微信JSSDK配置就绪");
// 可以在这里预检查一下 API
(window as any).wx.checkJsApi({
jsApiList: ["scanQRCode"],
success: function(res: any) {
console.log("初始化时API检查结果:", res);
}
});
});
(window as any).wx.error(function (res: any) {
console.error("微信JSSDK配置失败", {
error: res,
url: currentUrl,
config: response.data
});
});
}
} catch (error) {
console.error("初始化微信配置错误", error);
}
};
// 添加一个重新初始化的方法
const reinitWxConfig = () => {
console.log("尝试重新初始化微信配置");
initWxConfig();
};
onMounted(() => {
if (checkAdminLogin()) {
fetchVerifyRecords();
}
});
</script>
<style scoped>
.admin-verify-container {
min-height: 100vh;
background: #f5f7fa;
}
.actions-bar {
padding: 16px;
}
.verify-list-title {
padding: 0 16px;
margin-bottom: 10px;
}
.verify-list-title h3 {
font-size: 16px;
color: #333;
margin: 0;
}
.verify-list {
padding-bottom: 20px;
}
.scan-result {
padding: 20px;
}
.scan-item {
margin-bottom: 15px;
display: flex;
justify-content: space-between;
}
.scan-item .label {
color: #999;
}
.scan-item .value {
color: #333;
font-weight: 500;
}
.scan-item .highlight {
color: #ff6b00;
font-size: 18px;
font-weight: bold;
}
.scan-actions {
margin-top: 20px;
display: flex;
justify-content: flex-end;
gap: 10px;
}
:deep(.van-nav-bar__text) {
color: #000;
}
:deep(.van-button--primary) {
background-color: #ff6b00;
border-color: #ff6b00;
}
:deep(.van-dialog__confirm) {
color: #ff6b00;
}
:deep(.van-dialog__header) {
padding-top: 20px;
}
.dialog-content {
padding: 20px;
text-align: center;
line-height: 1.5;
}
</style>
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)