389 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 认证相关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: '***' } })
// 调用后端API
const response = await ApiRequest.post<any>('/biz/user/login', loginData)
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) {
actualCode = actualData.code
actualMessage = actualData.message
actualData = actualData.data
console.log('🔧 修正后的响应 (标准格式):', { code: actualCode, message: actualMessage, data: actualData })
}
}
// 检查响应格式并适配
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) {
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 || '',
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')
}
// 更新用户资料
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