添加注销账户功能已通过测试

This commit is contained in:
2026-01-08 16:25:15 +08:00
parent 9869ec0106
commit f546788f2a
17 changed files with 663 additions and 34 deletions

Binary file not shown.

View File

@@ -0,0 +1,228 @@
<template>
<div class="password-strength-indicator">
<!-- 密码强度进度条 -->
<div class="strength-bar-container">
<div
class="strength-bar"
:class="strengthClass"
:style="{ width: strengthPercentage + '%' }"
></div>
</div>
<!-- 强度文本提示 -->
<div class="strength-text" :class="strengthClass">
<span v-if="password && password.length > 0">
{{ $t(`passwordStrength.${strengthLevel}`) }}
</span>
</div>
<!-- 详细的校验项列表 -->
<div v-if="showDetails && password && password.length > 0" class="validation-checklist">
<div
v-for="(rule, key) in validationDetails"
:key="key"
class="validation-item"
:class="{ 'valid': rule.passed, 'invalid': !rule.passed }"
>
<i :class="rule.passed ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i>
<span>{{ $t(rule.message) }}</span>
</div>
</div>
</div>
</template>
<script>
import { checkPasswordStrength } from '@/utils/passwordValidator'
export default {
name: 'PasswordStrengthIndicator',
props: {
// 要校验的密码
password: {
type: String,
default: ''
},
// 是否显示详细的校验项
showDetails: {
type: Boolean,
default: true
}
},
computed: {
// 密码强度分析结果
strengthAnalysis() {
if (!this.password) {
return {
score: 0,
level: 'none',
validation: {
valid: false,
errors: [],
details: {
length: false,
hasLowercase: false,
hasUppercase: false,
hasNumber: false,
hasSpecialChar: false,
noChinese: false
}
}
}
}
return checkPasswordStrength(this.password)
},
// 强度等级
strengthLevel() {
return this.strengthAnalysis.level
},
// 强度百分比
strengthPercentage() {
return this.strengthAnalysis.score
},
// 强度等级对应的样式类
strengthClass() {
return `strength-${this.strengthLevel}`
},
// 校验详情(用于显示✓和✗)
validationDetails() {
const details = this.strengthAnalysis.validation.details
return {
length: {
passed: details.length,
message: 'passwordRules.length'
},
noChinese: {
passed: details.noChinese,
message: 'passwordRules.noChinese'
},
lowercase: {
passed: details.hasLowercase,
message: 'passwordRules.lowercase'
},
uppercase: {
passed: details.hasUppercase,
message: 'passwordRules.uppercase'
},
number: {
passed: details.hasNumber,
message: 'passwordRules.number'
},
specialChar: {
passed: details.hasSpecialChar,
message: 'passwordRules.specialChar'
}
}
}
},
watch: {
// 密码变化时通知父组件校验结果
strengthAnalysis: {
handler(newVal) {
this.$emit('strength-change', newVal)
},
deep: true,
immediate: true
}
}
}
</script>
<style scoped lang="scss">
.password-strength-indicator {
margin-top: 8px;
}
// 强度进度条容器
.strength-bar-container {
width: 100%;
height: 6px;
background-color: #e4e7ed;
border-radius: 3px;
overflow: hidden;
margin-bottom: 8px;
}
// 强度进度条
.strength-bar {
height: 100%;
transition: all 0.3s ease;
border-radius: 3px;
&.strength-weak {
background-color: #f56c6c; // 红色 - 弱
}
&.strength-medium {
background-color: #e6a23c; // 橙色 - 中等
}
&.strength-strong {
background-color: #67c23a; // 绿色 - 强
}
&.strength-none {
background-color: #e4e7ed; // 灰色 - 无
}
}
// 强度文本
.strength-text {
font-size: 12px;
margin-bottom: 8px;
font-weight: 500;
&.strength-weak {
color: #f56c6c;
}
&.strength-medium {
color: #e6a23c;
}
&.strength-strong {
color: #67c23a;
}
&.strength-none {
color: #909399;
}
}
// 校验项列表
.validation-checklist {
margin-top: 10px;
}
.validation-item {
display: flex;
align-items: center;
font-size: 12px;
margin-bottom: 6px;
transition: all 0.2s ease;
i {
margin-right: 6px;
font-size: 14px;
}
&.valid {
color: #67c23a;
i {
color: #67c23a;
}
}
&.invalid {
color: #909399;
i {
color: #dcdfe6;
}
}
}
</style>

