Преглед изворни кода

feat(auth): 增加重置密码功能并优化登录组件

- 添加重置密码相关 API 接口:resetPassword、getPasswordresetCode
- 修改退出登录接口为 POST 请求
- 在 LoginDialog 组件中新增“重置密码”标签页及相应表单逻辑
- 支持通过手机号或邮箱接收验证码进行密码重置
- 修复部分登录提示逻辑问题,并移除默认填充的测试账号信息
- 引入 ElMessage 提示用户操作结果
- 调整部分图标与交互逻辑以提升用户体验
zhangningning пре 1 недеља
родитељ
комит
be146bd0be
3 измењених фајлова са 164 додато и 15 уклоњено
  1. 3 1
      src/App.vue
  2. 9 1
      src/api/auth.js
  3. 152 13
      src/components/LoginDialog.vue

+ 3 - 1
src/App.vue

@@ -57,7 +57,7 @@ import { logout } from '@/api/auth.js'
 import LoginDialog from './components/LoginDialog.vue'
 import { computed,ref,onMounted } from 'vue'
 import LangSwitch from './components/LangSwitch.vue'
-import { ElConfigProvider } from 'element-plus'
+import { ElConfigProvider, ElMessage } from 'element-plus'
 import { useRoute, useRouter } from 'vue-router'
 // 在Pinia安装后再设置初始语言
 import { useLangStore } from '@/pinia/langStore'
@@ -104,6 +104,8 @@ const activeIndex = computed(() => {
 const handleLogout = () => {
   logout().then(() => {
     appStore.LOGOUT()
+    ElMessage.success('注销成功')
+    router.push('/')
   })
 };
 </script>

+ 9 - 1
src/api/auth.js

@@ -31,9 +31,17 @@ export function getUserInfo(data = {}) {
 }
 // 退出登录
 export function logout(data = {}) {
-  return request.get('/auth/user/logout',data)
+  return request.post('/auth/user/logout',data)
 }
 // 更新用户信息
 export function updateUserInfo(data = {}) {
   return request.post('/auth/user/info/update',data)
 }
+// 重置密码
+export function resetPassword(data = {}) {
+  return request.post('/auth/user/password/reset',data)
+}
+// 获取重置密码验证码
+export function getPasswordresetCode(data = {}) {
+  return request.get('/auth/user/password/reset/request',data)
+}

+ 152 - 13
src/components/LoginDialog.vue

@@ -43,7 +43,6 @@
                 v-model="passwordForm.captcha"
                 placeholder="请输入验证码"
                 prefix-icon="Lock"
-                show-password
                 class="login-input"
               />
               <img :src="captchaImg" alt="验证码" class="captcha-img" @click="getCaptchaFn">
@@ -51,10 +50,10 @@
           </el-form-item>
 
           <el-form-item class="login-form-item remember-item">
-            <el-checkbox v-model="passwordForm.remember" class="remember-checkbox">
+            <!-- <el-checkbox v-model="passwordForm.remember" class="remember-checkbox">
               <span class="remember-text">记住密码</span>
-            </el-checkbox>
-            <el-link type="primary" href="#" :underline="false" class="forgot-link">忘记密码?</el-link>
+            </el-checkbox> -->
+            <el-link type="primary" href="#" :underline="false" class="forgot-link" @click="activeTab = 'reset'">忘记密码?</el-link>
           </el-form-item>
           <el-form-item class="login-form-item">
             <el-button 
@@ -76,7 +75,7 @@
             <el-input
               v-model="smsForm.account"
               placeholder="请输入手机号或邮箱"
-              prefix-icon="Mobile"
+              prefix-icon="User"
               clearable
               class="login-input"
             />
@@ -115,6 +114,69 @@
           </el-form-item>
         </el-form>
       </el-tab-pane>
+      <el-tab-pane label="重置密码" name="reset">
+        <el-form ref="resetFormRef" :model="resetForm" :rules="resetRules" label-width="0">
+          <el-form-item prop="account" class="login-form-item">
+            <el-input
+              v-model="resetForm.account"
+              placeholder="请输入手机号或邮箱"
+              prefix-icon="User"
+              clearable
+              class="login-input"
+            />
+          </el-form-item>
+          <el-form-item prop="smsCode" class="login-form-item">
+            <el-input
+              v-model="resetForm.verifyCode"
+              placeholder="请输入验证码"
+              prefix-icon="Message"
+              clearable
+              class="login-input"
+            >
+              <template #append>
+                <el-button
+                  :disabled="passwordresetCountdown > 0"
+                  @click="sendPasswordresetCode"
+                  style="width:100px"
+                  :class="{'countdown-btn': passwordresetCountdown > 0}"
+                  size="small"
+                >
+                  {{ passwordresetCountdown > 0 ? `${passwordresetCountdown}s` : '发送验证码' }}
+                </el-button>
+              </template>
+            </el-input>
+          </el-form-item>
+          <el-form-item prop="newPassword" class="login-form-item">
+            <el-input
+              v-model="resetForm.newPassword"
+              placeholder="请输入新密码"
+              prefix-icon="Lock"
+              show-password
+              class="login-input"
+            />
+          </el-form-item>
+          <el-form-item prop="confirmPassword" class="login-form-item">
+            <el-input
+              v-model="resetForm.confirmPassword"
+              placeholder="请确认新密码"
+              prefix-icon="Lock"
+              show-password
+              class="login-input"
+            />
+          </el-form-item>
+          <el-form-item class="login-form-item">
+            <el-button 
+              type="primary" 
+              @click="handleResetPassword" 
+              :loading="loading" 
+              class="login-button"
+              size="large"
+            >
+              登录
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
     </el-tabs>
 
     <!-- 其他登录方式 -->
@@ -153,7 +215,7 @@ import { ref, reactive, watch, computed } from 'vue'
 import { ElMessage } from 'element-plus'
 import QQIcon from '@/assets/imgs/QQ.png'
 import WeChatIcon from '@/assets/imgs/WeChat.png'
-import { getCaptcha, loginUsername, loginPhone, loginEmail, getSmsCode, getEmailCode } from '@/api/auth.js'
+import { getCaptcha, loginUsername, loginPhone, loginEmail, getSmsCode, getEmailCode, resetPassword, getPasswordresetCode } from '@/api/auth.js'
 import { useAppStore } from '@/pinia/appStore'
 const appStore = useAppStore();
 // 正则表达式
@@ -206,8 +268,8 @@ const activeTab = ref('password')
 
 // 密码登录表单
 const passwordForm = reactive({
-  account: '',
-  password: '',
+  account: '13925214105',
+  password: 'zhangning13Z',
   captcha: '',
   uuid: ''
 })
@@ -218,15 +280,27 @@ const smsForm = reactive({
   verifyCode: ''
 })
 
+// 重置密码表单
+const resetForm = reactive({
+  account: '13925214105',
+  verifyCode: '',
+  newPassword: '',
+  confirmPassword: ''
+})
+
+
+
 // 表单引用
 const passwordFormRef = ref(null)
 const smsFormRef = ref(null)
+const resetFormRef = ref(null)
 
 // 加载状态
 const loading = ref(false)
 
 // 验证码倒计时
 const smsCountdown = ref(0)
+const passwordresetCountdown = ref(0)
 const emailCountdown = ref(0)
 
 // 表单验证规则
@@ -255,6 +329,26 @@ const smsRules = reactive({
     { min: 6, max: 6, message: '验证码长度为6个字符', trigger: 'blur' }
   ]
 })
+// 重置密码表单验证规则
+const resetRules = reactive({
+  account: [
+    { required: true, message: '请输入手机号或邮箱', trigger: 'blur' },
+    { validator: (rule, val) => PHONE_REGEX.test(val) || EMAIL_REGEX.test(val), message: '请输入正确的(手机号或邮箱)', trigger: 'blur' }
+  ],
+  verifyCode: [
+    { required: true, message: '请输入验证码', trigger: 'blur' },
+    { min: 6, max: 6, message: '验证码长度为6个字符', trigger: 'blur' }
+  ],
+  newPassword: [
+    { required: true, message: '请输入新密码', trigger: 'blur' },
+    { min: 6, message: '密码长度不能少于6个字符', trigger: 'blur' }
+  ],
+  confirmPassword: [
+    { required: true, message: '请确认新密码', trigger: 'blur' },
+    { validator: (rule, val) => val === resetForm.newPassword, message: '两次输入密码不一致', trigger: 'blur' }
+  ]
+})
+
 
 // 处理标签页切换
 const handleTabChange = () => {
@@ -351,8 +445,6 @@ const handlePasswordLogin = () => {
         dialogVisible.value = false;
         // 登录成功后,将token存储到localStorage
         setToken(res.token);
-      } else {
-        ElMessage.error(res.msg || '登录失败')
       }
     }
   })
