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 功能直接读取卡片
+
+
+
+
+
+ {{ 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;