View File

@@ -42,6 +42,32 @@ export const userLang_zh = {
modifiedSuccessfully:"密码修改成功,请登录",
verificationEnabled:"已开启验证",
newPassword2:"新密码",
},
// 密码错误详细提示
passwordError: {
tooShort: "密码长度不足8位",
tooLong: "密码长度超过32位",
containsChinese: "密码不能包含中文字符",
noLowercase: "密码必须包含小写字母(a-z)",
noUppercase: "密码必须包含大写字母(A-Z)",
noNumber: "密码必须包含数字(0-9)",
noSpecialChar: "密码必须包含特殊字符,可用字符: ! @ # $ % ^ & * ( ) _ + - = [ ] { } | ; : ' \" , . < > ? / \\ ` ~",
},
// 密码强度等级
passwordStrength: {
none: "请输入密码",
weak: "密码强度:弱",
medium: "密码强度:中等",
strong: "密码强度:强"
},
// 密码规则提示(用于✓✗列表)
passwordRules: {
length: "长度为8-32位",
noChinese: "不包含中文字符",
lowercase: "包含小写字母",
uppercase: "包含大写字母",
number: "包含数字",
specialChar: "包含特殊字符"
}
}
@@ -89,5 +115,31 @@ export const userLang_en = {
modifiedSuccessfully:"Password changed successfully, please log in",
verificationEnabled:"Verification enabled",
newPassword2:"New Password",
},
// Detailed password error messages
passwordError: {
tooShort: "Password must be at least 8 characters",
tooLong: "Password cannot exceed 32 characters",
containsChinese: "Password cannot contain Chinese characters",
noLowercase: "Password must contain lowercase letters (a-z)",
noUppercase: "Password must contain uppercase letters (A-Z)",
noNumber: "Password must contain numbers (0-9)",
noSpecialChar: "Password must contain special characters. Allowed: ! @ # $ % ^ & * ( ) _ + - = [ ] { } | ; : ' \" , . < > ? / \\ ` ~",
},
// Password strength levels
passwordStrength: {
none: "Please enter password",
weak: "Password Strength: Weak",
medium: "Password Strength: Medium",
strong: "Password Strength: Strong"
},
// Password rules checklist
passwordRules: {
length: "8-32 characters",
noChinese: "No Chinese characters",
lowercase: "Contains lowercase letter",
uppercase: "Contains uppercase letter",
number: "Contains number",
specialChar: "Contains special character"
}
}

View File

