690 lines
18 KiB
Vue
690 lines
18 KiB
Vue
<template>
|
||
<div id="userLayout" :class="['user-layout-wrapper']">
|
||
<div class="top" style="display: none">
|
||
<!-- <div class="header">-->
|
||
<!-- <img :src="oemSiteInfo.sysLogoUrl" style="height: 30px;">-->
|
||
<!-- </div>-->
|
||
<!-- <a class="mch-url" href="#">
|
||
<span>服务商登录</span>
|
||
<i class="bi bi-arrow-right-short" />
|
||
</a> -->
|
||
</div>
|
||
<div
|
||
class="container"
|
||
:style="[
|
||
{ background: 'url(' + oemSiteInfo.agent.loginPageBGImgUrl + ')' },
|
||
{ backgroundSize: 'cover' },
|
||
{ backgroundPosition: 'center top' },
|
||
{ backgroundRepeat: 'no-repeat' },
|
||
]"
|
||
>
|
||
<div class="user-layout-lang" />
|
||
<div class="user-layout-content">
|
||
<!-- 错误提示信息 -->
|
||
<a-alert
|
||
v-if="showRegisterErrorInfo"
|
||
type="error"
|
||
showIcon
|
||
style="margin-bottom: 15px"
|
||
:message="showRegisterErrorInfo"
|
||
/>
|
||
<div class="main">
|
||
<div class="desc">服务商注册</div>
|
||
<a-form
|
||
ref="formRegister"
|
||
class="user-layout-login"
|
||
:model="formState"
|
||
:rules="vdata.rules"
|
||
@submit="handleSubmit"
|
||
>
|
||
<!-- <a-form-item name="agentName" class="input-item">-->
|
||
<!-- <login-text-up-->
|
||
<!-- v-model:value="formState.agentName"-->
|
||
<!-- placeholder="服务商名称"-->
|
||
<!-- />-->
|
||
<!-- </a-form-item>-->
|
||
<a-form-item name="phone" class="input-item">
|
||
<login-text-up
|
||
v-model:value="formState.phone"
|
||
placeholder="手机号"
|
||
/>
|
||
</a-form-item>
|
||
|
||
<div class="code-body">
|
||
<div
|
||
class="code code-layout-item"
|
||
style="display: flex; justify-content: center"
|
||
>
|
||
<a-form-item name="vercode" class="input-item">
|
||
<login-text-up
|
||
v-model:value="formState.vercode"
|
||
:isLogin="true"
|
||
placeholder="图形验证码"
|
||
/>
|
||
</a-form-item>
|
||
|
||
<div class="code-img" style="position: relative">
|
||
<img
|
||
v-show="vercodeImgSrc"
|
||
:src="vercodeImgSrc"
|
||
@click="refVercode()"
|
||
/>
|
||
<div
|
||
v-show="isOverdue"
|
||
class="vercode-mask"
|
||
@click="refVercode()"
|
||
>
|
||
已过期 请刷新
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="code">
|
||
<a-form-item name="code" class="input-item">
|
||
<login-text-up
|
||
v-model:value="formState.code"
|
||
placeholder="请输入验证码"
|
||
/>
|
||
</a-form-item>
|
||
<div>
|
||
<a-button
|
||
type="primary"
|
||
:disabled="vdata.isDisabled"
|
||
style="height: 40px; margin-left: 10px"
|
||
@click="sendSMS()"
|
||
>{{ vdata.codeBtnText }}</a-button
|
||
>
|
||
</div>
|
||
</div>
|
||
<a-form-item name="password" class="input-item">
|
||
<login-text-up
|
||
v-model:value="formState.password"
|
||
placeholder="登录密码"
|
||
isPassword="password"
|
||
/>
|
||
</a-form-item>
|
||
<a-form-item name="confirmPwd" class="input-item">
|
||
<login-text-up
|
||
v-model:value="formState.confirmPwd"
|
||
placeholder="确认登录密码"
|
||
isPassword="password"
|
||
/>
|
||
</a-form-item>
|
||
<a-form-item name="inviteCode" class="input-item">
|
||
<login-text-up
|
||
v-model:value="formState.inviteCode"
|
||
placeholder="请输入邀请码(选填)"
|
||
/>
|
||
</a-form-item>
|
||
<a-form-item name="checked">
|
||
<a-checkbox
|
||
class="checked_size"
|
||
v-model:checked="formState.checked"
|
||
@click.stop.prevent="check"
|
||
>我已阅读并同意<a
|
||
class="forge-password checked_size"
|
||
@click.stop.prevent="serviceAgreement"
|
||
>《服务协议》</a
|
||
>和<a class="forge-password checked_size" @click.stop.prevent="privacyPolicy"
|
||
>《隐私政策》</a
|
||
></a-checkbox
|
||
>
|
||
</a-form-item>
|
||
<a-form-item class="input-item">
|
||
<a class="forge-password checked_size_login" style="float: right" @click="toLogin"
|
||
>去登录 >></a
|
||
>
|
||
</a-form-item>
|
||
</a-form>
|
||
<a-button
|
||
size="large"
|
||
type="primary"
|
||
htmlType="submit"
|
||
class="login-button submit"
|
||
:loading="loginBtnLoadingFlag"
|
||
style="width: 100%"
|
||
@click="handleSubmit"
|
||
>
|
||
注册
|
||
</a-button>
|
||
</div>
|
||
<div class="footer" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<a-modal
|
||
v-model:visible="vdata.visible"
|
||
:title="vdata.toastTitle"
|
||
:footer="null"
|
||
width="70%"
|
||
>
|
||
<div style="height: 70vh; overflow: auto" v-html="vdata.toastContent" />
|
||
</a-modal>
|
||
</template>
|
||
<script setup lang="ts">
|
||
import { sendSmsCode, register, $getPasswordRules } from "@/api/login";
|
||
import { $getTreaty } from "@/api/manage";
|
||
import router from "@/router";
|
||
import { useRoute } from "vue-router";
|
||
import { message } from "ant-design-vue";
|
||
import { ref, reactive, onMounted } from "vue";
|
||
import { useOem } from "@/store/modules/oem";
|
||
import { vercode } from "@/api/login";
|
||
|
||
// 获取网站信息
|
||
const oemSiteInfo = useOem().getSiteInfo();
|
||
|
||
let loginPosition = ref(""); // 决定登录框水平位置 左中右?
|
||
let loginPageCardPosition = oemSiteInfo.agent.loginPageCardPosition;
|
||
if (loginPageCardPosition === "right") {
|
||
loginPosition.value = "flex-end";
|
||
} else if (loginPageCardPosition === "center") {
|
||
loginPosition.value = "center";
|
||
} else if (loginPageCardPosition === "left") {
|
||
loginPosition.value = "flex-start";
|
||
}
|
||
|
||
let loginBtnLoadingFlag = false; // 登录按钮是否显示 加载状态
|
||
let showRegisterErrorInfo = ref(""); // 是否显示登录错误面板信息
|
||
let timer: number = -1;
|
||
let formRegister = ref();
|
||
let isOverdue = ref(false); // 设置过期样式
|
||
let vercodeImgSrc = ref(""); // 验证码图片
|
||
let vercodeToken = ref(""); // 验证码验证token
|
||
|
||
let formState: any = reactive({
|
||
agentName: "",
|
||
phone: "",
|
||
code: "",
|
||
password: "",
|
||
confirmPwd: "",
|
||
checked: false,
|
||
inviteCode: null,
|
||
});
|
||
|
||
const vdata = reactive({
|
||
visibleCode:false,
|
||
codeBtnText: "发送验证码",
|
||
visible: false, // 对话框
|
||
toastContent: "", // 对话框内容
|
||
toastTitle: "", // 对话框标题
|
||
isDisabled: false,
|
||
checked: false,
|
||
passwordRules: /^$/, //密码规则
|
||
passwordRulesText: "", //密码规则提示文字
|
||
rules: {
|
||
agentName: [
|
||
{ required: true, message: "请输入服务商名称", trigger: "blur" },
|
||
],
|
||
phone: [
|
||
{
|
||
required: true,
|
||
pattern: /^1\d{10}$/,
|
||
message: "请输入正确的手机号",
|
||
trigger: "blur",
|
||
},
|
||
],
|
||
code: [{ required: true, message: "请输入验证码", trigger: "blur" }],
|
||
password: [
|
||
{ required: false, trigger: "blur" },
|
||
{
|
||
validator: (rule, value) => {
|
||
if (!vdata.passwordRules.test(formState.password)) {
|
||
return Promise.reject(vdata.passwordRulesText);
|
||
} else if (formState.password !== formState.confirmPwd) {
|
||
return Promise.reject("两次输入密码不一致");
|
||
} else return Promise.resolve();
|
||
},
|
||
},
|
||
],
|
||
confirmPwd: [
|
||
{ required: true, trigger: "blur", message: "请输入确认登录密码" },
|
||
{
|
||
validator: (rule, value) => {
|
||
if (!vdata.passwordRules.test(formState.password)) {
|
||
return Promise.reject(vdata.passwordRulesText);
|
||
} else if (formState.password !== formState.confirmPwd) {
|
||
return Promise.reject("两次输入密码不一致");
|
||
} else return Promise.resolve();
|
||
},
|
||
},
|
||
],
|
||
checked: [
|
||
{
|
||
type: "boolean",
|
||
required: true,
|
||
message: "请勾选用户隐私协议",
|
||
trigger: "check",
|
||
},
|
||
{
|
||
validator: (rule, value) => {
|
||
if (formState.checked) {
|
||
return Promise.resolve();
|
||
} else {
|
||
return Promise.reject("请勾选用户隐私协议");
|
||
}
|
||
},
|
||
},
|
||
],
|
||
},
|
||
});
|
||
|
||
onMounted(() => {
|
||
formState.inviteCode = useRoute().query.c;
|
||
getPasswordRules();
|
||
refVercode();
|
||
});
|
||
|
||
|
||
function refVercode() {
|
||
// 刷新图片验证码
|
||
// 获取图形验证码
|
||
vercode().then((res) => {
|
||
vercodeImgSrc.value = res.imageBase64Data;
|
||
vercodeToken.value = res.vercodeToken;
|
||
|
||
isOverdue.value = false;
|
||
|
||
if (timer) clearInterval(timer); // 如果多次点击则清除已有的定时器
|
||
// 超过60秒提示过期刷新
|
||
timer = window.setInterval(() => {
|
||
res.expireTime--;
|
||
if (res.expireTime <= 0) {
|
||
isOverdue.value = true;
|
||
clearInterval(timer);
|
||
}
|
||
}, 1000);
|
||
});
|
||
}
|
||
function sendSMSCode() {
|
||
vdata.visibleCode = true;
|
||
refVercode();
|
||
}
|
||
|
||
function getPasswordRules() {
|
||
// 获取密码规则
|
||
$getPasswordRules().then((res) => {
|
||
vdata.passwordRules = new RegExp(res.regexpRules);
|
||
vdata.passwordRulesText = res.errTips;
|
||
});
|
||
}
|
||
|
||
// handler
|
||
function handleSubmit() {
|
||
formRegister.value
|
||
.validate()
|
||
.then((valid) => {
|
||
let params = {
|
||
agentName: formState.phone,
|
||
phone: formState.phone,
|
||
code: formState.code,
|
||
confirmPwd: formState.confirmPwd,
|
||
inviteCode: formState.inviteCode,
|
||
};
|
||
register(params)
|
||
.then((res) => {
|
||
message.success("注册成功");
|
||
router.push({ path: "/user/login" }); // 校验成功,返回登录页
|
||
})
|
||
.catch((err) => {
|
||
showRegisterErrorInfo = err.msg || JSON.stringify(err);
|
||
loginBtnLoadingFlag = false;
|
||
});
|
||
})
|
||
.catch((valid) => {});
|
||
}
|
||
|
||
function sendSMS() {
|
||
// 发送短信验证
|
||
if (!formState.phone) {
|
||
return message.error("请输入手机号!");
|
||
}
|
||
// 校验手机号
|
||
const reg = /^[1][0-9]{10}$/;
|
||
if (!reg.test(formState.phone)) {
|
||
return message.error("请输入正确的手机号!");
|
||
}
|
||
vdata.isDisabled = true;
|
||
|
||
sendSmsCode({
|
||
phone: formState.phone,
|
||
smsType: "register",
|
||
vercode: formState.vercode,
|
||
vercodeToken: vercodeToken.value,
|
||
})
|
||
.then((res) => {
|
||
return message.success("发送成功!");
|
||
})
|
||
.catch((err) => {
|
||
vdata.isDisabled = false;
|
||
showRegisterErrorInfo = err.msg || JSON.stringify(err);
|
||
loginBtnLoadingFlag = false;
|
||
// 出错后三秒停止计时
|
||
setTimeout(() => {
|
||
if (timer) clearInterval(timer);
|
||
vdata.isDisabled = false;
|
||
vdata.codeBtnText = "发送短信验证码";
|
||
}, 500);
|
||
});
|
||
|
||
let time = 60; // 重发验证码时间
|
||
vdata.codeBtnText = `${time}秒后重新发送`;
|
||
const timer = setInterval(() => {
|
||
time -= 1;
|
||
vdata.codeBtnText = `${time}秒后重新发送`;
|
||
if (time === 0) {
|
||
clearInterval(timer);
|
||
vdata.isDisabled = false;
|
||
vdata.codeBtnText = "发送短信验证码";
|
||
}
|
||
}, 1000);
|
||
}
|
||
|
||
// 跳转页面
|
||
function toLogin() {
|
||
router.push({ name: "login", path: "/user/login" });
|
||
}
|
||
|
||
// 服务协议
|
||
function serviceAgreement() {
|
||
vdata.visible = true;
|
||
vdata.toastTitle = "服务协议";
|
||
// message.success('服务协议')
|
||
getTreaty("服务协议");
|
||
}
|
||
|
||
// 隐私政策
|
||
function privacyPolicy() {
|
||
vdata.visible = true;
|
||
vdata.toastTitle = "隐私政策";
|
||
getTreaty("隐私政策");
|
||
}
|
||
|
||
// 隐私协议与服务政策
|
||
const getTreaty = (name) => {
|
||
$getTreaty().then((res) => {
|
||
name === "服务协议"
|
||
? (vdata.toastContent = res.agentServiceAgreement)
|
||
: (vdata.toastContent = res.agentPrivacyPolicy);
|
||
});
|
||
};
|
||
|
||
// 勾选用户协议
|
||
function check() {
|
||
formState.checked = !formState.checked;
|
||
}
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
#userLayout.user-layout-wrapper {
|
||
height: 100%;
|
||
.top {
|
||
height: 80px;
|
||
padding: 0 35px;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
.header {
|
||
height: 44px;
|
||
line-height: 44px;
|
||
}
|
||
.mch-url {
|
||
display: flex;
|
||
align-items: center;
|
||
color: #000;
|
||
cursor: pointer;
|
||
span {
|
||
margin-right: 10px;
|
||
}
|
||
&:hover {
|
||
color: steelblue;
|
||
.bi {
|
||
transform: translateX(10px);
|
||
}
|
||
}
|
||
}
|
||
.bi {
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
.container {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center; //修改这一项来决定登录对话框的水平位置,flex-start == left; center == center; flex-end == right
|
||
flex-direction: column;
|
||
box-sizing: border-box;
|
||
padding: 0;
|
||
width: 100%;
|
||
//height: calc(100vh - 80px);
|
||
height: calc(100vh + 0px) !important;
|
||
background: #f0f2f5 url(/src/assets/svg/background.svg) no-repeat 50%;
|
||
background-size: cover;
|
||
//padding: 50px 0 84px;
|
||
position: relative;
|
||
transition: 0.3s ease;
|
||
|
||
.user-layout-lang {
|
||
width: 100%;
|
||
// height: 40px;
|
||
// line-height: 44px;
|
||
height: 0;
|
||
text-align: right;
|
||
}
|
||
|
||
.user-layout-content {
|
||
width: 100%;
|
||
height: 100%;
|
||
transition: 0.3s ease;
|
||
input {
|
||
height: 40px !important;
|
||
}
|
||
|
||
.main {
|
||
padding: 50px 30px;
|
||
box-sizing: border-box;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-start;
|
||
background: #fff;
|
||
border-top: 1px solid #e7eaf3;
|
||
align-items: center;
|
||
transition: all 0.3s, border 0s ease;
|
||
.ant-form {
|
||
max-width: 300px;
|
||
}
|
||
.desc {
|
||
font-weight: bold;
|
||
font-size: 20px;
|
||
letter-spacing: 0.04em;
|
||
color: #2691ff;
|
||
margin-bottom: 20px;
|
||
text-align: center;
|
||
}
|
||
.input-item {
|
||
margin-bottom: 20px;
|
||
}
|
||
}
|
||
|
||
.footer {
|
||
// position: absolute;
|
||
width: 100%;
|
||
bottom: 0;
|
||
padding: 0 16px;
|
||
margin: 48px 0 24px;
|
||
text-align: center;
|
||
|
||
.links {
|
||
margin-bottom: 8px;
|
||
font-size: 14px;
|
||
a {
|
||
color: rgba(0, 0, 0, 0.45);
|
||
transition: all 0.3s;
|
||
&:not(:last-child) {
|
||
margin-right: 40px;
|
||
}
|
||
}
|
||
}
|
||
.copyright {
|
||
color: rgba(0, 0, 0, 0.45);
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
}
|
||
|
||
a {
|
||
text-decoration: none;
|
||
}
|
||
}
|
||
|
||
//登录页响应式的调整
|
||
@media screen and (min-width: 769px) and (max-width: 1024px) {
|
||
.container {
|
||
padding: 0 100px;
|
||
min-height: 700px;
|
||
height: calc(100vh - 80px);
|
||
align-items: v-bind(loginPosition);
|
||
.user-layout-content {
|
||
width: 360px;
|
||
height: auto;
|
||
.main {
|
||
width: 360px;
|
||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||
border: 0.0625rem solid #e7eaf3;
|
||
height: auto;
|
||
justify-content: center;
|
||
border-radius: 10px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
@media screen and (min-width: 1025px) and (max-width: 1366px) {
|
||
.container {
|
||
padding: 0 150px;
|
||
min-height: 700px;
|
||
height: calc(100vh - 80px);
|
||
align-items: v-bind(loginPosition);
|
||
.user-layout-content {
|
||
width: 360px;
|
||
height: auto;
|
||
.main {
|
||
width: 360px;
|
||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||
border: 0.0625rem solid #e7eaf3;
|
||
height: auto;
|
||
justify-content: center;
|
||
border-radius: 10px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
@media screen and (min-width: 1367px) and (max-width: 1600px) {
|
||
.container {
|
||
padding: 0 250px;
|
||
min-height: 700px;
|
||
height: calc(100vh - 80px);
|
||
align-items: v-bind(loginPosition);
|
||
.user-layout-content {
|
||
width: 360px;
|
||
height: auto;
|
||
.main {
|
||
width: 360px;
|
||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||
border: 0.0625rem solid #e7eaf3;
|
||
height: auto;
|
||
justify-content: center;
|
||
border-radius: 10px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
@media screen and (min-width: 1601px) {
|
||
.container {
|
||
padding: 0 300px;
|
||
min-height: 700px;
|
||
height: calc(100vh - 80px);
|
||
align-items: v-bind(loginPosition);
|
||
.user-layout-content {
|
||
width: 360px;
|
||
height: auto;
|
||
.main {
|
||
width: 360px;
|
||
box-shadow: 0 6px 12px rgb(140 152 164 / 8%);
|
||
border: 0.0625rem solid #e7eaf3;
|
||
height: auto;
|
||
justify-content: center;
|
||
border-radius: 10px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<style lang="less" scoped>
|
||
.user-layout-login {
|
||
label {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.forge-password {
|
||
font-size: 14px;
|
||
color: @jee-theme;
|
||
}
|
||
|
||
button.login-button {
|
||
padding: 0 15px;
|
||
font-size: 16px;
|
||
height: 40px;
|
||
width: 100%;
|
||
}
|
||
|
||
.user-login-other {
|
||
text-align: left;
|
||
margin-top: 24px;
|
||
line-height: 22px;
|
||
|
||
.item-icon {
|
||
font-size: 24px;
|
||
color: rgba(0, 0, 0, 0.2);
|
||
margin-left: 16px;
|
||
vertical-align: middle;
|
||
cursor: pointer;
|
||
transition: color 0.3s;
|
||
|
||
&:hover {
|
||
color: #1890ff;
|
||
}
|
||
}
|
||
|
||
.register {
|
||
float: right;
|
||
}
|
||
}
|
||
.code {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
.code-input {
|
||
width: 216px;
|
||
}
|
||
.code-img {
|
||
width: 120px;
|
||
height: 40px;
|
||
margin-left: 10px;
|
||
}
|
||
}
|
||
.submit {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
|
||
.checked_size {
|
||
font-size: 12px !important;
|
||
}
|
||
.checked_size_login {
|
||
margin-bottom: 15px;
|
||
}
|
||
</style>
|