221 lines
5.7 KiB
Vue
221 lines
5.7 KiB
Vue
<template>
|
||
<a-form
|
||
ref="formRef"
|
||
:model="form"
|
||
:rules="rules"
|
||
layout="vertical"
|
||
size="large"
|
||
class="login-form"
|
||
@submit="handleLogin"
|
||
>
|
||
<a-form-item field="phone" hide-label>
|
||
<a-select :options="['+86']" style="flex: 1 1" default-value="+86" />
|
||
<a-input
|
||
v-model="form.phone"
|
||
:placeholder="$t('login.phone.placeholder.phone')"
|
||
:max-length="11"
|
||
allow-clear
|
||
/>
|
||
</a-form-item>
|
||
<a-form-item field="captcha" hide-label>
|
||
<a-input
|
||
v-model="form.captcha"
|
||
:placeholder="$t('login.phone.placeholder.captcha')"
|
||
:max-length="4"
|
||
allow-clear
|
||
style="flex: 1 1"
|
||
/>
|
||
<a-button
|
||
class="captcha-btn"
|
||
:loading="captchaLoading"
|
||
:disabled="captchaDisable"
|
||
@click="handleSendCaptcha"
|
||
>
|
||
{{ captchaBtnName }}
|
||
</a-button>
|
||
</a-form-item>
|
||
<a-button
|
||
class="btn"
|
||
:loading="loading"
|
||
type="primary"
|
||
html-type="submit"
|
||
:disabled="captchaDisable"
|
||
>{{ $t('login.button') }}(演示不开放)
|
||
</a-button>
|
||
</a-form>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { getCurrentInstance, ref, toRefs, reactive, computed } from 'vue';
|
||
import { useI18n } from 'vue-i18n';
|
||
import { useRouter } from 'vue-router';
|
||
import { ValidatedError } from '@arco-design/web-vue';
|
||
import { useUserStore } from '@/store';
|
||
import { PhoneLoginReq } from '@/api/auth';
|
||
import { getSmsCaptcha } from '@/api/common/captcha';
|
||
|
||
const { proxy } = getCurrentInstance() as any;
|
||
const { t } = useI18n();
|
||
const router = useRouter();
|
||
const userStore = useUserStore();
|
||
const loading = ref(false);
|
||
const captchaLoading = ref(false);
|
||
const captchaDisable = ref(true);
|
||
const captchaTime = ref(60);
|
||
const captchaTimer = ref();
|
||
const captchaBtnNameKey = ref('login.captcha.get');
|
||
const captchaBtnName = computed(() => t(captchaBtnNameKey.value));
|
||
const data = reactive({
|
||
form: {
|
||
phone: '',
|
||
captcha: '',
|
||
} as PhoneLoginReq,
|
||
rules: {
|
||
phone: [
|
||
{ required: true, message: t('login.phone.error.required.phone') },
|
||
{
|
||
match: /^1[3-9]\d{9}$/,
|
||
message: t('login.phone.error.match.phone'),
|
||
},
|
||
],
|
||
captcha: [
|
||
{ required: true, message: t('login.phone.error.required.captcha') },
|
||
],
|
||
},
|
||
});
|
||
const { form, rules } = toRefs(data);
|
||
|
||
/**
|
||
* 重置验证码
|
||
*/
|
||
const resetCaptcha = () => {
|
||
window.clearInterval(captchaTimer.value);
|
||
captchaTime.value = 60;
|
||
captchaBtnNameKey.value = 'login.captcha.get';
|
||
captchaDisable.value = false;
|
||
};
|
||
|
||
/**
|
||
* 发送验证码
|
||
*/
|
||
const handleSendCaptcha = () => {
|
||
if (captchaLoading.value) return;
|
||
proxy.$refs.formRef.validateField('phone', (valid: any) => {
|
||
if (!valid) {
|
||
captchaLoading.value = true;
|
||
captchaBtnNameKey.value = 'login.captcha.ing';
|
||
getSmsCaptcha(form.value.phone)
|
||
.then((res) => {
|
||
captchaLoading.value = false;
|
||
captchaDisable.value = true;
|
||
captchaBtnNameKey.value = `${t(
|
||
'login.captcha.get'
|
||
)}(${(captchaTime.value -= 1)}s)`;
|
||
captchaTimer.value = window.setInterval(() => {
|
||
captchaTime.value -= 1;
|
||
captchaBtnNameKey.value = `${t('login.captcha.get')}(${
|
||
captchaTime.value
|
||
}s)`;
|
||
if (captchaTime.value <= 0) {
|
||
resetCaptcha();
|
||
}
|
||
}, 1000);
|
||
proxy.$message.success(res.msg);
|
||
})
|
||
.catch(() => {
|
||
resetCaptcha();
|
||
captchaLoading.value = false;
|
||
});
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 登录
|
||
*
|
||
* @param errors 表单验证错误
|
||
* @param values 表单数据
|
||
*/
|
||
const handleLogin = ({
|
||
errors,
|
||
values,
|
||
}: {
|
||
errors: Record<string, ValidatedError> | undefined;
|
||
values: Record<string, any>;
|
||
}) => {
|
||
if (loading.value) return;
|
||
if (!errors) {
|
||
loading.value = true;
|
||
userStore
|
||
.phoneLogin({
|
||
phone: values.phone,
|
||
captcha: values.captcha,
|
||
})
|
||
.then(() => {
|
||
const { redirect, ...othersQuery } = router.currentRoute.value.query;
|
||
router.push({
|
||
name: (redirect as string) || 'Workplace',
|
||
query: {
|
||
...othersQuery,
|
||
},
|
||
});
|
||
proxy.$notification.success(t('login.success'));
|
||
})
|
||
.catch(() => {
|
||
form.value.captcha = '';
|
||
})
|
||
.finally(() => {
|
||
loading.value = false;
|
||
});
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.login-form {
|
||
box-sizing: border-box;
|
||
padding: 0 5px;
|
||
margin-top: 16px;
|
||
.arco-input-wrapper,
|
||
:deep(.arco-select-view-single) {
|
||
background-color: var(--color-bg-white);
|
||
border: 1px solid var(--color-border-3);
|
||
height: 40px;
|
||
border-radius: 4px;
|
||
font-size: 13px;
|
||
}
|
||
.arco-input-wrapper.arco-input-error {
|
||
background-color: var(--color-danger-light-1);
|
||
border-color: var(--color-danger-light-4);
|
||
}
|
||
|
||
.captcha-btn {
|
||
height: 40px;
|
||
margin-left: 12px;
|
||
min-width: 98px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.arco-btn-secondary:not(.arco-btn-disabled) {
|
||
background-color: #f6f8fa;
|
||
border: 1px solid #dde2e9;
|
||
color: #41464f;
|
||
}
|
||
.arco-btn-secondary:not(.arco-btn-disabled):hover {
|
||
background-color: transparent;
|
||
border: 1px solid rgb(var(--primary-6));
|
||
}
|
||
|
||
.btn {
|
||
border-radius: 4px;
|
||
box-shadow: 0 0 0 1px #05f, 0 2px 1px rgba(0, 0, 0, 0.15);
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
height: 40px;
|
||
line-height: 22px;
|
||
margin: 20px 0 12px;
|
||
width: 100%;
|
||
}
|
||
}
|
||
</style>
|