first commit

This commit is contained in:
2025-10-16 21:32:16 +08:00
commit c446df73b5
229 changed files with 499497 additions and 0 deletions

View File

@@ -0,0 +1,455 @@
// 登录模块 - 处理用户登录、授权、用户信息管理
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<UserInfo> {
// 直接返回用户信息,不进行额外处理
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<void> {
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<boolean> {
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<boolean> {
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<boolean> {
try {
// 显示加载中提示
wx.showLoading({
title: '签到中...',
});
// 调用实际的签到接口
const signInResult = await userService.signIn();
wx.hideLoading();
if (signInResult.success) {
console.log('签到成功:', signInResult);
wx.showToast({
title: '签到成功',
icon: 'success',
duration: 2000
});
// 更新用户信息
if (signInResult.employeeInfo) {
// 将员工信息合并到用户信息中
const app = getApp<any>();
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('位置追踪服务已启动');
// 订阅位置更新回调,采用统一方式更新所有用户位置
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<boolean> {
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<any>();
// 游客定义:已登录但没有完善基本信息(姓名和电话)的用户
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':
case 'online':
return 'signed_in';
case 'signed_out':
case 'offline':
return 'signed_out';
case 'registered':
return 'registered';
case 'unregistered':
return 'unregistered';
default:
return null;
}
}
return null;
} catch (error) {
console.error('获取服务器状态失败:', error);
return null;
}
}
}