m2pool_web_frontend/mining-pool/src/views/register/register.vue

832 lines
22 KiB
Vue
Raw Normal View History

<template>
<div class="loginPage">
<section class="mobileMain" v-if="$isMobile">
<header class="headerBox2">
<img
@click="handelJump(`/`)"
src="../../assets/mobile/login/LOGO.svg"
alt="logo"
/>
<span class="title">{{ $t(`home.MRegister`) }}</span>
<span></span>
</header>
<div class="imgTop">
<img
src="../../assets/mobile/login/registertop.svg"
alt="register"
loading="lazy"
/>
</div>
<section class="formInput">
<el-form
:model="registerForm"
status-icon
:rules="registerRules"
ref="registerForm"
class="demo-ruleForm"
>
<el-form-item prop="email">
<el-input
type="email"
prefix-icon="el-icon-message"
v-model="registerForm.email"
autocomplete="off"
:placeholder="$t(`user.Account`)"
></el-input>
</el-form-item>
<el-form-item prop="emailCode">
<div class="verificationCode">
<el-input
type="text"
prefix-icon="el-icon-chat-line-square"
v-model="registerForm.emailCode"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
<el-button
class="codeBtn"
:disabled="btnDisabled"
@click="handelCode"
><span v-if="countDownTime < 60 && countDownTime > 0">{{
countDownTime
}}</span
>{{ $t(bthText) }}</el-button
>
</div>
</el-form-item>
<el-form-item prop="password">
<el-input
:title="$t(`user.passwordPrompt`)"
type="password"
v-model="registerForm.password"
prefix-icon="el-icon-unlock"
autocomplete="off"
:placeholder="$t(`user.password`)"
show-password
></el-input>
<p class="remind" :title="$t(`user.passwordPrompt`)">
{{ $t(`user.passwordPrompt`) }}
</p>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input
type="password"
v-model="registerForm.confirmPassword"
prefix-icon="el-icon-unlock"
autocomplete="off"
:placeholder="$t(`user.confirmPassword`)"
show-password
></el-input>
</el-form-item>
<div class="register">
<span
>{{ $t(`user.havingAnAccount`) }}
<span class="goLogin" @click="goLogin">{{
$t(`user.login`)
}}</span>
</span>
</div>
<el-form-item>
<el-button
style="
width: 100%;
background: #661fff;
color: aliceblue;
margin-top: 6%;
"
:loading="registerLoading"
@click="handleRegister"
>{{ $t(`user.register`) }}</el-button
>
<div style="text-align: left">
<el-radio @input="handelRadio" v-model="radio" label="zh"
>简体中文</el-radio
>
<el-radio @input="handelRadio" v-model="radio" label="en"
>English</el-radio
>
</div>
</el-form-item>
</el-form>
</section>
</section>
<section class="loginModular" v-else>
<div class="leftBox">
<img
class="logo"
src="../../assets/img/WILOGO.png"
alt="logo"
@click="handleClick"
/>
<img src="../../assets/img/reincon.png" alt="Register Mining Pool" />
</div>
<div class="loginBox">
<div class="closeBox" @click="handleClick">
<i class="iconfont icon-guanbi1 close"></i>
</div>
<el-form
:model="registerForm"
status-icon
:rules="registerRules"
ref="registerForm"
class="demo-ruleForm"
>
<el-form-item>
<p class="loginTitle">{{ $t(`user.newUser`) }}</p>
</el-form-item>
<el-form-item prop="email">
<el-input
type="email"
prefix-icon="el-icon-message"
v-model="registerForm.email"
autocomplete="off"
:placeholder="$t(`user.Account`)"
></el-input>
</el-form-item>
<el-form-item prop="emailCode">
<div class="verificationCode">
<el-input
type="text"
prefix-icon="el-icon-chat-line-square"
v-model="registerForm.emailCode"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
<el-button
class="codeBtn"
:disabled="btnDisabled"
@click="handelCode"
><span v-if="countDownTime < 60 && countDownTime > 0">{{
countDownTime
}}</span
>{{ $t(bthText) }}</el-button
>
</div>
</el-form-item>
<el-form-item prop="password">
<el-input
:title="$t(`user.passwordPrompt`)"
type="password"
v-model="registerForm.password"
prefix-icon="el-icon-unlock"
autocomplete="off"
:placeholder="$t(`user.password`)"
show-password
></el-input>
<p class="remind" :title="$t(`user.passwordPrompt`)">
{{ $t(`user.passwordPrompt`) }}
</p>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input
type="password"
v-model="registerForm.confirmPassword"
prefix-icon="el-icon-unlock"
autocomplete="off"
:placeholder="$t(`user.confirmPassword`)"
show-password
></el-input>
</el-form-item>
<div class="register">
<span
>{{ $t(`user.havingAnAccount`) }}
<span class="goLogin" @click="goLogin">{{
$t(`user.login`)
}}</span>
</span>
</div>
<el-form-item>
<el-button
style="
width: 100%;
background: #661fff;
color: aliceblue;
margin-top: 6%;
"
:loading="registerLoading"
@click="handleRegister"
>{{ $t(`user.register`) }}</el-button
>
<div style="text-align: left">
<el-radio @input="handelRadio" v-model="radio" label="zh"
>简体中文</el-radio
>
<el-radio @input="handelRadio" v-model="radio" label="en"
>English</el-radio
>
</div>
</el-form-item>
</el-form>
</div>
</section>
</div>
</template>
<script>
import { getRegister, getRegisterCode } from "../../api/login";
import { encryption } from "../../utils/fun";
export default {
data() {
// const equalToPassword = (rule, value, callback) => {
// if (this.registerForm.password !== value) {
// callback(new Error("两次输入的密码不一致"));
// } else {
// callback();
// }
// };
return {
registerForm: {
// userName: "",
password: "",
email: "",
emailCode: "",
confirmPassword: "",
},
registerRules: {
userName: [
{ required: true, trigger: "blur", message: "请输入您的账号" },
{
min: 3,
max: 16,
message: "用户账号长度必须介于 3 和 16 之间",
trigger: "blur",
},
],
email: [
{
required: true,
trigger: "blur",
message: this.$t(`user.emailVerification`),
type: "email",
},
],
password: [
{
required: true,
trigger: "blur",
message: this.$t(`user.inputPassword`),
},
{
min: 8,
max: 32,
message: this.$t(`user.passwordVerification`),
trigger: "blur",
},
],
confirmPassword: [
{
required: true,
trigger: "blur",
message: this.$t(`user.secondaryPassword`),
},
// { required: true, validator: equalToPassword, trigger: "blur" },
],
emailCode: [
{
required: true,
trigger: "blur",
message: this.$t(`user.inputCode`),
},
],
},
radio: `zh`,
loading: false,
codeParams: {
// userName: "",
email: "",
},
btnDisabled: false,
bthText: "user.obtainVerificationCode",
time: "",
registerLoading: false,
countDownTime: 60,
timer: null,
lang: "zh",
};
},
computed: {
countDown() {
const minutes = Math.floor(this.countDownTime / 60);
const seconds = this.countDownTime % 60;
const m = minutes < 10 ? "0" + minutes : minutes;
const s = seconds < 10 ? "0" + seconds : seconds;
return `${s}`;
// return`${s}`
},
},
created() {
if (window.sessionStorage.getItem("register_time")) {
this.countDownTime = Number(
window.sessionStorage.getItem("register_time")
);
this.startCountDown();
this.btnDisabled = true;
this.bthText = `user.again`;
}
},
watch: {
2025-07-04 05:46:11 +00:00
'$route'(to) {
// 路由变化时自动同步语言和radio
const match = to.path.match(/^\/(zh|en)(\/|$)/);
if (match) {
this.radio = match[1];
this.lang = match[1];
this.$i18n.locale = match[1];
localStorage.setItem("lang", match[1]);
}
},
"$i18n.locale": function () {
this.translate();
},
},
mounted() {
2025-07-04 05:46:11 +00:00
// this.lang = this.$i18n.locale;
// this.radio = localStorage.getItem("lang")
// ? localStorage.getItem("lang")
// : "en";
// 获取当前路由路径
const path = this.$route.path;
// 匹配 /zh/ 或 /en/ 作为语言前缀
const match = path.match(/^\/(zh|en)(\/|$)/);
if (match) {
this.radio = match[1];
this.lang = match[1];
this.$i18n.locale = match[1];
localStorage.setItem("lang", match[1]);
} else {
// fallback 到 localStorage 或 "en"
this.radio = localStorage.getItem("lang") || "en";
this.lang = this.radio;
this.$i18n.locale = this.radio;
}
for (const key in this.registerForm) {
this.registerForm[key] = "";
}
},
methods: {
handelJump(url) {
const cleanPath = url.startsWith("/") ? url.slice(1) : url;
this.$router.push(`/${this.lang}/${cleanPath}`);
},
translate() {
this.registerRules = {
userName: [
{
required: true,
trigger: "blur",
message: this.$t(`user.inputAccount`),
},
{
min: 3,
max: 16,
message: "用户账号长度必须介于 3 和 16 之间",
trigger: "blur",
},
],
email: [
{
required: true,
trigger: "blur",
message: this.$t(`user.emailVerification`),
type: "email",
},
],
password: [
{
required: true,
trigger: "blur",
message: this.$t(`user.inputPassword`),
},
{
min: 8,
max: 32,
message: this.$t(`user.passwordVerification`),
trigger: "blur",
},
],
confirmPassword: [
{
required: true,
trigger: "blur",
message: this.$t(`user.secondaryPassword`),
},
// { required: true, validator: equalToPassword, trigger: "blur" },
],
emailCode: [
{
required: true,
trigger: "blur",
message: this.$t(`user.inputCode`),
},
],
};
},
async fetchRegisterCode(params) {
const data = await getRegisterCode(params);
if (data && data.code === 200) {
this.$message({
message: this.$t(`user.verificationCodeSuccessful`),
type: "success",
showClose: true,
});
}
},
handelCode() {
// this.codeParams.userName = this.registerForm.userName;
this.codeParams.email = this.registerForm.email;
// if (!this.codeParams.userName) {
// this.$message({
// message: "请输入账号",
// type: "error",
// });
// return
// }
//邮箱格式验证 /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/;
let isMailbox = emailRegex.test(this.codeParams.email);
if (!this.codeParams.email || !isMailbox) {
this.$message({
message: this.$t(`user.emailVerification`),
type: "error",
showClose: true,
});
return;
}
this.fetchRegisterCode(this.codeParams);
if (window.sessionStorage.getItem("register_time") == null) {
this.startCountDown();
} else {
this.countDownTime = Number(
window.sessionStorage.getItem("register_time")
);
this.startCountDown();
}
// this.time = 60;
// let timer = setInterval(()=>{
// if ( this.time) {
// this.time--
// this.btnDisabled = true;
// // this.bthText= this.time+`s后重新获取`
// this.bthText= `user.again`
// }else {
// this.btnDisabled = false;
// this.bthText="user.obtainVerificationCode"
// this.time = "";
// clearTimeout(timer)
// }
// },1000)
},
startCountDown() {
this.timer = setInterval(() => {
if (this.countDownTime <= 1) {
//当监测到countDownTime为0时,清除计数器并且移除sessionStorage,然后执行提交试卷逻辑
clearInterval(this.timer);
sessionStorage.removeItem("register_time");
this.countDownTime = 60;
this.btnDisabled = false;
this.bthText = `user.obtainVerificationCode`;
} else if (this.countDownTime > 0) {
//每秒让countDownTime -1秒,并设置到sessionStorage中
this.countDownTime--;
this.btnDisabled = true;
this.bthText = `user.again`;
window.sessionStorage.setItem("register_time", this.countDownTime);
}
}, 1000);
},
goLogin() {
this.$router.push(`/${this.lang}/login`);
},
handelRadio(val) {
// 保存旧的语言值
const oldLang = this.lang;
// 更新语言设置
this.lang = val;
this.$i18n.locale = val;
localStorage.setItem("lang", val);
// 更新当前路由的语言部分
const currentPath = this.$route.path;
const newPath = currentPath.replace(`/${oldLang}`, `/${val}`);
// 保持查询参数
this.$router
.push({
path: newPath,
query: this.$route.query,
})
.catch((err) => {
if (err.name !== "NavigationDuplicated") {
console.error("Navigation failed:", err);
}
});
},
//点击注册
handleRegister() {
this.$refs.registerForm.validate((valid) => {
if (valid) {
this.loading = true;
//用户名规则1.长度限制3<=用户名<=16; 字符限制:仅允许使用字母、数字、下划线 用户名必须以字母开头
// const regex = /^[a-zA-Z][a-zA-Z0-9_]{2,15}$/; // 正则表达式
// const isValid = regex.test(this.registerForm.userName);
// if (!isValid) {
//
// this.$message({
// message: `请检查账户是否输入正确`,
// type: "error",
// });
// return;
// }
//邮箱格式验证
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/;
let isMailbox = emailRegex.test(this.registerForm.email);
if (!this.registerForm.email || !isMailbox) {
this.$message({
message: this.$t(`user.emailVerification`),
type: "error",
showClose: true,
});
return;
}
// 密码验证 8<=密码<=32 包含大小写字母、数字和特殊字符(!@#¥%……&*
// const regexPassword =
// /^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_]+$)(?![a-z0-9]+$)(?![a-z\W_]+$)(?![0-9\W_]+$)[a-zA-Z0-9\W_]{8,32}$/; // 正则表达式
const regexPassword =
/^(?!.*[\u4e00-\u9fa5])(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_]+$)(?![a-z0-9]+$)(?![a-z\W_]+$)(?![0-9\W_]+$)[a-zA-Z0-9\W_]{8,32}$/;
const PasswordIsValid = regexPassword.test(
this.registerForm.password
);
if (!PasswordIsValid) {
this.$message({
message: this.$t(`user.passwordFormat`),
type: "error",
});
return;
}
this.registerLoading = true;
//加密
const form = { ...this.registerForm };
form.password = encryption(this.registerForm.password);
form.confirmPassword = encryption(this.registerForm.confirmPassword);
getRegister(form)
.then((res) => {
const userName = this.registerForm.userName;
if (res.code == 200) {
this.$alert(
`<font color='red'>${this.$t(`user.congratulations`)}</font>`,
`${this.$t(`user.system`)}`,
{
dangerouslyUseHTMLString: true,
}
)
.then(() => {
this.$router.push(`/${this.lang}/login`);
})
.catch(() => {});
}
})
.catch(() => {
this.loading = false;
if (this.captchaOnOff) {
// this.getCode();
}
});
this.registerLoading = false;
}
});
},
handleClick() {
this.$router.push(`/${this.lang}`);
},
},
};
</script>
<style scoped lang="scss">
.loginPage {
width: 100%;
height: 100%;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
background-image: url(../../assets/img/logBg.png);
background-size: cover;
background-repeat: no-repeat;
.loginModular {
width: 53%;
height: 68%;
display: flex;
border-radius: 10px;
overflow: hidden;
box-shadow: 0px 0px 20px 18px #d6d2ea;
// box-shadow: 0px 0px 20PX 30PX #000;
}
.remind {
font-size: 0.8em;
padding: 0;
margin: 0;
min-height: 15px;
line-height: 15px;
color: #ff4081;
// text-overflow: ellipsis;
// overflow: hidden;
// white-space: nowrap;
// cursor: pointer;
}
.leftBox {
width: 47%;
height: 100%;
background-image: linear-gradient(150deg, #18b7e6 -20%, #651fff 60%);
position: relative;
img {
width: 100%;
position: absolute;
right: -15%;
bottom: 0;
z-index: 99;
}
.logo {
position: absolute;
left: 30px;
top: 18px;
width: 22%;
}
}
}
.el-form {
width: 90%;
padding: 0px 20px 50px 20px;
}
.el-form-item {
width: 100%;
}
.loginBox {
width: 53%;
// box-shadow: 0PX 0PX 5PX 1PX #ccc;
display: flex;
justify-content: center;
align-items: center;
border-radius: 10px;
position: relative;
flex-direction: column;
overflow: hidden;
padding: 0px 25px;
background: #fff;
.demo-ruleForm {
height: 100%;
padding-top: 3%;
}
img {
width: 18%;
position: absolute;
top: 20px;
right: 30px;
cursor: pointer;
}
.closeBox {
position: absolute;
top: 18px;
right: 30px;
cursor: pointer;
.close {
font-size: 1.3em;
}
}
.closeBox:hover {
color: #661fff;
}
}
.loginTitle {
font-size: 20px;
font-weight: 600;
margin-bottom: 30px;
text-align: center;
}
.loginColor {
width: 100%;
height: 15px;
background: #661fff;
}
.langBox {
display: flex;
justify-content: space-between;
align-content: center;
}
.register {
display: flex;
justify-content: start;
/* background: #CCC; */
margin: 0;
font-size: 12px;
height: 10px;
.goLogin:hover {
color: #661fff;
cursor: pointer;
}
}
.forget {
margin-left: 10px;
}
.forgotPassword {
display: inline-block;
width: 20%;
}
.verificationCode {
display: flex;
.codeBtn {
font-size: 13px;
margin-left: 2px;
}
}
// 手机端适配
@media screen and (min-width: 220px) and (max-width: 1279px) {
.mobileMain {
width: 100vw;
min-height: 100vh;
background: #fff;
background-image: url("../../assets/mobile/login/bgtop.svg");
background-repeat: no-repeat;
background-size: 115%;
background-position: 49% 47%;
box-sizing: border-box;
}
.headerBox2 {
width: 100%;
height: 60px;
// background: palegoldenrod;
// border-bottom: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: space-between;
line-height: 60px;
padding: 0px 20px;
padding-top: 10px;
box-shadow: 0px 0px 2px 1px #ccc;
img {
width: 30px;
}
.title {
height: 100%;
font-weight: 600;
}
}
.imgTop {
width: 100%;
display: flex;
justify-content: center;
margin-top: 2%;
img {
height: 159px;
}
}
.formInput {
width: 100%;
display: flex;
justify-content: center;
}
.register {
.goLogin {
color: #651fff;
padding: 0px 8px;
}
}
}
</style>