LoginForm.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <LoginFormTitle v-show="getShow" class="enter-x" />
  3. <Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef" v-show="getShow" @keypress.enter="handleLogin">
  4. <FormItem name="account" class="enter-x">
  5. <Input size="large" v-model:value="formData.account" :placeholder="t('sys.login.userName')" class="fix-auto-fill" />
  6. </FormItem>
  7. <FormItem name="password" class="enter-x">
  8. <InputPassword size="large" visibilityToggle v-model:value="formData.password" :placeholder="t('sys.login.password')" />
  9. </FormItem>
  10. <!--验证码-->
  11. <ARow class="enter-x">
  12. <ACol :span="12">
  13. <FormItem name="inputCode" class="enter-x">
  14. <Input size="large" v-model:value="formData.inputCode" :placeholder="t('sys.login.inputCode')" style="min-width: 100px" />
  15. </FormItem>
  16. </ACol>
  17. <ACol :span="8">
  18. <FormItem :style="{ 'text-align': 'right', 'margin-left': '20px' }" class="enter-x">
  19. <img v-if="randCodeData.requestCodeSuccess" style="margin-top: 2px; max-width: initial" :src="randCodeData.randCodeImage" @click="handleChangeCheckCode" />
  20. <img v-else style="margin-top: 2px; max-width: initial" src="../../../assets/images/checkcode.png" @click="handleChangeCheckCode" />
  21. </FormItem>
  22. </ACol>
  23. </ARow>
  24. <ARow class="enter-x">
  25. <ACol :span="12">
  26. <FormItem>
  27. <!-- No logic, you need to deal with it yourself -->
  28. <Checkbox v-model:checked="rememberMe" size="small">
  29. {{ t('sys.login.rememberMe') }}
  30. </Checkbox>
  31. </FormItem>
  32. </ACol>
  33. <ACol :span="12">
  34. <FormItem :style="{ 'text-align': 'right' }">
  35. <!-- No logic, you need to deal with it yourself -->
  36. <Button type="link" size="small" @click="setLoginState(LoginStateEnum.RESET_PASSWORD)">
  37. {{ t('sys.login.forgetPassword') }}
  38. </Button>
  39. </FormItem>
  40. </ACol>
  41. </ARow>
  42. <FormItem class="enter-x">
  43. <Button type="primary" size="large" block @click="handleLogin" :loading="loading">
  44. {{ t('sys.login.loginButton') }}
  45. </Button>
  46. <!-- <Button size="large" class="mt-4 enter-x" block @click="handleRegister">
  47. {{ t('sys.login.registerButton') }}
  48. </Button> -->
  49. </FormItem>
  50. <ARow class="enter-x">
  51. <ACol :md="8" :xs="24">
  52. <Button block @click="setLoginState(LoginStateEnum.MOBILE)">
  53. {{ t('sys.login.mobileSignInFormTitle') }}
  54. </Button>
  55. </ACol>
  56. <ACol :md="8" :xs="24" class="!my-2 !md:my-0 xs:mx-0 md:mx-2">
  57. <Button block @click="setLoginState(LoginStateEnum.QR_CODE)">
  58. {{ t('sys.login.qrSignInFormTitle') }}
  59. </Button>
  60. </ACol>
  61. <ACol :md="7" :xs="24">
  62. <Button block @click="setLoginState(LoginStateEnum.REGISTER)">
  63. {{ t('sys.login.registerButton') }}
  64. </Button>
  65. </ACol>
  66. </ARow>
  67. <Divider class="enter-x">{{ t('sys.login.otherSignIn') }}</Divider>
  68. <div class="flex justify-evenly enter-x" :class="`${prefixCls}-sign-in-way`">
  69. <a @click="onThirdLogin('github')" title="github"><GithubFilled /></a>
  70. <a @click="onThirdLogin('wechat_enterprise')" title="企业微信"> <icon-font class="item-icon" type="icon-qiyeweixin3" /></a>
  71. <a @click="onThirdLogin('dingtalk')" title="钉钉"><DingtalkCircleFilled /></a>
  72. <a @click="onThirdLogin('wechat_open')" title="微信"><WechatFilled /></a>
  73. </div>
  74. </Form>
  75. <!-- 第三方登录相关弹框 -->
  76. <ThirdModal ref="thirdModalRef"></ThirdModal>
  77. </template>
  78. <script lang="ts" setup>
  79. import { reactive, ref, toRaw, unref, computed, onMounted } from 'vue';
  80. import { Checkbox, Form, Input, Row, Col, Button, Divider } from 'ant-design-vue';
  81. import { GithubFilled, WechatFilled, DingtalkCircleFilled, createFromIconfontCN } from '@ant-design/icons-vue';
  82. import LoginFormTitle from './LoginFormTitle.vue';
  83. import ThirdModal from './ThirdModal.vue';
  84. import { useI18n } from '/@/hooks/web/useI18n';
  85. import { useMessage } from '/@/hooks/web/useMessage';
  86. import { useUserStore } from '/@/store/modules/user';
  87. import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin';
  88. import { useDesign } from '/@/hooks/web/useDesign';
  89. import { getCodeInfo } from '/@/api/sys/user';
  90. //import { onKeyStroke } from '@vueuse/core';
  91. const ACol = Col;
  92. const ARow = Row;
  93. const FormItem = Form.Item;
  94. const InputPassword = Input.Password;
  95. const IconFont = createFromIconfontCN({
  96. scriptUrl: '//at.alicdn.com/t/font_2316098_umqusozousr.js',
  97. });
  98. const { t } = useI18n();
  99. const { notification, createErrorModal } = useMessage();
  100. const { prefixCls } = useDesign('login');
  101. const userStore = useUserStore();
  102. const { setLoginState, getLoginState } = useLoginState();
  103. const { getFormRules } = useFormRules();
  104. const formRef = ref();
  105. const thirdModalRef = ref();
  106. const loading = ref(false);
  107. const rememberMe = ref(false);
  108. const formData = reactive({
  109. account: '',
  110. password: '',
  111. inputCode: '',
  112. });
  113. const randCodeData = reactive({
  114. randCodeImage: '',
  115. requestCodeSuccess: false,
  116. checkKey: null,
  117. });
  118. const { validForm } = useFormValid(formRef);
  119. //onKeyStroke('Enter', handleLogin);
  120. const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN);
  121. async function handleLogin() {
  122. const data = await validForm();
  123. if (!data) return;
  124. try {
  125. loading.value = true;
  126. const { userInfo } = await userStore.login(
  127. toRaw({
  128. password: data.password,
  129. username: data.account,
  130. captcha: data.inputCode,
  131. checkKey: randCodeData.checkKey,
  132. mode: 'none', //不要默认的错误提示
  133. })
  134. );
  135. if (userInfo) {
  136. notification.success({
  137. message: t('sys.login.loginSuccessTitle'),
  138. description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
  139. duration: 3,
  140. });
  141. }
  142. } catch (error) {
  143. notification.error({
  144. message: t('sys.api.errorTip'),
  145. description: error.message || t('sys.api.networkExceptionMsg'),
  146. duration: 3,
  147. });
  148. loading.value = false;
  149. //update-begin-author:taoyan date:2022-5-3 for: issues/41 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变
  150. handleChangeCheckCode();
  151. //update-end-author:taoyan date:2022-5-3 for: issues/41 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变
  152. }
  153. }
  154. function handleChangeCheckCode() {
  155. formData.inputCode = '';
  156. //TODO 兼容mock和接口,暂时这样处理
  157. randCodeData.checkKey = 1629428467008; //new Date().getTime();
  158. getCodeInfo(randCodeData.checkKey).then((res) => {
  159. randCodeData.randCodeImage = res;
  160. randCodeData.requestCodeSuccess = true;
  161. });
  162. }
  163. /**
  164. * 第三方登录
  165. * @param type
  166. */
  167. function onThirdLogin(type) {
  168. thirdModalRef.value.onThirdLogin(type);
  169. }
  170. //初始化验证码
  171. onMounted(() => {
  172. handleChangeCheckCode();
  173. });
  174. </script>