1038 lines
31 KiB
JavaScript
1038 lines
31 KiB
JavaScript
|
|
// 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();
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|