LoginForm.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <template>
  2. <LoginFormTitle v-show="getShow" class="enter-x" />
  3. <Form
  4. class="p-4 enter-x"
  5. :model="formData"
  6. :rules="getFormRules"
  7. ref="formRef"
  8. v-show="getShow"
  9. @keypress.enter="handleLogin"
  10. >
  11. <FormItem name="account" class="enter-x">
  12. <Input
  13. size="large"
  14. v-model:value="formData.account"
  15. :placeholder="t('sys.login.userName')"
  16. class="fix-auto-fill"
  17. />
  18. </FormItem>
  19. <FormItem name="password" class="enter-x">
  20. <InputPassword
  21. size="large"
  22. visibilityToggle
  23. v-model:value="formData.password"
  24. :placeholder="t('sys.login.password')"
  25. />
  26. </FormItem>
  27. <ARow :gutter="16">
  28. <ACol :span="16">
  29. <FormItem name="captcha">
  30. <Input
  31. v-model:value="formData.captcha"
  32. class="login-captcha"
  33. :placeholder="t('system.login.login-captcha')"
  34. size="large"
  35. />
  36. </FormItem>
  37. </ACol>
  38. <ACol :span="8">
  39. <Tooltip>
  40. <template #title>{{ t('system.login.captchaRefreshTooltip') }}</template>
  41. <img style="height: 40px" :src="computedCaptchaUrl" @click="handleChangeCaptcha" />
  42. </Tooltip>
  43. </ACol>
  44. </ARow>
  45. <ARow class="enter-x">
  46. <ACol :span="12">
  47. <FormItem>
  48. <!-- No logic, you need to deal with it yourself -->
  49. <Checkbox v-model:checked="rememberMe" size="small">
  50. {{ t('sys.login.rememberMe') }}
  51. </Checkbox>
  52. </FormItem>
  53. </ACol>
  54. <ACol :span="12">
  55. <FormItem :style="{ 'text-align': 'right' }">
  56. <!-- No logic, you need to deal with it yourself -->
  57. <Button type="link" size="small" @click="setLoginState(LoginStateEnum.RESET_PASSWORD)">
  58. {{ t('sys.login.forgetPassword') }}
  59. </Button>
  60. </FormItem>
  61. </ACol>
  62. </ARow>
  63. <FormItem class="enter-x">
  64. <Button type="primary" size="large" block @click="handleLogin" :loading="loading">
  65. {{ t('sys.login.loginButton') }}
  66. </Button>
  67. <!-- <Button size="large" class="mt-4 enter-x" block @click="handleRegister">
  68. {{ t('sys.login.registerButton') }}
  69. </Button> -->
  70. </FormItem>
  71. <ARow class="enter-x" :gutter="[16, 16]">
  72. <ACol :md="8" :xs="24">
  73. <Button block @click="setLoginState(LoginStateEnum.MOBILE)">
  74. {{ t('sys.login.mobileSignInFormTitle') }}
  75. </Button>
  76. </ACol>
  77. <ACol :md="8" :xs="24">
  78. <Button block @click="setLoginState(LoginStateEnum.QR_CODE)">
  79. {{ t('sys.login.qrSignInFormTitle') }}
  80. </Button>
  81. </ACol>
  82. <ACol :md="8" :xs="24">
  83. <Button block @click="setLoginState(LoginStateEnum.REGISTER)">
  84. {{ t('sys.login.registerButton') }}
  85. </Button>
  86. </ACol>
  87. </ARow>
  88. <Divider class="enter-x">{{ t('sys.login.otherSignIn') }}</Divider>
  89. <div class="flex justify-evenly enter-x" :class="`${prefixCls}-sign-in-way`">
  90. <GithubFilled />
  91. <WechatFilled />
  92. <AlipayCircleFilled />
  93. <GoogleCircleFilled />
  94. <TwitterCircleFilled />
  95. </div>
  96. </Form>
  97. </template>
  98. <script lang="ts" setup>
  99. import { reactive, ref, unref, computed } from 'vue';
  100. import { Checkbox, Form, Input, Row, Col, Button, Divider, Tooltip } from 'ant-design-vue';
  101. import {
  102. GithubFilled,
  103. WechatFilled,
  104. AlipayCircleFilled,
  105. GoogleCircleFilled,
  106. TwitterCircleFilled,
  107. } from '@ant-design/icons-vue';
  108. import LoginFormTitle from './LoginFormTitle.vue';
  109. import { useI18n } from '@/hooks/web/useI18n';
  110. import { useMessage } from '@/hooks/web/useMessage';
  111. import { useUserStore } from '@/store/modules/user';
  112. import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin';
  113. import { useDesign } from '@/hooks/web/useDesign';
  114. import { buildUUID } from '@/utils/uuid';
  115. import { ApiServiceEnum, defHttp } from '@/utils/http/axios';
  116. import { createPassword } from '@/utils/auth';
  117. //import { onKeyStroke } from '@vueuse/core';
  118. const ACol = Col;
  119. const ARow = Row;
  120. const FormItem = Form.Item;
  121. const InputPassword = Input.Password;
  122. const { t } = useI18n();
  123. const { notification, createErrorModal } = useMessage();
  124. const { prefixCls } = useDesign('login');
  125. const userStore = useUserStore();
  126. const { setLoginState, getLoginState } = useLoginState();
  127. const { getFormRules } = useFormRules();
  128. const formRef = ref();
  129. const loading = ref(false);
  130. const rememberMe = ref(false);
  131. const formData = reactive({
  132. account: 'admin',
  133. password: '123456',
  134. captcha: '',
  135. captchaKey: buildUUID(),
  136. });
  137. const { validForm } = useFormValid(formRef);
  138. //onKeyStroke('Enter', handleLogin);
  139. const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN);
  140. async function handleLogin() {
  141. const data = await validForm();
  142. if (!data) return;
  143. try {
  144. loading.value = true;
  145. const userInfo = await userStore.login({
  146. password: createPassword(data.account, data.password),
  147. username: data.account,
  148. mode: 'none', //不要默认的错误提示
  149. codeKey: formData.captchaKey,
  150. code: formData.captcha,
  151. });
  152. if (userInfo) {
  153. notification.success({
  154. message: t('sys.login.loginSuccessTitle'),
  155. description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realName}`,
  156. duration: 3,
  157. });
  158. }
  159. } catch (error) {
  160. createErrorModal({
  161. title: t('sys.api.errorTip'),
  162. content: (error as unknown as Error).message || t('sys.api.networkExceptionMsg'),
  163. getContainer: () => document.body.querySelector(`.${prefixCls}`) || document.body,
  164. });
  165. handleChangeCaptcha();
  166. } finally {
  167. loading.value = false;
  168. }
  169. }
  170. const computedCaptchaUrl = computed(() => {
  171. return `${defHttp.getApiUrlByService(ApiServiceEnum.SMART_AUTH)}/auth/createCaptcha?codeKey=${
  172. formData.captchaKey
  173. }`;
  174. });
  175. const handleChangeCaptcha = () => {
  176. formData.captchaKey = buildUUID();
  177. };
  178. </script>