index.js 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  1. const Parse = getApp().Parse;
  2. const company = getApp().globalData.company;
  3. const login = require("../../../utils/login");
  4. const clearLogin = require("../../../utils/clearLogin");
  5. Component({
  6. /**
  7. * 组件的属性列表
  8. */
  9. properties: {
  10. },
  11. data: {
  12. // 轮播图相关数据
  13. currentSwiperIndex: 0,
  14. // 是否显示 AI 相关内容(根据 Company.isPublishing 字段)
  15. showAI: false,
  16. },
  17. lifetimes: {
  18. created() {},
  19. attached: async function () {
  20. // 页面加载时检查是否首次访问
  21. this.checkFirstVisit();
  22. // 检查并清理异常的登录状态
  23. await this.checkAndCleanInvalidLoginState();
  24. // 在控制台显示当前登录用户信息
  25. this.showCurrentUser();
  26. // 检查 isPublishing 状态
  27. await this.checkPublishingStatus();
  28. },
  29. },
  30. pageLifetimes: {
  31. show: async function() {
  32. console.log('===========================================');
  33. console.log('======= 页面显示 (pageLifetimes.show) =======');
  34. // 重新检查 isPublishing 状态
  35. await this.checkPublishingStatus();
  36. // 延迟检查登录状态,等待 Parse 更新
  37. setTimeout(() => {
  38. const currentUser = Parse.User.current();
  39. console.log('当前用户:', currentUser ? currentUser.id : '无');
  40. console.log('手机号:', currentUser?.get('mobile') || '无');
  41. if (currentUser && currentUser.get('mobile')) {
  42. const userLogin = wx.getStorageSync('userLogin');
  43. console.log('userLogin 存储:', userLogin || '无');
  44. if (!userLogin || userLogin !== currentUser.id) {
  45. wx.setStorageSync("userLogin", currentUser.id);
  46. console.log('✅ 页面显示时更新 userLogin:', currentUser.id);
  47. // 清除游客模式标记
  48. wx.removeStorageSync('isGuestMode');
  49. console.log('✅ 已清除游客模式标记');
  50. }
  51. }
  52. console.log('===========================================');
  53. // 更新显示的用户信息
  54. this.showCurrentUser();
  55. }, 500); // 延迟 500ms,等待 Parse 更新
  56. }
  57. },
  58. /**
  59. * 组件的方法列表
  60. */
  61. methods: {
  62. /**
  63. * 检查并清理异常的登录状态
  64. * 在页面加载时自动执行,避免点击登录时白屏
  65. */
  66. async checkAndCleanInvalidLoginState() {
  67. try {
  68. const currentUser = Parse.User.current();
  69. const userLogin = wx.getStorageSync('userLogin');
  70. // 如果有 Parse 用户但没有 userLogin,说明状态不一致
  71. if (currentUser && !userLogin) {
  72. console.log('⚠️ 检测到异常登录状态:有 Parse 用户但没有 userLogin');
  73. console.log(' 用户 ID:', currentUser.id);
  74. console.log(' 手机号:', currentUser.get('mobile') || '无');
  75. // 如果用户有手机号,补充设置 userLogin
  76. if (currentUser.get('mobile')) {
  77. wx.setStorageSync('userLogin', currentUser.id);
  78. console.log('✅ 已补充设置 userLogin');
  79. } else {
  80. // 如果用户没有手机号,清除这个无效的用户
  81. // console.log('🧹 用户没有手机号,清除无效状态');
  82. // await clearLogin.clearAllLoginState();
  83. }
  84. }
  85. // 如果有 userLogin 但没有 Parse 用户,说明状态不一致
  86. if (!currentUser && userLogin) {
  87. console.log('⚠️ 检测到异常登录状态:有 userLogin 但没有 Parse 用户');
  88. console.log(' userLogin:', userLogin);
  89. console.log('🧹 清除无效的 userLogin');
  90. wx.removeStorageSync('userLogin');
  91. }
  92. } catch (error) {
  93. console.error('❌ 检查登录状态失败:', error);
  94. }
  95. },
  96. /**
  97. * 在控制台显示当前登录用户信息
  98. */
  99. showCurrentUser() {
  100. const currentUser = Parse.User.current();
  101. console.log('===========================================');
  102. console.log('======= 当前登录用户信息 =======');
  103. console.log('===========================================');
  104. if (currentUser) {
  105. console.log('✅ 用户已登录');
  106. console.log('📱 用户ID:', currentUser.id);
  107. console.log('📞 手机号:', currentUser.get('mobile') || '未设置');
  108. console.log('👤 用户名:', currentUser.get('username') || '未设置');
  109. console.log('🔑 Session Token:', currentUser.getSessionToken());
  110. console.log('📧 邮箱:', currentUser.get('email') || '未设置');
  111. console.log('📦 完整用户对象:', currentUser);
  112. console.log('📋 所有属性:', currentUser.attributes);
  113. } else {
  114. console.log('❌ 当前没有登录用户');
  115. }
  116. console.log('===========================================');
  117. },
  118. /**
  119. * 检查是否首次访问
  120. */
  121. checkFirstVisit() {
  122. try {
  123. const hasVisited = wx.getStorageSync('hasVisitedWelcome');
  124. if (!hasVisited) {
  125. console.log('首次访问,显示引导页');
  126. } else {
  127. console.log('已访问过,可选择是否直接跳转');
  128. // 如果需要自动跳转到主页,可以在这里调用 this.navigateToHome()
  129. }
  130. } catch (e) {
  131. console.error('检查访问状态失败:', e);
  132. }
  133. },
  134. /**
  135. * 检查登录状态(强制登录模式)
  136. * 当 isPublishing != true 时,必须登录才能访问
  137. * @returns {Promise<boolean>} 是否已登录或允许访问
  138. */
  139. async checkLoginRequired() {
  140. // 获取 isPublishing 状态
  141. const isPublishing = wx.getStorageSync('isPublishing');
  142. console.log('🔐 检查登录要求...');
  143. console.log(' isPublishing:', isPublishing);
  144. // 如果 isPublishing == true,不需要强制登录,允许游客访问
  145. if (isPublishing === true) {
  146. console.log('✅ isPublishing == true,允许游客访问');
  147. return true;
  148. }
  149. console.log('⚠️ isPublishing != true,需要强制登录');
  150. // 检查用户是否已登录
  151. const currentUser = Parse.User.current();
  152. const userLogin = wx.getStorageSync('userLogin');
  153. const isLoggedIn = currentUser && currentUser.get('mobile') && userLogin;
  154. console.log(' 当前用户:', currentUser ? currentUser.id : '无');
  155. console.log(' 手机号:', currentUser?.get('mobile') || '无');
  156. console.log(' userLogin:', userLogin || '无');
  157. console.log(' 登录状态:', isLoggedIn ? '已登录' : '未登录');
  158. if (!isLoggedIn) {
  159. console.log('❌ 用户未登录,显示登录提示');
  160. wx.showModal({
  161. title: '需要登录',
  162. content: '请先登录后再使用此功能',
  163. showCancel: false,
  164. confirmText: '立即登录',
  165. success: () => {
  166. // 跳转到登录页面
  167. console.log('🔄 跳转到登录页面');
  168. login.loginNow();
  169. }
  170. });
  171. return false;
  172. }
  173. console.log('✅ 用户已登录,允许访问');
  174. return true;
  175. },
  176. /**
  177. * 检查 Company 的 isPublishing 状态
  178. * 用于控制是否显示 AI 相关内容
  179. */
  180. async checkPublishingStatus() {
  181. try {
  182. console.log('🔍 开始检查 isPublishing 状态...');
  183. // 先尝试从缓存读取
  184. let isPublishing = wx.getStorageSync('isPublishing');
  185. if (isPublishing === '' || isPublishing === null || isPublishing === undefined) {
  186. console.log('📦 缓存中没有 isPublishing,尝试查询数据库...');
  187. try {
  188. // 缓存中没有,查询 Company 表(使用 master key,不需要登录)
  189. const companyQuery = new Parse.Query('Company');
  190. companyQuery.equalTo('objectId', getApp().globalData.company);
  191. companyQuery.select('isPublishing');
  192. // 使用 find 而不是 first,避免 session token 问题
  193. const results = await companyQuery.find();
  194. if (results && results.length > 0) {
  195. const companyObj = results[0];
  196. isPublishing = companyObj.get('isPublishing') === true;
  197. console.log('📋 从数据库查询 isPublishing:', isPublishing);
  198. // 保存到缓存
  199. wx.setStorageSync('isPublishing', isPublishing);
  200. getApp().globalData.isPublishing = isPublishing;
  201. } else {
  202. console.warn('⚠️ 未找到 Company 记录,默认为 false');
  203. isPublishing = false;
  204. // 也保存到缓存,避免重复查询
  205. wx.setStorageSync('isPublishing', false);
  206. getApp().globalData.isPublishing = false;
  207. }
  208. } catch (queryError) {
  209. console.error('❌ 查询 Company 失败:', queryError);
  210. // 查询失败时,默认为 false(需要登录)
  211. isPublishing = false;
  212. wx.setStorageSync('isPublishing', false);
  213. getApp().globalData.isPublishing = false;
  214. }
  215. } else {
  216. console.log('📦 从缓存读取 isPublishing:', isPublishing);
  217. }
  218. // 更新组件状态
  219. this.setData({
  220. showAI: isPublishing === true
  221. });
  222. console.log('✅ isPublishing 状态检查完成');
  223. console.log(' - isPublishing:', isPublishing);
  224. console.log(' - showAI:', isPublishing === true);
  225. console.log('===========================================');
  226. } catch (error) {
  227. console.error('❌ 检查 isPublishing 状态失败:', error);
  228. // 出错时默认不显示 AI(需要登录)
  229. this.setData({
  230. showAI: false
  231. });
  232. wx.setStorageSync('isPublishing', false);
  233. }
  234. },
  235. /**
  236. * 点击"立即开始探索"按钮
  237. */
  238. async onStart() {
  239. console.log('===========================================');
  240. console.log('🚀 调用了 onStart 方法(立即开始探索)');
  241. console.log('===========================================');
  242. // 检查 isPublishing 状态,如果不是 true,需要强制登录
  243. const isPublishing = this.data.showAI; // showAI 就是 isPublishing 的状态
  244. console.log('📋 isPublishing 状态:', isPublishing);
  245. // 如果 isPublishing != true,必须登录才能访问
  246. if (!isPublishing) {
  247. console.log('⚠️ isPublishing != true,需要强制登录');
  248. // 检查用户是否已登录
  249. const currentUser = Parse.User.current();
  250. const userLogin = wx.getStorageSync('userLogin');
  251. const isLoggedIn = currentUser && currentUser.get('mobile') && userLogin;
  252. console.log(' 当前用户:', currentUser ? currentUser.id : '无');
  253. console.log(' 手机号:', currentUser?.get('mobile') || '无');
  254. console.log(' userLogin:', userLogin || '无');
  255. console.log(' 登录状态:', isLoggedIn ? '已登录' : '未登录');
  256. if (!isLoggedIn) {
  257. console.log('❌ 用户未登录,直接跳转到登录页面');
  258. login.loginNow();
  259. return;
  260. }
  261. console.log('✅ 用户已登录,允许访问');
  262. } else {
  263. console.log('✅ isPublishing == true,允许游客访问');
  264. }
  265. // 标记已访问
  266. wx.setStorageSync('hasVisitedWelcome', true);
  267. // 跳转到 H5 主页
  268. this.navigateToHome();
  269. },
  270. /**
  271. * 点击"跳过引导"按钮
  272. */
  273. async onSkip() {
  274. // 检查是否需要强制登录
  275. const canAccess = await this.checkLoginRequired();
  276. if (!canAccess) {
  277. return;
  278. }
  279. // 标记已访问
  280. wx.setStorageSync('hasVisitedWelcome', true);
  281. // 跳转到 H5 主页
  282. this.navigateToHome();
  283. },
  284. /**
  285. * 点击"查看新手指南"
  286. */
  287. onGuide() {
  288. wx.showToast({
  289. title: '新手指南开发中',
  290. icon: 'none',
  291. duration: 2000
  292. });
  293. // TODO: 后续可以跳转到新手指南页面
  294. // wx.navigateTo({
  295. // url: '/pages/guide/index'
  296. // });
  297. },
  298. /**
  299. * 验证 token 是否有效
  300. */
  301. async validateToken(token) {
  302. try {
  303. console.log('🔍 开始验证 token 有效性...');
  304. // 使用 Parse.User.become() 验证 token
  305. const user = await Parse.User.become(token);
  306. if (user) {
  307. console.log('✅ Token 有效!用户:', user.id);
  308. return true;
  309. }
  310. console.log('⚠️ Token 验证返回空用户');
  311. return false;
  312. } catch (error) {
  313. console.error('❌ Token 验证失败:', error.message);
  314. return false;
  315. }
  316. },
  317. /**
  318. * 刷新用户 session token
  319. */
  320. async refreshToken() {
  321. try {
  322. console.log('🔄 开始刷新 token...');
  323. const currentUser = Parse.User.current();
  324. if (!currentUser) {
  325. console.error('❌ 当前没有登录用户,无法刷新 token');
  326. return null;
  327. }
  328. // 保存用户信息以触发 session token 刷新
  329. await currentUser.fetch();
  330. const newToken = currentUser.getSessionToken();
  331. console.log('✅ Token 刷新成功');
  332. console.log('🔑 新 Token (前20字符):', newToken.substring(0, 20));
  333. return newToken;
  334. } catch (error) {
  335. console.error('❌ Token 刷新失败:', error.message);
  336. return null;
  337. }
  338. },
  339. /**
  340. * 获取店铺 ID
  341. * 优先级:
  342. * 1. 扫码进入的 storeId(最高优先级)
  343. * 2. 用户历史访问的 storeId
  344. * 3. 超级门店 ID(默认值)
  345. *
  346. * 注意:如果需要切换店铺(非扫码),请先调用:
  347. * wx.removeStorageSync('storeId_from_scan')
  348. */
  349. async getStoreId() {
  350. try {
  351. console.log('🏪 开始获取店铺 ID...');
  352. const defaultStoreId = 'pkPdAnLAUZ'; // 超级门店ID
  353. // 检查是否是扫码进入
  354. const isFromScan = wx.getStorageSync('storeId_from_scan');
  355. const storedStoreId = wx.getStorageSync('storeId');
  356. const globalStoreId = getApp().globalData.storeId;
  357. let configuredStoreId;
  358. if (isFromScan && storedStoreId) {
  359. // 优先级1:扫码进入的店铺(最高优先级)
  360. configuredStoreId = storedStoreId;
  361. console.log('🎯 使用扫码进入的店铺 ID:', configuredStoreId);
  362. } else if (storedStoreId) {
  363. // 优先级2:用户历史访问的店铺
  364. configuredStoreId = storedStoreId;
  365. console.log('📍 使用历史访问的店铺 ID:', configuredStoreId);
  366. } else if (globalStoreId) {
  367. // 优先级3:全局设置的店铺
  368. configuredStoreId = globalStoreId;
  369. console.log('🌐 使用全局店铺 ID:', configuredStoreId);
  370. } else {
  371. // 优先级4:默认超级门店
  372. configuredStoreId = defaultStoreId;
  373. console.log('⭐ 使用默认超级门店 ID:', configuredStoreId);
  374. }
  375. console.log('✅ 最终使用店铺 ID:', configuredStoreId);
  376. return configuredStoreId;
  377. } catch (error) {
  378. console.error('❌ 获取店铺 ID 失败:', error);
  379. return 'pkPdAnLAUZ';
  380. }
  381. },
  382. /**
  383. * 获取店铺信息(id 与 名称)
  384. * 优先级:
  385. * 1. 扫码进入的 storeId(最高优先级)
  386. * 2. 用户历史访问的 storeId
  387. * 3. 超级门店 ID(默认值)
  388. */
  389. async getStoreInfo() {
  390. try {
  391. const defaultStoreId = 'pkPdAnLAUZ'; // 超级门店ID
  392. // 检查是否是扫码进入
  393. const isFromScan = wx.getStorageSync('storeId_from_scan');
  394. const storedStoreId = wx.getStorageSync('storeId');
  395. const globalStoreId = getApp().globalData.storeId;
  396. let effectiveStoreId;
  397. if (isFromScan && storedStoreId) {
  398. // 优先级1:扫码进入的店铺(最高优先级)
  399. effectiveStoreId = storedStoreId;
  400. console.log('🎯 使用扫码进入的店铺 ID:', effectiveStoreId);
  401. } else if (storedStoreId) {
  402. // 优先级2:用户历史访问的店铺
  403. effectiveStoreId = storedStoreId;
  404. console.log('📍 使用历史访问的店铺 ID:', effectiveStoreId);
  405. } else if (globalStoreId) {
  406. // 优先级3:全局设置的店铺
  407. effectiveStoreId = globalStoreId;
  408. console.log('🌐 使用全局店铺 ID:', effectiveStoreId);
  409. } else {
  410. // 优先级4:默认超级门店
  411. effectiveStoreId = defaultStoreId;
  412. console.log('⭐ 使用默认超级门店 ID:', effectiveStoreId);
  413. }
  414. const query = new Parse.Query('ShopStore');
  415. query.equalTo('objectId', effectiveStoreId);
  416. const store = await query.first();
  417. if (store) {
  418. const name = store.get('storeName') || '';
  419. console.log('✅ 获取店铺信息:', { id: effectiveStoreId, name });
  420. return { id: effectiveStoreId, name };
  421. } else {
  422. console.log('⚠️ 未找到店铺,仅返回 ID');
  423. return { id: effectiveStoreId, name: '' };
  424. }
  425. } catch (e) {
  426. console.error('获取店铺信息失败:', e);
  427. const fallbackId = wx.getStorageSync('storeId') || 'pkPdAnLAUZ';
  428. return { id: fallbackId, name: '' };
  429. }
  430. },
  431. /**
  432. * 跳转到 H5 主页
  433. */
  434. async navigateToHome() {
  435. console.log('===========================================');
  436. console.log('======= navigateToHome 被调用 =======');
  437. console.log('===========================================');
  438. let currentUser = Parse.User.current();
  439. let userInfo = wx.getStorageSync("userLogin");
  440. console.log('当前用户:', currentUser ? currentUser.id : '无');
  441. console.log('用户手机号:', currentUser?.get('mobile') || '无');
  442. console.log('userInfo:', userInfo || '无');
  443. // 如果有 Parse 用户但没有 userInfo,可能是刚登录,等待同步
  444. if (currentUser && currentUser.get('mobile') && !userInfo) {
  445. console.log('⏳ 检测到刚登录,等待状态同步...');
  446. // 等待 500ms
  447. await new Promise(resolve => setTimeout(resolve, 500));
  448. // 重新获取
  449. currentUser = Parse.User.current();
  450. userInfo = wx.getStorageSync("userLogin");
  451. // 如果还是没有,手动设置
  452. if (currentUser && currentUser.get('mobile') && !userInfo) {
  453. wx.setStorageSync("userLogin", currentUser.id);
  454. userInfo = currentUser.id;
  455. console.log('✅ 手动设置 userLogin:', userInfo);
  456. }
  457. }
  458. // 重新检查登录状态
  459. const isLoggedIn = currentUser && currentUser.get('mobile') && userInfo;
  460. console.log('最终登录状态:', isLoggedIn ? '已登录' : '未登录');
  461. // 检查 isPublishing 状态
  462. const isPublishing = wx.getStorageSync('isPublishing');
  463. // 如果用户未登录
  464. if (!isLoggedIn) {
  465. // 只有当 isPublishing == true 时才允许游客模式
  466. if (isPublishing === true) {
  467. console.log('⚠️ 用户未登录,但 isPublishing == true,进入游客模式');
  468. this.navigateToHomeAsGuest();
  469. return;
  470. } else {
  471. console.log('❌ 用户未登录且 isPublishing != true,直接跳转登录页面');
  472. login.loginNow();
  473. return;
  474. }
  475. }
  476. let token = currentUser.getSessionToken();
  477. if (!token) {
  478. console.error('❌ 无法获取 Session Token!');
  479. wx.showToast({
  480. title: '获取登录信息失败',
  481. icon: 'none'
  482. });
  483. return;
  484. }
  485. // 验证 token 是否有效
  486. const isValid = await this.validateToken(token);
  487. if (!isValid) {
  488. wx.showLoading({
  489. title: '正在刷新登录...'
  490. });
  491. // 尝试刷新 token
  492. const newToken = await this.refreshToken();
  493. wx.hideLoading();
  494. if (newToken) {
  495. token = newToken;
  496. } else {
  497. console.error('❌ Token 刷新失败,需要重新登录');
  498. wx.showModal({
  499. title: '提示',
  500. content: '登录已过期,请重新登录',
  501. showCancel: false,
  502. success: () => {
  503. wx.navigateTo({
  504. url: 'plugin://fm-plugin/fm-auth'
  505. });
  506. }
  507. });
  508. return;
  509. }
  510. } else {
  511. // token 验证通过
  512. }
  513. // 获取店铺信息
  514. const store = await this.getStoreInfo();
  515. const storeId = store && store.id ? store.id : null;
  516. const storeName = store && store.name ? store.name : '';
  517. // 构建 H5 URL(重要:storeId 和 token 作为查询参数)
  518. let h5Url = `https://app.fmode.cn/dev/pobingfeng/owner/nav/home?`;
  519. // 如果有 storeId,添加到 URL 中
  520. if (storeId) {
  521. h5Url += `storeId=${storeId}&`;
  522. }
  523. h5Url += `token=${token}`;
  524. console.log('🌐 H5 URL:', h5Url);
  525. console.log(' - URL 长度:', h5Url.length);
  526. if (storeId) {
  527. console.log(' - 店铺 ID:', storeId);
  528. }
  529. // 编码后的 URL
  530. const encodedUrl = encodeURIComponent(h5Url);
  531. console.log('📦 编码后的 URL:', encodedUrl.substring(0, 100) + '...');
  532. // 最终的小程序页面路径
  533. // 传递店铺信息给 web-view 页面,优先用于设置标题
  534. let webViewPath = `/common-page/pages/web-view/index?path=${encodedUrl}`;
  535. if (storeId) {
  536. webViewPath += `&storeId=${storeId}`;
  537. }
  538. if (storeName) {
  539. webViewPath += `&storeName=${encodeURIComponent(storeName)}`;
  540. }
  541. console.log('📄 web-view 页面路径:', webViewPath.substring(0, 100) + '...');
  542. console.log('===========================================');
  543. wx.navigateTo({
  544. url: webViewPath,
  545. success: () => {
  546. console.log('✅ 跳转成功');
  547. },
  548. fail: (err) => {
  549. console.error('❌ 跳转失败:', err);
  550. wx.showToast({
  551. title: '跳转失败,请重试',
  552. icon: 'none'
  553. });
  554. }
  555. });
  556. },
  557. /**
  558. * 游客模式跳转到主页
  559. */
  560. async navigateToHomeAsGuest() {
  561. try {
  562. console.log('===========================================');
  563. console.log('======= 游客模式访问 =======');
  564. console.log('===========================================');
  565. // 标记为游客模式
  566. wx.setStorageSync('isGuestMode', true);
  567. // ✅ 游客默认使用超级门店ID,确保有数据
  568. const superStoreId = 'pkPdAnLAUZ'; // 超级门店ID
  569. // 设置超级门店ID到存储
  570. wx.setStorageSync('storeId', superStoreId);
  571. getApp().globalData.storeId = superStoreId;
  572. console.log('✅ 游客使用超级门店ID:', superStoreId);
  573. // 获取店铺信息
  574. const store = await this.getStoreInfo();
  575. const storeId = store && store.id ? store.id : superStoreId;
  576. const storeName = store && store.name ? store.name : '超级门店';
  577. console.log('✅ 店铺信息:', { id: storeId, name: storeName });
  578. // 构建 H5 URL(游客模式,不传 token)
  579. let h5Url = `https://app.fmode.cn/dev/pobingfeng/owner/nav/home?`;
  580. h5Url += `storeId=${storeId}&`;
  581. // 添加游客模式标识
  582. h5Url += `guestMode=true`;
  583. console.log('🌐 游客模式 H5 URL:', h5Url);
  584. console.log('');
  585. console.log('⚠️⚠️⚠️ 重要提示 ⚠️⚠️⚠️');
  586. console.log('如果H5页面显示的不是超级门店,说明H5端没有正确使用URL中的storeId参数!');
  587. console.log('H5端需要确保:');
  588. console.log('1. 从URL中读取 storeId 参数');
  589. console.log('2. 优先使用URL传递的 storeId,不要被其他逻辑覆盖');
  590. console.log('3. 不要使用localStorage缓存的旧门店ID');
  591. console.log('');
  592. console.log('请复制以下URL在浏览器中测试:');
  593. console.log(h5Url);
  594. console.log('===========================================');
  595. // 编码后的 URL
  596. const encodedUrl = encodeURIComponent(h5Url);
  597. // 跳转
  598. let webViewPath = `/common-page/pages/web-view/index?path=${encodedUrl}`;
  599. webViewPath += `&storeId=${storeId}`;
  600. if (storeName) {
  601. webViewPath += `&storeName=${encodeURIComponent(storeName)}`;
  602. }
  603. console.log('📄 web-view 页面路径:', webViewPath.substring(0, 100) + '...');
  604. console.log('===========================================');
  605. wx.navigateTo({
  606. url: webViewPath,
  607. success: () => {
  608. console.log('✅ 游客模式跳转成功');
  609. },
  610. fail: (err) => {
  611. console.error('❌ 跳转失败:', err);
  612. wx.showToast({
  613. title: '跳转失败,请重试',
  614. icon: 'none'
  615. });
  616. }
  617. });
  618. } catch (error) {
  619. console.error('❌ 游客模式跳转失败:', error);
  620. wx.showToast({
  621. title: '加载失败,请重试',
  622. icon: 'none'
  623. });
  624. }
  625. },
  626. /**
  627. * 轮播图变化事件
  628. */
  629. onSwiperChange(e) {
  630. this.setData({
  631. currentSwiperIndex: e.detail.current
  632. });
  633. },
  634. /**
  635. * 跳转到案例展示页面
  636. */
  637. async navigateToCases() {
  638. console.log('===========================================');
  639. console.log('🏠 调用了 navigateToCases 方法(案例展示)');
  640. console.log('===========================================');
  641. // 检查 isPublishing 状态,如果不是 true,需要强制登录
  642. const isPublishing = this.data.showAI;
  643. // 检查是否需要强制登录
  644. const canAccess = await this.checkLoginRequired();
  645. if (!canAccess) {
  646. return;
  647. }
  648. // 案例展示允许游客访问(当 isPublishing == true 时)
  649. const currentUser = Parse.User.current();
  650. if (!currentUser) {
  651. console.log('游客访问案例展示');
  652. wx.setStorageSync('isGuestMode', true);
  653. await this.navigateToH5PageAsGuest('owner/nav/cases');
  654. } else {
  655. await this.navigateToH5Page('owner/nav/cases');
  656. }
  657. },
  658. /**
  659. * 跳转到产品中心页面
  660. * @param {string} productId - 可选的产品ID,用于直接跳转到特定产品详情
  661. */
  662. async navigateToProducts(productId = null) {
  663. console.log('===========================================');
  664. console.log('📦 调用了 navigateToProducts 方法(产品中心)');
  665. console.log('===========================================');
  666. // 检查是否需要强制登录
  667. const canAccess = await this.checkLoginRequired();
  668. if (!canAccess) {
  669. return;
  670. }
  671. // 产品中心允许游客访问(当 isPublishing == true 时)
  672. const currentUser = Parse.User.current();
  673. const params = productId ? { productId } : {};
  674. if (!currentUser) {
  675. console.log('游客访问产品中心');
  676. wx.setStorageSync('isGuestMode', true);
  677. await this.navigateToH5PageAsGuest('owner/nav/products', params);
  678. } else {
  679. await this.navigateToH5Page('owner/nav/products', params);
  680. }
  681. },
  682. /**
  683. * 跳转到方案定制/AI推荐页面
  684. */
  685. async navigateToConsultation() {
  686. console.log('===========================================');
  687. console.log('======= 点击咨询/方案定制 =======');
  688. console.log('===========================================');
  689. // 检查 isPublishing 状态,如果不是 true,需要强制登录
  690. const isPublishing = this.data.showAI;
  691. // 检查是否需要强制登录
  692. const canAccess = await this.checkLoginRequired();
  693. if (!canAccess) {
  694. return;
  695. }
  696. // 方案定制需要登录
  697. let currentUser = Parse.User.current();
  698. const isGuestMode = wx.getStorageSync('isGuestMode');
  699. let userLogin = wx.getStorageSync('userLogin');
  700. console.log('当前用户:', currentUser ? currentUser.id : '无');
  701. console.log('用户手机号:', currentUser?.get('mobile') || '无');
  702. console.log('游客模式:', isGuestMode);
  703. console.log('userLogin 存储:', userLogin || '无');
  704. // 如果有 Parse 用户但没有 userLogin,可能是刚授权完成,等待一下
  705. if (currentUser && currentUser.get('mobile') && !userLogin) {
  706. console.log('⏳ 检测到刚授权完成,等待状态同步...');
  707. // 等待 500ms 后重新检查
  708. await new Promise(resolve => setTimeout(resolve, 500));
  709. // 重新获取状态
  710. currentUser = Parse.User.current();
  711. userLogin = wx.getStorageSync('userLogin');
  712. // 如果还是没有 userLogin,手动设置
  713. if (currentUser && currentUser.get('mobile') && !userLogin) {
  714. wx.setStorageSync("userLogin", currentUser.id);
  715. userLogin = currentUser.id;
  716. console.log('✅ 手动设置 userLogin:', userLogin);
  717. }
  718. }
  719. // 检查用户是否真正登录(有手机号且有 userLogin 存储)
  720. const isReallyLoggedIn = currentUser && currentUser.get('mobile') && userLogin;
  721. console.log('最终登录状态:', isReallyLoggedIn ? '已登录' : '未登录');
  722. // 如果用户已经真正登录,清除游客模式标记
  723. if (isReallyLoggedIn && isGuestMode) {
  724. console.log('✅ 用户已登录,清除游客模式标记');
  725. wx.removeStorageSync('isGuestMode');
  726. }
  727. // 只有在真正未登录时才提示
  728. if (!isReallyLoggedIn) {
  729. console.log('⚠️ 用户未完成登录,显示登录提示');
  730. wx.showModal({
  731. title: '需要登录',
  732. content: '方案定制和咨询功能需要登录后使用,是否立即登录?',
  733. confirmText: '立即登录',
  734. cancelText: '取消',
  735. success: async (res) => {
  736. if (res.confirm) {
  737. console.log('用户选择:立即登录');
  738. // 不要清除登录状态,因为可能用户刚登录成功只是状态没同步
  739. // 直接跳转到登录页面
  740. console.log('准备调用 login.loginNow()');
  741. // 直接调用登录方法
  742. const loginResult = login.loginNow();
  743. console.log('login.loginNow() 返回值:', loginResult);
  744. // 如果返回 false,说明已经跳转到登录页面
  745. if (!loginResult) {
  746. console.log('✅ 已跳转到登录页面');
  747. // 设置待处理的跳转,登录成功后自动跳转到咨询页面
  748. wx.setStorageSync('pendingNavigation', 'consultation');
  749. console.log('📌 已设置待处理跳转: consultation');
  750. }
  751. } else {
  752. console.log('用户选择:取消');
  753. }
  754. }
  755. });
  756. return;
  757. }
  758. console.log('✅ 用户已登录,跳转到咨询页面');
  759. console.log('===========================================');
  760. await this.navigateToH5Page('owner/nav/consultation');
  761. },
  762. /**
  763. * 通用 H5 页面跳转方法
  764. * @param {string} pagePath - H5 页面路径(例如: 'owner/nav/cases')
  765. * @param {object} extraParams - 额外的URL参数对象(例如: { productId: 'xxx' })
  766. */
  767. async navigateToH5Page(pagePath, extraParams = {}) {
  768. console.log('===========================================');
  769. console.log(`======= 小程序跳转 H5: ${pagePath} =======`);
  770. console.log('===========================================');
  771. const currentUser = Parse.User.current();
  772. let userInfo = wx.getStorageSync("userLogin");
  773. console.log('📱 当前登录状态检查:');
  774. console.log(' Parse.User.current():', currentUser ? currentUser.id : '无');
  775. console.log(' 用户手机号:', currentUser?.get('mobile') || '无');
  776. console.log(' userLogin 存储:', userInfo || '无');
  777. console.log(' Session Token (前20字符):', currentUser?.getSessionToken()?.substring(0, 20) || '无');
  778. // 检查是否是游客模式
  779. const isGuestMode = wx.getStorageSync('isGuestMode');
  780. console.log(' 游客模式:', isGuestMode);
  781. // 定义允许游客访问的页面
  782. const guestAllowedPages = [
  783. 'owner/nav/home', // 首页
  784. 'owner/nav/products', // 产品中心
  785. 'owner/nav/cases' // 案例展示
  786. ];
  787. // 检查当前页面是否允许游客访问
  788. const isGuestAllowed = guestAllowedPages.some(page => pagePath.includes(page));
  789. if ((!currentUser || userInfo == '') && !isGuestMode) {
  790. // 未登录且不是游客模式,提示用户
  791. wx.showModal({
  792. title: '温馨提示',
  793. content: '登录后可以体验更多功能,是否立即登录?',
  794. confirmText: '立即登录',
  795. cancelText: '先随便看看',
  796. success: (res) => {
  797. if (res.confirm) {
  798. // 用户选择登录
  799. login.loginNow();
  800. } else {
  801. // 用户选择游客模式
  802. if (isGuestAllowed) {
  803. // 如果是允许游客访问的页面,继续访问
  804. wx.setStorageSync('isGuestMode', true);
  805. this.navigateToH5PageAsGuest(pagePath, extraParams);
  806. } else {
  807. // 如果不允许游客访问,提示需要登录
  808. wx.showToast({
  809. title: '此功能需要登录',
  810. icon: 'none'
  811. });
  812. }
  813. }
  814. }
  815. });
  816. return;
  817. }
  818. // 如果是游客模式,检查是否允许访问
  819. if (isGuestMode || !currentUser) {
  820. if (!isGuestAllowed) {
  821. // 游客不允许访问此页面
  822. wx.showModal({
  823. title: '需要登录',
  824. content: '此功能需要登录后使用,是否立即登录?',
  825. confirmText: '立即登录',
  826. cancelText: '取消',
  827. success: (res) => {
  828. if (res.confirm) {
  829. login.loginNow();
  830. }
  831. }
  832. });
  833. return;
  834. }
  835. // 游客访问允许的页面
  836. this.navigateToH5PageAsGuest(pagePath, extraParams);
  837. return;
  838. }
  839. let token = currentUser.getSessionToken();
  840. console.log('🔑 准备传递的 Token:');
  841. console.log(' 完整 Token:', token);
  842. console.log(' Token 长度:', token ? token.length : 0);
  843. console.log(' Token 前20个字符:', token ? token.substring(0, 20) : 'null');
  844. if (!token) {
  845. console.error('❌ 无法获取 Session Token!');
  846. wx.showToast({
  847. title: '获取登录信息失败',
  848. icon: 'none'
  849. });
  850. return;
  851. }
  852. // 验证 token 是否有效
  853. console.log('🔍 验证 token 有效性...');
  854. const isValid = await this.validateToken(token);
  855. if (!isValid) {
  856. console.log('⚠️ Token 已失效,尝试刷新...');
  857. wx.showLoading({
  858. title: '正在刷新登录...'
  859. });
  860. // 尝试刷新 token
  861. const newToken = await this.refreshToken();
  862. wx.hideLoading();
  863. if (newToken) {
  864. token = newToken;
  865. console.log('✅ 使用新的 token:', token.substring(0, 20));
  866. } else {
  867. console.error('❌ Token 刷新失败,需要重新登录');
  868. wx.showModal({
  869. title: '提示',
  870. content: '登录已过期,请重新登录',
  871. showCancel: false,
  872. success: () => {
  873. wx.navigateTo({
  874. url: 'plugin://fm-plugin/fm-auth'
  875. });
  876. }
  877. });
  878. return;
  879. }
  880. } else {
  881. console.log('✅ Token 验证通过');
  882. }
  883. // 获取店铺信息
  884. const store = await this.getStoreInfo();
  885. const storeId = store && store.id ? store.id : null;
  886. const storeName = store && store.name ? store.name : '';
  887. // 构建 H5 URL(重要:storeId 和 token 作为查询参数)
  888. let h5Url = `https://app.fmode.cn/dev/pobingfeng/${pagePath}?`;
  889. // 如果有 storeId,添加到 URL 中
  890. if (storeId) {
  891. h5Url += `storeId=${storeId}&`;
  892. }
  893. h5Url += `token=${token}`;
  894. console.log('🌐 构建的 H5 URL:');
  895. console.log(' 完整 URL:', h5Url);
  896. console.log(' URL 中的 token (前20字符):', token.substring(0, 20));
  897. // 添加额外的参数(如 productId)
  898. if (extraParams && Object.keys(extraParams).length > 0) {
  899. for (const [key, value] of Object.entries(extraParams)) {
  900. if (value) {
  901. h5Url += `&${key}=${encodeURIComponent(value)}`;
  902. console.log(` - 添加参数 ${key}:`, value);
  903. }
  904. }
  905. }
  906. // 编码后的 URL
  907. const encodedUrl = encodeURIComponent(h5Url);
  908. // 最终的小程序页面路径
  909. // 传递店铺信息给 web-view 页面,优先用于设置标题
  910. let webViewPath = `/common-page/pages/web-view/index?path=${encodedUrl}`;
  911. if (storeId) {
  912. webViewPath += `&storeId=${storeId}`;
  913. }
  914. if (storeName) {
  915. webViewPath += `&storeName=${encodeURIComponent(storeName)}`;
  916. }
  917. console.log('📄 最终跳转路径:', webViewPath.substring(0, 150) + '...');
  918. console.log('===========================================');
  919. wx.navigateTo({
  920. url: webViewPath,
  921. success: () => {
  922. console.log('✅ 跳转成功');
  923. },
  924. fail: (err) => {
  925. console.error('❌ 跳转失败:', err);
  926. wx.showToast({
  927. title: '跳转失败,请重试',
  928. icon: 'none'
  929. });
  930. }
  931. });
  932. },
  933. /**
  934. * 检查登录状态
  935. * @returns {boolean} 是否已登录
  936. */
  937. async checkLoginStatus() {
  938. let currentUser = Parse.User.current();
  939. let userLogin = wx.getStorageSync('userLogin');
  940. // 如果有 Parse 用户但没有 userLogin,等待同步
  941. if (currentUser && currentUser.get('mobile') && !userLogin) {
  942. console.log('⏳ 等待登录状态同步...');
  943. await new Promise(resolve => setTimeout(resolve, 500));
  944. currentUser = Parse.User.current();
  945. userLogin = wx.getStorageSync('userLogin');
  946. if (currentUser && currentUser.get('mobile') && !userLogin) {
  947. wx.setStorageSync("userLogin", currentUser.id);
  948. userLogin = currentUser.id;
  949. }
  950. }
  951. return currentUser && currentUser.get('mobile') && userLogin;
  952. },
  953. /**
  954. * 显示需要登录的提示
  955. */
  956. showLoginRequired() {
  957. wx.showModal({
  958. title: '需要登录',
  959. content: '此功能需要登录后使用,请先完成登录',
  960. confirmText: '立即登录',
  961. cancelText: '取消',
  962. success: (res) => {
  963. if (res.confirm) {
  964. console.log('用户选择:立即登录');
  965. login.loginNow();
  966. }
  967. }
  968. });
  969. },
  970. /**
  971. * 游客模式跳转 H5 页面
  972. * @param {string} pagePath - H5 页面路径
  973. * @param {object} extraParams - 额外参数
  974. */
  975. async navigateToH5PageAsGuest(pagePath, extraParams = {}) {
  976. try {
  977. console.log('===========================================');
  978. console.log(`======= 游客模式跳转 H5: ${pagePath} =======`);
  979. console.log('===========================================');
  980. // ✅ 游客默认使用超级门店ID,确保有数据
  981. const superStoreId = 'pkPdAnLAUZ'; // 超级门店ID
  982. // 确保使用超级门店ID
  983. wx.setStorageSync('storeId', superStoreId);
  984. getApp().globalData.storeId = superStoreId;
  985. console.log('✅ 游客使用超级门店ID:', superStoreId);
  986. // 获取店铺信息
  987. const store = await this.getStoreInfo();
  988. const storeId = store && store.id ? store.id : superStoreId;
  989. const storeName = store && store.name ? store.name : '超级门店';
  990. console.log('✅ 店铺信息:', { id: storeId, name: storeName });
  991. // 构建 H5 URL(游客模式,不传 token)
  992. let h5Url = `https://app.fmode.cn/dev/pobingfeng/${pagePath}?`;
  993. h5Url += `storeId=${storeId}&`;
  994. // 添加游客模式标识
  995. h5Url += `guestMode=true`;
  996. // 添加额外的参数
  997. if (extraParams && Object.keys(extraParams).length > 0) {
  998. for (const [key, value] of Object.entries(extraParams)) {
  999. if (value) {
  1000. h5Url += `&${key}=${encodeURIComponent(value)}`;
  1001. console.log(` - 添加参数 ${key}:`, value);
  1002. }
  1003. }
  1004. }
  1005. console.log('🌐 游客模式 H5 URL:', h5Url);
  1006. console.log('');
  1007. console.log('⚠️ 如果H5显示的不是超级门店,请检查H5端是否正确读取了URL中的storeId参数');
  1008. console.log('');
  1009. // 编码后的 URL
  1010. const encodedUrl = encodeURIComponent(h5Url);
  1011. // 最终的小程序页面路径
  1012. let webViewPath = `/common-page/pages/web-view/index?path=${encodedUrl}`;
  1013. webViewPath += `&storeId=${storeId}`;
  1014. if (storeName) {
  1015. webViewPath += `&storeName=${encodeURIComponent(storeName)}`;
  1016. }
  1017. console.log('📄 web-view 页面路径:', webViewPath.substring(0, 100) + '...');
  1018. console.log('===========================================');
  1019. wx.navigateTo({
  1020. url: webViewPath,
  1021. success: () => {
  1022. console.log('✅ 游客模式跳转成功');
  1023. },
  1024. fail: (err) => {
  1025. console.error('❌ 跳转失败:', err);
  1026. wx.showToast({
  1027. title: '跳转失败,请重试',
  1028. icon: 'none'
  1029. });
  1030. }
  1031. });
  1032. } catch (error) {
  1033. console.error('❌ 游客模式跳转失败:', error);
  1034. wx.showToast({
  1035. title: '加载失败,请重试',
  1036. icon: 'none'
  1037. });
  1038. }
  1039. }
  1040. }
  1041. })