// 登录模块 - 处理用户登录、授权、用户信息管理 import { showToast } from '../../../utils/helpers'; import { UserInfo } from '../../../types'; import userService from '../../../services/userService'; import locationTrackingService from '../../../services/locationTrackingService'; import { DataModule } from './dataModule'; export class LoginModule { private dataModule: DataModule; private pageContext: any; constructor(pageContext: any, dataModule: DataModule) { this.pageContext = pageContext; this.dataModule = dataModule; } /** * 处理用户信息 */ public async processUserInfo(userInfo: UserInfo): Promise { // 直接返回用户信息,不进行额外处理 return userInfo; } /** * 登录成功后更新页面状态 */ public updatePageAfterLogin(userInfo: UserInfo): void { this.dataModule.updateUserInfo(userInfo); } /** * 检查登录状态 */ public checkLoginStatus(): boolean { const globalUserInfo = userService.getGlobalUserInfo(); if (globalUserInfo) { this.dataModule.updateUserInfo(globalUserInfo); return true; } return false; } /** * 用户退出登录 */ public async logout(): Promise { try { // 停止位置追踪服务 try { await locationTrackingService.stopTracking(); console.log('位置追踪服务已停止'); } catch (trackingError) { console.warn('停止位置追踪失败,但不影响退出登录:', trackingError); } // 注意:这里不调用userService.logout(),因为服务器端的logout接口会删除token // 而用户只是签退不接单,不是完全退出应用,需要保持token有效 console.log('用户已退出登录(本地签退,保持token有效)'); showToast('已退出登录'); } catch (error) { console.error('退出登录失败:', error); } } /** * 显示手动登录模态框:如果静默登录失败后,让用户尝试手动登录 */ public async showManualLoginModal(): Promise { console.log('显示手动登录模态框'); return new Promise((resolve) => { wx.showModal({ title: '手动登录', content: '静默登录失败,请手动登录以使用完整功能', confirmText: '手动登录', cancelText: '暂不', success: async (res) => { if (res.confirm) { // 用户点击确定,执行手动登录 console.log('用户选择手动登录'); const success = await this.performLogin(); if (!success) { // 登录失败,再次提供选项 this.handleLoginFailure(resolve); } else { resolve(success); } } else { // 用户取消登录,显示关闭小程序选项 console.log('用户选择暂不登录'); this.showCloseAppOption(resolve); } } }); }); } /** * 执行登录流程 - 调用userService的登录方法 * 静默登录失败后,只专注于登录本身,不涉及注册、签到等复杂逻辑 */ private async performLogin(): Promise { try { // 执行微信登录 const result = await userService.wxLogin(); if (result.success && result.userInfo) { // 登录成功,更新页面状态 this.updatePageAfterLogin(result.userInfo); console.log('手动登录成功'); return true; } console.log('手动登录失败'); return false; } catch (error) { console.error('执行登录流程失败:', error); return false; } } /** * 处理登录失败的情况 */ public async handleLoginFailure(resolve: (value: boolean) => void) { console.log('登录失败,显示重试选项'); wx.showModal({ title: '登录失败', content: '登录遇到问题,是否重试?', confirmText: '重新登录', cancelText: '取消并关闭', success: async (res) => { if (res.confirm) { console.log('用户选择重新登录'); const success = await this.performLogin(); if (!success) { // 再次登录失败,递归调用以避免嵌套过深 this.handleLoginFailure(resolve); } else { resolve(success); } } else { console.log('用户选择取消并关闭小程序'); wx.showToast({ title: '即将退出小程序', icon: 'none', duration: 1500, complete: () => { setTimeout(() => { // 使用类型断言解决类型问题 (wx as any).exitMiniProgram(); }, 1500); } }); resolve(false); } } }); } /** * 显示关闭小程序选项 */ public showCloseAppOption(resolve: (value: boolean) => void) { console.log('显示关闭小程序选项'); wx.showModal({ title: '确认退出', content: '不登录将无法使用完整功能,是否退出小程序?', confirmText: '退出小程序', cancelText: '留在页面', success: (res) => { if (res.confirm) { console.log('用户确认退出小程序'); // 使用类型断言解决类型问题 (wx as any).exitMiniProgram(); resolve(false); } else { console.log('用户选择留在页面'); resolve(false); } } }); } /** * 处理签到流程 */ public async handleSignIn(): Promise { try { // 显示加载中提示 wx.showLoading({ title: '签到中...', }); // 先获取地图位置和当前时间 let initialLocation: { latitude: number; longitude: number; timestamp: number }; try { const location = await locationTrackingService.getCurrentLocation(); // 使用秒级时间戳(除以1000取整) initialLocation = { latitude: location.latitude, longitude: location.longitude, timestamp: Math.floor(Date.now() / 1000) }; console.log('获取到签到位置数据:', initialLocation); } catch (error) { console.error('获取位置失败:', error); throw new Error('获取位置失败,请检查位置权限设置'); } // 调用实际的签到接口,传递位置数据 const signInResult = await userService.signIn(initialLocation); wx.hideLoading(); if (signInResult.success) { console.log('签到成功:', signInResult); wx.showToast({ title: '签到成功', icon: 'success', duration: 2000 }); // 更新用户信息 if (signInResult.employeeInfo) { // 将员工信息合并到用户信息中 const app = getApp(); if (app.globalData.userInfo) { app.globalData.userInfo = { ...app.globalData.userInfo, name: signInResult.employeeInfo.name, phone: signInResult.employeeInfo.phone }; this.updatePageAfterLogin(app.globalData.userInfo); } } // 设置用户状态为已签到 if (this.pageContext && this.pageContext.setData) { this.pageContext.setData({ 'authStatus.userStatus': 'signed_in' }); // 更新按钮显示状态 if (this.pageContext.updateButtonDisplayStatus) { this.pageContext.updateButtonDisplayStatus(); } } // 启动位置追踪服务 try { // 先启动位置追踪服务 await locationTrackingService.startTrackingAfterSignIn(); console.log('位置追踪服务已启动'); // 然后调用位置模块的实时跟踪功能 const locationModule = this.dataModule.getLocationModule(); if (locationModule) { await locationModule.startRealTimeTracking(); console.log('位置模块实时跟踪已启动'); } // 订阅位置更新回调,采用统一方式更新所有用户位置 locationTrackingService.subscribeToLocationUpdates((onlineUsers) => { console.log('🚚 位置更新回调 - 在线用户列表已更新,用户数量:', onlineUsers.length); // 统一更新所有在线用户的位置标记点 onlineUsers.forEach(user => { if (user.lastLocation) { console.log(`📍 更新用户 ${user.userId} 标记点位置:`, user.lastLocation); // 统一调用数据模块更新用户标记点位置 this.dataModule.updateUserMarkerPosition( user.lastLocation.longitude, user.lastLocation.latitude, user.userId ); } }); }); } catch (trackingError) { console.warn('启动位置追踪失败,但不影响签到:', trackingError); } return true; } else { console.warn('签到失败:', signInResult.message); wx.showToast({ title: signInResult.message || '签到失败', icon: 'none', duration: 2000 }); return false; } } catch (error) { console.error('签到过程中发生错误:', error); wx.hideLoading(); wx.showToast({ title: '签到失败,请重试', icon: 'none', duration: 2000 }); return false; } } /** * 处理授权登录流程 */ public async handleAuthLogin(): Promise { try { const success = await this.showManualLoginModal(); if (success) { console.log('手动登录成功'); return true; } else { console.log('用户取消手动登录'); return false; } } catch (error) { console.error('手动登录过程中发生错误:', error); return false; } } /** * 判断用户是否为游客(已登录但信息不完整) */ public isTourist(): boolean { const app = getApp(); // 游客定义:已登录但没有完善基本信息(姓名和电话)的用户 if (app.globalData.isLoggedIn && app.globalData.userInfo) { const userInfo = app.globalData.userInfo; return !userInfo.name || !userInfo.phone; } return false; } /** * 计算是否显示签到按钮(基于用户状态和角色) */ public shouldShowSignInButton(): boolean { // 从页面上下文中获取数据 const pageData = this.dataModule.getData(); const authStatus = pageData.authStatus || {}; const userInfo = pageData.userInfo; // 显示条件:已获取微信code、用户状态不是已签到、且用户不是游客(已注册用户) const result = ( authStatus.hasWxCode && (authStatus.userStatus === 'registered' || authStatus.userStatus === 'signed_out') && userInfo !== null && userInfo.role !== 'GUEST' ); // 调试信息:打印不满足条件的原因 if (!result) { console.log('签到按钮不显示原因:'); if (!authStatus.hasWxCode) console.log(' - 未获取微信code'); if (authStatus.userStatus === 'signed_in') console.log(' - 用户状态为已签到'); if (authStatus.userStatus === 'unregistered') console.log(' - 用户状态为未注册'); if (userInfo === null) console.log(' - 用户信息为空'); if (userInfo && userInfo.role === 'GUEST') console.log(' - 用户角色为游客'); console.log('当前状态:', { hasWxCode: authStatus.hasWxCode, userStatus: authStatus.userStatus, userInfo: userInfo ? { role: userInfo.role } : null }); } else { console.log('签到按钮显示条件满足'); } return result; } /** * 计算是否显示注册按钮(基于用户状态和角色) */ public shouldShowRegisterButton(): boolean { // 从页面上下文中获取数据 const pageData = this.dataModule.getData(); const authStatus = pageData.authStatus || {}; const userInfo = pageData.userInfo; // 显示条件:已获取微信code、用户状态为未注册、且用户是游客 const result = ( authStatus.hasWxCode && authStatus.userStatus === 'unregistered' && userInfo !== null && userInfo.role === 'GUEST' ); // 调试信息:打印不满足条件的原因 if (!result) { console.log('注册按钮不显示原因:'); if (!authStatus.hasWxCode) console.log(' - 未获取微信code'); if (authStatus.userStatus !== 'unregistered') console.log(` - 用户状态为${authStatus.userStatus},不是未注册`); if (userInfo === null) console.log(' - 用户信息为空'); if (userInfo && userInfo.role !== 'GUEST') console.log(` - 用户角色为${userInfo.role},不是游客`); console.log('当前状态:', { hasWxCode: authStatus.hasWxCode, userStatus: authStatus.userStatus, userInfo: userInfo ? { role: userInfo.role } : null }); } else { console.log('注册按钮显示条件满足'); } return result; } /** * 根据用户信息确定用户状态(从服务器获取真实状态) */ public async determineUserStatus(userInfo: any): Promise<'registered' | 'unregistered' | 'signed_in' | 'signed_out'> { if (!userInfo) return 'signed_out'; try { // 从服务器获取用户真实状态 const serverStatus = await this.getUserStatusFromServer(); if (serverStatus) { console.log('从服务器获取的用户状态:', serverStatus); return serverStatus; } // 如果服务器获取失败,使用本地逻辑作为降级方案 console.warn('服务器状态获取失败,使用本地逻辑判断'); const isRegistered = userInfo.name && userInfo.phone; return isRegistered ? 'registered' : 'unregistered'; } catch (error) { console.error('获取用户状态失败:', error); // 网络错误时使用本地逻辑 const isRegistered = userInfo.name && userInfo.phone; return isRegistered ? 'registered' : 'unregistered'; } } /** * 从服务器获取用户签到状态 */ private async getUserStatusFromServer(): Promise<'registered' | 'unregistered' | 'signed_in' | 'signed_out' | null> { try { // 调用服务器接口获取用户状态 const response = await userService.getUserStatus(); // 如果返回null,表示服务器接口不存在 if (response === null) { console.log('服务器状态接口不存在,跳过服务器状态获取'); return null; } if (response && response.status) { // 根据服务器返回的状态映射到前端状态 switch (response.status) { case 'signed_in': return 'signed_in'; case 'signed_out': return 'signed_out'; case 'registered': return 'registered'; case 'unregistered': return 'unregistered'; default: return null; } } return null; } catch (error) { console.error('获取服务器状态失败:', error); return null; } } }