Procházet zdrojové kódy

feat:实现修改密码功能

chenjiayao před 1 rokem
rodič
revize
480273275a

+ 0 - 9
src/apis/auth.ts

@@ -16,15 +16,6 @@ const authApis = {
         })
     },
 
-
-    sendLoginVerifyCode: (officialEmail:string) => {
-        return axiosInstance.get(`${AUTH_PREFIX}/loginVerifyCode`, {
-            params: {
-                officialEmail
-            }
-        })
-    },
-
 }
 
 export default authApis

+ 29 - 0
src/apis/email.ts

@@ -0,0 +1,29 @@
+import axiosInstance from "@/apis/axios.config";
+
+const EMAIL_PREFIX = "/api/email"
+
+const emailApis = {
+    sendRegisterVerifyCode: (officialEmail:string) => {
+        return axiosInstance.get(`${EMAIL_PREFIX}/registerVerifyCode`, {
+            params: {
+                officialEmail
+            }
+        })
+    },
+    sendLoginVerifyCode: (officialEmail:string) => {
+        return axiosInstance.get(`${EMAIL_PREFIX}/loginVerifyCode`, {
+            params: {
+                officialEmail
+            }
+        })
+    },
+    sendPasswordChangeVerifyCode: (officialEmail:string) => {
+        return axiosInstance.get(`${EMAIL_PREFIX}/passwordChangeVerifyCode`, {
+            params: {
+                officialEmail
+            }
+        })
+    },
+}
+
+export default emailApis

+ 4 - 2
src/apis/index.ts

@@ -1,4 +1,4 @@
-import authApis from "./auth";
+import authApis from "@/apis/auth";
 import userApis from "@/apis/user";
 import testApis from "@/apis/test";
 import editorApis from "@/apis/editor";
@@ -8,6 +8,7 @@ import engagementApis from "@/apis/engagement";
 import assignmentApis from "@/apis/assignment";
 import courseApis from "@/apis/course";
 import fileApis from "@/apis/file";
+import emailApis from "@/apis/email";
 
 
 const apis = {
@@ -20,7 +21,8 @@ const apis = {
     ...dictApis,
     ...assignmentApis,
     ...courseApis,
-    ...fileApis
+    ...fileApis,
+    ...emailApis
 }
 
 // hook

+ 5 - 10
src/apis/user.ts

@@ -1,6 +1,5 @@
 import axiosInstance from "@/apis/axios.config";
-import { type ILoginUserFrom } from "@/types/user";
-import type {UserRegisterDTO, UserUpdateDTO} from "@/types/dto";
+import type {UserRegisterDTO, UserUpdateDTO, PasswordChangeDTO} from "@/types/dto";
 
 const USER_PREFIX = "/api/user"
 
@@ -13,14 +12,6 @@ const userApis = {
         })
     },
 
-    sendVerifyCode: (officialEmail:string) => {
-        return axiosInstance.get(`${USER_PREFIX}/verifyCode`, {
-            params: {
-                officialEmail
-            }
-        })
-    },
-
     register: (userRegisterDTO: UserRegisterDTO) => {
         return axiosInstance.post(`${USER_PREFIX}/register`, userRegisterDTO)
     },
@@ -31,6 +22,10 @@ const userApis = {
                 id: id,
             }
         })
+    },
+
+    updatePassword: (passwordChangeDTO: PasswordChangeDTO) => {
+        return axiosInstance.post(`${USER_PREFIX}/updatePassword`, passwordChangeDTO)
     }
 
 }

+ 6 - 2
src/router/index.ts

