|
|
@@ -294,6 +294,10 @@ Page({
|
|
|
// 即使登录失败,也允许继续访问(仅在非强制登录模式下)
|
|
|
if(!r) {
|
|
|
console.log('⚠️ 用户未登录或拒绝授权,允许游客访问');
|
|
|
+ if (wx.getStorageSync('need_scan_redirect') === true) {
|
|
|
+ await this.ensureTrackingUser();
|
|
|
+ await this.checkAndRecordUserSourceOnLogin();
|
|
|
+ }
|
|
|
// 不要 return,继续执行后面的跳转逻辑
|
|
|
} else {
|
|
|
// 登录成功,设置 userLogin
|
|
|
@@ -525,6 +529,24 @@ Page({
|
|
|
console.error('❌ 记录待处理扫码信息失败:', error);
|
|
|
}
|
|
|
},
|
|
|
+
|
|
|
+ async ensureTrackingUser() {
|
|
|
+ try {
|
|
|
+ let currentUser = Parse.User.current();
|
|
|
+ if (currentUser) {
|
|
|
+ return currentUser;
|
|
|
+ }
|
|
|
+ if (Parse.AnonymousUtils && typeof Parse.AnonymousUtils.logIn === 'function') {
|
|
|
+ await Parse.AnonymousUtils.logIn();
|
|
|
+ currentUser = Parse.User.current();
|
|
|
+ return currentUser || null;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('ensureTrackingUser 失败:', e?.message || e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ },
|
|
|
|
|
|
/**
|
|
|
* 记录用户来源信息到 _User 表
|
|
|
@@ -545,12 +567,7 @@ Page({
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 如果用户已经有来源信息,不再覆盖(首次来源原则)
|
|
|
const existingSource = currentUser.get('source');
|
|
|
- if (existingSource) {
|
|
|
- console.log('ℹ️ 用户已有来源信息,不覆盖:', existingSource);
|
|
|
- return;
|
|
|
- }
|
|
|
|
|
|
console.log('📊 ===========================================');
|
|
|
console.log('📊 [记录来源] 开始记录用户来源信息');
|
|
|
@@ -558,150 +575,169 @@ Page({
|
|
|
console.log('📊 ===========================================');
|
|
|
|
|
|
const { partnerId, employeeId, ownerId, userId, storeId } = scanInfo;
|
|
|
-
|
|
|
- let sourceInfo = {
|
|
|
- type: 'self_entry', // 默认为自主进入
|
|
|
- label: '自主进入',
|
|
|
- timestamp: new Date(),
|
|
|
- storeId: storeId
|
|
|
- };
|
|
|
-
|
|
|
- // 判断来源类型
|
|
|
- if (partnerId && employeeId) {
|
|
|
- // 情况2: 渠道xxx→异业xxx→员工xxx(员工后台添加的异业)
|
|
|
- console.log('🔍 [来源类型] 渠道→异业→员工');
|
|
|
+ console.log('📌 [扣减前置] storeId:', storeId || '无');
|
|
|
+ console.log('📌 [扣减前置] existingSource:', existingSource ? '有' : '无');
|
|
|
+ console.log('📌 [扣减前置] trafficDeducted:', currentUser.get('trafficDeducted') === true ? 'true' : 'false');
|
|
|
+ console.log('📌 [扣减前置] trafficDeductedStoreId:', currentUser.get('trafficDeductedStoreId') || '无');
|
|
|
+ console.log('📌 [扣减前置] trafficDeductedAt:', currentUser.get('trafficDeductedAt') || '无');
|
|
|
+
|
|
|
+ if (!existingSource) {
|
|
|
+ let sourceInfo = {
|
|
|
+ type: 'self_entry',
|
|
|
+ label: '自主进入',
|
|
|
+ timestamp: new Date(),
|
|
|
+ storeId: storeId
|
|
|
+ };
|
|
|
|
|
|
- try {
|
|
|
- // 查询异业信息
|
|
|
- const partnerQuery = new Parse.Query('Partner');
|
|
|
- const partner = await partnerQuery.get(partnerId);
|
|
|
- const partnerName = partner.get('name') || '未知异业';
|
|
|
- const channelName = partner.get('channelName') || partner.get('category') || '未知渠道';
|
|
|
+ if (partnerId && employeeId) {
|
|
|
+ console.log('🔍 [来源类型] 渠道→异业→员工');
|
|
|
|
|
|
- // 查询员工信息
|
|
|
- const employeeQuery = new Parse.Query('Employee');
|
|
|
- const employee = await employeeQuery.get(employeeId);
|
|
|
- const employeeName = employee.get('name') || '未知员工';
|
|
|
+ try {
|
|
|
+ const partnerQuery = new Parse.Query('Partner');
|
|
|
+ const partner = await partnerQuery.get(partnerId);
|
|
|
+ const partnerName = partner.get('name') || '未知异业';
|
|
|
+ const channelName = partner.get('channelName') || partner.get('category') || '未知渠道';
|
|
|
+
|
|
|
+ const employeeQuery = new Parse.Query('Employee');
|
|
|
+ const employee = await employeeQuery.get(employeeId);
|
|
|
+ const employeeName = employee.get('name') || '未知员工';
|
|
|
+
|
|
|
+ sourceInfo = {
|
|
|
+ type: 'channel_partner_employee',
|
|
|
+ label: `${channelName},${partnerName},员工${employeeName}`,
|
|
|
+ channelName: channelName,
|
|
|
+ partnerId: partnerId,
|
|
|
+ partnerName: partnerName,
|
|
|
+ employeeId: employeeId,
|
|
|
+ employeeName: employeeName,
|
|
|
+ timestamp: new Date(),
|
|
|
+ storeId: storeId
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('✅ [来源信息] 渠道→异业→员工:', sourceInfo.label);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 查询异业或员工信息失败:', error);
|
|
|
+ }
|
|
|
|
|
|
- sourceInfo = {
|
|
|
- type: 'channel_partner_employee',
|
|
|
- label: `${channelName},${partnerName},员工${employeeName}`,
|
|
|
- channelName: channelName,
|
|
|
- partnerId: partnerId,
|
|
|
- partnerName: partnerName,
|
|
|
- employeeId: employeeId,
|
|
|
- employeeName: employeeName,
|
|
|
- timestamp: new Date(),
|
|
|
- storeId: storeId
|
|
|
- };
|
|
|
+ } else if (partnerId && !employeeId) {
|
|
|
+ console.log('🔍 [来源类型] 渠道→异业');
|
|
|
|
|
|
- console.log('✅ [来源信息] 渠道→异业→员工:', sourceInfo.label);
|
|
|
- } catch (error) {
|
|
|
- console.error('❌ 查询异业或员工信息失败:', error);
|
|
|
- }
|
|
|
-
|
|
|
- } else if (partnerId && !employeeId) {
|
|
|
- // 情况1: 渠道xxx→异业xxx(老板后台添加的异业)
|
|
|
- console.log('🔍 [来源类型] 渠道→异业');
|
|
|
-
|
|
|
- try {
|
|
|
- // 查询异业信息
|
|
|
- const partnerQuery = new Parse.Query('Partner');
|
|
|
- const partner = await partnerQuery.get(partnerId);
|
|
|
- const partnerName = partner.get('name') || '未知异业';
|
|
|
- const channelName = partner.get('channelName') || partner.get('category') || '未知渠道';
|
|
|
+ try {
|
|
|
+ const partnerQuery = new Parse.Query('Partner');
|
|
|
+ const partner = await partnerQuery.get(partnerId);
|
|
|
+ const partnerName = partner.get('name') || '未知异业';
|
|
|
+ const channelName = partner.get('channelName') || partner.get('category') || '未知渠道';
|
|
|
+
|
|
|
+ sourceInfo = {
|
|
|
+ type: 'channel_partner',
|
|
|
+ label: `${channelName},${partnerName}`,
|
|
|
+ channelName: channelName,
|
|
|
+ partnerId: partnerId,
|
|
|
+ partnerName: partnerName,
|
|
|
+ timestamp: new Date(),
|
|
|
+ storeId: storeId
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('✅ [来源信息] 渠道→异业:', sourceInfo.label);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 查询异业信息失败:', error);
|
|
|
+ }
|
|
|
|
|
|
- sourceInfo = {
|
|
|
- type: 'channel_partner',
|
|
|
- label: `${channelName},${partnerName}`,
|
|
|
- channelName: channelName,
|
|
|
- partnerId: partnerId,
|
|
|
- partnerName: partnerName,
|
|
|
- timestamp: new Date(),
|
|
|
- storeId: storeId
|
|
|
- };
|
|
|
+ } else if (employeeId && !partnerId) {
|
|
|
+ console.log('🔍 [来源类型] 员工');
|
|
|
|
|
|
- console.log('✅ [来源信息] 渠道→异业:', sourceInfo.label);
|
|
|
- } catch (error) {
|
|
|
- console.error('❌ 查询异业信息失败:', error);
|
|
|
- }
|
|
|
-
|
|
|
- } else if (employeeId && !partnerId) {
|
|
|
- // 情况3: 员工xxx
|
|
|
- console.log('🔍 [来源类型] 员工');
|
|
|
-
|
|
|
- try {
|
|
|
- // 查询员工信息
|
|
|
- const employeeQuery = new Parse.Query('Employee');
|
|
|
- const employee = await employeeQuery.get(employeeId);
|
|
|
- const employeeName = employee.get('name') || '未知员工';
|
|
|
+ try {
|
|
|
+ const employeeQuery = new Parse.Query('Employee');
|
|
|
+ const employee = await employeeQuery.get(employeeId);
|
|
|
+ const employeeName = employee.get('name') || '未知员工';
|
|
|
+
|
|
|
+ sourceInfo = {
|
|
|
+ type: 'employee',
|
|
|
+ label: employeeName,
|
|
|
+ employeeId: employeeId,
|
|
|
+ employeeName: employeeName,
|
|
|
+ timestamp: new Date(),
|
|
|
+ storeId: storeId
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('✅ [来源信息] 员工:', sourceInfo.label);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 查询员工信息失败:', error);
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (ownerId) {
|
|
|
+ console.log('🔍 [来源类型] 老板');
|
|
|
|
|
|
sourceInfo = {
|
|
|
- type: 'employee',
|
|
|
- label: employeeName,
|
|
|
- employeeId: employeeId,
|
|
|
- employeeName: employeeName,
|
|
|
+ type: 'owner',
|
|
|
+ label: '老板',
|
|
|
+ ownerId: ownerId,
|
|
|
timestamp: new Date(),
|
|
|
storeId: storeId
|
|
|
};
|
|
|
|
|
|
- console.log('✅ [来源信息] 员工:', sourceInfo.label);
|
|
|
- } catch (error) {
|
|
|
- console.error('❌ 查询员工信息失败:', error);
|
|
|
- }
|
|
|
-
|
|
|
- } else if (ownerId) {
|
|
|
- // 情况4: 老板
|
|
|
- console.log('🔍 [来源类型] 老板');
|
|
|
-
|
|
|
- sourceInfo = {
|
|
|
- type: 'owner',
|
|
|
- label: '老板',
|
|
|
- ownerId: ownerId,
|
|
|
- timestamp: new Date(),
|
|
|
- storeId: storeId
|
|
|
- };
|
|
|
-
|
|
|
- console.log('✅ [来源信息] 老板');
|
|
|
-
|
|
|
- } else if (userId) {
|
|
|
- // 推广员(如果有的话)
|
|
|
- console.log('🔍 [来源类型] 推广员');
|
|
|
-
|
|
|
- try {
|
|
|
- // 查询推广员信息
|
|
|
- const userQuery = new Parse.Query('_User');
|
|
|
- const promoter = await userQuery.get(userId);
|
|
|
- const promoterName = promoter.get('username') || promoter.get('mobile') || '未知推广员';
|
|
|
+ console.log('✅ [来源信息] 老板');
|
|
|
|
|
|
- sourceInfo = {
|
|
|
- type: 'promoter',
|
|
|
- label: `推广员${promoterName}`,
|
|
|
- userId: userId,
|
|
|
- promoterName: promoterName,
|
|
|
- timestamp: new Date(),
|
|
|
- storeId: storeId
|
|
|
- };
|
|
|
+ } else if (userId) {
|
|
|
+ console.log('🔍 [来源类型] 推广员');
|
|
|
|
|
|
- console.log('✅ [来源信息] 推广员:', sourceInfo.label);
|
|
|
- } catch (error) {
|
|
|
- console.error('❌ 查询推广员信息失败:', error);
|
|
|
+ try {
|
|
|
+ const userQuery = new Parse.Query('_User');
|
|
|
+ const promoter = await userQuery.get(userId);
|
|
|
+ const promoterName = promoter.get('username') || promoter.get('mobile') || '未知推广员';
|
|
|
+
|
|
|
+ sourceInfo = {
|
|
|
+ type: 'promoter',
|
|
|
+ label: `推广员${promoterName}`,
|
|
|
+ userId: userId,
|
|
|
+ promoterName: promoterName,
|
|
|
+ timestamp: new Date(),
|
|
|
+ storeId: storeId
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('✅ [来源信息] 推广员:', sourceInfo.label);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 查询推广员信息失败:', error);
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ console.log('🔍 [来源类型] 自主进入');
|
|
|
+ console.log('✅ [来源信息] 自主进入');
|
|
|
}
|
|
|
|
|
|
+ currentUser.set('source', sourceInfo);
|
|
|
+ await currentUser.save();
|
|
|
+
|
|
|
+ console.log('✅ [保存成功] 用户来源信息已保存');
|
|
|
+ console.log(' - 来源类型:', sourceInfo.type);
|
|
|
+ console.log(' - 来源标签:', sourceInfo.label);
|
|
|
+ console.log('📊 ===========================================');
|
|
|
} else {
|
|
|
- // 情况5: 自主进入(无任何推荐)
|
|
|
- console.log('🔍 [来源类型] 自主进入');
|
|
|
- console.log('✅ [来源信息] 自主进入');
|
|
|
+ console.log('ℹ️ 用户已有来源信息,跳过覆盖:', existingSource);
|
|
|
}
|
|
|
|
|
|
- // 保存来源信息到用户
|
|
|
- currentUser.set('source', sourceInfo);
|
|
|
- await currentUser.save();
|
|
|
+ const trafficDeducted =
|
|
|
+ currentUser.get('trafficDeducted') === true ||
|
|
|
+ !!currentUser.get('trafficDeductedAt') ||
|
|
|
+ !!currentUser.get('trafficDeductedStoreId');
|
|
|
|
|
|
- console.log('✅ [保存成功] 用户来源信息已保存');
|
|
|
- console.log(' - 来源类型:', sourceInfo.type);
|
|
|
- console.log(' - 来源标签:', sourceInfo.label);
|
|
|
- console.log('📊 ===========================================');
|
|
|
+ if (storeId && !trafficDeducted) {
|
|
|
+ console.log('🧮 [扣减流量] 检测到新用户首次扣减,准备扣减门店流量');
|
|
|
+ try {
|
|
|
+ await decrementStoreTrafficImpl(Parse, storeId);
|
|
|
+ currentUser.set('trafficDeducted', true);
|
|
|
+ currentUser.set('trafficDeductedStoreId', storeId);
|
|
|
+ currentUser.set('trafficDeductedAt', new Date());
|
|
|
+ await currentUser.save();
|
|
|
+ console.log('✅ [扣减成功] 已为店铺扣减 1 个流量,storeId:', storeId);
|
|
|
+ } catch (decErr) {
|
|
|
+ console.error('❌ [扣减失败] 扣减门店流量失败:', decErr?.message || decErr);
|
|
|
+ }
|
|
|
+ } else if (!storeId) {
|
|
|
+ console.warn('⚠️ [扣减跳过] storeId 为空,无法扣减 ShopStore.traffic');
|
|
|
+ } else if (trafficDeducted) {
|
|
|
+ console.log('ℹ️ [扣减跳过] 已扣减过流量,不重复扣减');
|
|
|
+ }
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('❌ 记录用户来源失败:', error);
|
|
|
@@ -719,13 +755,6 @@ Page({
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 如果用户已经有来源信息,不再处理
|
|
|
- const existingSource = currentUser.get('source');
|
|
|
- if (existingSource) {
|
|
|
- console.log('ℹ️ 用户已有来源信息,跳过记录');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
// 检查是否有扫码参数
|
|
|
const scanStoreId = wx.getStorageSync('scan_storeId');
|
|
|
const scanPartnerId = wx.getStorageSync('scan_partnerId');
|
|
|
@@ -1699,3 +1728,36 @@ Page({
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
+
|
|
|
+async function decrementStoreTrafficImpl(Parse, storeId) {
|
|
|
+ const currentUser = Parse.User.current();
|
|
|
+ const sessionToken = currentUser && typeof currentUser.getSessionToken === 'function'
|
|
|
+ ? currentUser.getSessionToken()
|
|
|
+ : null;
|
|
|
+ const requestOptions = sessionToken ? { sessionToken } : undefined;
|
|
|
+
|
|
|
+ console.log('🧾 [traffic] 开始扣减 ShopStore.traffic');
|
|
|
+ console.log('🧾 [traffic] storeId:', storeId);
|
|
|
+ console.log('🧾 [traffic] userId:', currentUser ? currentUser.id : '无用户');
|
|
|
+ console.log('🧾 [traffic] hasSessionToken:', sessionToken ? 'true' : 'false');
|
|
|
+
|
|
|
+ const storeQuery = new Parse.Query('ShopStore');
|
|
|
+ const store = await storeQuery.get(storeId, requestOptions);
|
|
|
+ if (!store) {
|
|
|
+ console.error('🧾 [traffic] 未找到门店记录, storeId:', storeId);
|
|
|
+ throw new Error('未找到门店记录');
|
|
|
+ }
|
|
|
+ const trafficValue = store.get('traffic');
|
|
|
+ const trafficNumber = Number(trafficValue);
|
|
|
+ const traffic = Number.isFinite(trafficNumber) ? trafficNumber : 0;
|
|
|
+ const next = Math.max(traffic - 1, 0);
|
|
|
+ console.log('🧾 [traffic] before trafficValue:', trafficValue);
|
|
|
+ console.log('🧾 [traffic] parsed traffic:', traffic);
|
|
|
+ console.log('🧾 [traffic] next:', next);
|
|
|
+ if (next !== traffic || trafficValue === undefined) {
|
|
|
+ store.set('traffic', next);
|
|
|
+ const saved = await store.save(null, requestOptions);
|
|
|
+ console.log('🧾 [traffic] 保存成功 storeObjectId:', saved && saved.id ? saved.id : store.id);
|
|
|
+ }
|
|
|
+ console.log('🧾 [traffic] 结束扣减 ShopStore.traffic');
|
|
|
+}
|