UpdatePwd.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <template>
  2. <div class="login-container">
  3. <div class="login-form">
  4. <img :src="exitIcon" alt="关闭" class="exit-icon" @click="emit('close')" />
  5. <header class="login-form__header">
  6. <span>修改密码</span>
  7. </header>
  8. <main class="login-form__main">
  9. <el-form
  10. ref="formRef"
  11. :model="formValue"
  12. :rules="rules"
  13. label-width="auto"
  14. class="login-form__form"
  15. @keydown.enter="confirmUpdatePwd"
  16. >
  17. <el-form-item prop="oldPwd">
  18. <el-input
  19. placeholder="请输入原密码"
  20. v-model="formValue.oldPwd"
  21. type="password"
  22. autocomplete="off"
  23. show-password
  24. clearable
  25. class="el-input--default"
  26. />
  27. </el-form-item>
  28. <el-form-item prop="newPwd">
  29. <el-input
  30. placeholder="新密码(至少6位)"
  31. v-model="formValue.newPwd"
  32. type="password"
  33. autocomplete="off"
  34. show-password
  35. clearable
  36. class="el-input--default"
  37. />
  38. </el-form-item>
  39. <el-form-item prop="confirmPwd">
  40. <el-input
  41. placeholder="确认密码(至少6位)"
  42. v-model="formValue.confirmPwd"
  43. type="password"
  44. autocomplete="off"
  45. show-password
  46. clearable
  47. class="el-input--default"
  48. />
  49. </el-form-item>
  50. </el-form>
  51. </main>
  52. <footer class="login-form__footer">
  53. <el-button class="login-form__button" @click="confirmUpdatePwd">确定修改</el-button>
  54. </footer>
  55. </div>
  56. <div v-if="showOverlay" class="overlay">
  57. <div class="loading-text">{{ loadingText }}</div>
  58. </div>
  59. </div>
  60. </template>
  61. <script lang="ts" setup>
  62. import { ref, reactive, nextTick } from 'vue';
  63. import { ElMessage, ElLoading } from 'element-plus';
  64. import type { FormInstance } from 'element-plus';
  65. import exitIcon from 'assets/svg/exit.svg';
  66. import { useUserStore } from '@/store/modules/user';
  67. import router from '@/router';
  68. const userStore = useUserStore();
  69. const emit = defineEmits(['close']);
  70. const formValue = reactive({
  71. oldPwd: '',
  72. newPwd: '',
  73. confirmPwd: '',
  74. });
  75. const formRef = ref<FormInstance>();
  76. const showOverlay = ref(false);
  77. const loadingBaseText = '密码修改成功,正在退出登录';
  78. const loadingText = ref(loadingBaseText + '.');
  79. let dotCount = 1;
  80. let intervalId: number | null = null;
  81. // 启动省略号动画
  82. const startLoadingAnimation = async () => {
  83. showOverlay.value = true;
  84. intervalId = window.setInterval(() => {
  85. dotCount = (dotCount % 3) + 1;
  86. loadingText.value = loadingBaseText + '.'.repeat(dotCount);
  87. }, 200);
  88. };
  89. // 停止动画并跳转
  90. const stopLoadingAndRedirect = () => {
  91. if (intervalId !== null) {
  92. clearInterval(intervalId);
  93. intervalId = null;
  94. }
  95. showOverlay.value = false;
  96. };
  97. const validateConfirmPassword = (rule: any, value: string, callback: any) => {
  98. if (value !== formValue.newPwd) {
  99. callback(new Error('两次输入密码不一致'));
  100. } else {
  101. callback();
  102. }
  103. };
  104. const rules = {
  105. oldPwd: [{ required: true, message: '原密码不能为空', trigger: 'blur' }],
  106. newPwd: [
  107. { required: true, message: '新密码不能为空', trigger: 'blur' },
  108. { min: 6, message: '密码长度不能小于6位', trigger: 'blur' },
  109. ],
  110. confirmPwd: [
  111. { required: true, message: '请确认新密码', trigger: 'blur' },
  112. { validator: validateConfirmPassword, trigger: 'blur' },
  113. ],
  114. };
  115. const confirmUpdatePwd = () => {
  116. if (!formRef.value) return;
  117. formRef.value.validate((valid: boolean, ...rest) => {
  118. if (valid) {
  119. startLoadingAnimation();
  120. userStore
  121. .changePassword(formValue)
  122. .then(() => {
  123. emit('close');
  124. setTimeout(() => {
  125. stopLoadingAndRedirect();
  126. }, 20000);
  127. userStore.logout();
  128. router.push({ path: '/home' });
  129. })
  130. .catch(() => {
  131. ElMessage.error('修改密码失败');
  132. stopLoadingAndRedirect();
  133. });
  134. }
  135. });
  136. };
  137. </script>
  138. <style lang="scss" scoped>
  139. .login-container {
  140. @include flex-center;
  141. position: fixed;
  142. left: 0;
  143. top: 0;
  144. width: 100vw;
  145. height: 100vh;
  146. background-color: rgba(0, 0, 0, 0.42);
  147. z-index: 1000;
  148. }
  149. .login-form {
  150. position: relative;
  151. width: 700cpx;
  152. padding: 0 33cpx;
  153. background: $white-color;
  154. border-radius: 24cpx;
  155. &__header {
  156. width: 100%;
  157. height: 100cpx;
  158. font-size: 28cpx;
  159. font-weight: 550;
  160. color: #333;
  161. text-align: center;
  162. line-height: 100cpx;
  163. letter-spacing: 5cpx;
  164. }
  165. &__main {
  166. @include flex-center;
  167. flex-direction: column;
  168. gap: 20cpx;
  169. }
  170. &__code {
  171. @include flex-center;
  172. justify-content: space-between;
  173. width: 100%;
  174. height: 72cpx;
  175. .el-input--default {
  176. width: 50%;
  177. }
  178. }
  179. &__footer {
  180. width: 100%;
  181. height: 100cpx;
  182. margin-top: 18cpx;
  183. .login-form__button {
  184. width: 100%;
  185. height: 74cpx;
  186. font-size: 24cpx;
  187. color: $white-color;
  188. background-color: $primary-color;
  189. border-radius: 8cpx;
  190. cursor: pointer;
  191. }
  192. }
  193. .exit-icon {
  194. position: absolute;
  195. top: 15cpx;
  196. right: 16cpx;
  197. width: 40cpx;
  198. height: 40cpx;
  199. cursor: pointer;
  200. }
  201. }
  202. .login-form__form {
  203. display: flex;
  204. flex-direction: column;
  205. gap: 2cpx;
  206. width: 100%;
  207. }
  208. .el-input--default {
  209. width: 100%;
  210. height: 72cpx;
  211. :deep(.el-input__inner) {
  212. font-size: 20cpx;
  213. color: #999;
  214. }
  215. }
  216. .overlay {
  217. position: fixed;
  218. top: 0;
  219. left: 0;
  220. width: 100vw;
  221. height: 100vh;
  222. background-color: rgba(0, 0, 0, 0.6);
  223. display: flex;
  224. justify-content: center;
  225. align-items: center;
  226. z-index: 9999;
  227. }
  228. .loading-text {
  229. color: white;
  230. font-size: 20px;
  231. font-weight: bold;
  232. }
  233. </style>