pc端
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.
 
 
 
 
 
 

681 lines
25 KiB

<template>
<div style="background-color: #121318;">
<div class="vh-100 d-flex justify-content-center" style="align-items: center;height: 80vh !important;">
<div class="form-access my-auto">
<form class="register-body bg-panel">
<div class="text-center h3">
<span>{{$t('login.goRegister')}}</span>
</div>
<!-- Step1 -->
<template v-if="step == 1">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item" @click="registerType = 1">
<a :class="[`nav-link`, {active : registerType == 1}]" id="email-tab" data-toggle="tab" href="#email" role="tab" aria-controls="email" :aria-selected="registerType == 1">{{$t('login.email')}}</a>
</li>
<!-- <li class="nav-item" @click="registerType = 2">
<a :class="[`nav-link`, {active : registerType == 2}]" id="phone-tab" data-toggle="tab" href="#phone" role="tab" aria-controls="phone" :aria-selected="registerType == 2">{{$t('login.phone')}}</a>
</li> -->
</ul>
<!-- 切换显示不同类型的账号 -->
<div class="tab-content" id="myTabContent">
<!-- email address active为切换时的动画效果
show为默认的控制显示 这里替换为v-if的渲染 这样email和phone只能存在一个 避免同时创建require规则时报错-->
<div class="tab-pane fade" :class="{show:registerType == 1, active:registerType == 1}" v-if="registerType==1" id="email" role="tabpanel" aria-labelledby="email-tab">
<div class="form-group">
<input type="email" name="email" class="form-control" :placeholder="$t('login.pleaseEmail')" v-model="user.email" :data-has="$t('login.pleaseEmail')" :data-message="$t('login.invalidEmail')" />
</div>
</div>
<!-- phone number -->
<div class="tab-pane fade" :class="{show:registerType == 2, active:registerType == 2}" v-if="registerType==2" id="phone" role="tabpanel" aria-labelledby="phone-tab">
<div class="form-group">
<div class="d-flex">
<div class="mr-2">
<el-select v-model="user.country_id" filterable :placeholder="$t('login.country')">
<el-option v-for="(item, index) in cacheOption" :key="index" :value="`${item.id}`" :label="`+${item.country_code} ${item.name} ${item.code}`"></el-option>
</el-select>
</div>
<input type="text" name="phone" class="form-control" :placeholder="$t('login.enterMobile')" v-model="user.phone" :data-has="$t('login.enterMobile')"/>
</div>
</div>
</div>
</div>
<div class="form-group row password">
<input :type="pwdType" id="password" v-model="user.password" required :placeholder="$t('login.password')" class="form-control" />
<label for="password" @click="showType('pwdType')"></label>
</div>
<div class="form-group row password">
<!-- 使用data-type指定额外的类型验证 -->
<input :type="repwdType" id="repassword" v-model="user.repassword" required :placeholder="$t('login.confirm-password')" class="form-control" />
<label @click="showType('repwdType')"></label>
</div>
<div class="form-group row">
<input type="text" class="form-control" :disabled="$route.query.invite_code?true:false" v-model="user.parentCode" :placeholder="`${$t('login.referrer')}`" />
<!-- (${$t('login.optional')}) -->
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="form-checkbox" v-model="isAgree" />
<label class="custom-control-label" for="form-checkbox">
{{$t('login.iSee')}}
<router-link to="service/10">
<a>{{$t('login.terms')}}</a>
</router-link>
</label>
</div>
<button type="submit" class="btn btn-primary rounded-pill" @click.prevent.stop="step1">{{$t('login.reg')}}</button>
</template>
<!-- Step3 -->
<template v-if="step == 3">
<div v-if="registerType === 1" class="verify-code">
<div class="form-text text-muted">
{{$t('login.enterEmailCode',{email:ajar.email,num:6})}}
<br />
{{$t('login.accountActivated')}},
<a href @click.prevent="step = 1;">{{$t('login.backOld')}}</a>。
</div>
<section class="my-codes">
<header class="my-codes__title">{{$t('login.verCode')}}</header>
<div class="my-codes__controls">
<input type="text" v-for="pos in 6" :key="pos" pattern="[0-9]*" @focus="current=pos" @blur="current=-1" ref="spaces" class="form-control" @keyup="handleKeyUp(pos-1, $event)" @input="handleInput(pos-1, $event)" @paste="autofill" />
</div>
</section>
<aside class="prompt">
<header class="prompt__no-recieved">{{$t('login.notEmail')}}:</header>
<ul class="prompt__inner">
<li>· {{$t('login.confirmEmail')}}。</li>
<li>· {{$t('login.confing')}}。</li>
<li>· {{$t('login.checkTrashCan')}}。</li>
</ul>
</aside>
</div>
<div v-if="registerType === 2" class="verify-code">
<div class="form-text text-muted">
{{$t('login.enterPhone1')}} (
<b>{{ ajar.phone }}</b>
) {{$t('login.enterPhone2',{num:6})}}
<br />
{{$t('login.accountActivated')}},
<a href @click.prevent="step = 1;">{{$t('login.backOld')}}</a>。
</div>
<section class="my-codes">
<header class="my-codes__title">Code</header>
<div class="my-codes__controls">
<input type="text" v-for="pos in 6" :key="pos" pattern="[0-9]*" @focus="current=pos" @blur="current=-1" ref="spaces" class="form-control" @keyup="handleKeyUp(pos-1, $event)" @input="handleInput(pos-1, $event)" @paste="autofill" />
</div>
</section>
<aside class="prompt">
<header class="prompt__no-recieved">{{$t('login.smsNotReceived')}}:</header>
<ul class="prompt__inner">
<li>· {{$t('login.phoneCorrect')}}。</li>
<li>· {{$t('login.securePhone')}}。</li>
</ul>
</aside>
</div>
</template>
</form>
<h2>
{{$t('login.hasAccount')}}?
<router-link to="sign-in">{{$t('login.toLogin')}}</router-link>
</h2>
</div>
</div>
<!-- Step2 滑块验证码Modal弹框 使用javascript控制-->
<div class="modal fade" id="captcha" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-sm" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{$t('login.safety')}}</h5>
<!-- 自定义刷新验证码按钮 -->
<a href class="refresh" @click.prevent="refreshSlider">
<img src="@/assets/img/icon-refresh.svg" alt />
</a>
<!-- 模态原生支持的关闭按钮 -->
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<img src="@/assets/img/icon-close.svg" alt />
<!-- &times; 自带图标 -->
</button>
</div>
<!-- <div class="modal-body">
...
</div>-->
<iframe name="my-modal-body" class="my-modal-body" :src="`/static/SliderCaptcha/src/index.html?`+ encodeURIComponent(`nextStep=step2Register&slider_type=register&account=${account}&lang=${lang}`)" frameborder="0"></iframe>
</div>
</div>
</div>
</div>
</template>
<script>
import md5 from "md5";
import Member from "@/api/member";
export default {
data() {
return {
current: 0,
pwdType: "password",
repwdType: "password",
step: 1,
registerType:1,
cacheRegisterType: null, // 注册类型中间值
user: {
name: "",
email: "",
password: "",
repassword: "",
country_id: "", // 区号id
phone: "",
parentCode: ""
},
isAgree: false,
options: [], // 原始数据
cacheOption: [],
storeOption: null, // 存储的有效options
storeTel: null, // 存储的tel
valueTel: "",
valueTelPhone: "",
showBox: false, //滑动弹窗
ajar: {
email: "",
phone: ""
},
skipKeyup: null,
skipInput: null,
isFirst: {
smsCode: null,
emailCode: null
},
codes: new Array(6)
};
},
computed: {
// 当前语言
lang() {
let UALang = navigator.language.includes("zh") ? "cn" : "en";
return localStorage.lang || UALang;
},
// 根据语言切换注册的类型 2为手机 1为邮箱
registerType: {
get() {
if (this.cacheRegisterType) return this.cacheRegisterType;
else return this.lang == "cn" ? 2 : 1;
},
set(val) {
// 缓存注册类型值
this.cacheRegisterType = val;
}
},
//
account() {
return this.registerType === 2 ? this.user.phone : this.user.email;
},
// 当前选中的区号
country() {
return (
this.cacheOption.find(item => item.id == this.user.country_id) || {}
);
}
},
methods: {
showType(type) {
this[type] = this[type] == "text" ? "password" : "text";
},
step1: _.throttle(function () {
if (utils.validate(".register-body")) {
if (this.user.password !== this.user.repassword) {
this.$message(
{
type: "error",
message: this.$t('login.confirmpassword') + "!"
},
1000
);
return
}
// 其他补充的验证
if (!this.isAgree) {
// 没有同意条款
this.$message(
{
type: "warning",
message: this.$t("login.disagree") + "!"
},
1000
);
return;
}
if (this.user.parentCode=="") {
// 没有填写推荐人
this.$message(
{
type: "warning",
message: this.$t("login.referrer1") + "!"
},
1000
);
return;
}
// 滑块安全性验证
// if (this.user.parentCode) {
// // this.chkRefer(this.user.parentCode, () => {
// // this.showBox = true;
// // });
// } else {
// 调用模态框
// if (utils.isMobile()) {
this.step2();
// return;
// }
// $("#captcha").modal({
// backdrop: "static" // 点击背景时不关闭动态模态框
// // keyboard : true, // 按下esc时关闭动态视窗
// // show : false, // 初始化不显示
// });
// }
}
}, 1000),
step2(token) {
switch (
this.registerType // 发送邮箱验证码
) {
case 1:
Member.sendEmailCode({
email: this.user.email,
token
})
.then(data => {
const res = /^([\w\-\.]+)@([\w\.\-]+)$/.exec(this.user.email);
this.ajar.email = `${res[1].slice(0, 3)}${"*".repeat(5)}@${res[2]
}`;
this.step = 3;
// 自动第一个焦点
this.$nextTick(function () {
// DOM 现在更新了
this.$refs.spaces[0].focus();
});
})
.catch(err => { });
break;
case 2: // 发送手机验证码
Member.sendSmsCode({
phone: this.user.phone,
country_code: this.country.country_code, // 国际电话应该前缀00
token
})
.then(data => {
this.ajar.phone = this.user.phone.replace(
/^(\d{3})\d{4}(\d{4})$/,
"$1****$2"
);
this.step = 3;
// 自动第一个焦点
this.$nextTick(function () {
// DOM 现在更新了
this.$refs.spaces[0].focus();
});
})
.catch(err => { });
break;
default:
break;
}
// 关闭模态框
$("#captcha").modal("hide");
},
refreshSlider() {
// name标记的iframe返回窗口对象
// id标记的iframe返回dom对象 需要在通过contentWindow读取
window.frames["my-modal-body"].$captcha.sliderCaptcha("reset");
},
autofill($event) {
let data = $event.clipboardData.getData("text/plain"),
val;
if (!data) return;
else val = _.trim(data);
if (val.match(/^\d{6}$/)) {
$event.preventDefault();
this.skipInput = true;
this.$refs.spaces.forEach((item, index) => {
item.value = val.charAt(index);
this.chkLoginSave(index, val.charAt(index));
});
}
},
reset(checkType) {
// 清空输入框的值
Array.from(this.$refs.spaces).forEach(item => (item.value = ""));
// 清除存储的值
this.codes = new Array(6);
// 自动获取焦点
this.$refs.spaces[0].focus();
},
handleKeyUp(pos, $event) {
// 监听删除动作
switch ($event.code) {
case "Backspace":
if (this.skipKeyup === true) {
this.skipKeyup = false;
return;
}
if (pos - 1 >= 0) {
// 删除前值
this.$refs.spaces[pos - 1].value = "";
this.$refs.spaces[pos - 1].focus();
}
break;
case "ArrowLeft":
// case "ArrowUp":
if (pos - 1 >= 0) {
this.$refs.spaces[pos - 1].focus();
}
break;
// case "ArrowDown":
case "ArrowRight":
if (pos + 1 <= 5) {
this.$refs.spaces[pos + 1].focus();
}
break;
}
},
// 将值同步到vm 并验证提交
chkLoginSave(pos, value) {
this.codes[pos] = value;
// 所有框都填满时 触发提交
if (this.codes.join("").match(/^\d{6}$/)) this.step3();
// if (this[name].every(item => /^\d$/.test(item))) this.step3();
},
handleInput(pos, $event) {
if (this.skipInput == true) {
this.skipInput = false;
return;
}
let val = $event.target.value;
if (val) {
// 执行了输入
// 合法的值
if (val.match(/^\d{1,2}$/)) {
if (val.length == 2) {
// 再次输入时 重置值
val = _.trim(val, this.codes[pos]);
$event.target.value = val;
}
// 找到下一个空节点
const tmpArr = Array.from(this.$refs.spaces);
for (let item of tmpArr) {
if (!item.value) {
item.focus();
break;
}
}
this.chkLoginSave(pos, $event.target.value);
// 非法的值
} else {
$event.target.value = this.codes[pos] || "";
}
} else {
// 执行了删除 第一次删除跳过keyup事件
this.skipKeyup = true;
}
},
step3() {
// 基础参数
const base = {
password: this.user.password,
password_confirmation: this.user.password,
code: this.codes.join(""),
invite_code: this.user.parentCode
};
// 分离参数
let data = {};
switch (this.registerType) {
case 2: // 手机
data.type = `1`;
data.country_id = this.user.country_id;
data.account = this.user.phone;
data.country_code = this.country.country_code;
break;
case 1:
data.type = `2`;
data.account = this.user.email;
break;
default:
break;
}
// 服务端真实性验证
Member.register(Object.assign(base, data))
.then(response => {
this.$message({
type: "success",
message: this.$t("login.registrationSuccess"),
duration: 3000,
onClose: () => {
// 注册完成 进入登录页
this.$router.push("/sign-in");
// 手机访问提示下载
if (utils.isMobile()) {
this.$confirm(this.$t("home.download") + "?", '', {
center: true,
confirmButtonText:this.$t('common.confirmBtn'),
cancelButtonText: this.$t('common.cancelBtn'),
})
.then(() => {
location.origin = "/down";
})
.catch(() => { });
return;
}
}
});
})
.catch(err => {
this.reset(this.registerType);
});
}
},
created() {
Member.getCountryCode()
.then(data => {
this.cacheOption = data;
})
.catch(err => { });
if (this.$route.query.invite_code) {
this.user.parentCode = this.$route.query.invite_code;
if (document.body.clientWidth < 750) {
window.location.href = this.Globals.mobileUrl + '/#/pages/reg/index?invite_code=' + this.$route.query.invite_code
}
}
},
mounted() {
//
window.md5 = md5;
// 安全性验证成功时的回调函数
window.step2Register = this.step2;
}
};
</script>
<style lang="scss" scoped>
@import '@/assets/scss/base/_common.scss';
form.register-body {
.form-group {
margin: 1rem auto;
}
.password {
label {
width: 2em;
height: 2em;
// border: 1px solid red;
display: inline-block;
content: "";
background: url("../../assets/img/eyed.svg") no-repeat center center;
// background-repeat: no-repeat;
background-size: 1rem 1rem;
position: absolute;
right: 1em;
top: calc(50% - 1em);
cursor: pointer;
opacity: 0.5;
}
position: relative;
}
.area-phone-box {
// width: 100%;
@include flexible();
.area {
width: 123px;
margin-right: 3px;
}
.phone {
width: 162px;
}
}
// 去除搜索输入框自带的下拉图标
input::-webkit-calendar-picker-indicator {
display: none;
-webkit-appearance: none;
}
}
div.verify-code {
// min-width: 375px;
flex-basis: 400px;
@include flexible(column);
.my-codes {
width: 100%;
height: 138px;
@include flexible(column, center, flex-start);
// border: 1px solid red;
.my-codes__title {
color: #007bff;
margin: 10px 0;
}
.my-codes__controls {
width: 100%;
@include flexible(row, space-between, center);
.form-control {
width: 48px;
height: 48px;
text-align: center;
@include font(OpenSans-Regular, 22, 32, $clr);
}
}
}
.form-text {
@extend .break-word;
}
.text-muted {
color: $clr !important;
}
.prompt {
.prompt__no-recieved {
@include font(Overpass-Regular, 13, 30, $clr);
}
.prompt__inner {
@include font(Overpass-Regular, 12, 20, $clr);
@extend .form-text;
@extend .text-muted;
}
}
}
.modal-content {
// iframe 底部没有设置圆角 超出时 隐藏
overflow: hidden;
}
.modal-header {
// border:1px solid red;
.modal-title {
@include fs(16);
}
.refresh {
position: absolute;
right: 58px;
top: 18px;
}
}
.my-modal-body {
// border : 1px solid red;
// border: none;
width: calc(100% - 2px);
height: 260px;
padding: 0;
margin: 0;
}
.form-control:disabled, .form-control[disabled]{
background-color: #1e2834;
}
.form-control:disabled, .form-control[readonly]{
background-color: #1e2834;
}
.nav-tabs .nav-link.active {
color: #495057;
background-color: transparent;
border: none;
}
</style>