508 lines
14 KiB
JavaScript
508 lines
14 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');
|
|||
|
|
|
|||
|
|
App({
|
|||
|
|
globalData: {
|
|||
|
|
userInfo: null,
|
|||
|
|
isLoggedIn: false,
|
|||
|
|
appConfig: {
|
|||
|
|
name: config.appName,
|
|||
|
|
version: config.appVersion
|
|||
|
|
},
|
|||
|
|
systemInfo: null,
|
|||
|
|
networkStatus: 'unknown'
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 小程序启动
|
|||
|
|
onLaunch: async function () {
|
|||
|
|
console.log('=== FindMe小程序启动 ===');
|
|||
|
|
console.log('版本:', config.appVersion);
|
|||
|
|
console.log('环境:', config.debug?.enabled ? '开发' : '生产');
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 1. 初始化系统信息
|
|||
|
|
await this.initSystemInfo();
|
|||
|
|
|
|||
|
|
// 2. 监听网络状态
|
|||
|
|
this.initNetworkMonitoring();
|
|||
|
|
|
|||
|
|
// 3. 初始化认证管理器
|
|||
|
|
await this.initAuth();
|
|||
|
|
|
|||
|
|
// 4. 静默登录检查
|
|||
|
|
await this.checkSilentLogin();
|
|||
|
|
|
|||
|
|
console.log('=== 小程序启动完成 ===');
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('小程序启动过程中发生错误:', error);
|
|||
|
|
// 即使出错也要继续启动,不能阻塞用户使用
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 小程序显示
|
|||
|
|
onShow: function () {
|
|||
|
|
console.log('小程序显示');
|
|||
|
|
|
|||
|
|
// 检查网络状态
|
|||
|
|
this.checkNetworkStatus();
|
|||
|
|
|
|||
|
|
// 如果用户已登录,检查token是否需要刷新
|
|||
|
|
if (this.globalData.isLoggedIn) {
|
|||
|
|
this.refreshTokenIfNeeded();
|
|||
|
|
|
|||
|
|
// 🔥 自动检查账号同步状态(延迟执行,避免阻塞主流程)
|
|||
|
|
setTimeout(() => {
|
|||
|
|
this.checkAccountSync();
|
|||
|
|
}, 2000);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 小程序隐藏
|
|||
|
|
onHide: function () {
|
|||
|
|
console.log('小程序隐藏');
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 小程序错误处理
|
|||
|
|
onError: function (error) {
|
|||
|
|
console.error('小程序全局错误:', error);
|
|||
|
|
|
|||
|
|
// 这里可以集成错误上报服务
|
|||
|
|
// 例如:errorReporter.report(error);
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 页面未找到
|
|||
|
|
onPageNotFound: function (res) {
|
|||
|
|
console.error('页面未找到:', res);
|
|||
|
|
|
|||
|
|
// 重定向到首页
|
|||
|
|
wx.reLaunch({
|
|||
|
|
url: '/pages/map/map'
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 未处理的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;
|
|||
|
|
console.log('当前网络类型:', res.networkType);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 监听网络状态变化
|
|||
|
|
wx.onNetworkStatusChange((res) => {
|
|||
|
|
this.globalData.networkStatus = res.networkType;
|
|||
|
|
console.log('网络状态变化:', res);
|
|||
|
|
|
|||
|
|
if (res.isConnected) {
|
|||
|
|
console.log('网络连接恢复');
|
|||
|
|
// 网络恢复时,重新检查登录状态
|
|||
|
|
if (this.globalData.isLoggedIn) {
|
|||
|
|
this.refreshTokenIfNeeded();
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
console.log('网络连接断开');
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 初始化认证管理器
|
|||
|
|
async initAuth() {
|
|||
|
|
try {
|
|||
|
|
console.log('初始化认证管理器...');
|
|||
|
|
await authManager.init();
|
|||
|
|
console.log('认证管理器初始化完成');
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('认证管理器初始化失败:', error);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 静默登录检查
|
|||
|
|
async checkSilentLogin() {
|
|||
|
|
try {
|
|||
|
|
console.log('🔍 开始静默登录检查...');
|
|||
|
|
|
|||
|
|
// 🔥 先检查本地存储的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,直接返回false
|
|||
|
|
if (!storedUserInfo?.token && !directToken) {
|
|||
|
|
console.log('❌ 没有找到任何token,用户需要登录');
|
|||
|
|
this.globalData.isLoggedIn = false;
|
|||
|
|
this.globalData.userInfo = null;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const isAuthenticated = await authManager.silentLogin();
|
|||
|
|
|
|||
|
|
if (isAuthenticated) {
|
|||
|
|
console.log('✅ 静默登录成功,用户已登录');
|
|||
|
|
this.globalData.isLoggedIn = true;
|
|||
|
|
|
|||
|
|
// 🔥 再次验证token的有效性
|
|||
|
|
const finalUserInfo = wx.getStorageSync('userInfo');
|
|||
|
|
if (finalUserInfo && finalUserInfo.token && finalUserInfo.token.length > 0) {
|
|||
|
|
this.globalData.userInfo = finalUserInfo;
|
|||
|
|
console.log('✅ 已恢复完整用户信息,token长度:', finalUserInfo.token.length);
|
|||
|
|
} else {
|
|||
|
|
console.error('❌ 静默登录成功但无法获取有效token');
|
|||
|
|
this.globalData.isLoggedIn = false;
|
|||
|
|
this.globalData.userInfo = null;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
console.log('❌ 静默登录失败,用户需要手动登录');
|
|||
|
|
this.globalData.isLoggedIn = false;
|
|||
|
|
this.globalData.userInfo = null;
|
|||
|
|
|
|||
|
|
// 🔥 清理无效的存储数据
|
|||
|
|
wx.removeStorageSync('userInfo');
|
|||
|
|
wx.removeStorageSync('token');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} 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) {
|
|||
|
|
console.log('网络类型变化:', 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) {
|
|||
|
|
console.log('Token即将过期,尝试刷新');
|
|||
|
|
const refreshed = await authManager.refreshTokenIfNeeded(this.globalData.userInfo);
|
|||
|
|
|
|||
|
|
if (refreshed) {
|
|||
|
|
console.log('Token刷新成功');
|
|||
|
|
// 🔥 修复:获取完整的认证信息
|
|||
|
|
const storedUserInfo = wx.getStorageSync('userInfo');
|
|||
|
|
if (storedUserInfo && storedUserInfo.token) {
|
|||
|
|
this.globalData.userInfo = storedUserInfo;
|
|||
|
|
console.log('Token刷新后已更新完整用户信息');
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
console.log('Token刷新失败,需要重新登录');
|
|||
|
|
this.handleAuthExpired();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('Token刷新检查失败:', error);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 处理认证过期
|
|||
|
|
handleAuthExpired() {
|
|||
|
|
console.log('认证已过期,清除登录状态');
|
|||
|
|
|
|||
|
|
authManager.clearAuthData();
|
|||
|
|
this.globalData.isLoggedIn = false;
|
|||
|
|
this.globalData.userInfo = null;
|
|||
|
|
|
|||
|
|
// 显示提示
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '登录已过期,请重新登录',
|
|||
|
|
icon: 'none',
|
|||
|
|
duration: 2000
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 跳转到登录页
|
|||
|
|
setTimeout(() => {
|
|||
|
|
wx.reLaunch({
|
|||
|
|
url: '/pages/login/login'
|
|||
|
|
});
|
|||
|
|
}, 2000);
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 手动登录方法(供页面调用)
|
|||
|
|
async login(loginData) {
|
|||
|
|
try {
|
|||
|
|
console.log('执行登录,保存用户信息');
|
|||
|
|
|
|||
|
|
// 使用认证管理器保存登录信息
|
|||
|
|
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');
|
|||
|
|
return true;
|
|||
|
|
} else {
|
|||
|
|
console.error('登录信息保存失败:无法获取完整用户信息');
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
console.error('登录信息保存失败');
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('登录处理失败:', error);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 登出方法(供页面调用)
|
|||
|
|
async logout() {
|
|||
|
|
try {
|
|||
|
|
console.log('执行登出');
|
|||
|
|
|
|||
|
|
const success = await authManager.logout();
|
|||
|
|
|
|||
|
|
// 无论服务端登出是否成功,都要清除本地状态
|
|||
|
|
this.globalData.isLoggedIn = false;
|
|||
|
|
this.globalData.userInfo = null;
|
|||
|
|
|
|||
|
|
console.log('登出完成');
|
|||
|
|
return success;
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('登出失败:', error);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 检查是否需要登录(供页面调用)
|
|||
|
|
requireAuth() {
|
|||
|
|
return authManager.requireAuth();
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 获取用户显示信息(供页面调用)
|
|||
|
|
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;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 全局错误处理工具
|
|||
|
|
handleError(error, context = '') {
|
|||
|
|
console.error(`${context} 错误:`, error);
|
|||
|
|
|
|||
|
|
// 根据错误类型显示不同提示
|
|||
|
|
let message = '操作失败,请重试';
|
|||
|
|
|
|||
|
|
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 {
|
|||
|
|
console.log('开始检查账号同步状态...');
|
|||
|
|
|
|||
|
|
// 检查是否应该跳过绑定提示
|
|||
|
|
if (accountSyncManager.shouldSkipBinding()) {
|
|||
|
|
console.log('用户选择跳过绑定,24小时内不再提示');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 自动检查并引导用户绑定手机号
|
|||
|
|
await accountSyncManager.autoCheckAndBind();
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('账号同步检查失败:', error);
|
|||
|
|
// 不影响主要功能,静默处理错误
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|