@@ -0,0 +1,156 @@
/**
* 密码强度逐项校验工具
* @description 提供分步密码校验,精确指出每一项不符合的要求
*/
/**
* 密码校验规则配置
*/
export const PASSWORD_RULES = {
minLength: 8,
maxLength: 32,
requireLowercase: true,
requireUppercase: true,
requireNumber: true,
requireSpecialChar: true,
allowChinese: false
}
/**
* 允许的特殊字符列表(用于显示给用户)
* 实际上所有非字母数字字符都可以,这里列出常用的
*/
export const ALLOWED_SPECIAL_CHARS = '!@#$%^&*()_+-=[]{}|;:\'",.<>?/\\`~'
/**
* 校验结果接口
* @typedef {Object} ValidationResult
* @property {boolean} valid - 是否通过校验
* @property {Array<string>} errors - 错误信息数组(i18n key)
* @property {Object} details - 每项规则的详细校验结果
*/
/**
* 密码逐项校验函数
* @param {string} password - 待校验的密码
* @returns {ValidationResult} 校验结果对象
*/
export function validatePassword(password) {
const result = {
valid: true,
errors: [],
details: {
length: false,
hasLowercase: false,
hasUppercase: false,
hasNumber: false,
hasSpecialChar: false,
noChinese: false
}
}
// 1. 检查长度
if (password.length < PASSWORD_RULES.minLength) {
result.errors.push('passwordError.tooShort')
result.valid = false
} else if (password.length > PASSWORD_RULES.maxLength) {
result.errors.push('passwordError.tooLong')
result.valid = false
} else {
result.details.length = true
}
// 2. 检查是否包含中文
const chineseRegex = /[\u4e00-\u9fa5]/
if (chineseRegex.test(password)) {
result.errors.push('passwordError.containsChinese')
result.valid = false
} else {
result.details.noChinese = true
}
// 3. 检查小写字母
const lowercaseRegex = /[a-z]/
if (!lowercaseRegex.test(password)) {
result.errors.push('passwordError.noLowercase')
result.valid = false
} else {
result.details.hasLowercase = true
}
// 4. 检查大写字母
const uppercaseRegex = /[A-Z]/
if (!uppercaseRegex.test(password)) {
result.errors.push('passwordError.noUppercase')
result.valid = false
} else {
result.details.hasUppercase = true
}
// 5. 检查数字
const numberRegex = /[0-9]/
if (!numberRegex.test(password)) {
result.errors.push('passwordError.noNumber')
result.valid = false
} else {
result.details.hasNumber = true
}
// 6. 检查特殊字符
const specialCharRegex = /[\W_]/
if (!specialCharRegex.test(password)) {
result.errors.push('passwordError.noSpecialChar')
result.valid = false
} else {
result.details.hasSpecialChar = true
}
return result
}
/**
* 实时校验密码强度(适用于input输入时)
* @param {string} password - 当前输入的密码
* @returns {Object} 强度分析结果
*/
export function checkPasswordStrength(password) {
const validation = validatePassword(password)
// 计算强度分数(0-100)
const maxScore = 6
const passedRules = Object.values(validation.details).filter(v => v).length
const score = Math.round((passedRules / maxScore) * 100)
// 强度等级
let level = 'weak'
if (score >= 85) level = 'strong'
else if (score >= 50) level = 'medium'
return {
score,
level,
validation
}
}
/**
* 获取友好的错误提示(用于Message组件)
* @param {Array<string>} errorKeys - 错误的i18n key数组
* @param {Function} t - vue-i18n的$t函数
* @returns {string} 格式化的错误提示文本
*/
export function formatPasswordErrors(errorKeys, t) {
if (!errorKeys || errorKeys.length === 0) {
return ''
}
// 翻译所有错误信息
const errorMessages = errorKeys.map(key => t(key))
// 格式化为列表形式
if (errorMessages.length === 1) {
return errorMessages[0]
}
return errorMessages.map((msg, index) => `${index + 1}. ${msg}`).join('\n')
}

View File