@@ -29,7 +29,11 @@ const router = createRouter({
       name: 'register', 
       component: () => import('../views/LoginPage/RegisterPage.vue')
     },
-
+    {
+      path: '/passwordChange',
+      name: 'passwordChange',
+      component: () => import('../views/LoginPage/PasswordChangePage.vue')
+    },
     // 用户相关界面
     {
       path: '/home',
@@ -154,7 +158,7 @@ const router = createRouter({
 router.beforeEach((to) => {
   const store = useStore()
   // 判断是否是登录页面,如果是则直接放行
-  if (to.path === '/login' || to.path === '/register' || to.path === '/admin/login') {
+  if (to.path === '/login' || to.path === '/register' || to.path === '/passwordChange'|| to.path === '/admin/login') {
     return true;
   }
   // 判断是否登录,未登录需要登录

+ 5 - 0
src/types/dto.ts

@@ -64,3 +64,8 @@ export interface UserUpdateDTO {
     contentEmail?: string;
 }
 
+export interface PasswordChangeDTO {
+    password: string; 
+    officialEmail: string; 
+    verifyCode: string; 
+}

+ 29 - 0
src/views/LoginPage/PasswordChangePage.vue

@@ -0,0 +1,29 @@
+<template>
+  <div class="login-container">
+    <div class="container-box">
+      <div class="login-logo">
+        <div class="logo-image">
+          <img src="../LoginPage/seecoderLogo.png" alt="logo" width="400vh">
+        </div>
+      </div>
+      <div class="login-box">
+        <div class="register-box-content">
+          <PasswordChange/>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import "./index.scss"
+import PasswordChange from "@/views/LoginPage/component/PasswordChange.vue";
+    
+  </script>
+  <script lang="ts">
+
+  export default {
+    name: "PasswordChangePage"
+  }
+  </script>
+  

+ 32 - 44
src/views/LoginPage/component/Login.vue

@@ -28,7 +28,7 @@
                 placeholder="请输入验证码"
             >
               <template #suffix>
-                <el-button type="text" @click="getCode" :disabled="isStart">
+                <el-button type="text" @click="sendLoginVerifyCode" :disabled="isStart">
                   {{ isStart ? countdown : '获取验证码' }}
                 </el-button>
               </template>
@@ -42,9 +42,9 @@
             />
           </template>
         </el-form-item>
-        <div class="forget">忘记密码?</div>
+        <div class="forget" @click="toPasswordChange">忘记密码?</div>
         <el-form-item>
-          <el-button class="login-button" @click="handleLogin">用户登录</el-button>
+          <el-button class="login-button" @click="handleLogin(form)">用户登录</el-button>
         </el-form-item>
         <div class="sign" @click="onClickSign">注册账号</div>
       </el-form>
@@ -59,7 +59,7 @@
   import router from "@/router";
   import { useCountdown } from '@/hooks/useCountdown';
   import "./index.scss"
-  import { ElMessage } from 'element-plus';
+  import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
 
 
   interface LoginProps {
@@ -96,6 +96,7 @@
     code: '',
   });
 
+  const form = ref<FormInstance>()
   const rules = reactive({
     officialNumber: [
       { required: true, message: props.isCode ? '邮箱不能为空' : '账号不能为空', trigger: 'blur' },
@@ -105,44 +106,40 @@
     ],
   });
  
-  const getCode = () => {
+  const sendLoginVerifyCode = () => {
     start();
     props.onCode?.();
     
-    console.log('获取验证码');
     apis.sendLoginVerifyCode(data.officialNumber)
     .then((res: any) => {
       if (res.data.code === 200) {
-        ElMessage({
-        message: '验证码发送成功,请前往您的邮箱查看',
-          type: 'success',
-        })
+        ElMessage({message: '验证码发送成功,请前往您的邮箱查看', type: 'success'})
       } else {
-        ElMessage({
-          message: '验证码发送失败' + res.data.msg,
-          // message: '验证码发送失败',
-          type: 'error',
-        })
+        ElMessage({message: '验证码发送失败',type: 'error'})
+        console.log(res.data.msg)
       }
     })
     .catch((err: any) => {
-      ElMessage({
-        message: '验证码发送失败',
-        type: 'error',
-      })
+      ElMessage({message: '验证码发送失败',type: 'error'})
       console.log(err)
     })
-    .finally(() => {
-    });
+    .finally(() => {});
   };
 
   let assignmentId = ref(1)
-  const handleLogin = () => {
-    if(!props.isCode) {
-      login()
-    } else {
-      loginByEmail()
-    }
+  const handleLogin = async (formEl: FormInstance | undefined) => {
+    if (!formEl) return
+    await formEl.validate((valid, fields) => {
+      if (valid) {
+        if(!props.isCode) {
+          login()
+        } else {
+          loginByEmail()
+        }
+      } else {
+        ElMessage({message: '请将信息填写完整',type: 'warning'})
+      }
+    })
   };
 
   const login = () => {
@@ -151,7 +148,6 @@
       password: data.password
     }).then((_res:any) => {
       const data = _res.data.data
-      console.log(_res.data)
       if (_res.data.code === 200) {
         store.setUser(data);
         store.setToken(data?.token)
@@ -159,16 +155,10 @@
         localStorage.setItem('User', data);
         router.push(`/home`)
       } else if(_res.data.code === 400){
-        ElMessage({
-          message: '用户名或密码错误',
-          type: 'error',
-        })
+        ElMessage({message: '用户名或密码错误', type: 'error'})
       }
     }).catch((_err:any) => {
-      ElMessage({
-        message: '网络错误',
-        type: 'error',
-      })
+      ElMessage({message: '网络错误', type: 'error'})
       console.log("登陆失败", _err)
     })    
   }
@@ -186,16 +176,10 @@
         localStorage.setItem('User', data);
         router.push(`/home`)
       } else if(_res.data.code === 400){
-        ElMessage({
-          message: '邮箱或验证码错误' + _res.data.msg,
-          type: 'error',
-        })
+        ElMessage({message: '邮箱或验证码错误' + _res.data.msg, type: 'error'})
       }
     }).catch((_err:any) => {
-      ElMessage({
-        message: '网络错误',
-        type: 'error',
-      })
+      ElMessage({message: '网络错误', type: 'error'})
       console.log("登陆失败", _err)
     })    
   } 
@@ -204,6 +188,10 @@
     router.push('/register');
   };
 
+  const toPasswordChange = () => {
+    router.push('/passwordChange');
+  }
+
 </script>
 
 <script lang="ts">

+ 163 - 0
src/views/LoginPage/component/PasswordChange.vue

@@ -0,0 +1,163 @@
+<template>
+    <div class="login-style">
+      <div class="box-vessel">
+  
+        <div class="vessel-title">重置密码</div>
+
+        <el-form label-position="right" label-width="0" :rules="rules" :model="passwordChangeDTO" ref="formRef" :size="formSize">
+
+          <!--邮箱-->
+          <el-form-item prop="officialEmail">
+            <el-input v-model="passwordChangeDTO.officialEmail" placeholder="请输入邮箱"></el-input>
+          </el-form-item>
+
+          <!--密码-->
+          <el-form-item prop="password1">
+            <el-input v-model="passwordChangeDTO.password1" placeholder="请输入新密码" show-password></el-input>
+          </el-form-item>
+
+          <!--再次输入密码-->
+          <el-form-item prop="password2">
+            <el-input v-model="passwordChangeDTO.password2" placeholder="请再次输入密码" show-password></el-input>
+          </el-form-item>
+
+          <!--输入验证码-->
+            <el-form-item prop="verifyCode">
+              <el-input v-model="passwordChangeDTO.verifyCode" placeholder="输入验证码">
+                <template #suffix>
+                  <el-button type="text" @click="sendPasswordChangeVerifyCode" :disabled="isStart">
+                    {{ isStart ? countdown : '获取验证码' }}
+                  </el-button>
+                </template>
+              </el-input>
+            </el-form-item>
+  
+          <div style="display: flex; justify-content: center; align-items: center;">
+            <el-button @click="changePassword(formRef)" class="login-button">重置密码</el-button>
+          </div>
+  
+          <!-- 返回登录页面,下划线灰色小字 -->
+          <div style="display: flex; justify-content: center; align-items: center; margin-top: 10px;">
+            <router-link to="/login" style="color: #8e8e8e; text-decoration: underline;">记得密码? 前往登录</router-link>
+          </div>
+  
+        </el-form>
+  
+      </div>
+  
+    </div>
+  
+  
+  
+  </template>
+  
+  <script lang="ts" setup>
+  import "./index.scss";
+  import { reactive, ref } from "vue";
+  import useApis from "@/apis";
+  import { type ComponentSize, ElMessage, type FormInstance, type FormRules } from "element-plus";
+  import router from "@/router";
+  import { useCountdown } from '@/hooks/useCountdown';
+
+  const { start, isStart, countdown } = useCountdown();
+  
+  const apis = useApis()
+
+  type passwordChangeDTO = {
+    officialEmail: "",
+    password1: "",
+    password2: "",
+    verifyCode: ""
+  }
+  let passwordChangeDTO = reactive<passwordChangeDTO>({} as passwordChangeDTO)
+  
+
+  const formSize = ref<ComponentSize>('default')
+  const formRef = ref<FormInstance>()
+  const rules = reactive<FormRules<passwordChangeDTO>>({
+    officialEmail: [
+      {
+        required: true,
+        message: "邮箱不能为空",
+        trigger: 'blur'
+      }
+    ],
+    password1: [
+      {
+        required: true,
+        message: "请输入密码",
+        trigger: 'blur'
+      }
+    ],
+    password2: [
+      {
+        required: true,
+        message: "请再次输入密码",
+        trigger: 'blur'
+      }
+    ],
+    verifyCode: [
+      {
+        required: true,
+        message: "验证码不能为空",
+        trigger: 'blur'
+      }
+    ]
+  })
+
+
+  
+  const changePassword = async (formEl: FormInstance | undefined) => {
+    if (!formEl) return
+    await formEl.validate((valid, fields) => {
+      if (valid) {
+        if(passwordChangeDTO.password1 != passwordChangeDTO.password2) {
+          ElMessage({message: '两次输入密码不一致', type: 'error'})
+          return
+        } 
+        let data = {
+          officialEmail: passwordChangeDTO.officialEmail,
+          password: passwordChangeDTO.password1,
+          verifyCode: passwordChangeDTO.verifyCode
+        }
+        apis.updatePassword(data).then((res: any) => {
+          if (res.data.code === 200) {
+            ElMessage({message: '密码修改成功',type: 'success'})
+            router.push(`/login`);
+          } else {
+            ElMessage({message: '密码修改失败' + res.data.msg, type: 'error'})
+          }
+        }).catch((err: any) => {
+          ElMessage({message: '网络错误',type: 'error'})
+          console.log(err)
+        }).finally(() => {});
+      } else {
+        ElMessage({message: '请将信息填写完整',type: 'warning'})
+      }
+    })
+  }
+  
+  const sendPasswordChangeVerifyCode = () => {
+    start();
+    
+    apis.sendPasswordChangeVerifyCode(passwordChangeDTO.officialEmail)
+    .then((res: any) => {
+      if (res.data.code === 200) {
+        ElMessage({message: '验证码发送成功,请前往您的邮箱查看',type: 'success'})
+      } else {
+        ElMessage({message: '验证码发送失败' + res.data.msg, type: 'error'})
+      }
+    })
+    .catch((err: any) => {
+      ElMessage({message: '验证码发送失败',type: 'error'})
+      console.log(err)
+    })
+    .finally(() => {});
+  }
+  </script>
+  
+  <script lang="ts">
+  export default {
+    name: "PasswordChange"
+  }
+  </script>

+ 17 - 37
src/views/LoginPage/component/Register.vue

@@ -44,7 +44,9 @@
           <el-form-item label="验证码" prop="verifyCode">
             <el-input v-model="userRegisterDTO.verifyCode" placeholder="输入验证码">
               <template #suffix>
-                <el-button type="text" @click="sendVerifyCode">获取动态码</el-button>
+                <el-button type="text" @click="sendRegisterVerifyCode" :disabled="isStart">
+                  {{ isStart ? countdown : '获取验证码' }}
+                </el-button>
               </template>
             </el-input>
           </el-form-item>
@@ -76,7 +78,9 @@ import useApis from "@/apis";
 import { Role } from "@/types/enums";
 import { type ComponentSize, ElMessage, type FormInstance, type FormRules } from "element-plus";
 import router from "@/router";
+import { useCountdown } from '@/hooks/useCountdown';
 
+const { start, isStart, countdown } = useCountdown();
 const apis = useApis()
 let userRegisterDTO = reactive<UserRegisterDTO>({} as UserRegisterDTO)
 
@@ -145,66 +149,42 @@ const register = async (formEl: FormInstance | undefined) => {
   if (!formEl) return
   await formEl.validate((valid, fields) => {
     if (valid) {
-      console.log("合法输入")
       apis.register(userRegisterDTO)
         .then((res: any) => {
           if (res.data.code === 200) {
-            ElMessage({
-              message: '注册成功',
-              type: 'success',
-            })
+            ElMessage({message: '注册成功', type: 'success'})
             router.push(`/login`)
           } else {
-            ElMessage({
-              message: '注册失败: ' + res.data.msg,
-              type: 'error',
-            })
+            ElMessage({message: '注册失败: ' + res.data.msg, type: 'error'})
           }
         })
         .catch((err: any) => {
           console.error(err);
-          ElMessage({
-            message: '注册失败',
-            type: 'error',
-          })
+          ElMessage({message: '注册失败',type: 'error'})
         })
-        .finally(() => {
-        });
+        .finally(() => {});
     } else {
-      ElMessage({
-        message: '请将信息填写完整',
-        type: 'warning',
-      })
+      ElMessage({message: '请将信息填写完整', type: 'warning'})
     }
   })
 
 }
 
-const sendVerifyCode = () => {
-  apis.sendVerifyCode(userRegisterDTO.officialEmail)
+const sendRegisterVerifyCode = () => {
+  start()
+  apis.sendRegisterVerifyCode(userRegisterDTO.officialEmail)
     .then((res: any) => {
       if (res.data.code === 200) {
-        ElMessage({
-        message: '验证码发送成功,请前往您的邮箱查看',
-          type: 'success',
-        })
+        ElMessage({message: '验证码发送成功,请前往您的邮箱查看', type: 'success'})
       } else {
-        ElMessage({
-          // message: '验证码发送失败' + res.data.msg,
-          message: '验证码发送失败',
-          type: 'error',
-        })
+        ElMessage({message: '验证码发送失败' + res.data.msg, type: 'error'})
       }
     })
     .catch((err: any) => {
-      ElMessage({
-        message: '验证码发送失败',
-        type: 'error',
-      })
+      ElMessage({message: '验证码发送失败', type: 'error'})
       console.log(err)
     })
-    .finally(() => {
-    });
+    .finally(() => {});
 }
 </script>
 

+ 4 - 4
src/views/LoginPage/index.scss

@@ -45,11 +45,11 @@
       position: relative;
       .register-box-content {
         position: absolute;
-        width: 450px;
+        width: 400px;
         @extend .position-center-center;
         border: solid 1px var(--boder-color);
         border-radius: 7px;
-        height: 450px;
+        min-height: 350px;
         display: flex;
         flex-direction: column;
 
@@ -58,11 +58,11 @@
 
       .box-content {
         position: absolute;
-        width: 350px;
+        width: 400px;
         @extend .position-center-center;
         border: solid 1px var(--boder-color);
         border-radius: 7px;
-        height: 380px;
+        min-height: 350px;
         display: flex;
         flex-direction: column;