1
0

login.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <script setup lang="ts">
  2. import type { Recordable } from '@vben/types';
  3. import type { VbenFormSchema } from '@vben-core/form-ui';
  4. import type { AuthenticationProps } from './types';
  5. import { computed, onMounted, reactive, ref } from 'vue';
  6. import { useRouter } from 'vue-router';
  7. import { $t } from '@vben/locales';
  8. import { useVbenForm } from '@vben-core/form-ui';
  9. import { VbenButton, VbenCheckbox } from '@vben-core/shadcn-ui';
  10. import Title from './auth-title.vue';
  11. import ThirdPartyLogin from './third-party-login.vue';
  12. interface Props extends AuthenticationProps {
  13. formSchema: VbenFormSchema[];
  14. }
  15. defineOptions({
  16. name: 'AuthenticationLogin',
  17. });
  18. const props = withDefaults(defineProps<Props>(), {
  19. codeLoginPath: '/auth/code-login',
  20. forgetPasswordPath: '/auth/forget-password',
  21. formSchema: () => [],
  22. loading: false,
  23. qrCodeLoginPath: '/auth/qrcode-login',
  24. registerPath: '/auth/register',
  25. showCodeLogin: true,
  26. showForgetPassword: true,
  27. showQrcodeLogin: true,
  28. showRegister: true,
  29. showRememberMe: true,
  30. showThirdPartyLogin: true,
  31. submitButtonText: '',
  32. subTitle: '',
  33. title: '',
  34. });
  35. const emit = defineEmits<{
  36. submit: [Recordable<any>];
  37. }>();
  38. const [Form, { setFieldValue, validate, getValues }] = useVbenForm(
  39. reactive({
  40. commonConfig: {
  41. hideLabel: true,
  42. hideRequiredMark: true,
  43. },
  44. schema: computed(() => props.formSchema),
  45. showDefaultActions: false,
  46. }),
  47. );
  48. const router = useRouter();
  49. const REMEMBER_ME_KEY = `REMEMBER_ME_USERNAME_${location.hostname}`;
  50. const localUsername = localStorage.getItem(REMEMBER_ME_KEY) || '';
  51. const rememberMe = ref(!!localUsername);
  52. async function handleSubmit() {
  53. const { valid } = await validate();
  54. const values = await getValues();
  55. if (valid) {
  56. localStorage.setItem(
  57. REMEMBER_ME_KEY,
  58. rememberMe.value ? values?.username : '',
  59. );
  60. emit('submit', values);
  61. }
  62. }
  63. function handleGo(path: string) {
  64. router.push(path);
  65. }
  66. onMounted(() => {
  67. if (localUsername) {
  68. setFieldValue('username', localUsername);
  69. }
  70. });
  71. </script>
  72. <template>
  73. <div @keydown.enter.prevent="handleSubmit">
  74. <slot name="title">
  75. <Title>
  76. <slot name="title">
  77. {{ title || `${$t('authentication.welcomeBack')} 👋🏻` }}
  78. </slot>
  79. <template #desc>
  80. <span class="text-muted-foreground">
  81. <slot name="subTitle">
  82. {{ subTitle || $t('authentication.loginSubtitle') }}
  83. </slot>
  84. </span>
  85. </template>
  86. </Title>
  87. </slot>
  88. <Form />
  89. <div
  90. v-if="showRememberMe || showForgetPassword"
  91. class="mb-6 flex justify-between"
  92. >
  93. <div class="flex-center">
  94. <VbenCheckbox
  95. v-if="showRememberMe"
  96. v-model:checked="rememberMe"
  97. name="rememberMe"
  98. >
  99. {{ $t('authentication.rememberMe') }}
  100. </VbenCheckbox>
  101. </div>
  102. <span
  103. v-if="showForgetPassword"
  104. class="text-primary hover:text-primary-hover active:text-primary-active cursor-pointer text-sm font-normal"
  105. @click="handleGo(forgetPasswordPath)"
  106. >
  107. {{ $t('authentication.forgetPassword') }}
  108. </span>
  109. </div>
  110. <VbenButton
  111. :class="{
  112. 'cursor-wait': loading,
  113. }"
  114. :loading="loading"
  115. aria-label="login"
  116. class="w-full"
  117. @click="handleSubmit"
  118. >
  119. {{ submitButtonText || $t('common.login') }}
  120. </VbenButton>
  121. <div
  122. v-if="showCodeLogin || showQrcodeLogin"
  123. class="mb-2 mt-4 flex items-center justify-between"
  124. >
  125. <VbenButton
  126. v-if="showCodeLogin"
  127. class="w-1/2"
  128. variant="outline"
  129. @click="handleGo(codeLoginPath)"
  130. >
  131. {{ $t('authentication.mobileLogin') }}
  132. </VbenButton>
  133. <VbenButton
  134. v-if="showQrcodeLogin"
  135. class="ml-4 w-1/2"
  136. variant="outline"
  137. @click="handleGo(qrCodeLoginPath)"
  138. >
  139. {{ $t('authentication.qrcodeLogin') }}
  140. </VbenButton>
  141. </div>
  142. <!-- 第三方登录 -->
  143. <slot name="third-party-login">
  144. <ThirdPartyLogin v-if="showThirdPartyLogin" />
  145. </slot>
  146. <slot name="to-register">
  147. <div v-if="showRegister" class="mt-3 text-center text-sm">
  148. {{ $t('authentication.accountTip') }}
  149. <span
  150. class="text-primary hover:text-primary-hover active:text-primary-active cursor-pointer text-sm font-normal"
  151. @click="handleGo(registerPath)"
  152. >
  153. {{ $t('authentication.createAccount') }}
  154. </span>
  155. </div>
  156. </slot>
  157. </div>
  158. </template>