findme-miniprogram-frontend/app.js
2025-12-27 17:16:03 +08:00

1037 lines
31 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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();
}
})