add:登录页面和注册页面增加手机号码选项

This commit is contained in:
hrz
2025-05-18 17:38:20 +08:00
parent 91d2ab7d1d
commit fe88db2094
25 changed files with 701 additions and 217 deletions
@@ -48,8 +48,7 @@
<el-table ref="dictDataTable" :data="dictDataList" style="width: 100%"
v-loading="dictDataLoading" element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.7)"
class="data-table"
element-loading-background="rgba(255, 255, 255, 0.7)" class="data-table"
header-row-class-name="table-header">
<el-table-column label="选择" align="center" width="55">
<template slot-scope="scope">
@@ -546,6 +545,7 @@ export default {
:deep(.el-table__body-wrapper) {
max-height: calc(var(--table-max-height) - 40px);
overflow-y: auto;
}
:deep(.el-table__body) {
+1 -14
View File
@@ -66,20 +66,7 @@
cursor: pointer;
color: #fff;
line-height: 35px;
margin: 35px 15px 15px;
}
.code-send {
width: 70px;
height: 32px;
border-radius: 10px;
background: #e6ebff;
line-height: 32px;
font-weight: 400;
font-size: 14px;
color: #5778ff;
flex-shrink: 0;
cursor: pointer;
margin: 15px 30px 15px 30px;
}
.input-box {
+100 -19
View File
@@ -20,10 +20,27 @@
</div>
</div>
<div style="padding: 0 30px;">
<div class="input-box">
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/username.png" />
<el-input v-model="form.username" placeholder="请输入用户名" />
</div>
<!-- 用户名登录 -->
<template v-if="!isMobileLogin">
<div class="input-box">
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/username.png" />
<el-input v-model="form.username" placeholder="请输入用户名" />
</div>
</template>
<!-- 手机号登录 -->
<template v-else>
<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>
<el-input v-model="form.mobile" placeholder="请输入手机号码" />
</div>
</div>
</template>
<div class="input-box">
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
<el-input v-model="form.password" placeholder="请输入密码" type="password" />
@@ -42,6 +59,19 @@
</div>
</div>
<div class="login-btn" @click="login">登录</div>
<!-- 登录方式切换按钮 -->
<div class="login-type-container">
<el-tooltip content="手机号码登录" placement="bottom">
<el-button :type="isMobileLogin ? 'primary' : 'default'" icon="el-icon-mobile" circle
@click="switchLoginType('mobile')"></el-button>
</el-tooltip>
<el-tooltip content="用户名登录" placement="bottom">
<el-button :type="!isMobileLogin ? 'primary' : 'default'" icon="el-icon-user" circle
@click="switchLoginType('username')"></el-button>
</el-tooltip>
</div>
<div style="font-size: 14px;color: #979db1;">
登录即同意
<div style="display: inline-block;color: #5778FF;cursor: pointer;">用户协议</div>
@@ -60,7 +90,7 @@
<script>
import Api from '@/apis/api';
import VersionFooter from '@/components/VersionFooter.vue';
import { getUUID, goToPage, showDanger, showSuccess } from '@/utils';
import { getUUID, goToPage, showDanger, showSuccess, validateMobile } from '@/utils';
import { mapState } from 'vuex';
export default {
@@ -70,7 +100,9 @@ export default {
},
computed: {
...mapState({
allowUserRegister: state => state.pubConfig.allowUserRegister
allowUserRegister: state => state.pubConfig.allowUserRegister,
enableMobileRegister: state => state.pubConfig.enableMobileRegister,
mobileAreaList: state => state.pubConfig.mobileAreaList
})
},
data() {
@@ -80,15 +112,21 @@ export default {
username: '',
password: '',
captcha: '',
captchaId: ''
captchaId: '',
areaCode: '+86',
mobile: ''
},
captchaUuid: '',
captchaUrl: ''
captchaUrl: '',
isMobileLogin: false
}
},
mounted() {
this.fetchCaptcha();
this.$store.dispatch('fetchPubConfig');
this.$store.dispatch('fetchPubConfig').then(() => {
// 根据配置决定默认登录方式
this.isMobileLogin = this.enableMobileRegister;
});
},
methods: {
fetchCaptcha() {
@@ -110,6 +148,17 @@ export default {
}
},
// 切换登录方式
switchLoginType(type) {
this.isMobileLogin = type === 'mobile';
// 清空表单
this.form.username = '';
this.form.mobile = '';
this.form.password = '';
this.form.captcha = '';
this.fetchCaptcha();
},
// 封装输入验证逻辑
validateInput(input, message) {
if (!input.trim()) {
@@ -120,10 +169,21 @@ export default {
},
async login() {
// 验证用户名
if (!this.validateInput(this.form.username, '用户名不能为空')) {
return;
if (this.isMobileLogin) {
// 手机号登录验证
if (!validateMobile(this.form.mobile, this.form.areaCode)) {
showDanger('请输入正确的手机号码');
return;
}
// 拼接手机号作为用户名
this.form.username = this.form.areaCode + this.form.mobile;
} else {
// 用户名登录验证
if (!this.validateInput(this.form.username, '用户名不能为空')) {
return;
}
}
// 验证密码
if (!this.validateInput(this.form.password, '密码不能为空')) {
return;
@@ -135,12 +195,12 @@ export default {
this.form.captchaId = this.captchaUuid
Api.user.login(this.form, ({ data }) => {
if (data.code === 0) {
showSuccess('登录成功!');
this.$store.commit('setToken', JSON.stringify(data.data));
goToPage('/home');
} else {
showDanger(data.msg || '登录失败');
showSuccess('登录成功!');
this.$store.commit('setToken', JSON.stringify(data.data));
goToPage('/home');
}, (err) => {
if (err.data != null && err.data.msg != null && err.data.msg.indexOf('图形验证码') > -1) {
this.fetchCaptcha()
}
})
@@ -157,4 +217,25 @@ export default {
}
</script>
<style lang="scss" scoped>
@import './auth.scss'; // 添加这行引用</style>
@import './auth.scss';
.login-type-container {
margin: 10px 20px;
}
:deep(.el-button--primary) {
background-color: #5778ff;
border-color: #5778ff;
&:hover,
&:focus {
background-color: #4a6ae8;
border-color: #4a6ae8;
}
&:active {
background-color: #3d5cd6;
border-color: #3d5cd6;
}
}
</style>
+179 -48
View File
@@ -23,38 +23,78 @@
</div>
<div style="padding: 0 30px;">
<!-- 用户名输入框 -->
<div class="input-box">
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/username.png" />
<el-input v-model="form.username" placeholder="请输入用户名" />
</div>
<!-- 密码输入框 -->
<div class="input-box">
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
<el-input v-model="form.password" placeholder="请输入密码" type="password" />
</div>
<!-- 新增确认密码 -->
<div class="input-box">
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
<el-input v-model="form.confirmPassword" placeholder="请确认密码" type="password" />
</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" />
<el-input v-model="form.captcha" placeholder="请输入验证码" style="flex: 1;" />
<form @submit.prevent="register">
<!-- 用户名/手机号输入框 -->
<div class="input-box" v-if="!enableMobileRegister">
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/username.png" />
<el-input v-model="form.username" placeholder="请输入用户名" />
</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;">
<div style="cursor: pointer;" @click="goToLogin">已有账号立即登录</div>
</div>
<!-- 手机号注册部分 -->
<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>
<el-input v-model="form.mobile" placeholder="请输入手机号码" />
</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" />
<el-input v-model="form.captcha" placeholder="请输入验证码" style="flex: 1;" />
</div>
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
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" />
<el-input v-model="form.mobileCaptcha" placeholder="请输入手机验证码" style="flex: 1;" maxlength="6" />
</div>
<el-button type="primary" class="send-captcha-btn" :disabled="!canSendMobileCaptcha"
@click="sendMobileCaptcha">
<span>
{{ countdown > 0 ? `${countdown}秒后重试` : '发送验证码' }}
</span>
</el-button>
</div>
</template>
<!-- 密码输入框 -->
<div class="input-box">
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
<el-input v-model="form.password" placeholder="请输入密码" type="password" />
</div>
<!-- 新增确认密码 -->
<div class="input-box">
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
<el-input v-model="form.confirmPassword" placeholder="请确认密码" type="password" />
</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" />
<el-input v-model="form.captcha" placeholder="请输入验证码" style="flex: 1;" />
</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;">
<div style="cursor: pointer;" @click="goToLogin">已有账号立即登录</div>
</div>
</form>
</div>
<!-- 修改按钮文本 -->
@@ -81,7 +121,7 @@
<script>
import Api from '@/apis/api';
import VersionFooter from '@/components/VersionFooter.vue';
import { getUUID, goToPage, showDanger, showSuccess } from '@/utils';
import { getUUID, goToPage, showDanger, showSuccess, validateMobile } from '@/utils';
import { mapState } from 'vuex';
export default {
@@ -91,8 +131,13 @@ export default {
},
computed: {
...mapState({
allowUserRegister: state => state.pubConfig.allowUserRegister
})
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);
}
},
data() {
return {
@@ -101,9 +146,14 @@ export default {
password: '',
confirmPassword: '',
captcha: '',
captchaId: ''
captchaId: '',
areaCode: '+86',
mobile: '',
mobileCaptcha: ''
},
captchaUrl: ''
captchaUrl: '',
countdown: 0,
timer: null
}
},
mounted() {
@@ -141,12 +191,69 @@ export default {
}
return true;
},
// 注册逻辑
register() {
// 验证用户名
if (!this.validateInput(this.form.username, '用户名不能为空')) {
// 发送手机验证码
sendMobileCaptcha() {
if (!validateMobile(this.form.mobile, this.form.areaCode)) {
showDanger('请输入正确的手机号码');
return;
}
// 验证图形验证码
if (!this.validateInput(this.form.captcha, '请输入图形验证码')) {
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) => {
showSuccess('验证码发送成功');
}, (err) => {
showDanger(err.data.msg || '验证码发送失败');
this.countdown = 0;
this.fetchCaptcha();
});
},
// 注册逻辑
register() {
if (this.enableMobileRegister) {
// 手机号注册验证
if (!validateMobile(this.form.mobile, this.form.areaCode)) {
showDanger('请输入正确的手机号码');
return;
}
if (!this.form.mobileCaptcha) {
showDanger('请输入手机验证码');
return;
}
} else {
// 用户名注册验证
if (!this.validateInput(this.form.username, '用户名不能为空')) {
return;
}
}
// 验证密码
if (!this.validateInput(this.form.password, '密码不能为空')) {
return;
@@ -160,26 +267,50 @@ export default {
return;
}
if (this.enableMobileRegister) {
this.form.username = this.form.areaCode + this.form.mobile
}
Api.user.register(this.form, ({ data }) => {
if (data.code === 0) {
showSuccess('注册成功!')
goToPage('/login')
} else {
showDanger(data.msg || '注册失败')
showSuccess('注册成功!')
goToPage('/login')
}, (err) => {
showDanger(err.data.msg || '注册失败')
if (err.data != null && err.data.msg != null && err.data.msg.indexOf('图形验证码') > -1) {
this.fetchCaptcha()
}
})
setTimeout(() => {
this.fetchCaptcha()
}, 1000)
},
goToLogin() {
goToPage('/login')
}
},
beforeDestroy() {
if (this.timer) {
clearInterval(this.timer);
}
}
}
</script>
<style lang="scss" scoped>
@import './auth.scss'; // 修改为导入新建的SCSS文件</style>
@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>