login-form.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <template>
  2. <div class="login-form-wrapper">
  3. <div class="login-form-title">{{ $t('login.form.title') }}</div>
  4. <div class="login-form-sub-title">{{ $t('login.form.title') }}</div>
  5. <div class="login-form-error-msg">{{ errorMessage }}</div>
  6. <a-form
  7. ref="loginForm"
  8. :model="userInfo"
  9. class="login-form"
  10. layout="vertical"
  11. @submit="handleSubmit"
  12. >
  13. <a-form-item
  14. field="username"
  15. :rules="[{ required: true, message: $t('login.form.userName.errMsg') }]"
  16. :validate-trigger="['change', 'blur']"
  17. hide-label
  18. >
  19. <a-input
  20. v-model="userInfo.username"
  21. :placeholder="$t('login.form.userName.placeholder')"
  22. >
  23. <template #prefix>
  24. <icon-user />
  25. </template>
  26. </a-input>
  27. </a-form-item>
  28. <a-form-item
  29. field="password"
  30. :rules="[{ required: true, message: $t('login.form.password.errMsg') }]"
  31. :validate-trigger="['change', 'blur']"
  32. hide-label
  33. >
  34. <a-input-password
  35. v-model="userInfo.password"
  36. :placeholder="$t('login.form.password.placeholder')"
  37. allow-clear
  38. >
  39. <template #prefix>
  40. <icon-lock />
  41. </template>
  42. </a-input-password>
  43. </a-form-item>
  44. <a-space :size="16" direction="vertical">
  45. <div class="login-form-password-actions">
  46. <a-checkbox
  47. checked="rememberPassword"
  48. :model-value="loginConfig.rememberPassword"
  49. @change="setRememberPassword as any"
  50. >
  51. {{ $t('login.form.rememberPassword') }}
  52. </a-checkbox>
  53. <a-link>{{ $t('login.form.forgetPassword') }}</a-link>
  54. </div>
  55. <a-button type="primary" html-type="submit" long :loading="loading">
  56. {{ $t('login.form.login') }}
  57. </a-button>
  58. <a-button type="text" long class="login-form-register-btn">
  59. {{ $t('login.form.register') }}
  60. </a-button>
  61. </a-space>
  62. </a-form>
  63. </div>
  64. </template>
  65. <script lang="ts" setup>
  66. import { ref, reactive } from 'vue';
  67. import { useRouter } from 'vue-router';
  68. import { Message } from '@arco-design/web-vue';
  69. import { ValidatedError } from '@arco-design/web-vue/es/form/interface';
  70. import { useI18n } from 'vue-i18n';
  71. import { useStorage } from '@vueuse/core';
  72. import { useUserStore } from '@/store';
  73. import useLoading from '@/hooks/loading';
  74. import type { LoginData } from '@/api/user';
  75. const router = useRouter();
  76. const { t } = useI18n();
  77. const errorMessage = ref('');
  78. const { loading, setLoading } = useLoading();
  79. const userStore = useUserStore();
  80. const loginConfig = useStorage('login-config', {
  81. rememberPassword: true,
  82. username: 'admin', // 演示默认值
  83. password: 'admin', // demo default value
  84. });
  85. const userInfo = reactive({
  86. username: loginConfig.value.username,
  87. password: loginConfig.value.password,
  88. });
  89. const handleSubmit = async ({
  90. errors,
  91. values,
  92. }: {
  93. errors: Record<string, ValidatedError> | undefined;
  94. values: Record<string, any>;
  95. }) => {
  96. if (loading.value) return;
  97. if (!errors) {
  98. setLoading(true);
  99. try {
  100. const res = await userStore.login(values as LoginData);
  101. const { redirect, ...othersQuery } = router.currentRoute.value.query;
  102. if (res.success) {
  103. router.push({
  104. name: (redirect as string) || 'Workplace',
  105. query: {
  106. ...othersQuery,
  107. },
  108. });
  109. Message.success(t('login.form.login.success'));
  110. const { rememberPassword } = loginConfig.value;
  111. const { username, password } = values;
  112. // 实际生产环境需要进行加密存储。
  113. // The actual production environment requires encrypted storage.
  114. loginConfig.value.username = rememberPassword ? username : '';
  115. loginConfig.value.password = rememberPassword ? password : '';
  116. } else {
  117. Message.error(res.message);
  118. }
  119. } catch (err) {
  120. errorMessage.value = (err as Error).message;
  121. } finally {
  122. setLoading(false);
  123. }
  124. }
  125. };
  126. const setRememberPassword = (value: boolean) => {
  127. loginConfig.value.rememberPassword = value;
  128. };
  129. </script>
  130. <style lang="less" scoped>
  131. .login-form {
  132. &-wrapper {
  133. width: 320px;
  134. }
  135. &-title {
  136. color: var(--color-text-1);
  137. font-weight: 500;
  138. font-size: 24px;
  139. line-height: 32px;
  140. }
  141. &-sub-title {
  142. color: var(--color-text-3);
  143. font-size: 16px;
  144. line-height: 24px;
  145. }
  146. &-error-msg {
  147. height: 32px;
  148. color: rgb(var(--red-6));
  149. line-height: 32px;
  150. }
  151. &-password-actions {
  152. display: flex;
  153. justify-content: space-between;
  154. }
  155. &-register-btn {
  156. color: var(--color-text-3) !important;
  157. }
  158. }
  159. </style>