hookehuyr

docs: 添加无网络场景的扫码核销功能实现文档

1 +2. 关键功能模块实现(微信小程序示例)
2 +以下是核心代码实现,基于微信小程序的 wx.getNetworkType 检测网络、wx.setStorageSync 本地存储、自有后端同步的方案:
3 +```javascript
4 +// pages/verify/verify.js
5 +// 下面是主要思路和实现, 需要修改的是扫描成功之后需要跳转到另一个页面显示核销成功/失败的提示
6 +// 1. 调用 scanCodeVerify 方法开始扫码核销
7 +// 2. 扫码成功后,调用 handleVerify 方法处理核销逻辑
8 +// 3. 在 handleVerify 方法中,先检测网络状态
9 +// 4. 如果有网,实时校验核销码并调用后端核销接口
10 +// 5. 如果无网,先校验本地存储中是否有该核销码的记录
11 +// 6. 如果有记录,说明之前核销过,提示用户已核销
12 +// 7. 如果无记录,提示用户无网络,无法核销
13 +// 8. 核销成功后,同步更新本地记录(可选)
14 +Page({
15 + /**
16 + * 扫码核销核心方法
17 + */
18 + scanCodeVerify() {
19 + // 1. 调起微信扫码API
20 + wx.scanCode({
21 + onlyFromCamera: true, // 仅允许从相机扫码
22 + scanType: ['qrCode'], // 仅识别二维码
23 + success: (res) => {
24 + const verifyCode = res.result; // 扫码获取的核销码
25 + this.handleVerify(verifyCode);
26 + },
27 + fail: (err) => {
28 + wx.showToast({ title: '扫码失败,请重试', icon: 'none' });
29 + console.error('扫码失败:', err);
30 + }
31 + });
32 + },
33 +
34 + /**
35 + * 处理核销逻辑(核心)
36 + * @param {string} verifyCode 核销码
37 + */
38 + handleVerify(verifyCode) {
39 + wx.showLoading({ title: '核销中...' });
40 +
41 + // 第一步:检测网络状态
42 + wx.getNetworkType({
43 + success: (networkRes) => {
44 + const networkType = networkRes.networkType;
45 + // 判断是否有网(wifi/4g/5g为有网,none/unknown为无网)
46 + if (['wifi', '4g', '5g', '3g', '2g'].includes(networkType)) {
47 + // 有网场景:实时校验+核销
48 + this.verifyOnline(verifyCode);
49 + } else {
50 + // 无网场景:本地校验+离线核销
51 + this.verifyOffline(verifyCode);
52 + }
53 + },
54 + fail: () => {
55 + // 网络检测失败,默认走离线逻辑
56 + this.verifyOffline(verifyCode);
57 + wx.hideLoading();
58 + }
59 + });
60 + },
61 +
62 + /**
63 + * 有网核销逻辑
64 + * @param {string} verifyCode 核销码
65 + */
66 + verifyOnline(verifyCode) {
67 + wx.request({
68 + url: 'https://你的服务器域名/api/verify', // 后端核销接口
69 + method: 'POST',
70 + data: { verifyCode },
71 + success: (res) => {
72 + wx.hideLoading();
73 + if (res.data.code === 200) {
74 + wx.showToast({ title: '核销成功', icon: 'success' });
75 + // 同步本地预约状态(可选)
76 + this.updateLocalVerifyStatus(verifyCode, true);
77 + } else {
78 + wx.showToast({ title: res.data.msg || '核销失败', icon: 'none' });
79 + }
80 + },
81 + fail: (err) => {
82 + wx.hideLoading();
83 + // 网络请求失败,降级到离线核销
84 + wx.showToast({ title: '网络不稳定,将使用离线核销', icon: 'none' });
85 + setTimeout(() => {
86 + this.verifyOffline(verifyCode);
87 + }, 1500);
88 + console.error('在线核销失败:', err);
89 + }
90 + });
91 + },
92 +
93 + /**
94 + * 无网核销逻辑
95 + * @param {string} verifyCode 核销码
96 + */
97 + verifyOffline(verifyCode) {
98 + wx.hideLoading();
99 + // 1. 读取本地缓存的预约数据(需提前同步到本地)
100 + const localAppointments = wx.getStorageSync('localAppointments') || [];
101 + // 2. 本地校验核销码是否有效
102 + const targetAppointment = localAppointments.find(item => item.verifyCode === verifyCode);
103 +
104 + if (!targetAppointment) {
105 + wx.showToast({ title: '未找到该预约记录', icon: 'none' });
106 + return;
107 + }
108 + if (targetAppointment.isVerified) {
109 + wx.showToast({ title: '该预约已核销', icon: 'none' });
110 + return;
111 + }
112 +
113 + // 3. 本地核销:更新本地状态+记录离线操作
114 + targetAppointment.isVerified = true;
115 + const offlineVerifyRecords = wx.getStorageSync('offlineVerifyRecords') || [];
116 + offlineVerifyRecords.push({
117 + verifyCode,
118 + appointmentId: targetAppointment.id,
119 + verifyTime: new Date().getTime(), // 核销时间戳
120 + status: 'pending' // 待同步
121 + });
122 +
123 + // 4. 保存本地修改
124 + wx.setStorageSync('localAppointments', localAppointments);
125 + wx.setStorageSync('offlineVerifyRecords', offlineVerifyRecords);
126 +
127 + wx.showToast({ title: '离线核销成功,网络恢复后自动同步', icon: 'success' });
128 + },
129 +
130 + /**
131 + * 网络恢复后同步离线核销记录
132 + */
133 + syncOfflineRecords() {
134 + // 监听网络状态变化
135 + wx.onNetworkStatusChange((res) => {
136 + if (res.isConnected) {
137 + const offlineRecords = wx.getStorageSync('offlineVerifyRecords') || [];
138 + if (offlineRecords.length === 0) return;
139 +
140 + // 批量同步离线记录到服务器
141 + wx.request({
142 + url: 'https://你的服务器域名/api/syncOfflineVerify',
143 + method: 'POST',
144 + data: { records: offlineRecords },
145 + success: (res) => {
146 + if (res.data.code === 200) {
147 + // 同步成功:清空离线记录
148 + wx.setStorageSync('offlineVerifyRecords', []);
149 + wx.showToast({ title: '离线核销记录已同步', icon: 'success' });
150 + }
151 + },
152 + fail: (err) => {
153 + console.error('离线记录同步失败:', err);
154 + }
155 + });
156 + }
157 + });
158 + },
159 +
160 + /**
161 + * 提前同步预约数据到本地(页面加载时执行)
162 + */
163 + syncAppointmentsToLocal() {
164 + // 页面初始化/小程序启动时,拉取预约数据到本地
165 + wx.request({
166 + url: 'https://你的服务器域名/api/getAppointments',
167 + success: (res) => {
168 + if (res.data.code === 200) {
169 + wx.setStorageSync('localAppointments', res.data.data);
170 + }
171 + },
172 + fail: () => {
173 + // 网络失败则使用上次缓存的本地数据
174 + console.log('使用本地缓存的预约数据');
175 + }
176 + });
177 + },
178 +
179 + /**
180 + * 更新本地核销状态(辅助方法)
181 + */
182 + updateLocalVerifyStatus(verifyCode, isVerified) {
183 + const localAppointments = wx.getStorageSync('localAppointments') || [];
184 + const index = localAppointments.findIndex(item => item.verifyCode === verifyCode);
185 + if (index > -1) {
186 + localAppointments[index].isVerified = isVerified;
187 + wx.setStorageSync('localAppointments', localAppointments);
188 + }
189 + },
190 +
191 + /**
192 + * 页面加载时初始化
193 + */
194 + onLoad(options) {
195 + // 1. 同步预约数据到本地
196 + this.syncAppointmentsToLocal();
197 + // 2. 监听网络状态,同步离线记录
198 + this.syncOfflineRecords();
199 + // 3. 主动检查一次是否有未同步的离线记录
200 + wx.getNetworkType({
201 + success: (res) => {
202 + if (['wifi', '4g', '5g'].includes(res.networkType)) {
203 + this.syncOfflineRecords();
204 + }
205 + }
206 + });
207 + }
208 +});
209 +```
210 +3. 配套设计要点
211 +- 本地数据预处理
212 + - 小程序启动 / 核销页面加载时,主动拉取当前门店 / 账号下的待核销预约数据,缓存到本地(wx.setStorageSync 或 wx.setStorage);
213 + - 本地数据需包含:预约 ID、核销码、用户信息、预约时间、核销状态等核心字段,避免冗余。
214 +- 防重复核销设计
215 + - 本地记录核销码的核销状态(isVerified),即使无网也能避免重复核销;
216 + - 服务器端需做最终校验,同步离线记录时若发现已核销,返回提示并更新本地状态。
217 +- 数据安全与容错
218 + - 本地存储的核销记录需加简单加密(如 base64 + 时间戳),防止篡改;
219 + - 离线记录同步时,服务器需校验核销码有效性、时间范围(如预约有效期),避免无效核销;
220 + - 小程序退出 / 重启后,保留本地缓存(微信小程序本地缓存默认长期有效,可设置过期时间)。
221 +- 用户体验优化
222 + - 无网核销时,明确提示 “离线核销成功,网络恢复后自动同步”;
223 + - 网络恢复后自动同步,无需用户手动操作;
224 + - 提供 “离线记录查询” 入口,方便查看未同步的核销记录。
225 +
226 +
227 +总结
228 + 核心逻辑:无网时依赖本地缓存的预约数据完成核销,记录离线操作;有网时实时核销,网络恢复后自动同步离线记录;
229 + 关键保障:提前同步待核销数据到本地、本地标记核销状态防重复、服务器端做最终校验;
230 + 体验优化:明确的网络状态提示、自动同步机制,减少用户感知网络差异。