@@ -381,13 +473,60 @@ const handleSmsLogin = () => {
         dialogVisible.value = false;
         // 登录成功后,将token存储到localStorage
         setToken(res.token);
-      } else {
-        ElMessage.error(res.msg || '登录失败')
-      }
+      } 
+    }
+  })
+}
+// 发送重置密码验证码
+const sendPasswordresetCode = async () => {
+  if (!resetForm.account) {
+    ElMessage.warning('请先输入手机号或邮箱')
+    return
+  }
+
+  // 验证手机号格式
+  if (!PHONE_REGEX.test(resetForm.account) && !EMAIL_REGEX.test(resetForm.account)) {
+    ElMessage.warning('请输入正确的手机号或邮箱')
+    return
+  }
+
+  let res = await getPasswordresetCode({
+    account: resetForm.account
+  })
+
+  if(res.code !== 200){
+    return
+  }
+
+  // 模拟发送验证码
+  ElMessage.success('验证码发送成功')
+  
+  // 开始倒计时
+  passwordresetCountdown.value = 60
+  const timer = setInterval(() => {
+    passwordresetCountdown.value--
+    if (passwordresetCountdown.value <= 0) {
+      clearInterval(timer)
+    }
+  }, 1000)
+}
+// 重置密码
+const handleResetPassword = () => {
+  resetFormRef.value?.validate(async (valid) => {
+    if (valid) {
+      loading.value = true
+      const res = await resetPassword(resetForm);
+      loading.value = false
+      if (res.code === 200) {
+        ElMessage.success('密码重置成功')
+        activeTab.value = 'password';
+      } 
     }
   })
 }
 
+
+
 const setToken = (token) => {
   appStore.UPDATE_TOKEN(token);
 }