// app.js const config = require('./config/config.js'); const authManager = require('./utils/auth.js'); const apiClient = require('./utils/api-client.js'); const accountSyncManager = require('./utils/account-sync.js'); const animationManager = require('./utils/animation-manager.js'); const versionManager = require('./utils/simple-version-manager.js'); const screen = require('./utils/screen-adapter'); const { V2NIMConst, NIM } = require('./dist/nim'); const realtimeLogger = require('./utils/realtime-logger.js'); App({ globalData: { screen, userInfo:null, isLoggedIn: false, appConfig: { name: config.appName, version: config.appVersion }, systemInfo: null, networkStatus: 'unknown', needOpenLocationFavoriteBar: false, realtimeLogger: realtimeLogger }, async initScreen(page) { try { // 检查 screen 是否已正确导入 if (!screen || !screen.init) { console.error('屏幕适配器未正确导入'); return; } await screen.init(page); } catch (error) { console.error('屏幕适配初始化失败:', error); // 不抛出错误,让页面继续加载 } }, // 小程序启动 onLaunch: async function () { console.log('=== FindMe小程序启动 ==='); console.log('版本:', config.appVersion); console.log('环境:', config.debug?.enabled ? '开发' : '生产'); try { // 🔥 0. 优先检查版本更新(必须在所有逻辑之前) const hasVersionUpdate = versionManager.checkVersionUpdate(); if (hasVersionUpdate) { console.log('⚠️ 检测到版本更新,停止启动流程'); return; // 如果有版本更新,停止后续所有逻辑,等待用户处理 } // 1. 初始化系统信息 await this.initSystemInfo(); // 2. 监听网络状态 this.initNetworkMonitoring(); // 3. 初始化认证管理器 await this.initAuth(); // 4. 静默登录检查 await this.checkSilentLogin(); // 🔥 再次检查版本更新(防止在初始化过程中版本发生变化) const hasVersionUpdateAfter = versionManager.checkVersionUpdate(); if (hasVersionUpdateAfter) { console.log('⚠️ 初始化过程中检测到版本更新,停止启动流程'); return; } // 5. 🔥 在登录成功后初始化 NIM SDK if (this.globalData.isLoggedIn) { await this.initNim(); } console.log('=== 小程序启动完成 ==='); // 🔥 最后一次检查版本更新(在跳转前) const hasVersionUpdateBeforeJump = versionManager.checkVersionUpdate(); if (hasVersionUpdateBeforeJump) { console.log('⚠️ 跳转前检测到版本更新,取消自动跳转'); return; } // 6. 根据token检查结果决定跳转 // 🔥 如果token存在(无论是否过期后刷新),都跳转到地图页面 const finalUserInfo = wx.getStorageSync('userInfo'); const hasToken = finalUserInfo?.token || wx.getStorageSync('token'); // 如果token存在且已登录(包括刷新后登录),直接跳转到地图页面 if (hasToken && this.globalData.isLoggedIn) { console.log('✅ Token存在且已登录(或已刷新),直接跳转到地图页面'); setTimeout(() => { // 🔥 跳转前再次确认版本更新状态 const finalVersionCheck = versionManager.checkVersionUpdate(); if (!finalVersionCheck) { wx.reLaunch({ url: '/pages/map/map' }); } }, 0); } else if (hasToken && !this.globalData.isLoggedIn) { // 🔥 如果token存在但登录状态为false,说明token失效且刷新失败 // 这种情况下清理数据,跳转到登录页面 console.log('⚠️ Token存在但已失效且刷新失败,清理登录数据,跳转到登录页面'); authManager.clearAuthData(); setTimeout(() => { wx.reLaunch({ url: '/pages/login/login' }); }, 100); } else { console.log('⚠️ 没有token,保持启动页或跳转到登录页'); // 没有token的情况,可以由启动页处理后续跳转逻辑 } } catch (error) { console.error('小程序启动过程中发生错误:', error); } }, // 小程序显示 onShow: function () { console.log('=== 小程序从后台恢复 ==='); // 🔥 全局版本检查 - 每次从后台切回都检查 const hasVersionUpdate = versionManager.checkVersionUpdate(); if (hasVersionUpdate) { console.log('⚠️ 检测到版本更新'); return; // 如果有版本更新,直接返回,等待用户处理 } // 检查网络状态 this.checkNetworkStatus(); // 如果用户已登录,检查token是否需要刷新 if (this.globalData.isLoggedIn) { this.refreshTokenIfNeeded(); // 🔥 检查并重新初始化 NIM(防止黑屏后断开) this.checkAndReconnectNim(); // 🔥 自动检查账号同步状态(延迟执行,避免阻塞主流程) setTimeout(() => { this.checkAccountSync(); }, 2000); } }, // 小程序隐藏 onHide: function () { }, // 小程序错误处理 onError: function (error) { console.error('小程序全局错误:', error); // 这里可以集成错误上报服务 // 例如:errorReporter.report(error); }, // 页面未找到 onPageNotFound: function (res) { console.error('页面未找到:', res); // 重定向到首页 wx.reLaunch({ url: '/pages/map/map' }); }, // 全局路由拦截 onRoute: function () { // 监听页面跳转 const originalNavigateTo = wx.navigateTo; const originalRedirectTo = wx.redirectTo; const originalSwitchTab = wx.switchTab; const originalReLaunch = wx.reLaunch; const app = this; const needAuthPages = [ '/pages/social/friends/friends', '/pages/message/message', '/pages/circle/circle' ]; // 重写navigateTo方法 wx.navigateTo = function (options) { const url = options.url.split('?')[0]; if (needAuthPages.includes(url) && !app.globalData.isLoggedIn) { console.log('拦截未授权访问:', url); // 直接跳转到登录页 return originalRedirectTo({ url: '/pages/login/login', success: options.success, fail: options.fail }); } return originalNavigateTo.call(this, options); }; // 同样处理其他跳转方法 wx.redirectTo = function (options) { const url = options.url.split('?')[0]; if (needAuthPages.includes(url) && !app.globalData.isLoggedIn) { console.log('拦截未授权访问:', url); return originalRedirectTo({ url: '/pages/login/login', success: options.success, fail: options.fail }); } return originalRedirectTo.call(this, options); }; wx.switchTab = function (options) { const url = options.url.split('?')[0]; if (needAuthPages.includes(url) && !app.globalData.isLoggedIn) { console.log('拦截未授权访问Tab:', url); return originalRedirectTo({ url: '/pages/login/login', success: options.success, fail: options.fail }); } return originalSwitchTab.call(this, options); }; wx.reLaunch = function (options) { const url = options.url.split('?')[0]; if (needAuthPages.includes(url) && !app.globalData.isLoggedIn) { console.log('拦截未授权访问:', url); return originalRedirectTo({ url: '/pages/login/login', success: options.success, fail: options.fail }); } return originalReLaunch.call(this, options); }; }, // 初始化 NIM SDK async initNim() { realtimeLogger.nim('initNim-start', { timestamp: Date.now() }); // 只有用户已登录才初始化 NIM if (!this.globalData.isLoggedIn || !this.globalData.userInfo) { console.log('⚠️ 用户未登录,跳过NIM初始化') realtimeLogger.warn('NIM初始化跳过-用户未登录', { isLoggedIn: this.globalData.isLoggedIn, hasUserInfo: !!this.globalData.userInfo }); return } const userInfo = this.globalData.userInfo // 使用登录接口返回的 NIM 账号和密码 const nimAccount = userInfo?.neteaseIMAccid || userInfo.user?.neteaseIMAccid const nimToken = userInfo?.neteaseIMToken || userInfo.user?.neteaseIMToken if (!nimAccount || !nimToken) { console.warn('⚠️ 缺少NIM账号或token,跳过NIM初始化') realtimeLogger.error('NIM初始化失败-缺少凭证', { hasNimAccount: !!nimAccount, hasNimToken: !!nimToken, userInfoKeys: Object.keys(userInfo || {}), userKeys: Object.keys(userInfo?.user || {}) }); return } console.log('🔥 开始初始化NIM SDK...') console.log('NIM账号:', nimAccount) console.log('NIM Token:', nimToken) realtimeLogger.nim('nim-credentials', { nimAccount: nimAccount, hasNimToken: !!nimToken, nimTokenLength: nimToken?.length || 0 }); // NIM SDK 配置 const params = { appkey: config.nim?.appkey, apiVersion: config.nim?.apiVersion, enableV2CloudConversation: config.nim?.enableV2CloudConversation, debugLevel: config.debug?.enabled ? 'debug' : 'log' } realtimeLogger.nim('nim-config', { appkey: params.appkey, debugLevel: params.debugLevel, apiVersion: params.apiVersion }); // 获取或创建 NIM 实例 const nim = NIM.getInstance(params) this.globalData.nim = nim realtimeLogger.nim('nim-instance-created', { hasInstance: !!nim }); try { realtimeLogger.nim('nim-login-start', { nimAccount: nimAccount, timestamp: Date.now() }); // 登录 NIM await nim.V2NIMLoginService.login(nimAccount, nimToken, { retryCount: 3, // 登录失败后,重试登录的次数 timeout: 60000, // 登录超时时间,单位毫秒 forceMode: true, // 多端登录互踢时,是否强制登录 authType: 0 }) realtimeLogger.nim('nim-login-success', { nimAccount: nimAccount, timestamp: Date.now() }); } catch (err) { console.error('❌ NIM登录失败:', err) realtimeLogger.error('NIM登录失败', { nimAccount: nimAccount, error: err.toString(), errorMessage: err.message || '', errorCode: err.code || '', timestamp: Date.now() }); return; // 登录失败直接返回 } console.log('✅ NIM登录成功') // 初始化会话管理器 const nimConversationManager = require('./utils/nim-conversation-manager.js') nimConversationManager.init(nim) realtimeLogger.nim('conversation-manager-initialized', {}); // 初始化在线状态管理器 const nimPresenceManager = require('./utils/nim-presence-manager.js') nimPresenceManager.init(nim) console.log('✅ NIM 在线状态管理器已初始化') realtimeLogger.nim('presence-manager-initialized', {}); // 同步当前用户信息到 NIM const nimUserManager = require('./utils/nim-user-manager.js') nimUserManager.init() realtimeLogger.nim('user-manager-initialized', {}); // 提取用户头像和昵称 const avatar = userInfo.user?.avatar || userInfo.avatar const nickname = userInfo.user?.nickname || userInfo.nickname if (avatar || nickname) { realtimeLogger.nim('sync-user-info-start', { hasAvatar: !!avatar, hasNickname: !!nickname }); let res = await nimUserManager.updateSelfUserInfo({ avatar: avatar, nickname: nickname }) if (!res) { console.warn('⚠️ 同步用户信息到NIM失败') realtimeLogger.error('同步用户信息到NIM失败', { avatar: avatar, nickname: nickname }); return } console.log('✅ 用户信息已同步到 NIM') realtimeLogger.nim('sync-user-info-success', {}); } console.log('✅ NIM SDK初始化完成') realtimeLogger.nim('initNim-complete', { timestamp: Date.now() }); }, // 登出 NIM async logoutNim() { try { if (this.globalData.nim) { await this.globalData.nim.V2NIMLoginService.logout() console.log('✅ NIM登出成功') } } catch (error) { console.error('❌ NIM登出失败:', error) } }, // 🔥 检查并重连 NIM(用于从后台恢复时) async checkAndReconnectNim() { try { // 检查是否已有 NIM 实例 if (!this.globalData.nim) { console.log('⚠️ NIM 实例不存在,执行初始化'); await this.initNim(); return; } // 检查 NIM 连接状态 const nim = this.globalData.nim; const loginService = nim.V2NIMLoginService; // 获取当前登录状态 let loginStatus; try { loginStatus = await loginService.getLoginStatus(); console.log('📡 NIM 登录状态:', loginStatus); } catch (error) { console.warn('获取 NIM 登录状态失败:', error); loginStatus = 0; // 假设未登录 } // V2NIMLoginStatus: 0-未登录, 1-登录中, 2-已登录, 3-登录失败 if (loginStatus !== 2) { console.log('🔄 NIM 未处于登录状态,重新登录'); realtimeLogger.nim('nim-reconnect-triggered', { loginStatus: loginStatus, timestamp: Date.now() }); // 重新初始化 NIM await this.initNim(); } else { console.log('✅ NIM 已连接,无需重连'); } } catch (error) { console.error('❌ 检查 NIM 连接状态失败:', error); realtimeLogger.error('NIM重连检查失败', { error: error.toString(), timestamp: Date.now() }); // 如果检查失败,尝试重新初始化 try { console.log('🔄 尝试重新初始化 NIM'); await this.initNim(); } catch (retryError) { console.error('❌ 重新初始化 NIM 失败:', retryError); } } }, // 未处理的Promise拒绝 onUnhandledRejection: function (res) { console.error('未处理的Promise拒绝:', res); }, // 初始化系统信息 async initSystemInfo() { try { // 使用新的API替代废弃的wx.getSystemInfoSync const [windowInfo, deviceInfo, appBaseInfo] = await Promise.all([ this.getWindowInfo(), this.getDeviceInfo(), this.getAppBaseInfo() ]); // 合并系统信息 const systemInfo = { ...windowInfo, ...deviceInfo, ...appBaseInfo }; this.globalData.systemInfo = systemInfo; console.log('系统信息初始化成功:', { platform: systemInfo.platform, version: systemInfo.version, model: systemInfo.model, language: systemInfo.language }); } catch (error) { console.error('获取系统信息失败,使用兜底方案:', error); // 兜底使用统一的系统信息工具 try { const { getSystemInfoSync } = require('./utils/system-info-helper.js'); const systemInfo = getSystemInfoSync(); this.globalData.systemInfo = systemInfo; } catch (fallbackError) { console.error('兜底方案也失败:', fallbackError); } } }, // 获取窗口信息 getWindowInfo() { return new Promise((resolve) => { try { const windowInfo = wx.getWindowInfo(); resolve(windowInfo); } catch (error) { console.warn('获取窗口信息失败:', error); resolve({}); } }); }, // 获取设备信息 getDeviceInfo() { return new Promise((resolve) => { try { const deviceInfo = wx.getDeviceInfo(); resolve(deviceInfo); } catch (error) { console.warn('获取设备信息失败:', error); resolve({}); } }); }, // 获取应用基础信息 getAppBaseInfo() { return new Promise((resolve) => { try { const appBaseInfo = wx.getAppBaseInfo(); resolve(appBaseInfo); } catch (error) { console.warn('获取应用信息失败:', error); resolve({}); } }); }, // 初始化网络监听 initNetworkMonitoring() { // 获取当前网络状态 wx.getNetworkType({ success: (res) => { this.globalData.networkStatus = res.networkType; } }); // 监听网络状态变化 wx.onNetworkStatusChange((res) => { this.globalData.networkStatus = res.networkType; console.log('网络状态变化:', res); if (res.isConnected) { // 网络恢复时,重新检查登录状态 if (this.globalData.isLoggedIn) { this.refreshTokenIfNeeded(); } } else { } }); }, // 初始化认证管理器 async initAuth() { try { await authManager.init(); } catch (error) { console.error('认证管理器初始化失败:', error); } }, // 静默登录检查 async checkSilentLogin() { try { // 🔥 先检查本地存储的token const storedUserInfo = wx.getStorageSync('userInfo'); const directToken = wx.getStorageSync('token'); console.log('🔍 本地token检查:', { hasStoredUserInfo: !!storedUserInfo, hasUserInfoToken: !!(storedUserInfo?.token), hasDirectToken: !!directToken, userInfoTokenLength: storedUserInfo?.token?.length || 0, directTokenLength: directToken?.length || 0 }); // 如果没有任何token,直接返回(不设置登录状态) if (!storedUserInfo?.token && !directToken) { console.log('⚠️ 没有找到token,保持未登录状态'); this.globalData.isLoggedIn = false; this.globalData.userInfo = null; return; } // 🔥 检查token是否过期,如果过期则尝试刷新 let userInfo = storedUserInfo; if (userInfo && userInfo.token) { const isTokenValid = authManager.isTokenValid(userInfo); if (!isTokenValid) { console.log('⚠️ Token已过期,尝试刷新token...'); // 尝试刷新token if (userInfo.refreshToken) { const refreshResult = await authManager.refreshTokenIfNeeded(userInfo); if (refreshResult) { console.log('✅ Token刷新成功'); // 刷新成功后,从存储中获取更新后的userInfo userInfo = wx.getStorageSync('userInfo'); this.globalData.userInfo = userInfo; this.globalData.isLoggedIn = true; apiClient.setToken(userInfo.token); } else { console.log('❌ Token刷新失败,清理登录数据,跳转到登录页面'); // 刷新失败,清理数据 authManager.clearAuthData(); this.globalData.isLoggedIn = false; this.globalData.userInfo = null; // 跳转到登录页面 setTimeout(() => { wx.reLaunch({ url: '/pages/login/login' }); }, 100); return; } } else { console.log('❌ 没有refreshToken,无法刷新,清理登录数据,跳转到登录页面'); // 没有refreshToken,无法刷新 authManager.clearAuthData(); this.globalData.isLoggedIn = false; this.globalData.userInfo = null; // 跳转到登录页面 setTimeout(() => { wx.reLaunch({ url: '/pages/login/login' }); }, 100); return; } } else { console.log('✅ Token未过期,使用现有token'); // Token未过期,直接使用 this.globalData.userInfo = userInfo; this.globalData.isLoggedIn = true; apiClient.setToken(userInfo.token); } } else { // 有directToken但没有完整的userInfo,尝试通过silentLogin处理 const isAuthenticated = await authManager.silentLogin(); if (isAuthenticated) { console.log('✅ 通过silentLogin验证成功'); const finalUserInfo = wx.getStorageSync('userInfo'); if (finalUserInfo && finalUserInfo.token && finalUserInfo.token.length > 0) { this.globalData.userInfo = finalUserInfo; this.globalData.isLoggedIn = true; } else { console.error('❌ silentLogin成功但无法获取有效token'); this.globalData.isLoggedIn = false; this.globalData.userInfo = null; } } else { console.log('❌ silentLogin验证失败,清理登录数据'); this.globalData.isLoggedIn = false; this.globalData.userInfo = null; authManager.clearAuthData(); } } } catch (error) { console.error('❌ 静默登录检查失败:', error); this.globalData.isLoggedIn = false; this.globalData.userInfo = null; // 🔥 出错时清理存储数据 wx.removeStorageSync('userInfo'); wx.removeStorageSync('token'); } }, // 检查网络状态 checkNetworkStatus() { wx.getNetworkType({ success: (res) => { const oldStatus = this.globalData.networkStatus; this.globalData.networkStatus = res.networkType; if (oldStatus !== res.networkType) { } }, fail: (error) => { console.error('获取网络类型失败:', error); } }); }, // 刷新token(如果需要) async refreshTokenIfNeeded() { try { if (!this.globalData.userInfo) { return; } const isValid = authManager.isTokenValid(this.globalData.userInfo); if (!isValid) { const refreshed = await authManager.refreshTokenIfNeeded(this.globalData.userInfo); if (refreshed) { // 🔥 修复:获取完整的认证信息 const storedUserInfo = wx.getStorageSync('userInfo'); if (storedUserInfo && storedUserInfo.token) { this.globalData.userInfo = storedUserInfo; } } else { this.handleAuthExpired(); } } } catch (error) { console.error('Token刷新检查失败:', error); } }, // 处理认证过期 handleAuthExpired() { console.log('认证已过期,清除登录状态'); authManager.clearAuthData(); this.globalData.isLoggedIn = false; this.globalData.userInfo = null; // 只更新登录状态,不强制跳转到登录页 // 让用户先进入地图页面,使用需要登录的功能时再跳转 }, // 手动登录方法(供页面调用) async login(loginData) { try { console.log('执行登录,保存用户信息'); realtimeLogger.login('login-start', { hasToken: !!loginData.token, hasAccessToken: !!loginData.access_token, hasNeteaseIMAccid: !!loginData.neteaseIMAccid, hasNeteaseIMToken: !!loginData.neteaseIMToken }); if (!loginData.token) { loginData.token = loginData.access_token; } // 使用认证管理器保存登录信息 const success = await authManager.saveAuthData(loginData); if (success) { // 🔥 修复:获取完整的认证信息 const storedUserInfo = wx.getStorageSync('userInfo'); if (storedUserInfo && storedUserInfo.token) { this.globalData.userInfo = storedUserInfo; this.globalData.isLoggedIn = true; console.log('登录信息保存成功,包含token'); // 🔥 登录成功后立即初始化 NIM SDK if (storedUserInfo.neteaseIMAccid && storedUserInfo.neteaseIMToken) { console.log('检测到 NIM 凭证,开始初始化 NIM SDK...'); realtimeLogger.login('has-nim-credentials', { hasNeteaseIMAccid: !!storedUserInfo.neteaseIMAccid, hasNeteaseIMToken: !!storedUserInfo.neteaseIMToken }); await this.initNim(); } else { console.warn('⚠️ 登录数据中缺少 NIM 凭证,跳过 NIM 初始化'); realtimeLogger.warn('登录数据缺少NIM凭证', { userInfoKeys: Object.keys(storedUserInfo || {}) }); } realtimeLogger.login('login-success', {}); return true; } else { console.error('登录信息保存失败:无法获取完整用户信息'); return false; } } else { console.error('登录信息保存失败'); return false; } } catch (error) { console.error('登录处理失败:', error); return false; } }, // 登出方法(供页面调用) async logout() { try { console.log('执行登出'); // 🔥 设置退出登录标志,防止登录页误判 wx.setStorageSync('isLoggingOut', true); // 🔥 先登出 NIM await this.logoutNim(); const success = await authManager.logout(); // 🔥 无论服务端登出是否成功,都要清除本地状态 this.globalData.isLoggedIn = false; this.globalData.userInfo = null; this.globalData.nim = null; // 🔥 清除 NIM 实例 // 🔥 清除可能残留的登录信息 wx.removeStorageSync('userInfo'); wx.removeStorageSync('token'); wx.removeStorageSync('testWechatLogin-loginData'); console.log('✅ 登出完成,已清除所有登录状态'); return success; } catch (error) { console.error('登出失败:', error); // 🔥 即使失败也要清除状态 this.globalData.isLoggedIn = false; this.globalData.userInfo = null; this.globalData.nim = null; wx.removeStorageSync('isLoggingOut'); return false; } }, // 检查是否需要登录(供页面调用) // autoRedirect: 可选,是否在未登录时自动跳转登录页,默认false requireAuth(autoRedirect = false) { return authManager.requireAuth(autoRedirect); }, // 获取用户显示信息(供页面调用) getUserDisplayInfo() { return authManager.getUserDisplayInfo(); }, // 检查用户权限(供页面调用) hasPermission(permission) { return authManager.hasPermission(permission); }, // 获取当前token(供页面调用) getCurrentToken() { return authManager.getCurrentToken(); }, // 等待认证初始化完成(供页面调用) async waitForAuth() { await authManager.waitForInitialization(); return this.globalData.isLoggedIn; }, // 检查网络连接 isNetworkAvailable() { return this.globalData.networkStatus !== 'none'; }, // 显示网络错误提示 showNetworkError() { if (!this.isNetworkAvailable()) { wx.showToast({ title: '网络连接不可用', icon: 'none', duration: 2000 }); return true; } return false; }, // 更新全局头像并通知页面 updateUserAvatar(serverUrl, options = {}) { if (!serverUrl) { console.warn('updateUserAvatar 调用时缺少有效的头像地址'); return false; } try { const cachedUrl = options.cachedUrl || serverUrl; const providedInfo = options.userInfo; const storedInfo = providedInfo || this.globalData.userInfo || wx.getStorageSync('userInfo') || {}; const userBucket = storedInfo.user || {}; userBucket.avatar = serverUrl; userBucket.avatarUrl = serverUrl; storedInfo.user = userBucket; storedInfo.avatar = serverUrl; storedInfo.avatarUrl = serverUrl; this.globalData.userInfo = storedInfo; if (storedInfo.token) { this.globalData.isLoggedIn = true; } wx.setStorageSync('userInfo', storedInfo); if (cachedUrl) { wx.setStorageSync('latestAvatarUrl', cachedUrl); } else { wx.setStorageSync('latestAvatarUrl', serverUrl); } const payload = { avatarUrl: serverUrl, cachedUrl, userInfo: storedInfo }; const pages = getCurrentPages(); pages.forEach((page) => { try { if (typeof page.onAvatarUpdated === 'function') { page.onAvatarUpdated(payload); } const displayUrl = cachedUrl || serverUrl; const updates = {}; if (Object.prototype.hasOwnProperty.call(page.data || {}, 'userInfo')) { updates['userInfo.avatarUrl'] = displayUrl; updates['userInfo.avatar'] = displayUrl; } if (page.data && page.data.userInfo && typeof page.data.userInfo === 'object' && page.data.userInfo.user) { updates['userInfo.user.avatar'] = displayUrl; updates['userInfo.user.avatarUrl'] = displayUrl; } if (page.data && page.data.userInfo && typeof page.data.userInfo === 'object' && page.data.userInfo.profile) { updates['userInfo.profile.avatar'] = displayUrl; } if (Object.prototype.hasOwnProperty.call(page.data || {}, 'avatar')) { updates.avatar = displayUrl; } if (Object.prototype.hasOwnProperty.call(page.data || {}, 'avatarUrl')) { updates.avatarUrl = displayUrl; } if (Object.keys(updates).length > 0) { page.setData(updates); } } catch (pageError) { console.error('更新页面头像失败:', page.route, pageError); } }); return true; } catch (error) { console.error('更新全局头像失败:', error); return false; } }, // 全局错误处理工具 handleError(error, context = '') { console.error(`${context} 错误:`, error); // 根据错误类型显示不同提示 let message = '操作失败,请重试' + error; if (error.message) { message = error.message; } else if (error.errMsg) { if (error.errMsg.includes('timeout')) { message = '请求超时,请检查网络连接'; } else if (error.errMsg.includes('fail')) { message = '网络连接失败'; } } wx.showToast({ title: message, icon: 'none', duration: 2000 }); }, // 显示加载状态 showLoading(title = '加载中...') { wx.showLoading({ title: title, mask: true }); }, // 隐藏加载状态 hideLoading() { wx.hideLoading(); }, // 兼容性方法 - 检查登录状态 isLoggedIn() { return this.globalData.isLoggedIn; }, // 兼容性方法 - 获取用户信息 getUserInfo() { return this.globalData.userInfo; }, // 兼容性方法 - 获取token getToken() { return authManager.getCurrentToken(); }, // 🔥 账号同步检查 async checkAccountSync() { try { // 检查是否应该跳过绑定提示 if (accountSyncManager.shouldSkipBinding()) { return; } // 自动检查并引导用户绑定手机号 await accountSyncManager.autoCheckAndBind(); } catch (error) { console.error('账号同步检查失败:', error); // 不影响主要功能,静默处理错误 } }, // 🔥 全局版本检查方法 - 供页面调用 checkAppVersionUpdate: function () { return versionManager.checkVersionUpdate(); } })