From e222de1850c78a8c4da611f0ac74b432effb559f Mon Sep 17 00:00:00 2001 From: Kunagisa <1549184870@qq.com> Date: Fri, 13 Jun 2025 23:56:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=83=A8=E5=88=86=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ErrorDialog.vue | 150 +++++++++++++++++++++++++++++ src/components/login_module.vue | 80 +++++++++++++-- src/components/register_module.vue | 111 ++++++++++++++++----- src/views/index/EditorsMaps.vue | 87 ++++++++++++++++- src/views/index/MapDetail.vue | 87 ++++++++++------- 5 files changed, 446 insertions(+), 69 deletions(-) create mode 100644 src/components/ErrorDialog.vue diff --git a/src/components/ErrorDialog.vue b/src/components/ErrorDialog.vue new file mode 100644 index 0000000..e40a908 --- /dev/null +++ b/src/components/ErrorDialog.vue @@ -0,0 +1,150 @@ + + + + + \ No newline at end of file diff --git a/src/components/login_module.vue b/src/components/login_module.vue index 5548dfc..84bd4f5 100644 --- a/src/components/login_module.vue +++ b/src/components/login_module.vue @@ -9,7 +9,6 @@ id="username" v-model="username" placeholder="请输入QQ号" - @blur="validateUsername" :class="{ 'error': usernameError }" /> {{ usernameError }} @@ -21,7 +20,6 @@ id="password" v-model="password" placeholder="请输入密码" - @blur="validatePassword" :class="{ 'error': passwordError }" /> {{ passwordError }} @@ -34,7 +32,6 @@ id="captcha" v-model="captcha" placeholder="请输入验证码" - @blur="validateCaptcha" :class="{ 'error': captchaError }" /> 注册账号 + @@ -61,6 +64,7 @@ import { ref, onMounted, computed } from 'vue' import { useRouter } from 'vue-router' import { userLogin, getCaptcha } from '../api/login' +import ErrorDialog from './ErrorDialog.vue' const router = useRouter() const username = ref('') @@ -74,6 +78,11 @@ const usernameError = ref('') const passwordError = ref('') const captchaError = ref('') +// 错误弹窗相关 +const showError = ref(false) +const errorTitle = ref('错误提示') +const errorMessage = ref('') + const validateUsername = () => { if (!username.value) { usernameError.value = '请输入QQ号码' @@ -130,6 +139,12 @@ const isFormValid = computed(() => { captcha.value }) +const showErrorMessage = (message, title = '错误提示') => { + errorMessage.value = message + errorTitle.value = title + showError.value = true +} + const refreshCaptcha = async () => { try { const response = await getCaptcha() @@ -139,7 +154,7 @@ const refreshCaptcha = async () => { captcha.value = '' // 清空验证码输入 } catch (error) { console.error('获取验证码失败:', error) - alert('获取验证码失败,请刷新页面重试') + showErrorMessage('获取验证码失败,请刷新页面重试') } } @@ -172,10 +187,16 @@ const handleLogin = async () => { } } catch (error) { console.error('登录失败:', error) - if (error.response && error.response.status === 401) { - alert('错误的用户名或密码') + if (error.response) { + switch (error.response.status) { + case 401: + showErrorMessage('错误的用户名或密码') + break + default: + showErrorMessage(error.response?.data?.message || error.message || '登录失败,请稍后重试') + } } else { - alert(error.response?.data?.message || error.message || '登录失败,请稍后重试') + showErrorMessage(error.message || '登录失败,请稍后重试') } // 登录失败时刷新验证码 refreshCaptcha() @@ -183,7 +204,50 @@ const handleLogin = async () => { } const validateForm = () => { - return validateUsername() && validatePassword() && validateCaptcha() + // 重置所有错误信息 + usernameError.value = '' + passwordError.value = '' + captchaError.value = '' + + // 验证用户名 + if (!username.value) { + usernameError.value = '请输入QQ号码' + return false + } + if (!/^[/\d/g]+$/.test(username.value)) { + usernameError.value = 'QQ号码只能包含数字' + return false + } + if (username.value.length < 4) { + usernameError.value = 'QQ号码长度不能小于4个字符' + return false + } + + // 验证密码 + if (!password.value) { + passwordError.value = '请输入密码' + return false + } + if (password.value.length < 4) { + passwordError.value = '密码长度不能小于4个字符' + return false + } + if (password.value.length > 20) { + passwordError.value = '密码长度不能超过20个字符' + return false + } + + // 验证验证码 + if (!captcha.value) { + captchaError.value = '请输入验证码' + return false + } + if (captcha.value.length !== 4) { + captchaError.value = '验证码长度不正确' + return false + } + + return true } diff --git a/src/components/register_module.vue b/src/components/register_module.vue index c51bfbf..0e1346e 100644 --- a/src/components/register_module.vue +++ b/src/components/register_module.vue @@ -4,20 +4,20 @@
- {{ usernameError }}
- {{ passwordError }}
+ :class="{ 'error': confirmPasswordError }" /> {{ confirmPasswordError }}
@@ -28,7 +28,6 @@ id="captcha" v-model="captcha" placeholder="请输入验证码" - @blur="validateCaptcha" :class="{ 'error': captchaError }" /> {{ captchaError }}
+ @@ -55,6 +60,7 @@ import { ref, onMounted, computed } from 'vue' import { useRouter } from 'vue-router' import { userRegister, getCaptcha } from "@/api/login.js"; +import ErrorDialog from './ErrorDialog.vue' const router = useRouter() const username = ref('') @@ -73,6 +79,17 @@ const passwordError = ref('') const confirmPasswordError = ref('') const captchaError = ref('') +// 错误弹窗相关 +const showError = ref(false) +const errorTitle = ref('错误提示') +const errorMessage = ref('') + +const showErrorMessage = (message, title = '错误提示') => { + errorMessage.value = message + errorTitle.value = title + showError.value = true +} + // 表单验证规则 const validateUsername = () => { if (!username.value) { @@ -127,18 +144,6 @@ const validateCaptcha = () => { return true } -// 计算表单是否有效 -const isFormValid = computed(() => { - return !usernameError.value && - !passwordError.value && - !confirmPasswordError.value && - !captchaError.value && - username.value && - password.value && - confirmPassword.value && - captcha.value -}) - const refreshCaptcha = async () => { try { const response = await getCaptcha() @@ -147,7 +152,7 @@ const refreshCaptcha = async () => { captcha.value = '' // 清空验证码输入 } catch (error) { console.error('获取验证码失败:', error) - alert('获取验证码失败,请刷新页面重试') + showErrorMessage('获取验证码失败,请刷新页面重试') } } @@ -158,7 +163,7 @@ onMounted(() => { const handleRegister = async () => { try { // 验证表单 - if (!validateUsername() || !validatePassword() || !validateConfirmPassword() || !validateCaptcha()) { + if (!validateForm()) { return } @@ -170,20 +175,80 @@ const handleRegister = async () => { captcha.value ) - alert('注册成功') + showErrorMessage('注册成功', '提示') // 切换到登录模块 emit('login') } catch (error) { console.error('注册失败:', error) - if (error.response && error.response.status === 400) { - alert('该QQ号已被注册') + if (error.response) { + switch (error.response.status) { + case 400: + showErrorMessage('该QQ号已被注册') + break + case 409: + showErrorMessage('用户名已存在') + break + default: + showErrorMessage(error.response?.data?.message || error.message || '注册失败,请稍后重试') + } } else { - alert(error.response?.data?.message || error.message || '注册失败,请稍后重试') + showErrorMessage(error.message || '注册失败,请稍后重试') } // 注册失败时刷新验证码 refreshCaptcha() } } + +const validateForm = () => { + // 重置所有错误信息 + usernameError.value = '' + passwordError.value = '' + confirmPasswordError.value = '' + captchaError.value = '' + + // 验证用户名 + if (!username.value) { + usernameError.value = '请输入QQ号码' + return false + } + // 只允许纯数字 + if (!/^\d+$/.test(username.value)) { + usernameError.value = 'QQ号只能包含数字' + return false + } + + // 验证密码 + if (!password.value) { + passwordError.value = '请输入密码' + return false + } + if (password.value.length < 6) { + passwordError.value = '密码长度不能小于6个字符' + return false + } + + // 验证确认密码 + if (!confirmPassword.value) { + confirmPasswordError.value = '请再次输入密码' + return false + } + if (confirmPassword.value !== password.value) { + confirmPasswordError.value = '两次输入的密码不一致' + return false + } + + // 验证验证码 + if (!captcha.value) { + captchaError.value = '请输入验证码' + return false + } + if (captcha.value.length !== 4) { + captchaError.value = '验证码长度不正确' + return false + } + + return true +} \ No newline at end of file diff --git a/src/views/index/MapDetail.vue b/src/views/index/MapDetail.vue index 67df520..558f74f 100644 --- a/src/views/index/MapDetail.vue +++ b/src/views/index/MapDetail.vue @@ -50,7 +50,7 @@ -
+
@@ -69,11 +69,6 @@ @click="mapScore = star" >★
-
@@ -87,11 +82,6 @@ @click="authorScore = star" >★
-
+ + @@ -108,11 +105,33 @@ import { ref, onMounted } from 'vue' import { useRoute, useRouter } from 'vue-router' import { getMapDetail } from '../../api/maps.js' import { hasValidToken } from '../../utils/jwt' +import ErrorDialog from '@/components/ErrorDialog.vue' const route = useRoute() const router = useRouter() const map = ref(null) +// 错误弹窗相关 +const showError = ref(false) +const errorTitle = ref('') +const errorMessage = ref('') +const pendingAction = ref(null) + +const showErrorMessage = (message, title = '', action = null) => { + errorMessage.value = message + errorTitle.value = title + showError.value = true + pendingAction.value = action +} + +const handleErrorClose = () => { + showError.value = false + if (pendingAction.value) { + pendingAction.value() + pendingAction.value = null + } +} + // 评分相关的响应式变量 const showScoreDialog = ref(false) const mapScore = ref(0) @@ -129,16 +148,17 @@ const handleDownload = () => { // 处理评分点击 const handleScoreClick = () => { if (!hasValidToken()) { - alert('请先登录后再进行评分') - router.push({ - path: '/backend/login', - query: { redirect: route.fullPath } + showErrorMessage('请先登录后再进行评分', '', () => { + router.push({ + path: '/backend/login', + query: { redirect: route.fullPath } + }) }) return } if (!hasDownloaded.value) { - alert('请先下载地图后再进行评分') + showErrorMessage('请先下载地图后再进行评分') return } @@ -150,6 +170,7 @@ const fetchMapDetail = async () => { map.value = await getMapDetail(route.params.id) } catch (error) { console.error('获取地图详情失败:', error) + showErrorMessage('获取地图详情失败,请稍后重试') } } @@ -164,7 +185,7 @@ const formatDate = (dateString) => { // 提交评分 const submitScores = async () => { if (mapScore.value === 0 || authorScore.value === 0) { - alert('请为地图和作者都进行评分') + showErrorMessage('请为地图和作者都进行评分') return } @@ -184,10 +205,10 @@ const submitScores = async () => { mapComment.value = '' authorComment.value = '' - alert('评分成功!') + showErrorMessage('评分成功!') } catch (error) { console.error('评分失败:', error) - alert('评分失败,请稍后重试') + showErrorMessage('评分失败,请稍后重试') } } @@ -380,6 +401,15 @@ onMounted(() => { } /* 评分弹窗样式 */ +.score-dialog { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; +} + .dialog-overlay { position: fixed; top: 0; @@ -387,7 +417,7 @@ onMounted(() => { right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); - z-index: 100; + z-index: 1001; } .dialog-content { @@ -400,7 +430,7 @@ onMounted(() => { border-radius: 8px; width: 90%; max-width: 500px; - z-index: 101; + z-index: 1002; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15); } @@ -456,17 +486,6 @@ onMounted(() => { color: #ffd700; } -.comment-input { - width: 100%; - height: 80px; - padding: 8px; - border: 1px solid #ddd; - border-radius: 4px; - resize: vertical; - font-size: 14px; - margin-top: 10px; -} - .dialog-footer { display: flex; justify-content: flex-end; @@ -515,9 +534,5 @@ onMounted(() => { .star { font-size: 20px; } - - .comment-input { - height: 60px; - } } \ No newline at end of file