diff --git a/package-lock.json b/package-lock.json index 7b810d8..d657f5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "axios": "^1.9.0", + "process": "^0.11.10", "vue": "^3.5.13", "vue-router": "^4.5.1", "vue-tournament-bracket": "^3.0.0", @@ -2472,6 +2473,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmmirror.com/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", diff --git a/package.json b/package.json index f19b35f..853c993 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "axios": "^1.9.0", + "process": "^0.11.10", "vue": "^3.5.13", "vue-router": "^4.5.1", "vue-tournament-bracket": "^3.0.0", diff --git a/src/api/centre_maps.js b/src/api/centre_maps.js index 1dbc884..cc0b9a6 100644 --- a/src/api/centre_maps.js +++ b/src/api/centre_maps.js @@ -12,3 +12,83 @@ export const getMapEditors = async () => { throw error; } }; + +/** + * 用户提交地图评分 + * @param {string} mapName - 地图名称 + * @param {number} reward - 评分(1~5) + * @returns {Promise} 返回提交评分的响应数据 + */ +export const submitMapReward = async (mapName, reward) => { + try { + const payload = { + mapname: mapName, + reward: reward + }; + const response = await axiosInstance.post('/user/map/reward', payload); + return response.data; + } catch (error) { + console.error('提交地图评分失败:', error); + throw error; + } +}; + +/** + * 获取用户地图信息 + * @param {string} mapName - 地图名称 + * @returns {Promise} 返回用户地图信息的Promise对象 + */ +export const getUserMapInfo = async (mapName) => { + try { + const response = await axiosInstance.get(`/user/map/${mapName}`); + return response.data; + } catch (error) { + console.error('获取用户地图信息失败:', error); + throw error; + } +}; + +/** + * 更新用户下载地图信息 + * @param {string} mapName - 地图名称 + * @returns {Promise} 返回更新下载信息的响应数据 + */ +export const updateUserDownloadMapInfo = async (mapName) => { + try { + const response = await axiosInstance.post(`/map/download/${mapName}`); + return response.data; + } catch (error) { + console.error('更新用户下载地图信息失败:', error); + throw error; + } +}; + +/** + * 获取指定地图评分 + * @param {string} mapName - 地图名称 + * @returns {Promise} 返回一个包含指定地图评分信息的Promise对象 + */ +export const getAppointMapRating = async (mapName) => { + try { + const response = await axiosInstance.get(`/map/reward/${mapName}`); + return response.data; + } catch (error) { + console.error('获取指定地图评分失败:', error); + throw error; + } +}; + +/** + * 获取所有地图的评分 + * @returns {Promise} 返回一个包含所有地图评分信息的Promise对象 + */ +export const getAllMapRating = async () => { + try { + const response = await axiosInstance.get(`/map/reward`); + return response.data; + } catch (error) { + console.error('获取所有地图评分失败:', error); + throw error; + } +}; + diff --git a/src/api/login.js b/src/api/login.js index a1fef94..2ade08b 100644 --- a/src/api/login.js +++ b/src/api/login.js @@ -81,7 +81,7 @@ export const userLogin = async (username, password, token, captcha) => { }); if (response.data.access_token) { - loginSuccess(response.data.access_token); + loginSuccess(response.data.access_token, username); } return response.data; diff --git a/src/components/SuccessDialog.vue b/src/components/SuccessDialog.vue new file mode 100644 index 0000000..b438108 --- /dev/null +++ b/src/components/SuccessDialog.vue @@ -0,0 +1,128 @@ + + + + + \ No newline at end of file diff --git a/src/components/login_module.vue b/src/components/login_module.vue index 138b52a..c5de07c 100644 --- a/src/components/login_module.vue +++ b/src/components/login_module.vue @@ -45,7 +45,7 @@ {{ captchaError }} @@ -61,6 +66,7 @@ import { ref, onMounted, computed } from 'vue' import { useRouter } from 'vue-router' import { userRegister, getCaptcha } from "@/api/login.js"; import ErrorDialog from './ErrorDialog.vue' +import SuccessDialog from './SuccessDialog.vue' const router = useRouter() const username = ref('') @@ -84,12 +90,21 @@ const showError = ref(false) const errorTitle = ref('错误提示') const errorMessage = ref('') +// 成功提示相关 +const showSuccess = ref(false) +const successMessage = ref('') + const showErrorMessage = (message, title = '错误提示') => { errorMessage.value = message errorTitle.value = title showError.value = true } +const showSuccessMessage = (message) => { + successMessage.value = message + showSuccess.value = true +} + const refreshCaptcha = async () => { try { const response = await getCaptcha() @@ -98,7 +113,13 @@ const refreshCaptcha = async () => { captcha.value = '' // 清空验证码输入 } catch (error) { console.error('获取验证码失败:', error) - showErrorMessage('获取验证码失败,请刷新页面重试') + // 优先使用API返回的detail字段 + const apiError = error.response?.data?.detail || error.response?.data?.message + if (apiError) { + showErrorMessage(apiError) + } else { + showErrorMessage('获取验证码失败,请刷新页面重试') + } } } @@ -121,21 +142,31 @@ const handleRegister = async () => { captcha.value ) - showErrorMessage('注册成功', '提示') - // 切换到登录模块 - emit('login') + // 显示成功提示 + showSuccessMessage('注册成功!正在切换到登录页面...') + + // 清空表单数据 + username.value = '' + password.value = '' + confirmPassword.value = '' + captcha.value = '' + + // 刷新验证码 + refreshCaptcha() + + // 延迟1.5秒后切换到登录模块,让用户看到成功提示 + setTimeout(() => { + emit('login') + }, 1500) } catch (error) { console.error('注册失败:', error) if (error.response) { - switch (error.response.status) { - case 400: - showErrorMessage('该QQ号已被注册') - break - case 409: - showErrorMessage('用户名已存在') - break - default: - showErrorMessage(error.response?.data?.message || error.message || '注册失败,请稍后重试') + // 优先使用API返回的detail字段 + const apiError = error.response?.data?.detail || error.response?.data?.message + if (apiError) { + showErrorMessage(apiError) + } else { + showErrorMessage('注册失败,请稍后重试') } } else { showErrorMessage(error.message || '注册失败,请稍后重试') @@ -281,7 +312,7 @@ const validateForm = () => { transition: background 0.2s; } -.login-button button:hover:not(:disabled) { +.login-button button:hover { background: linear-gradient(90deg, #66b1ff 0%, #6dd5fa 100%); } diff --git a/src/utils/jwt.js b/src/utils/jwt.js index 6872e80..4abb70e 100644 --- a/src/utils/jwt.js +++ b/src/utils/jwt.js @@ -72,16 +72,24 @@ export const logoutUser = () => { // 不再是 async,因为它不执行异步 * @param {string} userId - 用户ID。 */ export const loginSuccess = (accessToken, userId) => { - // console.log('jwt.js: loginSuccess. Storing token and user ID.'); + // 清除可能存在的旧数据 + localStorage.removeItem('access_token'); + localStorage.removeItem('user_id'); + sessionStorage.removeItem('currentUser'); + + // 存储新的认证信息 localStorage.setItem('access_token', accessToken); if (userId) { localStorage.setItem('user_id', userId); } - justLoggedIn.value = true; // Set the flag before navigation + // 设置登录标志 + justLoggedIn.value = true; - // 登录成功后重定向 - // 尝试获取之前尝试访问的路径,否则重定向到默认路径(例如仪表盘) - const redirectPath = router.currentRoute.value.query.redirect || '/backend/dashboard'; + // 获取重定向路径,优先使用查询参数中的redirect,否则跳转到首页 + const currentRoute = router.currentRoute.value; + const redirectPath = currentRoute.query.redirect || '/'; + + // 使用replace而不是push,避免在历史记录中留下登录页面 router.replace(redirectPath); }; \ No newline at end of file diff --git a/src/views/backend/Login.vue b/src/views/backend/Login.vue index 26e347e..1d6f582 100644 --- a/src/views/backend/Login.vue +++ b/src/views/backend/Login.vue @@ -11,16 +11,17 @@ 返回主界面
- - + +