389 lines
13 KiB
TypeScript
Raw Normal View History

2025-08-10 22:42:56 +08:00
// 认证相关API接口
import { ApiRequest } from '../request'
import type {
ApiResponse,
User,
LoginRequest,
LoginResponse,
// BackendLoginResponse,
RegisterRequest,
UserProfile,
} from '../types'
/**
* API模块
*/
export class AuthApi {
// 用户登录
static async login(data: LoginRequest): Promise<ApiResponse<LoginResponse>> {
try {
// 转换参数格式将email/phone转换为username
const loginData = {
username: data.email || data.phone || '',
password: data.password
}
console.log('🚀 发送登录请求:', { url: '/biz/user/login', data: { ...loginData, password: '***' } })
2025-08-10 22:42:56 +08:00
// 调用后端API
const response = await ApiRequest.post<any>('/biz/user/login', loginData)
2025-08-10 22:42:56 +08:00
console.log('🔍 Login API Response:', response)
console.log('🔍 Response Code:', response.code)
console.log('🔍 Response Data:', response.data)
console.log('🔍 Response Data Type:', typeof response.data)
// 处理响应格式问题 - 如果code和message是undefined可能是响应拦截器的问题
let actualCode = response.code
let actualMessage = response.message
let actualData = response.data
// 如果response.code是undefined检查response.data是否包含完整的API响应
if (actualCode === undefined && actualData && typeof actualData === 'object') {
// 检查是否是标准的jeecg-boot响应格式 (success, code, message, result)
if ('success' in actualData && 'code' in actualData && 'message' in actualData && 'result' in actualData) {
actualCode = actualData.code
actualMessage = actualData.message
actualData = actualData.result
console.log('🔧 修正后的响应 (jeecg-boot格式):', { code: actualCode, message: actualMessage, data: actualData })
}
// 检查是否是其他格式 (code, message, data)
else if ('code' in actualData && 'message' in actualData && 'data' in actualData) {
2025-08-10 22:42:56 +08:00
actualCode = actualData.code
actualMessage = actualData.message
actualData = actualData.data
console.log('🔧 修正后的响应 (标准格式):', { code: actualCode, message: actualMessage, data: actualData })
2025-08-10 22:42:56 +08:00
}
}
// 检查响应格式并适配
if (actualCode === 200 || actualCode === 0) {
// 如果后端返回的是完整的用户信息格式mock数据格式
if (actualData && actualData.user && actualData.token) {
return {
code: actualCode,
message: actualMessage,
data: actualData
} as ApiResponse<LoginResponse>
}
// 如果后端返回的是jeecg-boot格式只包含token
if (actualData && actualData.token) {
2025-08-10 22:42:56 +08:00
const adaptedResponse: ApiResponse<LoginResponse> = {
code: actualCode,
message: actualMessage || '登录成功',
data: {
user: {
id: 1, // 真实API没有返回用户ID使用默认值
email: data.email || '',
phone: data.phone || '',
username: data.email || data.phone || '',
2025-08-10 22:42:56 +08:00
nickname: '用户',
avatar: '',
role: 'student',
status: 'active',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
},
token: actualData.token,
refreshToken: '', // 真实API没有返回refreshToken
expiresIn: 3600 // 默认1小时过期
}
}
return adaptedResponse
}
// 如果后端返回的是简化格式BackendLoginResponse
if (actualData && actualData.token) {
const adaptedResponse: ApiResponse<LoginResponse> = {
code: actualCode,
message: actualMessage || '登录成功',
data: {
user: {
id: actualData.id || 1,
email: data.email || '',
phone: data.phone || '',
username: data.phone || data.email?.split('@')[0] || 'user',
nickname: '用户',
avatar: '',
role: 'student',
status: 'active',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
},
token: actualData.token,
refreshToken: actualData.refreshToken || '',
expiresIn: actualData.expiresIn || 3600
}
}
return adaptedResponse
}
// 如果只有token字段直接使用token
if (typeof actualData === 'string') {
const adaptedResponse: ApiResponse<LoginResponse> = {
code: actualCode,
message: actualMessage || '登录成功',
data: {
user: {
id: 1,
email: data.email || '',
phone: data.phone || '',
username: data.phone || data.email?.split('@')[0] || 'user',
nickname: '用户',
avatar: '',
role: 'student',
status: 'active',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
},
token: actualData,
refreshToken: '',
expiresIn: 3600
}
}
return adaptedResponse
}
// 如果data是null或undefined但响应成功可能是某些API的特殊情况
if (!actualData) {
console.warn('⚠️ API返回成功但data为空可能需要检查API实现')
throw new Error('登录成功但未返回用户信息')
}
// 尝试处理其他可能的响应格式
console.warn('⚠️ 未知的响应格式,尝试通用处理:', actualData)
// 如果data是对象但不包含预期字段尝试创建默认响应
if (typeof actualData === 'object') {
const adaptedResponse: ApiResponse<LoginResponse> = {
code: actualCode,
message: actualMessage || '登录成功',
data: {
user: {
id: actualData.id || actualData.userId || 1,
email: data.email || '',
phone: data.phone || '',
username: data.phone || data.email?.split('@')[0] || 'user',
nickname: actualData.nickname || actualData.name || '用户',
avatar: actualData.avatar || '',
role: actualData.role || 'student',
status: 'active',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
},
token: actualData.accessToken || actualData.access_token || 'temp_token_' + Date.now(),
refreshToken: actualData.refreshToken || actualData.refresh_token || '',
expiresIn: actualData.expiresIn || actualData.expires_in || 3600
}
}
return adaptedResponse
}
}
// 如果响应格式不符合预期,抛出错误
console.error('🚨 Unexpected response format:', {
code: actualCode,
message: actualMessage,
data: actualData,
dataType: typeof actualData
})
throw new Error(actualMessage || '登录响应格式错误')
} catch (error) {
console.error('🚨 Login API Error:', error)
throw error
}
}
// 用户注册
static register(data: RegisterRequest): Promise<ApiResponse<User>> {
return ApiRequest.post('/auth/register', data)
}
// 用户登出
static logout(): Promise<ApiResponse<null>> {
// 尝试多个可能的登出端点
return ApiRequest.post('/auth/logout').catch(async (error) => {
// 如果 /auth/logout 失败,尝试其他可能的端点
if (error.response?.status === 404) {
try {
return await ApiRequest.post('/users/logout')
} catch (secondError) {
// 如果所有端点都失败,返回成功(客户端登出)
console.log('所有登出端点都不存在,执行客户端登出')
return {
code: 200,
message: '登出成功',
data: null
}
}
}
throw error
})
}
// 刷新Token
static refreshToken(refreshToken: string): Promise<ApiResponse<LoginResponse>> {
return ApiRequest.post('/auth/refresh', { refreshToken })
}
// 获取当前用户信息
static getCurrentUser(): Promise<ApiResponse<User>> {
return ApiRequest.get('/users/info')
2025-08-10 22:42:56 +08:00
}
// 更新用户资料
static updateProfile(data: Partial<UserProfile>): Promise<ApiResponse<User>> {
return ApiRequest.put('/auth/profile', data)
}
// 修改密码
static changePassword(data: {
oldPassword: string
newPassword: string
confirmPassword: string
}): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/change-password', data)
}
// 忘记密码 - 发送重置邮件
static forgotPassword(email: string): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/forgot-password', { email })
}
// 重置密码
static resetPassword(data: {
token: string
password: string
confirmPassword: string
}): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/reset-password', data)
}
// 发送邮箱验证码
static sendEmailVerification(email: string): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/send-email-verification', { email })
}
// 验证邮箱
static verifyEmail(data: {
email: string
code: string
}): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/verify-email', data)
}
// 发送手机验证码
static sendSmsVerification(phone: string): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/send-sms-verification', { phone })
}
// 验证手机号
static verifyPhone(data: {
phone: string
code: string
}): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/verify-phone', data)
}
// 绑定第三方账号
static bindThirdParty(data: {
provider: 'wechat' | 'qq' | 'weibo' | 'github'
code: string
state?: string
}): Promise<ApiResponse<User>> {
return ApiRequest.post('/auth/bind-third-party', data)
}
// 解绑第三方账号
static unbindThirdParty(provider: string): Promise<ApiResponse<null>> {
return ApiRequest.delete(`/auth/unbind-third-party/${provider}`)
}
// 获取第三方登录URL
static getThirdPartyLoginUrl(provider: string, redirectUrl?: string): Promise<ApiResponse<{ url: string }>> {
return ApiRequest.get(`/auth/third-party-login-url/${provider}`, { redirectUrl })
}
// 第三方登录回调
static thirdPartyLoginCallback(data: {
provider: string
code: string
state?: string
}): Promise<ApiResponse<LoginResponse>> {
return ApiRequest.post('/auth/third-party-login-callback', data)
}
// 上传头像
static uploadAvatar(file: File, onProgress?: (progress: number) => void): Promise<ApiResponse<{ url: string }>> {
return ApiRequest.upload('/auth/upload-avatar', file, onProgress)
}
// 删除账号
static deleteAccount(password: string): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/delete-account', { password })
}
// 获取账号安全信息
static getSecurityInfo(): Promise<ApiResponse<{
hasPassword: boolean
hasEmail: boolean
hasPhone: boolean
emailVerified: boolean
phoneVerified: boolean
twoFactorEnabled: boolean
thirdPartyAccounts: Array<{
provider: string
nickname: string
avatar?: string
bindTime: string
}>
loginHistory: Array<{
ip: string
location: string
device: string
loginTime: string
}>
}>> {
return ApiRequest.get('/auth/security-info')
}
// 启用两步验证
static enableTwoFactor(): Promise<ApiResponse<{
qrCode: string
secret: string
backupCodes: string[]
}>> {
return ApiRequest.post('/auth/enable-two-factor')
}
// 确认启用两步验证
static confirmTwoFactor(code: string): Promise<ApiResponse<{
backupCodes: string[]
}>> {
return ApiRequest.post('/auth/confirm-two-factor', { code })
}
// 禁用两步验证
static disableTwoFactor(data: {
password: string
code: string
}): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/disable-two-factor', data)
}
// 生成新的备用码
static generateBackupCodes(): Promise<ApiResponse<{
backupCodes: string[]
}>> {
return ApiRequest.post('/auth/generate-backup-codes')
}
// 验证两步验证码
static verifyTwoFactor(code: string): Promise<ApiResponse<null>> {
return ApiRequest.post('/auth/verify-two-factor', { code })
}
}
export default AuthApi