login.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <script setup lang="ts">
  2. import {
  3. VbenButton,
  4. VbenCheckbox,
  5. VbenInput,
  6. VbenInputPassword,
  7. } from '@vben-core/shadcn-ui';
  8. import { $t } from '@vben/locales';
  9. import { computed, reactive } from 'vue';
  10. import { useRouter } from 'vue-router';
  11. import Title from './auth-title.vue';
  12. import ThirdPartyLogin from './third-party-login.vue';
  13. import type { LoginEmits } from './typings';
  14. interface Props {
  15. /**
  16. * @zh_CN 验证码登录路径
  17. */
  18. codeLoginPath?: string;
  19. /**
  20. * @zh_CN 忘记密码路径
  21. */
  22. forgetPasswordPath?: string;
  23. /**
  24. * @zh_CN 是否处于加载处理状态
  25. */
  26. loading?: boolean;
  27. /**
  28. * @zh_CN 密码占位符
  29. */
  30. passwordPlaceholder?: string;
  31. /**
  32. * @zh_CN 二维码登录路径
  33. */
  34. qrCodeLoginPath?: string;
  35. /**
  36. * @zh_CN 注册路径
  37. */
  38. registerPath?: string;
  39. /**
  40. * @zh_CN 是否显示验证码登录
  41. */
  42. showCodeLogin?: boolean;
  43. /**
  44. * @zh_CN 是否显示忘记密码
  45. */
  46. showForgetPassword?: boolean;
  47. /**
  48. * @zh_CN 是否显示二维码登录
  49. */
  50. showQrcodeLogin?: boolean;
  51. /**
  52. * @zh_CN 是否显示注册按钮
  53. */
  54. showRegister?: boolean;
  55. /**
  56. * @zh_CN 是否显示第三方登录
  57. */
  58. showThirdPartyLogin?: boolean;
  59. /**
  60. * @zh_CN 用户名占位符
  61. */
  62. usernamePlaceholder?: string;
  63. }
  64. defineOptions({
  65. name: 'AuthenticationLogin',
  66. });
  67. withDefaults(defineProps<Props>(), {
  68. codeLoginPath: '/auth/code-login',
  69. forgetPasswordPath: '/auth/forget-password',
  70. loading: false,
  71. passwordPlaceholder: '',
  72. qrCodeLoginPath: '/auth/qrcode-login',
  73. registerPath: '/auth/register',
  74. showCodeLogin: true,
  75. showForgetPassword: true,
  76. showQrcodeLogin: true,
  77. showRegister: true,
  78. showThirdPartyLogin: true,
  79. usernamePlaceholder: '',
  80. });
  81. const emit = defineEmits<{
  82. submit: LoginEmits['submit'];
  83. }>();
  84. const router = useRouter();
  85. const REMEMBER_ME_KEY = 'REMEMBER_ME_USERNAME';
  86. const localUsername = localStorage.getItem(REMEMBER_ME_KEY) || '';
  87. const formState = reactive({
  88. password: '',
  89. rememberMe: !!localUsername,
  90. submitted: false,
  91. username: localUsername,
  92. });
  93. const usernameStatus = computed(() => {
  94. return formState.submitted && !formState.username ? 'error' : 'default';
  95. });
  96. const passwordStatus = computed(() => {
  97. return formState.submitted && !formState.password ? 'error' : 'default';
  98. });
  99. function handleSubmit() {
  100. formState.submitted = true;
  101. if (
  102. usernameStatus.value !== 'default' ||
  103. passwordStatus.value !== 'default'
  104. ) {
  105. return;
  106. }
  107. localStorage.setItem(
  108. REMEMBER_ME_KEY,
  109. formState.rememberMe ? formState.username : '',
  110. );
  111. emit('submit', {
  112. password: formState.password,
  113. username: formState.username,
  114. });
  115. }
  116. function handleGo(path: string) {
  117. router.push(path);
  118. }
  119. </script>
  120. <template>
  121. <div @keypress.enter.prevent="handleSubmit">
  122. <Title>
  123. {{ $t('authentication.welcome-back') }} 👋🏻
  124. <template #desc>
  125. <span class="text-muted-foreground">
  126. {{ $t('authentication.login-subtitle') }}
  127. </span>
  128. </template>
  129. </Title>
  130. <VbenInput
  131. v-model="formState.username"
  132. :status="usernameStatus"
  133. :error-tip="$t('authentication.username-tip')"
  134. :label="$t('authentication.username')"
  135. name="username"
  136. :placeholder="usernamePlaceholder || $t('authentication.username')"
  137. type="text"
  138. required
  139. :autofocus="false"
  140. />
  141. <VbenInputPassword
  142. v-model="formState.password"
  143. :status="passwordStatus"
  144. :error-tip="$t('authentication.password-tip')"
  145. :label="$t('authentication.password')"
  146. name="password"
  147. :placeholder="passwordPlaceholder || $t('authentication.password')"
  148. required
  149. type="password"
  150. />
  151. <div class="mb-6 mt-4 flex justify-between">
  152. <div class="flex-center flex">
  153. <VbenCheckbox v-model:checked="formState.rememberMe" name="rememberMe">
  154. {{ $t('authentication.remember-me') }}
  155. </VbenCheckbox>
  156. </div>
  157. <span
  158. v-if="showForgetPassword"
  159. class="text-primary hover:text-primary/80 cursor-pointer text-sm font-normal"
  160. @click="handleGo(forgetPasswordPath)"
  161. >
  162. {{ $t('authentication.forget-password') }}
  163. </span>
  164. <!-- <VbenButton variant="ghost" @click="handleGo('/auth/forget-password')">
  165. 忘记密码?
  166. </VbenButton> -->
  167. </div>
  168. <VbenButton :loading="loading" class="w-full" @click="handleSubmit">
  169. {{ $t('common.login') }}
  170. </VbenButton>
  171. <div class="mb-2 mt-4 flex items-center justify-between">
  172. <VbenButton
  173. v-if="showCodeLogin"
  174. variant="outline"
  175. class="w-1/2"
  176. @click="handleGo(codeLoginPath)"
  177. >
  178. {{ $t('authentication.mobile-login') }}
  179. </VbenButton>
  180. <VbenButton
  181. v-if="showQrcodeLogin"
  182. variant="outline"
  183. class="ml-4 w-1/2"
  184. @click="handleGo(qrCodeLoginPath)"
  185. >
  186. {{ $t('authentication.qrcode-login') }}
  187. </VbenButton>
  188. <!-- <VbenButton
  189. :loading="loading"
  190. variant="outline"
  191. class="w-1/3"
  192. @click="handleGo('/auth/register')"
  193. >
  194. 创建账号
  195. </VbenButton> -->
  196. </div>
  197. <!-- 第三方登录 -->
  198. <ThirdPartyLogin v-if="showThirdPartyLogin" />
  199. <div v-if="showRegister" class="text-center text-sm">
  200. {{ $t('authentication.account-tip') }}
  201. <span
  202. class="text-primary hover:text-primary/80 cursor-pointer text-sm font-normal"
  203. @click="handleGo(registerPath)"
  204. >
  205. {{ $t('authentication.create-account') }}
  206. </span>
  207. </div>
  208. </div>
  209. </template>