LoginForm.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <template>
  2. <el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" size="large">
  3. <el-form-item prop="username">
  4. <el-input v-model="loginForm.username" placeholder="请输入用户名">
  5. <template #prefix>
  6. <el-icon class="el-input__icon">
  7. <user />
  8. </el-icon>
  9. </template>
  10. </el-input>
  11. </el-form-item>
  12. <el-form-item prop="password">
  13. <el-input v-model="loginForm.password" type="password" placeholder="请输入密码" show-password autocomplete="new-password">
  14. <template #prefix>
  15. <el-icon class="el-input__icon">
  16. <lock />
  17. </el-icon>
  18. </template>
  19. </el-input>
  20. </el-form-item>
  21. <el-form-item prop="captcha">
  22. <div class="captcha-row">
  23. <el-input v-model="loginForm.captcha" placeholder="请输入验证码" maxlength="6" />
  24. <div class="captcha-code" @click="refreshCaptcha" title="点击刷新验证码">
  25. {{ captchaCode }}
  26. </div>
  27. </div>
  28. </el-form-item>
  29. </el-form>
  30. <div class="login-btn">
  31. <el-button :icon="CircleClose" round size="large" @click="resetForm(loginFormRef)"> 重置 </el-button>
  32. <el-button :icon="UserFilled" round size="large" type="primary" :loading="loading" @click="login(loginFormRef)">
  33. 登录
  34. </el-button>
  35. </div>
  36. <!-- <div class="form-footer">
  37. 还没有账号?
  38. <el-button link type="primary" @click="goRegister">立即注册</el-button>
  39. </div> -->
  40. </template>
  41. <script setup lang="ts">
  42. import { ref, reactive, onMounted, onBeforeUnmount } from "vue";
  43. import { useRouter } from "vue-router";
  44. import { HOME_URL, REGISTER_URL } from "@/config";
  45. // import { getTimeState } from "@/utils";
  46. import { Login } from "@/api/interface/index";
  47. import { ElNotification } from "element-plus";
  48. import { loginApi } from "@/api/modules/login";
  49. import { useUserStore } from "@/stores/modules/user";
  50. import { useTabsStore } from "@/stores/modules/tabs";
  51. import { useKeepAliveStore } from "@/stores/modules/keepAlive";
  52. import { initDynamicRouter } from "@/routers/modules/dynamicRouter";
  53. import { CircleClose, UserFilled } from "@element-plus/icons-vue";
  54. import type { ElForm } from "element-plus";
  55. import md5 from "md5";
  56. const router = useRouter();
  57. const userStore = useUserStore();
  58. const tabsStore = useTabsStore();
  59. const keepAliveStore = useKeepAliveStore();
  60. type FormInstance = InstanceType<typeof ElForm>;
  61. const loginFormRef = ref<FormInstance>();
  62. const loginRules = reactive({
  63. username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
  64. password: [{ required: true, message: "请输入密码", trigger: "blur" }],
  65. captcha: [{ required: true, message: "请输入验证码", trigger: "blur" }]
  66. });
  67. const loading = ref(false);
  68. const loginForm = reactive<Login.ReqLoginForm & { captcha: string }>({
  69. username: "",
  70. password: "",
  71. captcha: ""
  72. });
  73. const captchaCode = ref("");
  74. const generateCaptcha = () => {
  75. captchaCode.value = Math.floor(Math.random() * 1000000)
  76. .toString()
  77. .padStart(6, "0");
  78. };
  79. const refreshCaptcha = () => {
  80. generateCaptcha();
  81. loginForm.captcha = "";
  82. };
  83. // login
  84. const login = (formEl: FormInstance | undefined) => {
  85. if (!formEl) return;
  86. formEl.validate(async valid => {
  87. if (!valid) return;
  88. if (loginForm.captcha !== captchaCode.value) {
  89. ElNotification({
  90. title: "验证码错误",
  91. message: "请重新输入验证码",
  92. type: "error",
  93. duration: 5000
  94. });
  95. refreshCaptcha();
  96. return;
  97. }
  98. loading.value = true;
  99. try {
  100. // 1.执行登录接口
  101. const loginPayload = {
  102. username: loginForm.username,
  103. // password: md5(loginForm.password)
  104. password: loginForm.password
  105. };
  106. const { data } = (await loginApi(loginPayload)) as { data: Login.ResLogin };
  107. console.log(data);
  108. if (data.result) {
  109. userStore.setToken(data.token);
  110. const extraInfo: any = data;
  111. const firmId = extraInfo?.firmId ?? extraInfo?.lawFirmId ?? extraInfo?.userInfo?.firmId ?? "";
  112. userStore.setUserInfo({ name: loginForm.username, firmId });
  113. // 2.添加动态路由
  114. await initDynamicRouter();
  115. // 3.清空 tabs、keepAlive 数据
  116. tabsStore.setTabs([]);
  117. keepAliveStore.setKeepAliveName([]);
  118. // 4.跳转到首页
  119. router.push(HOME_URL);
  120. // ElNotification({
  121. // title: getTimeState(),
  122. // message: "欢迎登录 Geeker-Admin",
  123. // type: "success",
  124. // duration: 3000
  125. // });
  126. ElNotification({
  127. title: "登录成功",
  128. dangerouslyUseHTMLString: true,
  129. type: "success",
  130. duration: 8000
  131. });
  132. } else {
  133. ElNotification({
  134. title: "登录失败,请检查用户名和密码",
  135. dangerouslyUseHTMLString: true,
  136. type: "error",
  137. duration: 8000
  138. });
  139. }
  140. } finally {
  141. loading.value = false;
  142. }
  143. });
  144. };
  145. // resetForm
  146. const resetForm = (formEl: FormInstance | undefined) => {
  147. if (!formEl) return;
  148. formEl.resetFields();
  149. refreshCaptcha();
  150. };
  151. onMounted(() => {
  152. generateCaptcha();
  153. // 监听 enter 事件(调用登录)
  154. document.onkeydown = (e: KeyboardEvent) => {
  155. if (e.code === "Enter" || e.code === "enter" || e.code === "NumpadEnter") {
  156. if (loading.value) return;
  157. login(loginFormRef.value);
  158. }
  159. };
  160. });
  161. onBeforeUnmount(() => {
  162. document.onkeydown = null;
  163. });
  164. const goRegister = () => {
  165. router.push(REGISTER_URL);
  166. };
  167. </script>
  168. <style scoped lang="scss">
  169. @import "../index";
  170. .captcha-row {
  171. display: flex;
  172. gap: 12px;
  173. align-items: center;
  174. }
  175. .captcha-code {
  176. padding: 0 16px;
  177. font-weight: 600;
  178. color: var(--el-color-primary);
  179. text-align: center;
  180. letter-spacing: 4px;
  181. cursor: pointer;
  182. user-select: none;
  183. background-color: var(--el-color-primary-light-9);
  184. border: 1px solid var(--el-color-primary);
  185. border-radius: 6px;
  186. }
  187. </style>