首先,通过getCode方法调用api接口,在调用接口前,需要对表单中的电话号码进行校验,可以使用element-plus的validateField方法对表单的单一字段进行校验。调用api接口成功获取验证码之后,调用倒计时方法。获取失败则对错误进行处理。
通过调用倒计时方法修改获取验证码的按钮状态,防止用户多次点击。
获取验证码成功之后调用登录方法,进行登录接口,登录成功跳转至首页
全部代码如下:
<template>
<div class="form">
<div class="code">
<div class="image-wrapper_15 flex-row">
<img
class="label_14"
referrerpolicy="no-referrer"
src="https://lanhu.oss-cn-beijing.aliyuncs.com/c4fe81a8aa2ee4dda5afd4861e3a168c"
/>
<img
class="image_26"
referrerpolicy="no-referrer"
src="https://lanhu.oss-cn-beijing.aliyuncs.com/8307344052962e63f1e639924c80db38"
/>
</div>
<div class="hidden_image"></div>
</div>
<div class="form">
<p class="form-title">登录</p>
<el-form ref="formRef" :model="form" :rules="rules" size="small">
<el-form-item prop="user_phone">
<el-input v-model="form.user_phone" class="w-50 m-2" placeholder="请输入手机号" size="large">
<template #append>
<el-button
size="large"
style="width: 150px; color: white; background-color: #409eff"
@click="getCode(formRef)"
:loading="code_loading"
:disabled="code_disabled"
>
{{ code_text }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item prop="code">
<el-input v-model="form.code" class="w-50 m-2" placeholder="请输入验证码" size="large" />
</el-form-item>
</el-form>
<div class="check-btn">
<el-checkbox size="large" :checked="accept" @change="isAccept">
我已阅读并接受
<el-button link size="large" style="margin-bottom: 2px; color: #409eff">服务条款</el-button>
</el-checkbox>
</div>
<el-button style="color: white; background-color: #409eff; border-radius: 20px" size="large" @click="onSubmit(formRef)">
登录/注册
</el-button>
<!-- <el-button link size="large" @click="register('register')" style="margin-top: 20px; color: #409eff">立即注册</el-button> -->
</div>
</div>
</template>
<script lang="ts" setup>
import { ElMessage, ElNotification, FormInstance } from "element-plus";
import { onBeforeUnmount, onMounted, ref } from "vue";
import { useRouter } from "vue-router";
import { useUserStore } from "@/stores/modules/user";
import { getTimeState } from "@/utils/index";
import { initDynamicRouter } from "@/routers/modules/dynamicRouter";
import { HOME_URL } from "@/config";
import { checkPhoneNumber } from "@/utils/eleValidate";
import { CodeApi, phoneLoginApi } from "@/api/modules/login";
const accept = ref<boolean>(false);
const userStore = useUserStore();
const formRef = ref<FormInstance>();
const router = useRouter();
const loading = ref(false);
const code_text = ref("获取验证码");
const code_disabled = ref(false);
const code_loading = ref(false);
const code_timer = ref<number | null | undefined>();
const form = ref({
//表单信息
user_phone: "",
code: ""
});
const getCode = (formRef: FormInstance | undefined) => {
if (!formRef) {
return;
}
formRef.validateField("user_phone", (valid: any) => {
if (valid) {
code_loading.value = true;
code_text.value = "发送中";
CodeApi({ mobile: form.value.user_phone })
.then(res => {
if (res.code === 200) {
ElMessage.success("获取成功");
countdown();
}
})
.catch(() => {
code_loading.value = false;
code_text.value = "获取验证码";
});
}
});
};
const validateVcode = (rule: any, value: any, callback: any) => {
//自定义验证
if (value === "") {
callback(new Error("验证码不能为空"));
} else {
callback();
}
};
//表单验证
const rules = ref({
user_phone: [{ validator: checkPhoneNumber, trigger: "change" }],
code: [{ validator: validateVcode, trigger: "change" }]
});
const onSubmit = (formRef: FormInstance | undefined) => {
if (!formRef) {
return;
}
formRef.validate((valid: any) => {
//执行规则验证
if (valid) {
//通过时执行
if (!accept.value) {
ElMessage.error("请选择接受服务条款");
return;
}
login();
} else {
return false;
}
});
};
const login = async () => {
loading.value = true;
try {
// 1.执行登录接口
await phoneLoginApi({ mobile: form.value.user_phone, code: form.value.code }).then(res => {
userStore.setToken(res.data.token);
});
// 2.添加动态路由
await initDynamicRouter();
// // 3.清空 tabs、keepAlive 数据
// tabsStore.closeMultipleTab();
// keepAliveStore.setKeepAliveName();
// 4.跳转到首页
router.push(HOME_URL);
ElNotification({
title: getTimeState(),
message: "欢迎登录-灵工谷",
type: "success",
duration: 3000
});
} finally {
loading.value = false;
}
};
const isAccept = () => {
accept.value = !accept.value;
};
onMounted(() => {
// 监听 enter 事件(调用登录)
document.onkeydown = (e: KeyboardEvent) => {
e = (window.event as KeyboardEvent) || e;
if (e.code === "Enter" || e.code === "enter" || e.code === "NumpadEnter") {
if (loading.value) return;
onSubmit(formRef.value);
}
};
});
/** 倒计时 */
const countdown = () => {
let second = 60; // 默认时间
code_loading.value = false; // 取消加载
code_disabled.value = true; // 禁用按钮
code_text.value = `${second}秒`; // 按钮文本
// 判断是否存在定时器,存在则先清除
if (code_timer.value) {
clearInterval(code_timer.value);
}
// 开启定时器
code_timer.value = Number(
setInterval(() => {
second--;
code_text.value = `${second}秒`; // 按钮文本
if (second <= 0) {
code_text.value = `重新获取`; // 按钮文本
code_disabled.value = false; // 启用按钮
clearInterval(code_timer.value as number); // 清除倒计时
}
}, 1000)
);
};
// 组件销毁之前 - 生命周期
onBeforeUnmount(() => {
clearInterval(code_timer.value as number); // 清除倒计时
});
</script>