index.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <template>
  2. <div class="login-container">
  3. <el-form ref="loginFormRef" :model="loginData" :rules="loginRules" class="login-form">
  4. <div class="title">
  5. <span>登录</span>
  6. </div>
  7. <el-form-item prop="phone">
  8. <span class="m-2"> <svg-icon icon-class="username" size="30px" /> </span>|
  9. <el-input
  10. ref="username"
  11. v-model="loginData.phone"
  12. class="flex-1"
  13. placeholder="请输入登录账号"
  14. name="username" />
  15. </el-form-item>
  16. <el-form-item prop="password">
  17. <span class="m-2"> <svg-icon icon-class="password" size="30px" /> </span>|
  18. <el-input
  19. v-model="loginData.password"
  20. class="flex-1"
  21. placeholder="请输入登录密码"
  22. :type="passwordVisible === false ? 'password' : 'input'"
  23. name="password"
  24. @keyup.enter="handleLogin" />
  25. <span class="mr-3" @click="passwordVisible = !passwordVisible">
  26. <svg-icon :icon-class="!passwordVisible ? 'eye' : 'eye-open'" class="cursor-pointer" size="18px" />
  27. </span>
  28. </el-form-item>
  29. <el-button :loading="loading" class="w-full" size="default" type="primary" @click.prevent="handleLogin"
  30. >登录
  31. </el-button>
  32. <el-checkbox v-model="autoLogin" fill="#727272" label="自动登录" size="small" />
  33. </el-form>
  34. </div>
  35. </template>
  36. <script setup lang="ts">
  37. import router from "@/router";
  38. import SvgIcon from "@/components/SvgIcon/index.vue";
  39. // 状态管理依赖
  40. import {useUserStore} from "@/store/modules/user";
  41. // API依赖
  42. import {LocationQuery, LocationQueryValue, useRoute} from "vue-router";
  43. import {LoginData} from "@/api/auth/types";
  44. const userStore = useUserStore();
  45. const route = useRoute();
  46. /**
  47. * 按钮loading
  48. */
  49. const loading = ref(false);
  50. /**
  51. * 密码是否可见
  52. */
  53. const passwordVisible = ref(false);
  54. /**
  55. * 登录表单引用
  56. */
  57. const loginFormRef = ref(ElForm);
  58. const autoLogin = ref(true);
  59. const loginData = ref<LoginData>({
  60. // phone: "18770033942",
  61. // password: "123456",
  62. phone: atob(localStorage.getItem("autoName") || ""),
  63. password: atob(localStorage.getItem("autoPass") || ""),
  64. });
  65. const loginRules = {
  66. phone: [{required: true, trigger: "blur", validator: usernameValidator}],
  67. password: [{required: true, trigger: "blur", validator: passwordValidator}],
  68. };
  69. /**
  70. * 用户名校验
  71. */
  72. function usernameValidator(rule: any, value: any, callback: any) {
  73. if (value * 1 === 0) {
  74. callback(new Error("输入的手机号码不能为空"));
  75. }
  76. if (!new RegExp(/^1[3-9][0-9]{9}$/).test(value)) {
  77. callback(new Error("输入的手机号码格式错误"));
  78. }
  79. callback();
  80. }
  81. /**
  82. * 密码校验器
  83. */
  84. function passwordValidator(rule: any, value: any, callback: any) {
  85. if (value.length < 6) {
  86. callback(new Error("密码格式错误"));
  87. } else {
  88. callback();
  89. }
  90. }
  91. /**
  92. * 登录
  93. */
  94. function handleLogin() {
  95. loginFormRef.value.validate((valid: boolean) => {
  96. if (valid) {
  97. loading.value = true;
  98. if (autoLogin.value) {
  99. // 自动登录存入本地存储
  100. localStorage.setItem("autoName", btoa(<string>loginData.value.phone));
  101. localStorage.setItem("autoPass", btoa(<string>loginData.value.password));
  102. }
  103. userStore
  104. .login(loginData.value)
  105. .then(() => {
  106. const query: LocationQuery = route.query;
  107. const redirect = (query.redirect as LocationQueryValue) ?? "/";
  108. const otherQueryParams = Object.keys(query).reduce((acc: any, cur: string) => {
  109. if (cur !== "redirect") {
  110. acc[cur] = query[cur];
  111. }
  112. return acc;
  113. }, {});
  114. router.push({path: redirect, query: otherQueryParams});
  115. })
  116. .catch((error) => {
  117. console.log("登录", error);
  118. // 验证失败,重新生成验证码
  119. new Error("您输入的密码错误");
  120. })
  121. .finally(() => {
  122. loading.value = false;
  123. });
  124. }
  125. });
  126. }
  127. </script>
  128. <style lang="scss" scoped>
  129. .login-container {
  130. box-sizing: border-box;
  131. width: 100%;
  132. height: 100%;
  133. min-height: 750px;
  134. padding-top: 260px;
  135. overflow: hidden;
  136. background: #eaf7fd url("../../assets/login/login.jpg") no-repeat left top;
  137. background-size: auto 100%;
  138. .login-form {
  139. width: 500px;
  140. max-width: 100%;
  141. padding: 0 42px 20px;
  142. margin: 0 auto;
  143. overflow: hidden;
  144. background: #fff;
  145. box-shadow: 0 0 10px #f2f3f5;
  146. .title {
  147. height: 98px;
  148. font-size: 30px;
  149. line-height: 98px;
  150. color: #151515;
  151. }
  152. .svg-icon {
  153. width: 18px;
  154. height: 18px;
  155. }
  156. }
  157. .el-form-item {
  158. height: 54px;
  159. margin-bottom: 40px;
  160. font-size: 16px;
  161. line-height: 54px;
  162. color: #747474;
  163. background: #f2f3f5;
  164. border: 1px solid #f2f3f5;
  165. border-radius: 5px;
  166. }
  167. .el-button {
  168. height: 54px;
  169. margin: 20px auto 10px;
  170. font-size: 18px;
  171. line-height: 54px;
  172. background: #006eff;
  173. }
  174. }
  175. @media only screen and (width >= 1080px) {
  176. .login-container {
  177. padding-left: 660px;
  178. }
  179. }
  180. @media only screen and (width <= 1080px) {
  181. .login-container {
  182. padding: 400px 0;
  183. background-position: center center;
  184. }
  185. }
  186. @media only screen and (width <= 600px) {
  187. .login-container {
  188. .login-form .title {
  189. height: 80px;
  190. line-height: 80px;
  191. }
  192. .el-form-item {
  193. margin-bottom: 20px;
  194. }
  195. }
  196. }
  197. .el-input {
  198. height: 54px;
  199. line-height: 54px;
  200. background: transparent;
  201. // 子组件 scoped 无效,使用 :deep
  202. :deep(.el-input__wrapper) {
  203. height: 54px;
  204. padding: 0;
  205. background: transparent;
  206. box-shadow: none;
  207. .el-input__inner {
  208. height: 54px;
  209. text-indent: 1.5em;
  210. background: transparent;
  211. border: 0;
  212. border-radius: 0;
  213. &:-webkit-autofill {
  214. box-shadow: 0 0 0 1000px transparent inset !important;
  215. -webkit-text-fill-color: #fff !important;
  216. }
  217. // 设置输入框自动填充的延迟属性
  218. &:-webkit-autofill,
  219. &:-webkit-autofill:hover,
  220. &:-webkit-autofill:focus,
  221. &:-webkit-autofill:active {
  222. transition: color 99999s ease-out, background-color 99999s ease-out;
  223. transition-delay: 99999s;
  224. }
  225. }
  226. }
  227. }
  228. :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
  229. background-color: #727272;
  230. border-color: #727272;
  231. }
  232. :deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
  233. color: #727272;
  234. }
  235. </style>