From b51f87790fc52bc3949b3ea35e30547321a6ab47 Mon Sep 17 00:00:00 2001 From: WindowBird <13870814+windows-bird@user.noreply.gitee.com> Date: Thu, 20 Nov 2025 13:55:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=8B=E6=9C=BA=E8=8E=B7=E5=8F=96nfc?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/memorial/nfcPairing.vue | 271 +++++++++++++++++++++++++++++++++- 1 file changed, 267 insertions(+), 4 deletions(-) diff --git a/pages/memorial/nfcPairing.vue b/pages/memorial/nfcPairing.vue index 53a35a3..bc0cd2a 100644 --- a/pages/memorial/nfcPairing.vue +++ b/pages/memorial/nfcPairing.vue @@ -11,9 +11,23 @@ /> {{ connectionText }} - - 请保持手机在线,等待刷卡设备将NFC卡号传递到本页面。 - + + 请保持手机在线,等待刷卡设备将NFC卡号传递到本页面。 + + 或使用手机 NFC 功能直接读取卡片 + + + + + + {{ nfcStatusText }} + + + {{ nfcError }} + + NFC卡号 {{ cardNo || "等待刷卡..." }} @@ -101,6 +115,11 @@ export default { usingGlobalSocketEvents: false, globalSocketHandlers: null, connectTimeout: null, + // NFC 相关状态 + nfcAdapter: null, + nfcSupported: false, + nfcEnabled: false, + nfcError: "", }; }, computed: { @@ -113,6 +132,15 @@ export default { } return this.socketConnected ? "已连接,等待刷卡" : "连接中..."; }, + nfcStatusText() { + if (!this.nfcSupported) { + return "设备不支持 NFC"; + } + if (this.nfcError) { + return `NFC 错误: ${this.nfcError}`; + } + return this.nfcEnabled ? "NFC 已开启,请将卡片贴近手机" : "NFC 未开启"; + }, }, onLoad(options = {}) { if (options.unitId) { @@ -122,9 +150,11 @@ export default { this.deviceMac = options.mac; } this.initSocket(); + this.initNFC(); }, onUnload() { this.cleanupSocket(); + this.cleanupNFC(); }, methods: { buildSocketUrl() { @@ -366,7 +396,6 @@ export default { } else if (errorMsg.includes("fail")) { userFriendlyMsg = "网络连接失败,请检查网络和服务器地址"; } - this.connectionError = userFriendlyMsg; this.socketConnected = false; }, @@ -550,6 +579,203 @@ export default { uni.hideLoading(); } }, + // NFC 相关方法 + initNFC() { + // 检查是否支持 NFC(微信小程序环境) + // #ifdef MP-WEIXIN + if (typeof wx === "undefined" || !wx.getNFCAdapter) { + console.warn("当前环境不支持 NFC 功能"); + this.nfcSupported = false; + return; + } + + try { + // 获取 NFC 适配器 + const nfcAdapter = wx.getNFCAdapter(); + if (!nfcAdapter) { + console.warn("无法获取 NFC 适配器"); + this.nfcSupported = false; + return; + } + + this.nfcAdapter = nfcAdapter; + this.nfcSupported = true; + + // 开始发现 NFC 标签 + this.startNFCDiscovery(); + } catch (error) { + console.error("初始化 NFC 失败:", error); + this.nfcSupported = false; + this.nfcError = error.message || "初始化失败"; + } + // #endif + + // #ifndef MP-WEIXIN + // 非微信小程序环境,不支持 NFC + console.warn("NFC 功能仅在微信小程序中支持"); + this.nfcSupported = false; + // #endif + }, + startNFCDiscovery() { + if (!this.nfcAdapter) return; + + try { + // 监听 NFC 标签发现事件 + this.nfcAdapter.onDiscovered((res) => { + this.handleNfcDiscovered(res); + }); + + // 开始发现 NFC 标签 + this.nfcAdapter.startDiscovery({ + success: () => { + console.log("NFC 发现已启动"); + this.nfcEnabled = true; + this.nfcError = ""; + this.lastMessage = "NFC 已开启,请将卡片贴近手机"; + }, + fail: (err) => { + console.error("启动 NFC 发现失败:", err); + this.nfcEnabled = false; + this.nfcError = err.errMsg || "启动失败"; + + // 如果是权限问题,给出提示 + if (err.errMsg && err.errMsg.includes("permission")) { + this.nfcError = "需要 NFC 权限,请在设置中开启"; + } else if (err.errMsg && err.errMsg.includes("not support")) { + this.nfcError = "设备不支持 NFC 功能"; + this.nfcSupported = false; + } + }, + }); + } catch (error) { + console.error("启动 NFC 发现异常:", error); + this.nfcEnabled = false; + this.nfcError = error.message || "启动异常"; + } + }, + handleNfcDiscovered(res) { + console.log("发现 NFC 标签:", res); + + try { + let cardNo = ""; + + console.log("移动号获取NFC:res", res); + console.log("res.id 类型:", typeof res.id, res.id); + console.log("res.techs:", res.techs); + + // NFC 卡号主要存储在 res.id 中,格式为 ArrayBuffer + // 对于 MIFARE Classic 等卡片,UID 就存储在 id 字段 + // 根据调试信息:[[ArrayBufferData]]: 1312 表示4字节的数值 + if (res.id) { + // id 通常是 ArrayBuffer,需要转换为字符串 + if (res.id instanceof ArrayBuffer) { + // 将 ArrayBuffer 转换为十六进制字符串 + const uint8Array = new Uint8Array(res.id); + const bytes = Array.from(uint8Array); + + console.log("=== NFC 卡号提取详情 ==="); + console.log("ArrayBuffer 字节长度:", res.id.byteLength); + console.log("ArrayBuffer 字节数组(十进制):", bytes); + console.log("ArrayBuffer 字节数组(十六进制):", bytes.map(b => "0x" + b.toString(16).padStart(2, "0").toUpperCase())); + + // 转换为十六进制字符串(每字节两位,不足补0) + // NFC 卡号通常按照字节顺序(大端序)存储 + cardNo = bytes + .join("") + .toUpperCase(); + + // 如果字节数组是 [0, 0, 5, 32],则卡号为 "00000520" + // 如果字节数组是 [32, 5, 0, 0],则卡号为 "20050000" + console.log("转换后的卡号(十六进制字符串):", cardNo); + console.log("卡号长度:", cardNo.length, "字符"); + console.log("========================"); + } else if (typeof res.id === "string") { + cardNo = res.id; + console.log("卡号(字符串):", cardNo); + } else { + console.warn("res.id 格式未知:", res.id); + } + } + + // 如果 id 字段没有值,尝试从 techs 中获取 + if (!cardNo && res.techs && res.techs.length > 0) { + // 尝试从 techs 中读取数据 + for (const tech of res.techs) { + if (tech.id) { + if (tech.id instanceof ArrayBuffer) { + const uint8Array = new Uint8Array(tech.id); + cardNo = Array.from(uint8Array) + .map((b) => b.toString(16).padStart(2, "0")) + .join("") + .toUpperCase(); + break; + } else if (typeof tech.id === "string") { + cardNo = tech.id; + break; + } + } + } + } + + // 如果还是没有获取到,尝试从其他字段获取 + if (!cardNo) { + // 尝试从 res 的其他字段获取 + if (res.serialNumber) { + cardNo = res.serialNumber; + } else if (res.uid) { + cardNo = res.uid; + } else if (res.cardId) { + cardNo = res.cardId; + } + } + + if (cardNo) { + // 清理卡号格式(去除空格、冒号等) + cardNo = cardNo.replace(/[\s:]/g, "").toUpperCase(); + this.cardNo = cardNo; + this.lastMessage = "已通过 NFC 读取卡号"; + uni.showToast({ + title: "读取成功", + icon: "success", + duration: 1500, + }); + console.log("NFC 读取到的卡号:", cardNo); + } else { + console.warn("无法从 NFC 标签中提取卡号:", res); + uni.showToast({ + title: "无法读取卡号", + icon: "none", + duration: 2000, + }); + } + } catch (error) { + console.error("处理 NFC 标签数据失败:", error); + uni.showToast({ + title: "读取失败", + icon: "none", + duration: 2000, + }); + } + }, + cleanupNFC() { + if (this.nfcAdapter) { + try { + // 停止 NFC 发现 + this.nfcAdapter.stopDiscovery({ + success: () => { + console.log("NFC 发现已停止"); + }, + fail: (err) => { + console.warn("停止 NFC 发现失败:", err); + }, + }); + } catch (error) { + console.warn("清理 NFC 资源失败:", error); + } + this.nfcAdapter = null; + } + this.nfcEnabled = false; + }, }, }; @@ -610,6 +836,43 @@ export default { line-height: 1.5; } +.nfc-hint { + display: block; + margin-top: 8rpx; +} + +.nfc-hint-text { + color: #4a90e2; + font-size: 22rpx; +} + +.nfc-status { + margin-top: 24rpx; + padding: 20rpx; + background: rgba(74, 144, 226, 0.08); + border-radius: 16rpx; + border-left: 4rpx solid #4a90e2; +} + +.nfc-status-header { + display: flex; + align-items: center; + gap: 12rpx; +} + +.nfc-status-title { + font-size: 26rpx; + color: #333; + font-weight: 500; +} + +.nfc-error-text { + margin-top: 12rpx; + padding: 12rpx; + background: #fef0f0; + border-radius: 8rpx; +} + .card-box { margin-top: 24rpx; border: 2rpx dashed #f0b400;