Parcourir la source

feat: 新增修改密码组件

bxy il y a 11 mois
Parent
commit
38a9612f99
4 fichiers modifiés avec 281 ajouts et 10 suppressions
  1. 8 2
      src/api/system/user.ts
  2. 9 7
      src/components/Nav.vue
  3. 256 0
      src/components/UpdatePwd.vue
  4. 8 1
      src/store/modules/user.ts

+ 8 - 2
src/api/system/user.ts

@@ -94,12 +94,18 @@ export function login(params: LoginParams) {
   );
 }
 
+export interface UpdateMyPwdParams {
+  userId?: number; // 用户ID: 修改自己的密码时为空
+  oldPwd?: string; // 旧密码
+  newPwd: string; // 新密码
+}
+
 /**
  * @description: 用户修改密码
  */
-export function changePassword(params) {
+export function changePassword(params: UpdateMyPwdParams) {
   return http.request({
-    url: '/login/updatePwd',
+    url: '/login/updateMyPwd',
     method: 'POST',
     params,
   });

+ 9 - 7
src/components/Nav.vue

@@ -23,15 +23,12 @@
       </div>
       <div class="platform__right__login">
         <span @click="handleLogin('login')" v-if="!userStore.info?.id">登录</span>
-        <UserInfo
-          v-else
-          @switchAccount="handleLogin('switchAccount')"
-          @modifyPassword="handleLogin('modifyPassword')"
-        />
+        <UserInfo v-else @switchAccount="handleLogin('switchAccount')" @modifyPassword="handleUpdatePwd" />
       </div>
     </div>
   </header>
   <Login v-if="userStore.showLogin" @close="userStore.showLogin = false" class="fadeIn" />
+  <UpdatePwd v-if="userStore.showUpdatePwd" @close="userStore.showUpdatePwd = false" class="fadeIn" />
 </template>
 
 <script lang="ts" setup>
@@ -41,6 +38,7 @@
   import logo from 'assets/images/home/comac-logo@1X.png';
   import searchIcon from 'assets/svg/search.svg';
   import Login from '@/components/Login.vue';
+  import UpdatePwd from '@/components/UpdatePwd.vue';
   import UserInfo from '@/components/UserInfo.vue';
   import { useGlobSetting } from '@/hooks/setting';
   import { useUserStore } from '@/store/modules/user';
@@ -49,17 +47,21 @@
   const activeNav = ref(NAV_LIST[0].name);
   const router = useRouter();
   const searchValue = ref('');
-  const loginType = ref<'login' | 'switchAccount' | 'modifyPassword'>('login');
+  const loginType = ref<'login' | 'switchAccount'>('login');
 
   const handleSearch = () => {
     console.log('searchValue', searchValue.value);
   };
 
-  const handleLogin = (type: 'login' | 'switchAccount' | 'modifyPassword') => {
+  const handleLogin = (type: 'login' | 'switchAccount') => {
     loginType.value = type;
     userStore.showLogin = true;
   };
 
+  const handleUpdatePwd = () => {
+    userStore.showUpdatePwd = true;
+  };
+
   const currentRoute = useRoute();
   const { title } = useGlobSetting();
 

+ 256 - 0
src/components/UpdatePwd.vue

@@ -0,0 +1,256 @@
+<template>
+  <div class="login-container">
+    <div class="login-form">
+      <img :src="exitIcon" alt="关闭" class="exit-icon" @click="emit('close')" />
+      <header class="login-form__header">
+        <span>修改密码</span>
+      </header>
+      <main class="login-form__main">
+        <el-form
+          ref="formRef"
+          :model="formValue"
+          :rules="rules"
+          label-width="auto"
+          class="login-form__form"
+          @keydown.enter="confirmUpdatePwd"
+        >
+          <el-form-item prop="oldPwd">
+            <el-input
+              placeholder="请输入原密码"
+              v-model="formValue.oldPwd"
+              type="password"
+              autocomplete="off"
+              show-password
+              clearable
+              class="el-input--default"
+            />
+          </el-form-item>
+          <el-form-item prop="newPwd">
+            <el-input
+              placeholder="新密码(至少6位)"
+              v-model="formValue.newPwd"
+              type="password"
+              autocomplete="off"
+              show-password
+              clearable
+              class="el-input--default"
+            />
+          </el-form-item>
+
+          <el-form-item prop="confirmPwd">
+            <el-input
+              placeholder="确认密码(至少6位)"
+              v-model="formValue.confirmPwd"
+              type="password"
+              autocomplete="off"
+              show-password
+              clearable
+              class="el-input--default"
+            />
+          </el-form-item>
+        </el-form>
+      </main>
+      <footer class="login-form__footer">
+        <el-button class="login-form__button" @click="confirmUpdatePwd">确定修改</el-button>
+      </footer>
+    </div>
+    <div v-if="showOverlay" class="overlay">
+      <div class="loading-text">{{ loadingText }}</div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { ref, reactive, nextTick } from 'vue';
+  import { ElMessage, ElLoading } from 'element-plus';
+  import type { FormInstance } from 'element-plus';
+  import exitIcon from 'assets/svg/exit.svg';
+  import { useUserStore } from '@/store/modules/user';
+  import router from '@/router';
+
+  const userStore = useUserStore();
+
+  const emit = defineEmits(['close']);
+
+  const formValue = reactive({
+    oldPwd: '',
+    newPwd: '',
+    confirmPwd: '',
+  });
+  const formRef = ref<FormInstance>();
+  const showOverlay = ref(false);
+  const loadingBaseText = '密码修改成功,正在退出登录';
+  const loadingText = ref(loadingBaseText + '.');
+  let dotCount = 1;
+  let intervalId: number | null = null;
+
+  // 启动省略号动画
+  const startLoadingAnimation = async () => {
+    showOverlay.value = true;
+    intervalId = window.setInterval(() => {
+      dotCount = (dotCount % 3) + 1;
+      loadingText.value = loadingBaseText + '.'.repeat(dotCount);
+    }, 200);
+  };
+
+  // 停止动画并跳转
+  const stopLoadingAndRedirect = () => {
+    if (intervalId !== null) {
+      clearInterval(intervalId);
+      intervalId = null;
+    }
+    showOverlay.value = false;
+  };
+
+  const validateConfirmPassword = (rule: any, value: string, callback: any) => {
+    if (value !== formValue.newPwd) {
+      callback(new Error('两次输入密码不一致'));
+    } else {
+      callback();
+    }
+  };
+
+  const rules = {
+    oldPwd: [{ required: true, message: '原密码不能为空', trigger: 'blur' }],
+    newPwd: [
+      { required: true, message: '新密码不能为空', trigger: 'blur' },
+      { min: 6, message: '密码长度不能小于6位', trigger: 'blur' },
+    ],
+    confirmPwd: [
+      { required: true, message: '请确认新密码', trigger: 'blur' },
+      { validator: validateConfirmPassword, trigger: 'blur' },
+    ],
+  };
+
+  const confirmUpdatePwd = () => {
+    if (!formRef.value) return;
+    formRef.value.validate((valid: boolean, ...rest) => {
+      if (valid) {
+        startLoadingAnimation();
+        userStore
+          .changePassword(formValue)
+          .then(() => {
+            emit('close');
+            setTimeout(() => {
+              stopLoadingAndRedirect();
+            }, 20000);
+            userStore.logout();
+            router.push({ path: '/home' });
+          })
+          .catch(() => {
+            ElMessage.error('修改密码失败');
+            stopLoadingAndRedirect();
+          });
+      }
+    });
+  };
+</script>
+
+<style lang="scss" scoped>
+  .login-container {
+    @include flex-center;
+    position: fixed;
+    left: 0;
+    top: 0;
+    width: 100vw;
+    height: 100vh;
+    background-color: rgba(0, 0, 0, 0.42);
+    z-index: 1000;
+  }
+
+  .login-form {
+    position: relative;
+    width: 700cpx;
+    padding: 0 33cpx;
+    background: $white-color;
+    border-radius: 24cpx;
+
+    &__header {
+      width: 100%;
+      height: 100cpx;
+      font-size: 28cpx;
+      font-weight: 550;
+      color: #333;
+      text-align: center;
+      line-height: 100cpx;
+      letter-spacing: 5cpx;
+    }
+
+    &__main {
+      @include flex-center;
+      flex-direction: column;
+      gap: 20cpx;
+    }
+
+    &__code {
+      @include flex-center;
+      justify-content: space-between;
+      width: 100%;
+      height: 72cpx;
+      .el-input--default {
+        width: 50%;
+      }
+    }
+
+    &__footer {
+      width: 100%;
+      height: 100cpx;
+      margin-top: 18cpx;
+
+      .login-form__button {
+        width: 100%;
+        height: 74cpx;
+        font-size: 24cpx;
+        color: $white-color;
+        background-color: $primary-color;
+        border-radius: 8cpx;
+        cursor: pointer;
+      }
+    }
+
+    .exit-icon {
+      position: absolute;
+      top: 15cpx;
+      right: 16cpx;
+      width: 40cpx;
+      height: 40cpx;
+      cursor: pointer;
+    }
+  }
+
+  .login-form__form {
+    display: flex;
+    flex-direction: column;
+    gap: 2cpx;
+    width: 100%;
+  }
+
+  .el-input--default {
+    width: 100%;
+    height: 72cpx;
+
+    :deep(.el-input__inner) {
+      font-size: 20cpx;
+      color: #999;
+    }
+  }
+
+  .overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100vw;
+    height: 100vh;
+    background-color: rgba(0, 0, 0, 0.6);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    z-index: 9999;
+  }
+
+  .loading-text {
+    color: white;
+    font-size: 20px;
+    font-weight: bold;
+  }
+</style>

+ 8 - 1
src/store/modules/user.ts

@@ -3,7 +3,7 @@ import { createStorage } from '@/utils/Storage';
 import { store } from '@/store';
 import { ACCESS_TOKEN, CURRENT_USER, IS_LOCKSCREEN, TENANT_TOKEN } from '@/store/mutation-types';
 import { ResultEnum } from '@/enums/httpEnum';
-import { getUserInfo, login, LoginParams, logoutApi } from '@/api/system/user';
+import { getUserInfo, login, LoginParams, logoutApi, changePassword, UpdateMyPwdParams } from '@/api/system/user';
 import { storage } from '@/utils/Storage';
 import { useGlobSetting } from '@/hooks/setting';
 import { PERM } from '@/types/permission/type';
@@ -35,6 +35,7 @@ export interface IUserState {
     tenantId: number;
   };
   showLogin: boolean;
+  showUpdatePwd: boolean;
 }
 
 export const useUserStore = defineStore({
@@ -46,6 +47,7 @@ export const useUserStore = defineStore({
     permissions: [],
     info: {} as IUserState['info'],
     showLogin: false,
+    showUpdatePwd: false,
   }),
   getters: {
     getToken(): string {
@@ -132,6 +134,11 @@ export const useUserStore = defineStore({
       return logoutApi();
     },
 
+    // 修改密码
+    async changePassword(params: UpdateMyPwdParams) {
+      return changePassword(params);
+    },
+
     /**
      * 用户是否有某个权限
      * @param permission