无网场景的扫码核销.md 8.42 KB
  1. 关键功能模块实现(微信小程序示例) 以下是核心代码实现,基于微信小程序的 wx.getNetworkType 检测网络、wx.setStorageSync 本地存储、自有后端同步的方案: ```javascript // pages/verify/verify.js // 下面是主要思路和实现, 需要修改的是扫描成功之后需要跳转到另一个页面显示核销成功/失败的提示 // 1. 调用 scanCodeVerify 方法开始扫码核销 // 2. 扫码成功后,调用 handleVerify 方法处理核销逻辑 // 3. 在 handleVerify 方法中,先检测网络状态 // 4. 如果有网,实时校验核销码并调用后端核销接口 // 5. 如果无网,先校验本地存储中是否有该核销码的记录 // 6. 如果有记录,说明之前核销过,提示用户已核销 // 7. 如果无记录,提示用户无网络,无法核销 // 8. 核销成功后,同步更新本地记录(可选) Page({ /** * 扫码核销核心方法 */ scanCodeVerify() { // 1. 调起微信扫码API wx.scanCode({ onlyFromCamera: true, // 仅允许从相机扫码 scanType: ['qrCode'], // 仅识别二维码 success: (res) => { const verifyCode = res.result; // 扫码获取的核销码 this.handleVerify(verifyCode); }, fail: (err) => { wx.showToast({ title: '扫码失败,请重试', icon: 'none' }); console.error('扫码失败:', err); } }); },

/**

  • 处理核销逻辑(核心)
  • @param {string} verifyCode 核销码 */ handleVerify(verifyCode) { wx.showLoading({ title: '核销中...' });

    // 第一步:检测网络状态 wx.getNetworkType({ success: (networkRes) => { const networkType = networkRes.networkType; // 判断是否有网(wifi/4g/5g为有网,none/unknown为无网) if (['wifi', '4g', '5g', '3g', '2g'].includes(networkType)) { // 有网场景:实时校验+核销 this.verifyOnline(verifyCode); } else { // 无网场景:本地校验+离线核销 this.verifyOffline(verifyCode); } }, fail: () => { // 网络检测失败,默认走离线逻辑 this.verifyOffline(verifyCode); wx.hideLoading(); } }); },

/**

  • 有网核销逻辑
  • @param {string} verifyCode 核销码 */ verifyOnline(verifyCode) { wx.request({ url: 'https://你的服务器域名/api/verify', // 后端核销接口 method: 'POST', data: { verifyCode }, success: (res) => { wx.hideLoading(); if (res.data.code === 200) { wx.showToast({ title: '核销成功', icon: 'success' }); // 同步本地预约状态(可选) this.updateLocalVerifyStatus(verifyCode, true); } else { wx.showToast({ title: res.data.msg || '核销失败', icon: 'none' }); } }, fail: (err) => { wx.hideLoading(); // 网络请求失败,降级到离线核销 wx.showToast({ title: '网络不稳定,将使用离线核销', icon: 'none' }); setTimeout(() => { this.verifyOffline(verifyCode); }, 1500); console.error('在线核销失败:', err); } }); },

/**

  • 无网核销逻辑
  • @param {string} verifyCode 核销码 */ verifyOffline(verifyCode) { wx.hideLoading(); // 1. 读取本地缓存的预约数据(需提前同步到本地) const localAppointments = wx.getStorageSync('localAppointments') || []; // 2. 本地校验核销码是否有效 const targetAppointment = localAppointments.find(item => item.verifyCode === verifyCode);

    if (!targetAppointment) { wx.showToast({ title: '未找到该预约记录', icon: 'none' }); return; } if (targetAppointment.isVerified) { wx.showToast({ title: '该预约已核销', icon: 'none' }); return; }

    // 3. 本地核销:更新本地状态+记录离线操作 targetAppointment.isVerified = true; const offlineVerifyRecords = wx.getStorageSync('offlineVerifyRecords') || []; offlineVerifyRecords.push({ verifyCode, appointmentId: targetAppointment.id, verifyTime: new Date().getTime(), // 核销时间戳 status: 'pending' // 待同步 });

    // 4. 保存本地修改 wx.setStorageSync('localAppointments', localAppointments); wx.setStorageSync('offlineVerifyRecords', offlineVerifyRecords);

    wx.showToast({ title: '离线核销成功,网络恢复后自动同步', icon: 'success' }); },

/**

  • 网络恢复后同步离线核销记录 */ syncOfflineRecords() { // 监听网络状态变化 wx.onNetworkStatusChange((res) => { if (res.isConnected) { const offlineRecords = wx.getStorageSync('offlineVerifyRecords') || []; if (offlineRecords.length === 0) return;

    // 批量同步离线记录到服务器
    wx.request({
      url: 'https://你的服务器域名/api/syncOfflineVerify',
      method: 'POST',
      data: { records: offlineRecords },
      success: (res) => {
        if (res.data.code === 200) {
          // 同步成功:清空离线记录
          wx.setStorageSync('offlineVerifyRecords', []);
          wx.showToast({ title: '离线核销记录已同步', icon: 'success' });
        }
      },
      fail: (err) => {
        console.error('离线记录同步失败:', err);
      }
    });
    

    } }); },

/**

  • 提前同步预约数据到本地(页面加载时执行) */ syncAppointmentsToLocal() { // 页面初始化/小程序启动时,拉取预约数据到本地 wx.request({ url: 'https://你的服务器域名/api/getAppointments', success: (res) => { if (res.data.code === 200) { wx.setStorageSync('localAppointments', res.data.data); } }, fail: () => { // 网络失败则使用上次缓存的本地数据 console.log('使用本地缓存的预约数据'); } }); },

/**

  • 更新本地核销状态(辅助方法) */ updateLocalVerifyStatus(verifyCode, isVerified) { const localAppointments = wx.getStorageSync('localAppointments') || []; const index = localAppointments.findIndex(item => item.verifyCode === verifyCode); if (index > -1) { localAppointments[index].isVerified = isVerified; wx.setStorageSync('localAppointments', localAppointments); } },

/**

  • 页面加载时初始化 */ onLoad(options) { // 1. 同步预约数据到本地 this.syncAppointmentsToLocal(); // 2. 监听网络状态,同步离线记录 this.syncOfflineRecords(); // 3. 主动检查一次是否有未同步的离线记录 wx.getNetworkType({ success: (res) => { if (['wifi', '4g', '5g'].includes(res.networkType)) { this.syncOfflineRecords(); } } }); } }); ``` 3. 配套设计要点 - 本地数据预处理 - 小程序启动 / 核销页面加载时,主动拉取当前门店 / 账号下的待核销预约数据,缓存到本地(wx.setStorageSync 或 wx.setStorage); - 本地数据需包含:预约 ID、核销码、用户信息、预约时间、核销状态等核心字段,避免冗余。 - 防重复核销设计 - 本地记录核销码的核销状态(isVerified),即使无网也能避免重复核销; - 服务器端需做最终校验,同步离线记录时若发现已核销,返回提示并更新本地状态。 - 数据安全与容错 - 本地存储的核销记录需加简单加密(如 base64 + 时间戳),防止篡改; - 离线记录同步时,服务器需校验核销码有效性、时间范围(如预约有效期),避免无效核销; - 小程序退出 / 重启后,保留本地缓存(微信小程序本地缓存默认长期有效,可设置过期时间)。 - 用户体验优化 - 无网核销时,明确提示 “离线核销成功,网络恢复后自动同步”; - 网络恢复后自动同步,无需用户手动操作; - 提供 “离线记录查询” 入口,方便查看未同步的核销记录。

总结 核心逻辑:无网时依赖本地缓存的预约数据完成核销,记录离线操作;有网时实时核销,网络恢复后自动同步离线记录; 关键保障:提前同步待核销数据到本地、本地标记核销状态防重复、服务器端做最终校验; 体验优化:明确的网络状态提示、自动同步机制,减少用户感知网络差异。