You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ocr-web/src/views/login/components/Login.vue

676 lines
18 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script lang="ts" setup>
import { computed, onMounted, reactive, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useMessage } from "naive-ui";
// import captcha from './captcha.vue'
import { PageEnum } from "@/enums/pageEnum";
import { useUserStore } from "@/store/modules/user";
import { ResultEnum } from "@/enums/httpEnum";
import { getCode, smsLogin } from "@/api/login/login";
import SvgIcon from "@/components/Icon/SvgIcon.vue";
const emit = defineEmits(["close", "forget"]);
interface FormState {
enterprisecode?: string;
username: string;
password: string;
}
interface FormSms {
agentcode: string;
phone: string;
phonecode: string;
}
const formRef = ref();
const formRefSms = ref();
const message = useMessage();
const loading = ref(false);
const autoLogin = ref(false);
const LOGIN_NAME = PageEnum.BASE_LOGIN_NAME;
const userStore = useUserStore();
const router = useRouter();
const route = useRoute();
const show = ref(false);
const flag = ref(true);
const loginSuccess = ref(true);
const loginRejectMessge = ref("");
let formInline: FormState = reactive({
// enterprisecode: "演示公司",
// username: "yanshi01",
// password: "123456",
enterprisecode: "",
username: "",
password: "",
});
let formSms: FormSms = reactive({
agentcode: "",
phone: "",
phonecode: "",
});
const tab = ref(0);
const countTime = ref("获取验证码");
const rules = {
enterprisecode: [
{ required: true, message: "请输入企业编码", trigger: "blur" },
{
trigger: ["blur", "input", "change"],
level: "error",
validator(_rule, value) {
if (loginSuccess.value || !value) {
return true;
}
if (loginRejectMessge.value.indexOf("企业") > -1) {
return new Error(loginRejectMessge.value);
}
},
},
],
agentcode: [
{ required: true, message: "请输入验证码", trigger: "blur" },
{
trigger: ["blur", "input", "change"],
level: "error",
validator(_rule, value) {
if (loginSuccess.value || !value) {
return true;
}
if (loginRejectMessge.value.indexOf("验证码") > -1) {
return new Error(loginRejectMessge.value);
}
},
},
],
phone: [
{ required: true, message: "请输入手机号", trigger: "blur" },
{
trigger: ["blur", "input", "change"],
level: "error",
validator(_rule, value) {
if (loginSuccess.value || !value) {
return true;
}
if (loginRejectMessge.value.indexOf("手机号") > -1) {
return new Error(loginRejectMessge.value);
}
},
},
],
phonecode: [
{ required: true, message: "请输入验证码", trigger: "blur" },
{
trigger: ["blur", "input", "change"],
level: "error",
validator(_rule, value) {
if (value.length < 4 && value.length > 0) {
return new Error("请正确填写4位手机短信验证码");
}
if (loginSuccess.value || !value) {
return true;
}
if (loginRejectMessge.value.indexOf("验证码") > -1) {
return new Error(loginRejectMessge.value);
}
},
},
],
username: [
{ required: true, message: "请输入账号", trigger: "blur" },
{
trigger: ["blur", "input", "change"],
level: "error",
validator(_rule, value) {
if (loginSuccess.value || !value) {
return true;
}
if (loginRejectMessge.value.indexOf("账号") > -1) {
return new Error(loginRejectMessge.value);
}
},
},
],
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{
trigger: ["blur", "input", "change"],
level: "error",
validator(_rule, value) {
if (loginSuccess.value || !value) {
return true;
}
if (loginRejectMessge.value.indexOf("密码") > -1) {
return new Error(loginRejectMessge.value);
}
},
},
],
captcha: [{ required: true, message: "请输入验证码", trigger: "blur" }],
};
function handleSubmit(e) {
e.preventDefault();
loginSuccess.value = true;
formRef.value.validate(async (errors) => {
if (!errors) {
const { username, password, enterprisecode } = formInline;
message.loading("登录中...");
loading.value = true;
const params = {
username,
password,
codetoken: userStore.getCapToken,
agentcode: enterprisecode,
};
try {
const { code, message: msg } = await userStore.login(params);
loginRejectMessge.value = msg;
if (code === ResultEnum.SUCCESS) {
// 是否保存账号
if (autoLogin.value) {
localStorage.setItem("LOGIN_FORM_PASS", JSON.stringify(formInline));
} else {
localStorage.removeItem("LOGIN_FORM_PASS");
}
loginSuccess.value = true;
const { data: userInfo } = await userStore.getInformation();
message.destroyAll();
const toPath = decodeURIComponent((route.query?.redirect || "/") as string);
message.success("登录成功,即将进入系统");
if (route.name === LOGIN_NAME)
router.replace(
userInfo.frontmenuTList ? userInfo.frontmenuTList[0]["resUrl"] : "/"
);
else router.replace(toPath);
} else {
loginSuccess.value = false;
message.destroyAll();
message.info(msg || "登录失败");
formRef.value.validate();
}
} finally {
loading.value = false;
}
} else {
message.error("请填写完整信息,并且进行验证码校验");
}
});
}
onMounted(() => {
let data: any = localStorage.getItem("LOGIN_FORM_SMS");
if (data) {
data = JSON.parse(data) as any;
formSms.agentcode = data.agentcode;
formSms.phone = data.phone;
formSms.phonecode = "";
autoLogin.value = true;
}
data = localStorage.getItem("LOGIN_FORM_PASS");
if (data) {
data = JSON.parse(data) as any;
formInline.username = data.username;
formInline.password = "";
// formInline.password = data.password;
formInline.enterprisecode = data.enterprisecode;
autoLogin.value = true;
}
});
function handleSmsSubmit(e) {
e.preventDefault();
loginSuccess.value = true;
formRefSms.value.validate(async (errors) => {
if (!errors) {
const { phone, agentcode, phonecode } = formSms;
message.loading("登录中...");
loading.value = true;
try {
const res = await smsLogin({
phone,
agentcode,
phonecode,
});
const { code, message: msg } = res;
loginRejectMessge.value = msg;
if (code === ResultEnum.SUCCESS) {
// 是否保存账号
if (autoLogin.value) {
localStorage.setItem("LOGIN_FORM_SMS", JSON.stringify(formSms));
} else {
localStorage.removeItem("LOGIN_FORM_SMS");
}
loginSuccess.value = true;
// const { code, message: msg } = await userStore.login(params)
await userStore.setStorageToken(res.data);
const { data: userInfo } = await userStore.getInformation();
message.destroyAll();
const toPath = decodeURIComponent((route.query?.redirect || "/") as string);
message.success("登录成功,即将进入系统");
if (route.name === LOGIN_NAME)
router.replace(
userInfo.frontmenuTList ? userInfo.frontmenuTList[0]["resUrl"] : "/"
);
else router.replace(toPath);
} else {
message.destroyAll();
message.info(msg || "登录失败");
loginSuccess.value = false;
formRefSms.value.validate();
}
} catch (e) {
} finally {
loading.value = false;
}
} else {
message.error("请填写完整信息,并且进行验证码校验");
}
});
}
function close() {
loading.value = false;
emit("close");
}
function switchTab(type: number) {
loading.value = false;
tab.value = type;
}
function computedForm() {
if (tab.value == 0) {
return !formInline.enterprisecode || !formInline.username || !formInline.password;
}
if (tab.value == 1) {
return !formSms.agentcode || !formSms.phone || !formSms.phonecode;
}
}
async function sendCode(value) {
if (!formSms.phone) return;
if (!flag.value) return;
flag.value = false;
const res = await getCode({
phone: formSms.phone,
agentcode: formSms.agentcode,
});
if(res.code == 'OK'){
startCount();
}else{
message.error(res.message)
}
}
function startCount() {
let time = 60;
countTime.value = "60s";
const timer = setInterval(() => {
countTime.value = `${--time}s`;
if (time === 0) {
clearInterval(timer);
countTime.value = "重新获取";
flag.value = true;
}
}, 1000);
}
function forget() {
loading.value = false;
emit("forget");
}
</script>
<template>
<div class="form-login">
<img class="img-close" src="@/assets/images/login/close.png" alt="" @click="close" />
<div class="tab">
<div
:class="{ 'tab-item-active': tab === 0 }"
class="tab-item"
@click="switchTab(0)"
>
密码登录
<div class="line" />
</div>
<div
:class="{ 'tab-item-active': tab === 1 }"
class="tab-item"
@click="switchTab(1)"
>
短信登录
<div class="line" />
</div>
</div>
<div v-if="tab === 0" class="form-1">
<n-form
ref="formRef"
label-placement="left"
size="large"
:model="formInline"
:rules="rules"
>
<n-form-item class="form-item" path="enterprisecode">
<n-input
v-model:value="formInline.enterprisecode"
class="item-input"
placeholder="请输入企业编码"
maxlength="20"
>
<template #prefix>
<svg-icon size="20" name="enterprise" />
</template>
</n-input>
</n-form-item>
<n-form-item class="form-item" path="username">
<n-input
v-model:value="formInline.username"
class="item-input"
placeholder="请输入用户名"
maxlength="16"
>
<template #prefix>
<svg-icon size="20" name="account" />
</template>
</n-input>
</n-form-item>
<n-form-item class="form-item" path="password">
<n-input
v-model:value="formInline.password"
class="item-input"
type="password"
show-password-on="click"
placeholder="请输入密码"
maxlength="16"
>
<template #prefix>
<svg-icon size="20" name="password" />
</template>
</n-input>
</n-form-item>
<!-- <n-form-item class="form-item"> -->
<n-button
:class="{ 'btn-disabled': computedForm() }"
class="btn"
type="primary"
size="large"
:loading="loading"
block
@click="handleSubmit"
:disabled="computedForm()"
>
登录
</n-button>
<!-- </n-form-item> -->
<n-form-item class="default-color">
<div class="flex justify-between w-full">
<div class="flex-initial">
<n-checkbox v-model:checked="autoLogin">
<span class="forgetSpan">记住账号</span>
</n-checkbox>
</div>
<div class="flex-initial order-last" @click="forget">
<a href="javascript:">忘记密码?</a>
</div>
</div>
</n-form-item>
</n-form>
</div>
<div v-else class="form-1">
<n-form
ref="formRefSms"
label-placement="left"
size="large"
:model="formSms"
:rules="rules"
>
<n-form-item class="form-item" path="agentcode">
<n-input
v-model:value="formSms.agentcode"
class="item-input"
placeholder="请输入企业编码"
>
<template #prefix>
<svg-icon size="20" name="enterprise" />
</template>
</n-input>
</n-form-item>
<n-form-item class="form-item" path="phone">
<n-input
v-model:value="formSms.phone"
class="item-input"
placeholder="请输入手机号"
maxlength="11"
>
<template #prefix>
<img
class="img-phone"
src="@/assets/images/login/phone.png"
alt=""
@click="close"
/>
</template>
</n-input>
</n-form-item>
<n-form-item class="form-item" path="phonecode">
<n-input
v-model:value="formSms.phonecode"
maxlength="4"
class="item-input"
placeholder="请输入验证码"
clearable
>
<template #prefix>
<img
class="img-phone"
src="@/assets/images/login/auth.png"
alt=""
@click="close"
/>
</template>
<template #suffix>
<div
:class="{
'code-count':
countTime !== '获取验证码' || !(formSms.phone.length == 11),
}"
class="code"
@click="sendCode"
>
{{ countTime }}
</div>
</template>
</n-input>
</n-form-item>
<!-- <n-form-item class="form-item"> -->
<n-button
:class="{ 'btn-disabled': computedForm() }"
class="btn"
type="primary"
size="large"
:loading="loading"
block
@click="handleSmsSubmit"
:disabled="computedForm()"
>
登录
</n-button>
<!-- </n-form-item> -->
<n-form-item class="default-color">
<div class="flex justify-between w-full">
<div class="flex-initial save-btn">
<n-checkbox v-model:checked="autoLogin">
<span class="forgetSpan">记住账号</span>
</n-checkbox>
</div>
<div class="flex-initial order-last" @click="forget">
<a href="javascript:">忘记密码</a>
</div>
</div>
</n-form-item>
</n-form>
</div>
</div>
</template>
<style lang="less" scoped>
.form-login {
width: 26.25rem;
height: 26.0625rem;
box-sizing: border-box;
background: linear-gradient(
136deg,
rgba(226, 236, 255, 0.8) 3%,
rgba(251, 251, 251, 0.8) 97%
);
border: 1px solid #ffffff;
border-radius: 6px;
box-shadow: 0px 6px 12px 0px rgba(0, 0, 0, 0.04);
backdrop-filter: blur(12px);
position: relative;
padding: 3rem 1.6875rem 2rem;
.img-close {
position: absolute;
right: 0;
top: -2.75rem;
width: 1.75rem;
height: 1.75rem;
cursor: pointer;
}
.tab {
display: flex;
.tab-item {
width: 4.5rem;
height: 1.5625rem;
font-size: 1.125rem;
font-family: PingFang SC, PingFang SC-Medium;
font-weight: 600;
text-align: left;
color: #666666;
line-height: 2.0625rem;
margin-right: 1.5rem;
cursor: pointer;
&-active {
width: 6rem;
height: 2.0625rem;
font-size: 1.5rem;
font-family: PingFang SC, PingFang SC-Medium;
font-weight: 600;
text-align: left;
color: #507afd;
line-height: 2.0625rem;
.line {
background: linear-gradient(234deg, #96aaff 0%, #1c43ff 100%);
}
}
.line {
width: 2rem;
height: 0.25rem;
border-radius: 2px;
margin: 0 auto;
margin-top: 0.5625rem;
}
}
}
.form-1 {
margin-top: 1.8125rem;
.form-item {
height: 3.75rem;
}
.item-input {
width: 22.875rem;
// height: 2.75rem;
background: rgba(255, 255, 255, 0.5);
border-radius: 4px;
// margin-bottom: 1rem;
font-size: 1rem;
}
.btn {
width: 22.875rem;
height: 2.75rem;
background: linear-gradient(234deg, #96aaff 0%, #1c43ff 100%);
border-radius: 3px;
margin-top: 1rem;
// margin-bottom: -0.875rem;
&-disabled {
opacity: 0.5;
background: linear-gradient(234deg, #96aaff 0%, #1c43ff 100%);
}
}
}
.img-phone {
width: 1.25rem;
height: 1.25rem;
}
.order-last {
font-size: 1rem;
font-family: PingFang SC, PingFang SC-Regular;
font-weight: Regular;
color: #507afd;
}
.code {
font-size: 0.9375rem;
font-family: PingFang SC, PingFang SC-Regular;
font-weight: Regular;
color: #507afd;
margin-left: 0.75rem;
cursor: pointer;
&-count {
font-size: 0.875rem;
color: #999999;
}
}
}
::v-deep(.n-form-item-feedback--error) {
color: #ff4e4f !important;
}
.forgetSpan {
font-size: 0.9375rem;
font-family: PingFang SC, PingFang SC-Regular;
font-weight: Regular;
text-align: center;
color: #999999;
line-height: 1rem;
}
::v-deep(.n-base-clear > .n-base-clear__clear > .n-base-icon > svg) {
color: #c9c9c9;
}
::v-deep(.n-input .n-input__input-el) {
height: 2.75rem !important;
font-size: 1rem !important;
}
::v-deep(.n-input .n-input-wrapper) {
height: 2.75rem !important;
}
.save-btn {
font-size: 0.9375rem;
}
::v-deep(.n-form-item .n-form-item-feedback-wrapper) {
height: 1rem;
padding: 0 !important;
margin: 0 !important;
line-height: normal !important;
min-height: 0 !important;
// margin-bottom: .5rem;
}
</style>