// var Parse = getApp().Parse; // var app = getApp() // const { wxLogin } = require('./utils/login') const CONFIG = require("config.js"); let config = { appid: CONFIG.default.appid, company: CONFIG.default.company, rootPage: CONFIG.default.rootPage, } const plugin = requirePlugin('fm-plugin') const { Parse, checkAuth } = plugin Page({ /** * 页面的初始数据 */ data: { splashUrl: wx.getStorageSync("enabledOptions")[0], loading:true }, /** * 生命周期函数--监听页面加载 */ onLoad: async function (options) { wx.login({ success: function (res) { if (res.code) { console.log(res); // wx.request({ // url: "https://server.fmode.cn/api/wxapp/auth_wxapp", // data: { // c: getApp().globalData.company, // code: res.code, // }, // async success(res) { // wx.setStorageSync("userInfo", res.data); // resolve(res) // }, // }); } }, fail: function (err) { wx.showToast({ title: '服务器繁忙,请稍后重试', }) } }); wx.setStorageSync("invite", null); // 处理扫码链接(options.q 包含完整的URL或activityId) if (options.q) { let str = decodeURIComponent(options.q); // 扫描二维码获得的跳转链接 // 兼容一些环境中把 & 编码成 & 的情况,防止参数解析错误(如 scanCount=0&storeId=...) if (str.indexOf('&') !== -1) { console.log('🔧 检测到 URL 中包含 &,自动还原为 &'); str = str.replace(/&/g, '&'); } // 检查是否是员工邀请链接(app.fmode.cn/dev/pobingfeng/manager/staff?invite=xxx) if (str.includes('app.fmode.cn/dev/pobingfeng/manager/staff')) { let obj = this.getParaName(str); if (obj && obj.invite) { wx.setStorageSync("invite", obj.invite); console.log('✅ 检测到员工邀请链接,invite:', obj.invite); } // 员工邀请链接不需要跳转到店铺,直接返回 this.setData({ options: options }); plugin.init(config, wx.getStorageSync('invite')); return; } // 检查是否是活动海报二维码(activityId作为qrCode参数值) // 如果str不包含http/https,且看起来像是一个ID,则可能是activityId if (!str.includes('http://') && !str.includes('https://') && !str.includes('?')) { // 可能是活动ID,尝试作为activityId处理 if (str && str.length > 0 && !isNaN(str)) { options.activityId = str; console.log('✅ 检测到活动海报二维码,activityId:', str); // 活动二维码需要特殊处理,先保存activityId wx.setStorageSync("activityId", str); } } // 处理店铺相关的二维码链接(pwa.fmode.cn/gomini/pmd/) // 从完整URL中提取参数 if (str.includes('pwa.fmode.cn/gomini/pmd') || str.includes('?')) { let obj = this.getParaName(str); if (obj && obj.invite) { wx.setStorageSync("invite", obj.invite); } // 将所有参数合并到 options 中 obj && Object.keys(obj).forEach(key=> options[key] = obj[key]); } } // 兼容从编译参数或页面直达传入的 storeId if (options && options.scene && !options.storeId) { try { const sceneStr = decodeURIComponent(options.scene) if (sceneStr) { const pairs = sceneStr.split('&') for (const p of pairs) { const [k, v] = p.split('=') if (k === 'storeId' && v) { options.storeId = v break } } } } catch (e) { console.warn('解析 scene 失败:', e) } } this.setData({ options: options }) let { time, dramaId, roomId, orderId, shopId, invite, activityId, company, inviteHost, storeId } = options time && wx.setStorageSync("time", time); dramaId && wx.setStorageSync("dramaId", dramaId); roomId && wx.setStorageSync("roomId", roomId); orderId && wx.setStorageSync("orderId", orderId); shopId && wx.setStorageSync("shopId", shopId); invite && wx.setStorageSync("invite", invite); activityId && wx.setStorageSync("activityId", activityId); inviteHost && wx.setStorageSync("inviteHost", true); if (storeId) { wx.setStorageSync('storeId', storeId) getApp().globalData.storeId = storeId console.log('✅ 入口页已设置店铺 ID:', storeId) } if (company) getApp().globalData.toCompany = true; // 检查是否是扫码进入(需要统计扫码次数) this.checkAndHandleScan(options); plugin.init(config, wx.getStorageSync('invite')) }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady: async function () { }, /** * 生命周期函数--监听页面显示 */ onShow: async function () { await this.review() }, async review(force){ try { let options = this.data.options let url = getApp().globalData.rootPage || getApp().globalData.defaultTabBar.list[0].pagePath if (options) { let objArr = Object.keys(options) if (objArr && objArr.length > 0) { let parms = '?' objArr.forEach((o, index) => { if (index > 0) { parms += '&' + o + '=' + options[o] } else { parms += o + '=' + options[o] } }) url += parms } } let currentUser = Parse.User.current() console.log(Parse.User.current()) if (!currentUser || force) { // let data = await wxLogin() // if (data.statusCode == 200) { let r = await checkAuth(true) console.log(r); // getApp().Parse = Parse // getApp().checkAuth = checkAuth if(!r) return // } } else { this.updateUser(currentUser.id) } getApp().Parse = Parse getApp().checkAuth = checkAuth if (!await this.getCompanyServerExpire(url)) { return } // 检查是否需要跳转到活动页面 if (wx.getStorageSync('need_activity_redirect') === true) { await this.redirectToActivityPage(); return; } // 检查是否需要跳转到扫码统计页面 if (this.shouldRedirectToScanPage()) { await this.redirectToScanPage(); return; } wx.redirectTo({ url: url, }); } catch (err) { console.log(err); /* 登录身份信息到期,重新登陆 */ if((err?.message.indexOf('Session token is expired') != -1 || err?.message.indexOf('Invalid session token') != -1) && !force){ let invite = wx.getStorageSync('invite') wx.clearStorageSync() invite && wx.setStorageSync('invite', invite) /* 强制重新登录 */ this.review(true) return } this.setData({ loading:false }) wx.showModal({ title: '温馨提示', content: '服务器正在升级,请稍后重试。', showCancel: false, cancelText: '取消', cancelColor: '#000000', confirmText: '确定', confirmColor: '#3CC51F', success: (result) => { if (result.confirm) { wx.exitMiniProgram() } }, }); } }, async updateUser(id) { let User = new Parse.Query('_User') let user = await User.get(id) let invite = wx.getStorageSync('invite') //查询邀请人user let query = new Parse.Query("_User") query.equalTo('objectId', invite) let result = await query.first() if (result && result.id && result.get("invite")?.id == user.id) { console.error('邀请人不能是自己的下级') return } if (invite && !user.get('invite') && user.id != invite && !user.get('agentLevel')) { console.log('上下级绑定成功'); user.set('invite', { __type: "Pointer", className: "_User", objectId: invite }) user.set('agent', { __type: "Pointer", className: "_User", objectId: invite }) await Parse.Cloud.run('user_save', { userJson: user.toJSON() }) } }, async getCompanyServerExpire(url) { let query = new Parse.Query('Company') query.equalTo('objectId', getApp().globalData.company) query.select('expireDate', 'expireMap') let com = await query.first() if (com?.id && com?.get('expireDate')) { let now = + new Date() let expireTime = + new Date(com?.get('expireDate')) if (com?.get('expireMap') && com.get('expireMap')[getApp().globalData.appid]) { expireTime = + new Date(com.get('expireMap')[getApp().globalData.appid]) } if (now >= expireTime) { console.log('服务器到期'); wx.reLaunch({ url: `common-page/pages/loading/index?url=${url}`, }); return } } return true }, onUnload: function () { wx.setStorageSync("active", 0); }, getParaName(url) { if (!url || url.indexOf('?') == -1) { return } // 兼容 URL 中 & 的情况,先统一还原为 & if (url.indexOf('&') !== -1) { url = url.replace(/&/g, '&'); } // 提取查询参数部分(去除可能的 hash 部分) let queryString = url.split('?')[1]; // 如果包含 #,只取 # 之前的部分 if (queryString.indexOf('#') !== -1) { queryString = queryString.split('#')[0]; } return this.setObject(queryString) //封装成对象 }, setObject(paraArr) { let obj = {} let arr1 = paraArr.split('&') arr1.forEach(item => { let str = item.split('=') let key = str[0] let val = str[1] obj[key] = val }) return obj }, /** * 检查并处理扫码参数 * 支持所有类型的二维码: * 1. 推广员二维码: ?scanCount=0&storeId=xxx&userId=xxx * 2. 产品二维码: ?scanCount=0&storeId=xxx&productId=xxx * 3. 活动海报二维码: activityId作为qrCode参数值 * 4. 异业合作伙伴二维码(移动端 / PC端统一): ?scanCount=xxx&storeId=xxx&partnerId=xxx * 5. 员工邀请二维码(移动端): ?scanCount=0&storeId=xxx&employeeId=xxx * 6. 我的二维码(老板): ?scanCount=0&storeId=xxx&ownerId=xxx * 7. 我的二维码(员工): ?scanCount=0&storeId=xxx&employeeId=xxx */ checkAndHandleScan(options) { const { scanCount, ownerId, employeeId, partnerId, storeId, productId, userId, // 推广员二维码使用userId activityId } = options; // 处理活动海报二维码(activityId作为qrCode参数值) if (activityId && !storeId) { console.log('==========================================='); console.log('======= 检测到活动海报二维码 ======='); console.log('活动ID (activityId):', activityId); console.log('==========================================='); // 活动二维码需要跳转到活动页面,不需要跳转到店铺 wx.setStorageSync('scan_activityId', activityId); wx.setStorageSync('need_activity_redirect', true); return; } // 如果存在 storeId,说明是扫码进入具体门店(包括异业分享) if (storeId) { console.log('==========================================='); console.log('======= 检测到扫码参数 ======='); console.log('店铺ID (storeId):', storeId); console.log('扫码次数 (scanCount):', scanCount || '0'); // 确定来源类型 let sourceType = 'unknown'; let sourceId = null; if (employeeId) { sourceType = 'employee'; sourceId = employeeId; console.log('来源类型: 员工展业'); console.log('员工ID (employeeId):', employeeId); } else if (userId) { // 推广员二维码使用userId sourceType = 'promoter'; sourceId = userId; console.log('来源类型: 推广员展业'); console.log('推广员ID (userId):', userId); } else if (ownerId) { sourceType = 'owner'; sourceId = ownerId; console.log('来源类型: 老板展业'); console.log('老板ID (ownerId):', ownerId); } else if (partnerId) { sourceType = 'partner'; sourceId = partnerId; console.log('来源类型: 异业合作伙伴'); console.log('合作伙伴ID (partnerId):', partnerId); } else { sourceType = 'store'; console.log('来源类型: 店铺分享'); } if (productId) { console.log('产品ID (productId):', productId); } console.log('==========================================='); // 保存到临时存储,用于后续跳转和统计 wx.setStorageSync('scan_storeId', storeId); wx.setStorageSync('scan_scanCount', scanCount || '0'); wx.setStorageSync('scan_sourceType', sourceType); wx.setStorageSync('scan_sourceId', sourceId || ''); wx.setStorageSync('scan_ownerId', ownerId || ''); wx.setStorageSync('scan_employeeId', employeeId || ''); wx.setStorageSync('scan_partnerId', partnerId || ''); wx.setStorageSync('scan_userId', userId || ''); if (productId) { wx.setStorageSync('scan_productId', productId); } wx.setStorageSync('need_scan_redirect', true); } else if (partnerId) { // 理论上异业二维码现在也必须带 storeId,这里仅作为兜底保护 console.warn('⚠️ 检测到异业合作伙伴二维码缺少 storeId,无法确定门店,请检查二维码生成逻辑'); } }, /** * 判断是否需要跳转到扫码统计页面 */ shouldRedirectToScanPage() { return wx.getStorageSync('need_scan_redirect') === true; }, /** * 跳转到扫码对应的店铺页面 * 根据 storeId 跳转到对应店铺,同时记录所有来源信息用于统计 */ async redirectToScanPage() { try { // 获取所有扫码相关参数 const storeId = wx.getStorageSync('scan_storeId'); const scanCount = wx.getStorageSync('scan_scanCount'); const sourceType = wx.getStorageSync('scan_sourceType'); const sourceId = wx.getStorageSync('scan_sourceId'); const ownerId = wx.getStorageSync('scan_ownerId'); const employeeId = wx.getStorageSync('scan_employeeId'); const partnerId = wx.getStorageSync('scan_partnerId'); const userId = wx.getStorageSync('scan_userId'); const productId = wx.getStorageSync('scan_productId'); // 清除临时存储 wx.removeStorageSync('scan_storeId'); wx.removeStorageSync('scan_scanCount'); wx.removeStorageSync('scan_sourceType'); wx.removeStorageSync('scan_sourceId'); wx.removeStorageSync('scan_ownerId'); wx.removeStorageSync('scan_employeeId'); wx.removeStorageSync('scan_partnerId'); wx.removeStorageSync('scan_userId'); wx.removeStorageSync('scan_productId'); wx.removeStorageSync('need_scan_redirect'); if (!storeId) { console.error('❌ 缺少 storeId 参数,无法跳转'); return; } console.log('==========================================='); console.log('======= 扫码进入店铺 ======='); console.log('店铺 ID (storeId):', storeId); console.log('来源类型 (sourceType):', sourceType); console.log('来源 ID (sourceId):', sourceId || '无'); console.log('扫码次数 (scanCount):', scanCount); if (ownerId) console.log('老板 ID (ownerId):', ownerId); if (employeeId) console.log('员工 ID (employeeId):', employeeId); if (partnerId) console.log('合作伙伴 ID (partnerId):', partnerId); if (userId) console.log('推广员 ID (userId):', userId); if (productId) console.log('产品 ID (productId):', productId); console.log('==========================================='); // 设置店铺 ID 到全局和本地存储 wx.setStorageSync('storeId', storeId); getApp().globalData.storeId = storeId; // 保存来源信息到本地存储(用于后续统计或绑定关系) if (sourceId) { wx.setStorageSync('scan_from_sourceType', sourceType); wx.setStorageSync('scan_from_sourceId', sourceId); console.log('✅ 已记录来源信息:', sourceType, sourceId); } // 记录扫码统计(调用后端接口记录扫码次数) await this.recordScanStatistics({ storeId, sourceType, sourceId, ownerId, employeeId, partnerId, userId, productId, scanCount }); // 获取默认首页路径并跳转 let url = getApp().globalData.rootPage || getApp().globalData.defaultTabBar.list[0].pagePath; url += `?storeId=${storeId}`; // 如果有产品ID,添加到URL参数中 if (productId) { url += `&productId=${productId}`; } console.log('✅ 跳转到店铺页面:', url); wx.redirectTo({ url: url, fail: (err) => { console.error('❌ 跳转失败:', err); // 如果 redirectTo 失败,尝试 reLaunch wx.reLaunch({ url: url, fail: (err2) => { console.error('❌ reLaunch 也失败:', err2); } }); } }); } catch (error) { console.error('❌ 跳转到店铺页面失败:', error); } }, /** * 跳转到活动页面 */ async redirectToActivityPage() { try { const activityId = wx.getStorageSync('scan_activityId'); // 清除临时存储 wx.removeStorageSync('scan_activityId'); wx.removeStorageSync('need_activity_redirect'); if (!activityId) { console.error('❌ 缺少 activityId 参数,无法跳转'); return; } console.log('==========================================='); console.log('======= 扫码进入活动页面 ======='); console.log('活动 ID (activityId):', activityId); console.log('==========================================='); // 保存活动ID wx.setStorageSync('activityId', activityId); // 获取默认首页路径并跳转(活动页面可能需要根据实际路由调整) let url = getApp().globalData.rootPage || getApp().globalData.defaultTabBar.list[0].pagePath; url += `?activityId=${activityId}`; console.log('✅ 跳转到活动页面:', url); wx.redirectTo({ url: url, fail: (err) => { console.error('❌ 跳转失败:', err); wx.reLaunch({ url: url, fail: (err2) => { console.error('❌ reLaunch 也失败:', err2); } }); } }); } catch (error) { console.error('❌ 跳转到活动页面失败:', error); } }, /** * 记录扫码统计信息 * @param {Object} params - 扫码参数对象 * @param {string} params.storeId - 店铺 ID * @param {string} params.sourceType - 来源类型 (employee/owner/partner/promoter/store) * @param {string} params.sourceId - 来源 ID * @param {string} params.ownerId - 老板 ID * @param {string} params.employeeId - 员工 ID * @param {string} params.partnerId - 合作伙伴 ID * @param {string} params.userId - 推广员 ID * @param {string} params.productId - 产品 ID * @param {string} params.scanCount - 扫码次数 */ async recordScanStatistics(params) { try { const { storeId, sourceType, sourceId, ownerId, employeeId, partnerId, userId, productId, scanCount } = params; // 如果没有来源信息,不记录统计 if (!sourceId && !ownerId && !employeeId && !partnerId && !userId) { console.log('ℹ️ 无来源信息,跳过统计记录'); return; } // 创建扫码记录 const ScanRecord = Parse.Object.extend('ScanRecord'); const record = new ScanRecord(); record.set('company', { __type: 'Pointer', className: 'Company', objectId: getApp().globalData.company }); record.set('storeId', storeId); record.set('sourceType', sourceType || 'unknown'); record.set('scanCount', parseInt(scanCount) || 0); record.set('scanTime', new Date()); // 根据来源类型设置对应的ID if (ownerId) { record.set('ownerId', ownerId); } if (employeeId) { record.set('employeeId', employeeId); } if (partnerId) { record.set('partnerId', partnerId); } if (userId) { record.set('userId', userId); } if (productId) { record.set('productId', productId); } // 如果用户已登录,记录扫码用户 const currentUser = Parse.User.current(); if (currentUser) { record.set('user', { __type: 'Pointer', className: '_User', objectId: currentUser.id }); } await record.save(); console.log('✅ 扫码记录已保存'); // 如果存在异业合作伙伴ID,则在其 scanCount 字段上自增 1(数据库中的 Partner 表) if (partnerId) { try { const Partner = Parse.Object.extend('Partner'); const partnerQuery = new Parse.Query(Partner); const partnerObj = await partnerQuery.get(partnerId); if (partnerObj) { partnerObj.increment('scanCount', 1); await partnerObj.save(); console.log('✅ 已为异业合作伙伴累加一次扫码次数,partnerId:', partnerId); } } catch (e) { console.warn('⚠️ 更新异业合作伙伴扫码次数失败:', e); } } } catch (error) { console.warn('⚠️ 保存扫码记录失败:', error); // 不影响主流程 } } });