2025-03-12 13:38:44 +08:00
|
|
|
<template>
|
2025-04-16 11:42:05 +08:00
|
|
|
<div class="welcome" @keyup.enter="register">
|
2025-03-12 13:38:44 +08:00
|
|
|
<el-container style="height: 100%;">
|
|
|
|
|
<!-- 保持相同的头部 -->
|
|
|
|
|
<el-header>
|
|
|
|
|
<div style="display: flex;align-items: center;margin-top: 15px;margin-left: 10px;gap: 10px;">
|
2025-04-05 20:19:28 +08:00
|
|
|
<img loading="lazy" alt="" src="@/assets/xiaozhi-logo.png" style="width: 45px;height: 45px;" />
|
2025-04-05 21:22:54 +08:00
|
|
|
<img loading="lazy" alt="" src="@/assets/xiaozhi-ai.png" style="height: 18px;" />
|
2025-03-12 13:38:44 +08:00
|
|
|
</div>
|
|
|
|
|
</el-header>
|
2025-04-05 21:22:54 +08:00
|
|
|
<div class="login-person">
|
2025-04-06 20:55:11 +08:00
|
|
|
<img loading="lazy" alt="" src="@/assets/login/register-person.png" style="width: 100%;" />
|
2025-04-05 21:22:54 +08:00
|
|
|
</div>
|
2025-03-12 13:38:44 +08:00
|
|
|
<el-main style="position: relative;">
|
|
|
|
|
<div class="login-box">
|
|
|
|
|
<!-- 修改标题部分 -->
|
|
|
|
|
<div style="display: flex;align-items: center;gap: 20px;margin-bottom: 39px;padding: 0 30px;">
|
2025-04-05 20:19:28 +08:00
|
|
|
<img loading="lazy" alt="" src="@/assets/login/hi.png" style="width: 34px;height: 34px;" />
|
2025-09-11 17:10:50 +08:00
|
|
|
<div class="login-text">{{ $t('register.title') }}</div>
|
2025-03-12 13:38:44 +08:00
|
|
|
<div class="login-welcome">
|
2025-09-11 17:10:50 +08:00
|
|
|
{{ $t('register.welcome') }}
|
2025-03-12 13:38:44 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style="padding: 0 30px;">
|
2025-05-18 17:38:20 +08:00
|
|
|
<form @submit.prevent="register">
|
|
|
|
|
<!-- 用户名/手机号输入框 -->
|
|
|
|
|
<div class="input-box" v-if="!enableMobileRegister">
|
|
|
|
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/username.png" />
|
2025-09-11 17:10:50 +08:00
|
|
|
<el-input v-model="form.username" :placeholder="$t('register.usernamePlaceholder')" />
|
2025-03-12 13:38:44 +08:00
|
|
|
</div>
|
|
|
|
|
|
2025-05-18 17:38:20 +08:00
|
|
|
<!-- 手机号注册部分 -->
|
|
|
|
|
<template v-if="enableMobileRegister">
|
|
|
|
|
<div class="input-box">
|
|
|
|
|
<div style="display: flex; align-items: center; width: 100%;">
|
|
|
|
|
<el-select v-model="form.areaCode" style="width: 220px; margin-right: 10px;">
|
|
|
|
|
<el-option v-for="item in mobileAreaList" :key="item.key" :label="`${item.name} (${item.key})`"
|
|
|
|
|
:value="item.key" />
|
|
|
|
|
</el-select>
|
2025-09-11 17:10:50 +08:00
|
|
|
<el-input v-model="form.mobile" :placeholder="$t('register.mobilePlaceholder')" />
|
2025-05-18 17:38:20 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
|
|
|
|
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
|
|
|
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/shield.png" />
|
2025-09-11 17:10:50 +08:00
|
|
|
<el-input v-model="form.captcha" :placeholder="$t('register.captchaPlaceholder')" style="flex: 1;" />
|
2025-05-18 17:38:20 +08:00
|
|
|
</div>
|
2025-09-17 11:36:25 +08:00
|
|
|
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
|
2025-05-18 17:38:20 +08:00
|
|
|
style="width: 150px; height: 40px; cursor: pointer;" @click="fetchCaptcha" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 手机验证码 -->
|
|
|
|
|
|
|
|
|
|
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
|
|
|
|
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
|
|
|
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/phone.png" />
|
2025-09-11 17:10:50 +08:00
|
|
|
<el-input v-model="form.mobileCaptcha" :placeholder="$t('register.mobileCaptchaPlaceholder')" style="flex: 1;" maxlength="6" />
|
2025-05-18 17:38:20 +08:00
|
|
|
</div>
|
|
|
|
|
<el-button type="primary" class="send-captcha-btn" :disabled="!canSendMobileCaptcha"
|
|
|
|
|
@click="sendMobileCaptcha">
|
|
|
|
|
<span>
|
2025-09-17 11:36:25 +08:00
|
|
|
{{ countdown > 0 ? `${countdown}${$t('register.secondsLater')}` : $t('register.sendCaptcha') }}
|
2025-05-18 17:38:20 +08:00
|
|
|
</span>
|
|
|
|
|
</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- 密码输入框 -->
|
|
|
|
|
<div class="input-box">
|
|
|
|
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
2025-09-11 17:10:50 +08:00
|
|
|
<el-input v-model="form.password" :placeholder="$t('register.passwordPlaceholder')" type="password" show-password />
|
2025-05-18 17:38:20 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 新增确认密码 -->
|
|
|
|
|
<div class="input-box">
|
|
|
|
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
2025-09-11 17:10:50 +08:00
|
|
|
<el-input v-model="form.confirmPassword" :placeholder="$t('register.confirmPasswordPlaceholder')" type="password" show-password />
|
2025-05-18 17:38:20 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 验证码部分保持相同 -->
|
|
|
|
|
<div v-if="!enableMobileRegister"
|
|
|
|
|
style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
|
|
|
|
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
|
|
|
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/shield.png" />
|
2025-09-11 17:10:50 +08:00
|
|
|
<el-input v-model="form.captcha" :placeholder="$t('register.captchaPlaceholder')" style="flex: 1;" />
|
2025-05-18 17:38:20 +08:00
|
|
|
</div>
|
|
|
|
|
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
|
|
|
|
|
style="width: 150px; height: 40px; cursor: pointer;" @click="fetchCaptcha" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 修改底部链接 -->
|
|
|
|
|
<div style="font-weight: 400;font-size: 14px;text-align: left;color: #5778ff;margin-top: 20px;">
|
2025-09-11 17:10:50 +08:00
|
|
|
<div style="cursor: pointer;" @click="goToLogin">{{ $t('register.goToLogin') }}</div>
|
2025-05-18 17:38:20 +08:00
|
|
|
</div>
|
|
|
|
|
</form>
|
2025-03-12 13:38:44 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 修改按钮文本 -->
|
2025-09-11 17:10:50 +08:00
|
|
|
<div class="login-btn" @click="register">{{ $t('register.registerButton') }}</div>
|
2025-03-12 13:38:44 +08:00
|
|
|
|
|
|
|
|
<!-- 保持相同的协议声明 -->
|
|
|
|
|
<div style="font-size: 14px;color: #979db1;">
|
2025-09-11 17:10:50 +08:00
|
|
|
{{ $t('register.agreeTo') }}
|
|
|
|
|
<div style="display: inline-block;color: #5778FF;cursor: pointer;">{{ $t('register.userAgreement') }}</div>
|
|
|
|
|
{{ $t('register.and') }}
|
|
|
|
|
<div style="display: inline-block;color: #5778FF;cursor: pointer;">{{ $t('register.privacyPolicy') }}</div>
|
2025-03-12 13:38:44 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</el-main>
|
|
|
|
|
|
|
|
|
|
<!-- 保持相同的页脚 -->
|
|
|
|
|
<el-footer>
|
2025-04-15 01:46:36 +08:00
|
|
|
<version-footer />
|
2025-03-12 13:38:44 +08:00
|
|
|
</el-footer>
|
|
|
|
|
</el-container>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import Api from '@/apis/api';
|
2025-04-15 01:46:36 +08:00
|
|
|
import VersionFooter from '@/components/VersionFooter.vue';
|
2025-09-25 09:15:41 +08:00
|
|
|
import { getUUID, goToPage, showDanger, showSuccess, validateMobile, generateSm2KeyPairHex, sm2Encrypt, isBase64 } from '@/utils';
|
2025-04-15 13:03:29 +08:00
|
|
|
import { mapState } from 'vuex';
|
2025-09-25 09:15:41 +08:00
|
|
|
import Constant from '@/utils/constant';
|
2025-03-12 13:38:44 +08:00
|
|
|
|
2025-09-11 17:10:50 +08:00
|
|
|
// 导入语言切换功能
|
|
|
|
|
import { changeLanguage } from '@/i18n';
|
|
|
|
|
|
2025-03-12 13:38:44 +08:00
|
|
|
export default {
|
|
|
|
|
name: 'register',
|
2025-04-15 01:46:36 +08:00
|
|
|
components: {
|
|
|
|
|
VersionFooter
|
|
|
|
|
},
|
2025-04-15 13:03:29 +08:00
|
|
|
computed: {
|
|
|
|
|
...mapState({
|
2025-05-18 17:38:20 +08:00
|
|
|
allowUserRegister: state => state.pubConfig.allowUserRegister,
|
|
|
|
|
enableMobileRegister: state => state.pubConfig.enableMobileRegister,
|
|
|
|
|
mobileAreaList: state => state.pubConfig.mobileAreaList
|
|
|
|
|
}),
|
|
|
|
|
canSendMobileCaptcha() {
|
|
|
|
|
return this.countdown === 0 && validateMobile(this.form.mobile, this.form.areaCode);
|
|
|
|
|
}
|
2025-04-15 13:03:29 +08:00
|
|
|
},
|
2025-03-12 13:38:44 +08:00
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
form: {
|
|
|
|
|
username: '',
|
|
|
|
|
password: '',
|
|
|
|
|
confirmPassword: '',
|
|
|
|
|
captcha: '',
|
2025-05-18 17:38:20 +08:00
|
|
|
captchaId: '',
|
|
|
|
|
areaCode: '+86',
|
|
|
|
|
mobile: '',
|
|
|
|
|
mobileCaptcha: ''
|
2025-03-12 13:38:44 +08:00
|
|
|
},
|
2025-05-18 17:38:20 +08:00
|
|
|
captchaUrl: '',
|
|
|
|
|
countdown: 0,
|
2025-09-25 09:15:41 +08:00
|
|
|
timer: null,
|
|
|
|
|
serverPublicKey: "", // 服务器公钥
|
|
|
|
|
clientKeyPair: null, // 客户端密钥对
|
|
|
|
|
isGettingPublicKey: false // 获取公钥状态
|
2025-03-12 13:38:44 +08:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
mounted() {
|
2025-04-15 13:03:29 +08:00
|
|
|
this.$store.dispatch('fetchPubConfig').then(() => {
|
|
|
|
|
if (!this.allowUserRegister) {
|
2025-09-12 11:41:31 +08:00
|
|
|
showDanger(this.$t('register.notAllowRegister'));
|
2025-04-15 13:03:29 +08:00
|
|
|
setTimeout(() => {
|
|
|
|
|
goToPage('/login');
|
|
|
|
|
}, 1500);
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-03-12 13:38:44 +08:00
|
|
|
this.fetchCaptcha();
|
2025-09-25 09:15:41 +08:00
|
|
|
// 获取服务器公钥
|
|
|
|
|
this.getServerPublicKey();
|
|
|
|
|
// 生成客户端密钥对
|
|
|
|
|
this.generateClientKeyPair();
|
2025-03-12 13:38:44 +08:00
|
|
|
},
|
|
|
|
|
methods: {
|
2025-09-25 09:15:41 +08:00
|
|
|
// 获取服务器公钥
|
|
|
|
|
getServerPublicKey() {
|
|
|
|
|
console.log('开始获取服务器公钥...');
|
|
|
|
|
// 先从本地存储获取
|
|
|
|
|
const storedPublicKey = localStorage.getItem(Constant.STORAGE_KEY.PUBLIC_KEY);
|
|
|
|
|
if (storedPublicKey) {
|
|
|
|
|
console.log('从本地存储获取到公钥,长度:', storedPublicKey.length);
|
|
|
|
|
this.serverPublicKey = storedPublicKey;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('本地存储无公钥,从服务器获取...');
|
|
|
|
|
// 从服务器获取公钥
|
|
|
|
|
Api.user.getSM2PublicKey(
|
|
|
|
|
(res) => {
|
|
|
|
|
if (res.data && res.data.data) {
|
|
|
|
|
console.log('获取到服务器公钥,长度:', res.data.data.length);
|
|
|
|
|
this.serverPublicKey = res.data.data;
|
|
|
|
|
// 存储到本地
|
|
|
|
|
localStorage.setItem(Constant.STORAGE_KEY.PUBLIC_KEY, this.serverPublicKey);
|
|
|
|
|
console.log('公钥已存储到本地');
|
|
|
|
|
} else {
|
|
|
|
|
console.error('服务器返回数据格式异常:', res);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
(err) => {
|
|
|
|
|
console.error("获取SM2公钥失败:", err);
|
|
|
|
|
showDanger(this.$t('sm2.failedToGetPublicKey'));
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 生成客户端密钥对
|
|
|
|
|
generateClientKeyPair() {
|
|
|
|
|
this.clientKeyPair = generateSm2KeyPairHex();
|
|
|
|
|
},
|
|
|
|
|
|
2025-03-12 13:38:44 +08:00
|
|
|
// 复用验证码获取方法
|
|
|
|
|
fetchCaptcha() {
|
2025-03-12 23:31:59 +08:00
|
|
|
this.form.captchaId = getUUID();
|
|
|
|
|
Api.user.getCaptcha(this.form.captchaId, (res) => {
|
2025-03-12 13:38:44 +08:00
|
|
|
if (res.status === 200) {
|
2025-04-05 20:19:28 +08:00
|
|
|
const blob = new Blob([res.data], { type: res.data.type });
|
2025-03-12 13:38:44 +08:00
|
|
|
this.captchaUrl = URL.createObjectURL(blob);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
console.error('验证码加载异常:', error);
|
2025-09-12 11:41:31 +08:00
|
|
|
showDanger(this.$t('register.captchaLoadFailed'));
|
2025-03-12 13:38:44 +08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
2025-03-20 16:05:06 +08:00
|
|
|
// 封装输入验证逻辑
|
|
|
|
|
validateInput(input, message) {
|
|
|
|
|
if (!input.trim()) {
|
|
|
|
|
showDanger(message);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
},
|
2025-05-18 17:38:20 +08:00
|
|
|
|
|
|
|
|
// 发送手机验证码
|
|
|
|
|
sendMobileCaptcha() {
|
|
|
|
|
if (!validateMobile(this.form.mobile, this.form.areaCode)) {
|
2025-09-12 11:41:31 +08:00
|
|
|
showDanger(this.$t('register.inputCorrectMobile'));
|
2025-03-20 16:05:06 +08:00
|
|
|
return;
|
2025-03-12 13:38:44 +08:00
|
|
|
}
|
2025-05-18 17:38:20 +08:00
|
|
|
|
|
|
|
|
// 验证图形验证码
|
2025-09-12 11:41:31 +08:00
|
|
|
if (!this.validateInput(this.form.captcha, this.$t('register.inputCaptcha'))) {
|
2025-05-19 21:19:24 +08:00
|
|
|
this.fetchCaptcha();
|
2025-05-18 17:38:20 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 清除可能存在的旧定时器
|
|
|
|
|
if (this.timer) {
|
|
|
|
|
clearInterval(this.timer);
|
|
|
|
|
this.timer = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 开始倒计时
|
|
|
|
|
this.countdown = 60;
|
|
|
|
|
this.timer = setInterval(() => {
|
|
|
|
|
if (this.countdown > 0) {
|
|
|
|
|
this.countdown--;
|
|
|
|
|
} else {
|
|
|
|
|
clearInterval(this.timer);
|
|
|
|
|
this.timer = null;
|
|
|
|
|
}
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
|
|
// 调用发送验证码接口
|
|
|
|
|
Api.user.sendSmsVerification({
|
|
|
|
|
phone: this.form.areaCode + this.form.mobile,
|
|
|
|
|
captcha: this.form.captcha,
|
|
|
|
|
captchaId: this.form.captchaId
|
|
|
|
|
}, (res) => {
|
2025-09-12 11:41:31 +08:00
|
|
|
showSuccess(this.$t('register.captchaSendSuccess'));
|
2025-05-18 17:38:20 +08:00
|
|
|
}, (err) => {
|
2025-09-12 11:41:31 +08:00
|
|
|
showDanger(err.data.msg || this.$t('register.captchaSendFailed'));
|
2025-05-18 17:38:20 +08:00
|
|
|
this.countdown = 0;
|
|
|
|
|
this.fetchCaptcha();
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 注册逻辑
|
2025-09-25 09:15:41 +08:00
|
|
|
async register() {
|
2025-05-18 17:38:20 +08:00
|
|
|
if (this.enableMobileRegister) {
|
|
|
|
|
// 手机号注册验证
|
|
|
|
|
if (!validateMobile(this.form.mobile, this.form.areaCode)) {
|
2025-09-12 11:41:31 +08:00
|
|
|
showDanger(this.$t('register.inputCorrectMobile'));
|
2025-05-18 17:38:20 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!this.form.mobileCaptcha) {
|
2025-09-17 11:36:25 +08:00
|
|
|
showDanger(this.$t('register.requiredMobileCaptcha'));
|
2025-05-18 17:38:20 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 用户名注册验证
|
2025-09-17 11:36:25 +08:00
|
|
|
if (!this.validateInput(this.form.username, this.$t('register.requiredUsername'))) {
|
2025-05-18 17:38:20 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-20 16:05:06 +08:00
|
|
|
// 验证密码
|
2025-09-17 11:36:25 +08:00
|
|
|
if (!this.validateInput(this.form.password, this.$t('register.requiredPassword'))) {
|
2025-03-20 16:05:06 +08:00
|
|
|
return;
|
2025-03-12 13:38:44 +08:00
|
|
|
}
|
|
|
|
|
if (this.form.password !== this.form.confirmPassword) {
|
2025-09-12 11:41:31 +08:00
|
|
|
showDanger(this.$t('register.passwordsNotMatch'))
|
2025-03-12 13:38:44 +08:00
|
|
|
return
|
|
|
|
|
}
|
2025-03-20 16:05:06 +08:00
|
|
|
// 验证验证码
|
2025-09-17 11:36:25 +08:00
|
|
|
if (!this.validateInput(this.form.captcha, this.$t('register.requiredCaptcha'))) {
|
2025-03-20 16:05:06 +08:00
|
|
|
return;
|
2025-03-12 13:38:44 +08:00
|
|
|
}
|
2025-03-20 16:05:06 +08:00
|
|
|
|
2025-09-25 09:15:41 +08:00
|
|
|
// 检查服务器公钥是否已获取,如果未获取则重新获取
|
|
|
|
|
if (!this.serverPublicKey) {
|
|
|
|
|
try {
|
|
|
|
|
// 等待公钥获取完成
|
|
|
|
|
await new Promise((resolve, reject) => {
|
|
|
|
|
this.getServerPublicKey();
|
|
|
|
|
// 设置超时检查,最多等待3秒
|
|
|
|
|
const checkInterval = setInterval(() => {
|
|
|
|
|
if (this.serverPublicKey) {
|
|
|
|
|
clearInterval(checkInterval);
|
|
|
|
|
resolve();
|
|
|
|
|
}
|
|
|
|
|
}, 100);
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
clearInterval(checkInterval);
|
|
|
|
|
if (!this.serverPublicKey) {
|
|
|
|
|
reject(new Error('获取公钥超时'));
|
|
|
|
|
}
|
|
|
|
|
}, 3000);
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
showDanger(this.$t('sm2.failedToGetPublicKey'));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-05-18 17:38:20 +08:00
|
|
|
}
|
|
|
|
|
|
2025-09-25 09:15:41 +08:00
|
|
|
// 加密密码
|
|
|
|
|
let encryptedPassword = this.form.password;
|
|
|
|
|
if (!this.isSM2Encrypted(this.form.password)) {
|
|
|
|
|
try {
|
|
|
|
|
encryptedPassword = sm2Encrypt(this.serverPublicKey, this.form.password);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("密码加密失败:", error);
|
|
|
|
|
showDanger(this.$t('sm2.encryptionFailed'));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 加密用户名
|
|
|
|
|
let encryptedUsername = this.form.username;
|
|
|
|
|
if (this.enableMobileRegister) {
|
|
|
|
|
this.form.username = this.form.areaCode + this.form.mobile;
|
|
|
|
|
encryptedUsername = this.form.username;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!this.isSM2Encrypted(encryptedUsername)) {
|
|
|
|
|
try {
|
|
|
|
|
encryptedUsername = sm2Encrypt(this.serverPublicKey, encryptedUsername);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("用户名加密失败:", error);
|
|
|
|
|
showDanger(this.$t('sm2.encryptionFailed'));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 准备注册数据
|
|
|
|
|
const registerData = {
|
|
|
|
|
...this.form,
|
|
|
|
|
username: encryptedUsername,
|
|
|
|
|
password: encryptedPassword,
|
|
|
|
|
confirmPassword: encryptedPassword
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Api.user.register(registerData, ({ data }) => {
|
2025-09-12 11:41:31 +08:00
|
|
|
showSuccess(this.$t('register.registerSuccess'))
|
2025-05-18 17:38:20 +08:00
|
|
|
goToPage('/login')
|
|
|
|
|
}, (err) => {
|
2025-09-12 11:41:31 +08:00
|
|
|
showDanger(err.data.msg || this.$t('register.registerFailed'))
|
2025-05-18 17:38:20 +08:00
|
|
|
if (err.data != null && err.data.msg != null && err.data.msg.indexOf('图形验证码') > -1) {
|
2025-03-12 13:38:44 +08:00
|
|
|
this.fetchCaptcha()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
goToLogin() {
|
|
|
|
|
goToPage('/login')
|
2025-09-25 09:15:41 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 判断字符串是否为SM2加密格式(十六进制格式)
|
|
|
|
|
* @param {string} str 待判断的字符串
|
|
|
|
|
* @returns {boolean} 是否为SM2加密格式
|
|
|
|
|
*/
|
|
|
|
|
isSM2Encrypted(str) {
|
|
|
|
|
if (typeof str !== 'string' || str.trim() === '') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// 长度大于100且只包含0-9,a-f,A-F字符
|
|
|
|
|
return str.length > 100 && /^[0-9a-fA-F]+$/.test(str);
|
2025-03-12 13:38:44 +08:00
|
|
|
}
|
2025-05-18 17:38:20 +08:00
|
|
|
},
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
if (this.timer) {
|
|
|
|
|
clearInterval(this.timer);
|
|
|
|
|
}
|
2025-03-12 13:38:44 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
2025-03-20 16:05:06 +08:00
|
|
|
<style lang="scss" scoped>
|
2025-05-18 17:38:20 +08:00
|
|
|
@import './auth.scss';
|
|
|
|
|
|
|
|
|
|
.send-captcha-btn {
|
|
|
|
|
margin-right: -5px;
|
|
|
|
|
min-width: 100px;
|
|
|
|
|
height: 40px;
|
|
|
|
|
line-height: 40px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
background: rgb(87, 120, 255);
|
|
|
|
|
border: none;
|
|
|
|
|
padding: 0px;
|
|
|
|
|
|
|
|
|
|
&:disabled {
|
|
|
|
|
background: #c0c4cc;
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|