diff --git a/src/api/index.ts b/src/api/index.ts index 08742be..a2a5407 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -21,7 +21,7 @@ export const API_ENDPOINTS = { AUTH: { LOGIN: '/aiol/aiolUser/login', USER_INFO: '/aiol/aiolUser/info', - REGISTER: '/auth/register', + REGISTER: '/aiol/aiolUser/register', LOGOUT: '/auth/logout', REFRESH: '/auth/refresh', ME: '/auth/me', diff --git a/src/api/modules/auth.ts b/src/api/modules/auth.ts index 55a5015..f592a6d 100644 --- a/src/api/modules/auth.ts +++ b/src/api/modules/auth.ts @@ -7,6 +7,7 @@ import type { LoginResponse, // BackendLoginResponse, RegisterRequest, + BackendRegisterRequest, UserProfile, BackendUserInfo, UserInfoResponse, @@ -198,8 +199,59 @@ export class AuthApi { } // 用户注册 - static register(data: RegisterRequest): Promise> { - return ApiRequest.post('/auth/register', data) + static async register(data: RegisterRequest): Promise> { + try { + // 转换为后端接口格式 + const registerData: BackendRegisterRequest = { + studentNumber: data.email || data.phone || data.username, + inviteCode: data.inviteCode || '', + password: data.password + } + + console.log('🚀 发送注册请求:', { url: '/aiol/aiolUser/register', data: { ...registerData, password: '***' } }) + + // 调用后端注册API + const response = await ApiRequest.post('/aiol/aiolUser/register', registerData) + + console.log('🔍 Register API Response:', response) + + // 处理响应格式 + let actualCode = response.code + let actualMessage = response.message + + // 如果响应被包装在data中 + if (response.data && typeof response.data === 'object' && 'code' in response.data) { + actualCode = response.data.code + actualMessage = response.data.message + } + + // 检查注册是否成功 + if (actualCode === 200 || actualCode === 0) { + // 注册成功,返回标准格式 + const adaptedResponse: ApiResponse = { + code: 200, + message: actualMessage || '注册成功', + data: { + id: Date.now(), // 临时ID + username: registerData.studentNumber, + email: data.email || '', + phone: data.phone || '', + nickname: registerData.studentNumber, + avatar: '', + role: 'student', + status: 'active', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString() + } + } + return adaptedResponse + } else { + throw new Error(actualMessage || '注册失败') + } + } catch (error) { + console.error('🚨 Register API Error:', error) + throw error + } } // 用户登出 @@ -266,6 +318,10 @@ export class AuthApi { static convertBackendUserToUser(backendUser: BackendUserInfo): User { const { baseInfo, roles, extendedInfo } = backendUser + console.log('🔄 convertBackendUserToUser - 原始后端数据:', backendUser) + console.log('🔄 convertBackendUserToUser - baseInfo.avatar:', baseInfo.avatar) + console.log('🔄 convertBackendUserToUser - baseInfo.realname:', baseInfo.realname) + // 转换性别 let gender: 'male' | 'female' | 'other' = 'other' if (baseInfo.sex === 1) gender = 'male' @@ -282,7 +338,7 @@ export class AuthApi { role = 'teacher' } - return { + const convertedUser = { id: parseInt(baseInfo.id) || 0, username: baseInfo.username, email: baseInfo.email, @@ -303,6 +359,11 @@ export class AuthApi { socialLinks: {} } } + + console.log('✅ convertBackendUserToUser - 转换后的用户数据:', convertedUser) + console.log('✅ convertBackendUserToUser - 转换后的头像:', convertedUser.avatar) + + return convertedUser } // 更新用户资料 diff --git a/src/api/modules/exam.ts b/src/api/modules/exam.ts index 90b4760..5a1865f 100644 --- a/src/api/modules/exam.ts +++ b/src/api/modules/exam.ts @@ -127,7 +127,20 @@ export class ExamApi { */ static async createQuestion(data: CreateQuestionRequest): Promise> { console.log('🚀 添加题目:', data) - const response = await ApiRequest.post('/aiol/aiolQuestion/add', data) + + // 提取repoId作为查询参数,其他数据作为请求体 + const { repoId, ...questionData } = data + + // 构建查询参数(只有repoId) + const params: any = {} + if (repoId) { + params.repoId = repoId + } + + console.log('🔍 API查询参数:', params) + console.log('🔍 API请求体:', questionData) + + const response = await ApiRequest.post('/aiol/aiolQuestion/add', questionData, { params }) console.log('✅ 添加题目成功:', response) return response } @@ -161,7 +174,7 @@ export class ExamApi { */ static async createQuestionOption(data: CreateQuestionOptionRequest): Promise> { console.log('🚀 添加题目选项:', data) - const response = await ApiRequest.post('/gen/questionoption/questionOption/add', data) + const response = await ApiRequest.post('/aiol/aiolQuestionOption/add', data) console.log('✅ 添加题目选项成功:', response) return response } diff --git a/src/api/types.ts b/src/api/types.ts index 90ccc8e..cd0d1f4 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -123,6 +123,13 @@ export interface RegisterRequest { inviteCode?: string } +// 后端注册接口请求格式 +export interface BackendRegisterRequest { + studentNumber: string + inviteCode?: string + password: string +} + // 课程相关类型 export interface Course { id: string // 改为string类型,保持后端ID的原始格式 @@ -773,12 +780,15 @@ export interface UpdateRepoRequest { } export interface CreateQuestionRequest { + repoId?: string parentId?: string type: number content: string analysis?: string difficulty: number score: number + degree?: number + ability?: number } export interface UpdateQuestionRequest { diff --git a/src/components/common/SafeAvatar.vue b/src/components/common/SafeAvatar.vue index 9764a12..cdf1547 100644 --- a/src/components/common/SafeAvatar.vue +++ b/src/components/common/SafeAvatar.vue @@ -6,12 +6,14 @@ height: size + 'px' }" > -
{{ avatarText }} @@ -20,7 +22,7 @@ diff --git a/src/components/layout/AppHeader.vue b/src/components/layout/AppHeader.vue index 4a7c983..b0b50f7 100644 --- a/src/components/layout/AppHeader.vue +++ b/src/components/layout/AppHeader.vue @@ -162,6 +162,7 @@ const userStore = useUserStore() console.log('🔍 AppHeader - 当前用户信息:', userStore.user) console.log('🔍 AppHeader - 用户真实姓名:', userStore.user?.profile?.realName) console.log('🔍 AppHeader - 用户头像:', userStore.user?.avatar) +console.log('🔍 AppHeader - 用户头像类型:', typeof userStore.user?.avatar) // 监听用户信息变化 watch(() => userStore.user, (newUser) => { @@ -169,9 +170,15 @@ watch(() => userStore.user, (newUser) => { if (newUser) { console.log('🔄 AppHeader - 新的真实姓名:', newUser.profile?.realName) console.log('🔄 AppHeader - 新的头像:', newUser.avatar) + console.log('🔄 AppHeader - 新的头像类型:', typeof newUser.avatar) } }, { deep: true }) +// 监听头像变化 +watch(() => userStore.user?.avatar, (newAvatar) => { + console.log('🖼️ AppHeader - 头像URL变化:', newAvatar) +}, { immediate: true }) + // 移动端菜单状态 const mobileMenuOpen = ref(false) diff --git a/src/stores/user.ts b/src/stores/user.ts index 7630246..713a5bc 100644 --- a/src/stores/user.ts +++ b/src/stores/user.ts @@ -143,6 +143,7 @@ export const useUserStore = defineStore('user', () => { // 强制刷新用户信息 const refreshUserInfo = async () => { + console.log('🔄 强制刷新用户信息...') return await getCurrentUser(true) } @@ -181,9 +182,35 @@ export const useUserStore = defineStore('user', () => { user.value = JSON.parse(savedUser) token.value = savedToken - // 不强制刷新用户信息,避免API超时导致白屏 - // 如果需要验证token有效性,可以在用户操作时进行 console.log('✅ 用户认证状态已恢复') + + // 验证token有效性并获取最新用户信息 + try { + console.log('🔍 验证token有效性并获取最新用户信息...') + const userInfoResponse = await AuthApi.getUserInfo() + + if (userInfoResponse.success && userInfoResponse.result) { + // 将后端用户信息转换为前端格式 + const convertedUser = AuthApi.convertBackendUserToUser(userInfoResponse.result) + + // 更新用户信息 + user.value = convertedUser + localStorage.setItem('user', JSON.stringify(convertedUser)) + + console.log('✅ 用户信息已更新:', convertedUser) + } else { + console.warn('⚠️ 获取用户信息失败,保持本地缓存的用户信息') + } + } catch (error: any) { + console.warn('⚠️ 验证token或获取用户信息失败:', error) + + // 如果是401错误,说明token已过期,清除认证状态 + if (error.response?.status === 401) { + console.log('🔄 Token已过期,清除认证状态') + await logout() + } + // 其他错误(如网络错误)保持本地缓存的用户信息 + } } catch (error) { console.error('Failed to parse saved user data:', error) await logout() diff --git a/src/views/Login.vue b/src/views/Login.vue index 4a59465..2773663 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -210,6 +210,25 @@ const handleSubmit = async () => { // 显示加载状态 userStore.isLoading = true + if (isRegisterMode.value) { + // 注册逻辑 + await handleRegister() + } else { + // 登录逻辑 + await handleLogin() + } + } catch (error: any) { + console.error('表单提交失败:', error) + if (error.message) { + message.error(error.message) + } + } finally { + userStore.isLoading = false + } +} + +// 处理登录 +const handleLogin = async () => { console.log('🚀 开始登录:', { account: formData.studentId, password: '***' }) console.log('🔍 表单密码长度:', formData.password?.length) @@ -315,25 +334,52 @@ const handleSubmit = async () => { console.error('❌ 登录失败,响应码:', response.code) message.error(response.message || '登录失败') } +} + +// 处理注册 +const handleRegister = async () => { + console.log('🚀 开始注册:', { account: formData.studentId, inviteCode: formData.inviteCode }) + + try { + // 调用注册API + const response = await AuthApi.register({ + username: formData.studentId, + email: formData.studentId.includes('@') ? formData.studentId : '', + phone: /^[0-9]+$/.test(formData.studentId) ? formData.studentId : '', + password: formData.password, + confirmPassword: formData.password, + captcha: '', // 暂时不需要验证码 + inviteCode: formData.inviteCode + }) + + console.log('✅ 注册响应:', response) + + if (response.code === 200 || response.code === 0) { + message.success('注册成功!请使用您的账号登录') + + // 注册成功后切换到登录模式 + isRegisterMode.value = false + + // 清空邀请码,保留账号和密码方便登录 + formData.inviteCode = '' + } else { + message.error(response.message || '注册失败') + } } catch (error: any) { - console.error('登录失败:', error) + console.error('注册失败:', error) // 处理不同类型的错误 - if (error.response?.status === 401) { - message.error('邮箱或密码错误') - } else if (error.response?.status === 429) { - message.error('登录尝试过于频繁,请稍后再试') + if (error.response?.status === 400) { + message.error('请求参数错误,请检查输入信息') + } else if (error.response?.status === 409) { + message.error('账号已被注册,请使用其他账号') } else if (error.response?.data?.message) { - // 显示后端返回的具体错误信息 message.error(error.response.data.message) } else if (error.message) { - // 显示错误对象中的消息 message.error(error.message) } else { message.error('网络错误,请检查网络连接') } - } finally { - userStore.isLoading = false } } diff --git a/src/views/teacher/ExamPages/AddQuestion.vue b/src/views/teacher/ExamPages/AddQuestion.vue index eec5760..5de21e8 100644 --- a/src/views/teacher/ExamPages/AddQuestion.vue +++ b/src/views/teacher/ExamPages/AddQuestion.vue @@ -398,7 +398,7 @@ const goBack = () => { // 根据当前路由上下文决定跳转路径 const currentRoute = route.path; const bankId = route.params.bankId; - + if (currentRoute.includes('/course-editor/')) { // 如果在课程编辑器中,返回课程编辑器的题库管理 const courseId = route.params.id || route.params.courseId; @@ -511,12 +511,15 @@ const createNewQuestion = async (bankId: string) => { try { // 只调用一次API创建题目 const questionData = { + repoId: bankId, // 题库ID parentId: undefined, // 父题目ID,普通题目为undefined type: getQuestionTypeNumber(questionForm.type), content: questionForm.title, analysis: questionForm.explanation || '', difficulty: getDifficultyNumber(questionForm.difficulty), - score: questionForm.score + score: questionForm.score, + degree: 1, // 程度,默认为1 + ability: 1 // 能力,默认为1 }; console.log('🚀 创建题目,数据:', questionData); @@ -541,31 +544,102 @@ const createNewQuestion = async (bankId: string) => { } } - if (!success) { - throw new Error('创建题目失败'); + if (!success || !questionId) { + throw new Error('创建题目失败:未获取到题目ID'); } console.log('✅ 题目创建成功,题目ID:', questionId); - message.success('题目保存成功'); - - // 根据当前路由上下文决定跳转路径 - const currentRoute = route.path; - if (currentRoute.includes('/course-editor/')) { - // 如果在课程编辑器中,返回课程编辑器的题库管理 - const courseId = route.params.id || route.params.courseId; - router.push(`/teacher/course-editor/${courseId}/question-bank/${bankId}/questions`); - } else { - // 如果在考试管理中,返回考试管理的题库管理 - router.push(`/teacher/exam-management/question-bank/${bankId}/questions`); + // 如果是选择题或判断题,需要创建选项 + const questionType = getQuestionTypeNumber(questionForm.type); + if (questionType === 0 || questionType === 1 || questionType === 2) { // 单选、多选、判断题 + await createQuestionOptions(questionId, questionType); } + message.success('题目创建成功!'); + router.back(); + } catch (error: any) { - console.error('创建题目流程失败:', error); + console.error('❌ 创建题目失败:', error); + message.error(error.message || '创建题目失败'); throw error; } }; +// 创建题目选项 +const createQuestionOptions = async (questionId: string, questionType: number) => { + try { + console.log('🚀 开始创建题目选项,题目ID:', questionId, '题目类型:', questionType); + + let optionsToCreate: Array<{ + content: string; + izCorrent: number; + orderNo: number; + }> = []; + + if (questionType === 0) { // 单选题 + // 获取选项数据 + const options = questionForm.options || []; + const correctAnswer = questionForm.correctAnswer; + + optionsToCreate = options.map((option: any, index: number) => ({ + content: option.content || option.text || '', + izCorrent: option.letter === correctAnswer ? 1 : 0, + orderNo: index + })); + + } else if (questionType === 1) { // 多选题 + const options = questionForm.options || []; + const correctAnswers = questionForm.correctAnswers || []; + + optionsToCreate = options.map((option: any, index: number) => ({ + content: option.content || option.text || '', + izCorrent: correctAnswers.includes(option.letter) ? 1 : 0, + orderNo: index + })); + + } else if (questionType === 2) { // 判断题 + // 判断题固定两个选项:正确和错误 + const correctAnswer = questionForm.correctAnswer; + const isCorrectTrue = String(correctAnswer) === 'true' || correctAnswer === 1; + optionsToCreate = [ + { + content: '正确', + izCorrent: isCorrectTrue ? 1 : 0, + orderNo: 0 + }, + { + content: '错误', + izCorrent: isCorrectTrue ? 0 : 1, + orderNo: 1 + } + ]; + } + + console.log('📊 准备创建的选项:', optionsToCreate); + + // 批量创建选项 + for (const option of optionsToCreate) { + const optionData = { + questionId: questionId, + content: option.content, + izCorrent: option.izCorrent, + orderNo: option.orderNo + }; + + console.log('🚀 创建选项:', optionData); + const optionResponse = await ExamApi.createQuestionOption(optionData); + console.log('✅ 选项创建成功:', optionResponse); + } + + console.log('✅ 所有选项创建完成'); + + } catch (error: any) { + console.error('❌ 创建题目选项失败:', error); + throw new Error('创建题目选项失败:' + (error.message || '未知错误')); + } +}; + // 验证答案设置