@@ -30,6 +30,7 @@
<el-input
prefix-icon="el-icon-user"
v-model="loginForm.userName"
@input="handleEmailInput($event)"
autocomplete="off"
:placeholder="$t('user.Account')"
></el-input>
@@ -38,6 +39,7 @@
<el-input
type="password"
v-model="loginForm.password"
@input="handlePasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
showPassword
@@ -50,6 +52,7 @@
type="text"
prefix-icon="el-icon-chat-line-square"
v-model="loginForm.code"
@input="handleCodeInput($event)"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
@@ -132,6 +135,7 @@
<el-input
prefix-icon="el-icon-user"
v-model="loginForm.userName"
@input="handleEmailInput($event)"
autocomplete="off"
:placeholder="$t('user.Account')"
type="email"
@@ -141,6 +145,7 @@
<el-input
type="password"
v-model="loginForm.password"
@input="handlePasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
showPassword
@@ -153,6 +158,7 @@
type="text"
prefix-icon="el-icon-chat-line-square"
v-model="loginForm.code"
@input="handleCodeInput($event)"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
@@ -213,6 +219,7 @@ import {
} from "../../api/login";
import { encryption } from "../../utils/fun";
import { getAccountList } from "../../api/personalCenter";
import { validatePassword, formatPasswordErrors } from "../../utils/passwordValidator";
export default {
@@ -709,16 +716,16 @@ export default {
// }
}
// 密码验证 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.loginForm.password);
if (!PasswordIsValid) {
// 如果输入不符合要求,可以根据具体需求给出错误提示或进行其他处理
// 密码验证 - 使用优化后的详细校验逻辑
const validation = validatePassword(this.loginForm.password);
if (!validation.valid) {
// 生成友好的逐项错误提示
const errorMessage = formatPasswordErrors(validation.errors, this.$t.bind(this));
this.$message({
message: this.$t(`user.PasswordReminder`),
message: errorMessage,
type: "error",
showClose: true,
duration: 5000, // 延长显示时间,因为错误信息可能有多条
});
return;
@@ -734,6 +741,38 @@ export default {
handleClick() {
this.$router.push(`/${this.lang}`);
},
/**
* 去除输入值中的空格
* @param {string} value - 输入值
* @returns {string} 去除空格后的值
*/
removeSpaces(value) {
if (typeof value === 'string') {
return value.replace(/\s/g, '');
}
return value;
},
/**
* 处理邮箱输入,自动去除空格
* @param {string} value - 输入值
*/
handleEmailInput(value) {
this.loginForm.userName = this.removeSpaces(value);
},
/**
* 处理密码输入,自动去除空格
* @param {string} value - 输入值
*/
handlePasswordInput(value) {
this.loginForm.password = this.removeSpaces(value);
},
/**
* 处理验证码输入,自动去除空格
* @param {string} value - 输入值
*/
handleCodeInput(value) {
this.loginForm.code = this.removeSpaces(value);
},
},
};
</script>

View File

@@ -1,6 +1,7 @@
import { getIfBind, getBindInfo, getBindGoogle, getBindCode, getCloseStepTwo, getCloseCode, getUpdatePwd, getUpdatePwdCode } from "../../../api/personalCenter"
import { encryption } from "../../../utils/fun";
import { getResetPwd, getResetPwdCode, sendCloseAccount, closeAccount } from "../../../api/login"
import { validatePassword, formatPasswordErrors } from "../../../utils/passwordValidator";
export default {
data() {
return {
@@ -250,6 +251,8 @@ export default {
this.dialogVisible = false
this.verificationDialogVisible = false
localStorage.removeItem("token")
// 修改密码成功后跳转到登录页面
const lang = this.$i18n.locale || this.lang || 'zh';
this.$router.push(`/${lang}/login`);
}
this.setLoading('ResetPwdLoading', false);
@@ -601,17 +604,16 @@ export default {
}
// 密码验证 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.changePasswordParams.password);
if (!PasswordIsValid) {
// 如果输入不符合要求,可以根据具体需求给出错误提示或进行其他处理
// 密码验证 - 使用优化后的详细校验逻辑
const validation = validatePassword(this.changePasswordParams.password);
if (!validation.valid) {
// 生成友好的逐项错误提示
const errorMessage = formatPasswordErrors(validation.errors, this.$t.bind(this));
this.$message({
message: this.$t(`user.PasswordReminder`),
message: errorMessage,
type: "error",
showClose: true
showClose: true,
duration: 5000, // 延长显示时间,因为错误信息可能有多条
});
return;
@@ -803,6 +805,49 @@ export default {
// this.bthText="user.obtainVerificationCode"
// this.time = "";
},
/**
* 去除输入值中的空格
* @param {string} value - 输入值
* @returns {string} 去除空格后的值
*/
removeSpaces(value) {
if (typeof value === 'string') {
return value.replace(/\s/g, '');
}
return value;
},
/**
* 处理密码输入,自动去除空格
* @param {string} value - 输入值
* @param {string} field - 字段名
*/
handlePasswordInput(value, field) {
const trimmedValue = this.removeSpaces(value);
if (field === 'password') {
this.changePasswordParams.password = trimmedValue;
} else if (field === 'newPassword') {
this.newPassword = trimmedValue;
} else if (field === 'pwd') {
this.params.pwd = trimmedValue;
}
},
/**
* 处理验证码输入,自动去除空格
* @param {string} value - 输入值
* @param {string} field - 字段名
*/
handleCodeInput(value, field) {
const trimmedValue = this.removeSpaces(value);
if (field === 'updatePwdCode') {
this.changePasswordParams.updatePwdCode = trimmedValue;
} else if (field === 'eCode') {
this.closeParams.eCode = trimmedValue;
} else if (field === 'paramsECode') {
this.params.eCode = trimmedValue;
} else if (field === 'deleteAccountECode') {
this.deleteAccountParams.eCode = trimmedValue;
}
},

View File

@@ -202,6 +202,7 @@
<el-input
type="email"
v-model="changePasswordParams.updatePwdCode"
@input="handleCodeInput($event, 'updatePwdCode')"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
@@ -223,6 +224,7 @@
type="password"
showPassword
v-model="changePasswordParams.password"
@input="handlePasswordInput($event, 'password')"
:placeholder="$t(`personal.pleaseEnter`)"
></el-input>
<p class="remind" :title="$t(`user.passwordPrompt`)">
@@ -236,8 +238,10 @@
type="password"
showPassword
v-model="newPassword"
@input="handlePasswordInput($event, 'newPassword')"
:placeholder="$t(`personal.pleaseEnter`)"
></el-input>
</div>
<!--
<div class="inputItem" v-if="isItBound">
@@ -269,6 +273,7 @@
<el-input
type="text"
v-model="closeParams.eCode"
@input="handleCodeInput($event, 'eCode')"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
@@ -369,6 +374,7 @@
showPassword
type="password"
v-model="params.pwd"
@input="handlePasswordInput($event, 'pwd')"
:placeholder="$t(`personal.pleaseEnter`)"
></el-input>
</div>
@@ -378,6 +384,7 @@
<el-input
type="email"
v-model="params.eCode"
@input="handleCodeInput($event, 'paramsECode')"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
@@ -460,6 +467,7 @@
<el-input
type="text"
v-model="deleteAccountParams.eCode"
@input="handleCodeInput($event, 'deleteAccountECode')"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>

View File

@@ -30,6 +30,7 @@
type="email"
prefix-icon="el-icon-message"
v-model="registerForm.email"
@input="handleEmailInput($event)"
autocomplete="off"
:placeholder="$t(`user.Account`)"
></el-input>
@@ -40,6 +41,7 @@
type="text"
prefix-icon="el-icon-chat-line-square"
v-model="registerForm.emailCode"
@input="handleCodeInput($event)"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
@@ -59,6 +61,7 @@
:title="$t(`user.passwordPrompt`)"
type="password"
v-model="registerForm.password"
@input="handlePasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
:placeholder="$t(`user.password`)"
@@ -73,6 +76,7 @@
<el-input
type="password"
v-model="registerForm.confirmPassword"
@input="handleConfirmPasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
:placeholder="$t(`user.confirmPassword`)"
@@ -144,6 +148,7 @@
type="email"
prefix-icon="el-icon-message"
v-model="registerForm.email"
@input="handleEmailInput($event)"
autocomplete="off"
:placeholder="$t(`user.Account`)"
></el-input>
@@ -154,6 +159,7 @@
type="text"
prefix-icon="el-icon-chat-line-square"
v-model="registerForm.emailCode"
@input="handleCodeInput($event)"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
@@ -173,6 +179,7 @@
:title="$t(`user.passwordPrompt`)"
type="password"
v-model="registerForm.password"
@input="handlePasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
:placeholder="$t(`user.password`)"
@@ -187,6 +194,7 @@
<el-input
type="password"
v-model="registerForm.confirmPassword"
@input="handleConfirmPasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
:placeholder="$t(`user.confirmPassword`)"
@@ -233,6 +241,7 @@
<script>
import { getRegister, getRegisterCode } from "../../api/login";
import { encryption } from "../../utils/fun";
import { validatePassword, formatPasswordErrors } from "../../utils/passwordValidator";
export default {
data() {
// const equalToPassword = (rule, value, callback) => {
@@ -574,18 +583,15 @@ const path = this.$route.path;
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) {
// 密码验证 - 使用优化后的详细校验逻辑
const validation = validatePassword(this.registerForm.password);
if (!validation.valid) {
// 生成友好的逐项错误提示
const errorMessage = formatPasswordErrors(validation.errors, this.$t.bind(this));
this.$message({
message: this.$t(`user.passwordFormat`),
message: errorMessage,
type: "error",
duration: 5000, // 延长显示时间,因为错误信息可能有多条
});
return;
@@ -628,6 +634,45 @@ const path = this.$route.path;
handleClick() {
this.$router.push(`/${this.lang}`);
},
/**
* 去除输入值中的空格
* @param {string} value - 输入值
* @returns {string} 去除空格后的值
*/
removeSpaces(value) {
if (typeof value === 'string') {
return value.replace(/\s/g, '');
}
return value;
},
/**
* 处理邮箱输入,自动去除空格
* @param {string} value - 输入值
*/
handleEmailInput(value) {
this.registerForm.email = this.removeSpaces(value);
},
/**
* 处理验证码输入,自动去除空格
* @param {string} value - 输入值
*/
handleCodeInput(value) {
this.registerForm.emailCode = this.removeSpaces(value);
},
/**
* 处理密码输入,自动去除空格
* @param {string} value - 输入值
*/
handlePasswordInput(value) {
this.registerForm.password = this.removeSpaces(value);
},
/**
* 处理确认密码输入,自动去除空格
* @param {string} value - 输入值
*/
handleConfirmPasswordInput(value) {
this.registerForm.confirmPassword = this.removeSpaces(value);
},
},
};
</script>

View File

@@ -29,6 +29,7 @@
<el-input
prefix-icon="el-icon-user"
v-model="loginForm.email"
@input="handleEmailInput($event)"
autocomplete="off"
:placeholder="$t('user.Account')"
></el-input>
@@ -39,6 +40,7 @@
type="text"
prefix-icon="el-icon-chat-line-square"
v-model="loginForm.resetPwdCode"
@input="handleCodeInput($event)"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
@@ -58,6 +60,7 @@
<el-input
type="password"
v-model="loginForm.password"
@input="handlePasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
showPassword
@@ -71,11 +74,13 @@
<el-input
type="password"
v-model="loginForm.newPassword"
@input="handleNewPasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
showPassword
:placeholder="$t('user.newPassword')"
></el-input>
</el-form-item>
<!-- <el-form-item prop="gCode" v-if="isItBound">
<el-input
@@ -150,6 +155,7 @@
<el-input
prefix-icon="el-icon-user"
v-model="loginForm.email"
@input="handleEmailInput($event)"
autocomplete="off"
:placeholder="$t('user.Account')"
></el-input>
@@ -160,6 +166,7 @@
type="text"
prefix-icon="el-icon-chat-line-square"
v-model="loginForm.resetPwdCode"
@input="handleCodeInput($event)"
autocomplete="off"
:placeholder="$t(`user.verificationCode`)"
></el-input>
@@ -179,6 +186,7 @@
<el-input
type="password"
v-model="loginForm.password"
@input="handlePasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
showPassword
@@ -192,11 +200,13 @@
<el-input
type="password"
v-model="loginForm.newPassword"
@input="handleNewPasswordInput($event)"
prefix-icon="el-icon-unlock"
autocomplete="off"
showPassword
:placeholder="$t('user.newPassword')"
></el-input>
</el-form-item>
<!-- <el-form-item prop="gCode" v-if="isItBound">
<el-input
@@ -248,6 +258,7 @@ import { getResetPwd, getResetPwdCode } from "../../api/login";
import { encryption } from "../../utils/fun";
import { getEmailIfBind } from "../../api/personalCenter";
import { Debounce,throttle }from "../../utils/publicMethods";
import { validatePassword, formatPasswordErrors } from "../../utils/passwordValidator";
export default {
data() {
return {
@@ -573,16 +584,16 @@ export default {
// }
}
// 密码验证 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.loginForm.password);
if (!PasswordIsValid) {
// 如果输入不符合要求,可以根据具体需求给出错误提示或进行其他处理
// 密码验证 - 使用优化后的详细校验逻辑
const validation = validatePassword(this.loginForm.password);
if (!validation.valid) {
// 生成友好的逐项错误提示
const errorMessage = formatPasswordErrors(validation.errors, this.$t.bind(this));
this.$message({
message: this.$t(`user.PasswordReminder`),
message: errorMessage,
type: "error",
showClose: true,
duration: 5000, // 延长显示时间,因为错误信息可能有多条
});
return;
@@ -681,6 +692,45 @@ export default {
handleClick() {
this.$router.push(`/${this.lang}`);
},
/**
* 去除输入值中的空格
* @param {string} value - 输入值
* @returns {string} 去除空格后的值
*/
removeSpaces(value) {
if (typeof value === 'string') {
return value.replace(/\s/g, '');
}
return value;
},
/**
* 处理邮箱输入,自动去除空格
* @param {string} value - 输入值
*/
handleEmailInput(value) {
this.loginForm.email = this.removeSpaces(value);
},
/**
* 处理验证码输入,自动去除空格
* @param {string} value - 输入值
*/
handleCodeInput(value) {
this.loginForm.resetPwdCode = this.removeSpaces(value);
},
/**
* 处理密码输入,自动去除空格
* @param {string} value - 输入值
*/
handlePasswordInput(value) {
this.loginForm.password = this.removeSpaces(value);
},
/**
* 处理新密码输入,自动去除空格
* @param {string} value - 输入值
*/
handleNewPasswordInput(value) {
this.loginForm.newPassword = this.removeSpaces(value);
},
},
};
</script>

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><meta name=google-site-verification content=pKAZogQ0NQ6L4j9-V58WJMjm7zYCFwkJXSJzWu9UDM8><meta name=robots content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"><meta name=googlebot content="index, follow"><meta name=googlebot-news content="index, follow"><meta name=bingbot content="index, follow"><link rel=alternate hreflang=zh href=https://m2pool.com/zh><link rel=alternate hreflang=en href=https://m2pool.com/en><link rel=alternate hreflang=x-default href=https://m2pool.com/en><meta property=og:title content="M2pool - Stable leading high-yield mining pool"><meta property=og:description content="M2Pool provides professional mining services, supporting multiple cryptocurrency mining"><meta property=og:url content=https://m2pool.com/en><meta property=og:site_name content=M2Pool><meta property=og:type content=website><meta property=og:image content=https://m2pool.com/logo.png><link rel=icon href=/favicon.ico><link rel=stylesheet href=//at.alicdn.com/t/c/font_4582735_7i8wfzc0art.css><title>M2pool - Stable leading high-yield mining pool</title><meta name=keywords content="M2Pool, cryptocurrency mining pool,entropyx, bitcoin mining, DGB mining, mining pool service, 加密货币矿池, 比特币挖矿, DGB挖矿"><meta name=description content="M2Pool provides professional mining services, supporting multiple cryptocurrency mining, including nexa, grs, mona, dgb, rxd"><script defer=defer src=/js/chunk-vendors-c0d76f48.f34181ba.js></script><script defer=defer src=/js/chunk-vendors-bc050c32.8062ab74.js></script><script defer=defer src=/js/chunk-vendors-3003db77.d0b93d36.js></script><script defer=defer src=/js/chunk-vendors-9d134daf.bb668c99.js></script><script defer=defer src=/js/chunk-vendors-96cecd74.a7d9b845.js></script><script defer=defer src=/js/chunk-vendors-c2f7d60e.3710fdc2.js></script><script defer=defer src=/js/chunk-vendors-89d5c698.2190b4ca.js></script><script defer=defer src=/js/chunk-vendors-377fed06.0e89b4b7.js></script><script defer=defer src=/js/chunk-vendors-c9ff040c.57bd8c18.js></script><script defer=defer src=/js/app-42f9d7e6.11a01d0a.js></script><script defer=defer src=/js/app-5c551db8.3726e21e.js></script><script defer=defer src=/js/app-45954fd3.1331a09e.js></script><script defer=defer src=/js/app-72600b29.ead62671.js></script><script defer=defer src=/js/app-5a0d40dd.b726f201.js></script><script defer=defer src=/js/app-113c6c50.ede228a3.js></script><link href=/css/chunk-vendors-bc050c32.6f97509c.css rel=stylesheet><link href=/css/app-189e7968.ecff2d4d.css rel=stylesheet></head><body><div id=app></div></body></html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><meta name=google-site-verification content=pKAZogQ0NQ6L4j9-V58WJMjm7zYCFwkJXSJzWu9UDM8><meta name=robots content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"><meta name=googlebot content="index, follow"><meta name=googlebot-news content="index, follow"><meta name=bingbot content="index, follow"><link rel=alternate hreflang=zh href=https://m2pool.com/zh><link rel=alternate hreflang=en href=https://m2pool.com/en><link rel=alternate hreflang=x-default href=https://m2pool.com/en><meta property=og:title content="M2pool - Stable leading high-yield mining pool"><meta property=og:description content="M2Pool provides professional mining services, supporting multiple cryptocurrency mining"><meta property=og:url content=https://m2pool.com/en><meta property=og:site_name content=M2Pool><meta property=og:type content=website><meta property=og:image content=https://m2pool.com/logo.png><link rel=icon href=/favicon.ico><link rel=stylesheet href=//at.alicdn.com/t/c/font_4582735_7i8wfzc0art.css><title>M2pool - Stable leading high-yield mining pool</title><meta name=keywords content="M2Pool, cryptocurrency mining pool,entropyx, bitcoin mining, DGB mining, mining pool service, 加密货币矿池, 比特币挖矿, DGB挖矿"><meta name=description content="M2Pool provides professional mining services, supporting multiple cryptocurrency mining, including nexa, grs, mona, dgb, rxd"><script defer=defer src=/js/chunk-vendors-c0d76f48.f34181ba.js></script><script defer=defer src=/js/chunk-vendors-bc050c32.8062ab74.js></script><script defer=defer src=/js/chunk-vendors-3003db77.d0b93d36.js></script><script defer=defer src=/js/chunk-vendors-9d134daf.bb668c99.js></script><script defer=defer src=/js/chunk-vendors-96cecd74.a7d9b845.js></script><script defer=defer src=/js/chunk-vendors-c2f7d60e.3710fdc2.js></script><script defer=defer src=/js/chunk-vendors-89d5c698.2190b4ca.js></script><script defer=defer src=/js/chunk-vendors-377fed06.0e89b4b7.js></script><script defer=defer src=/js/chunk-vendors-c9ff040c.57bd8c18.js></script><script defer=defer src=/js/app-42f9d7e6.4bc16611.js></script><script defer=defer src=/js/app-5c551db8.e2a6dea3.js></script><script defer=defer src=/js/app-45954fd3.1331a09e.js></script><script defer=defer src=/js/app-72600b29.ca319ab4.js></script><script defer=defer src=/js/app-5a0d40dd.3a7bea46.js></script><script defer=defer src=/js/app-113c6c50.bea1eb5d.js></script><link href=/css/chunk-vendors-bc050c32.6f97509c.css rel=stylesheet><link href=/css/app-189e7968.5f96dc5b.css rel=stylesheet></head><body><div id=app></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long