feat: 增加忘记密码
parent
ce41faacc5
commit
edfe5a56e2
|
|
@ -26,6 +26,9 @@ declare module 'vue' {
|
|||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
||||
ATextarea: typeof import('ant-design-vue/es')['Textarea']
|
||||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||
Empty: typeof import('./src/components/empty/Empty.vue')['default']
|
||||
ImageCropper: typeof import('./src/components/image-cropper/index.vue')['default']
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ export function logout() {
|
|||
}
|
||||
export function getConfig(params) {
|
||||
return request.get('/sms/v1/logo', {
|
||||
params: wrapperParams(params),
|
||||
params: wrapperParams(params)
|
||||
})
|
||||
}
|
||||
export function getDict(data) {
|
||||
return request.get('/dict/children', {
|
||||
params: wrapperParams(data),
|
||||
params: wrapperParams(data)
|
||||
})
|
||||
}
|
||||
export function getSysconf() {
|
||||
|
|
@ -48,7 +48,7 @@ export function getPortal(params) {
|
|||
}
|
||||
export function getServiceQuota(tenantId, data) {
|
||||
return request.get(`/cos/v1/tenants/${tenantId}/quotas`, {
|
||||
params: wrapperParams(data),
|
||||
params: wrapperParams(data)
|
||||
})
|
||||
}
|
||||
export function replaceToken(params) {
|
||||
|
|
@ -69,7 +69,7 @@ export function getSystemTreeConfigs(params) {
|
|||
// 更新系统配置信息
|
||||
export function updateSystemConfigs(params) {
|
||||
return request.put('/sms/v1/system-configs', params, {
|
||||
headers: { 'Content-Type': 'multipart/form-data', BsmAjaxHeader: true, options: { noSeri: true } },
|
||||
headers: { 'Content-Type': 'multipart/form-data', BsmAjaxHeader: true, options: { noSeri: true } }
|
||||
})
|
||||
}
|
||||
// 测试连接
|
||||
|
|
@ -79,3 +79,8 @@ export function testLinkApi(category) {
|
|||
export function getVertifyCode(params) {
|
||||
return request.post('/sms/v1/users/code', wrapperParams(params))
|
||||
}
|
||||
|
||||
// 忘记密码
|
||||
export function forgetPassword(params) {
|
||||
return request.post('/sms/v1/users/forget', params)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,13 +42,42 @@
|
|||
<a-switch v-model:checked="remember"></a-switch>
|
||||
<span class="m-l-xs">记住密码</span>
|
||||
</span>
|
||||
<a :href="`mailto:${configs.helpInformationLink}`" type="text" class="text-info pull-right help-info" :title="configs.helpInformationContent">{{ configs.helpInformationContent }}</a>
|
||||
<a :href="`mailto:${configs.helpInformationLink}`" type="text" class="text-info help-info" :title="configs.helpInformationContent">{{ configs.helpInformationContent }}</a>
|
||||
<a type="text" class="m-l text-info forgot-password" @click="openForgotPasswordDialog">忘记密码</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-button class="login-btn" type="primary" size="medium" :loading="loading" @click="handleLogin">登录</a-button>
|
||||
</a-form>
|
||||
</div>
|
||||
<div class="copyright-info">{{ configs.copyrightInformation }}</div>
|
||||
<!-- 忘记密码弹窗 -->
|
||||
<a-modal title="忘记密码" v-model:visible="showForgotPasswordDialog" width="600px" :confirm-loading="forgotPasswordLoading" @ok="handleForgotPassword" :close-on-click-modal="false">
|
||||
<a-form :model="forgotPasswordForm" ref="forgotPasswordFormRef" label-position="left" :labelCol="{ style: { width: '80px' } }">
|
||||
<a-form-item label="用户名" name="account" :rules="[{ ...required, message: '请输入用户名' }]">
|
||||
<a-input class="w-lg" v-model:value="forgotPasswordForm.account" placeholder="请输入用户名"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="新密码" name="password" :rules="[{ ...required, message: '请输入密码' }]">
|
||||
<a-input class="w-lg" v-model:value="forgotPasswordForm.password" type="password" placeholder="请输入新密码" show-password></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="确认密码" name="confirmPassword" :rules="[{ ...required, message: '请输入密码' }]">
|
||||
<a-input class="w-lg" v-model:value="forgotPasswordForm.confirmPassword" type="password" placeholder="请再次输入新密码" show-password></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="验证码" name="verificationCode" :rules="[{ ...required, message: '请输入验证码' }]">
|
||||
<div class="verification-code-input">
|
||||
<a-input class="w-lg m-r" v-model:value="forgotPasswordForm.verificationCode" placeholder="请输入验证码"></a-input>
|
||||
<a-button type="primary" :disabled="codeCountdown > 0" @click="getVerificationCode" :loading="codeLoading">
|
||||
{{ codeCountdown > 0 ? `${codeCountdown}s后重新获取` : '获取验证码' }}
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<a-button @click="showForgotPasswordDialog = false">取消</a-button>
|
||||
<a-button type="primary" :loading="forgotPasswordLoading" @click="handleForgotPassword">确定</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -61,8 +90,8 @@ import { useStore } from 'vuex'
|
|||
import { useRouter, useRoute } from 'vue-router'
|
||||
import setLoginData from './tools'
|
||||
import { required } from '@/validate'
|
||||
import { getVertifyCode } from '@/services'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { getVertifyCode, forgetPassword } from '@/services'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
|
||||
export default {
|
||||
components: { UserOutlined, LockOutlined },
|
||||
|
|
@ -78,11 +107,23 @@ export default {
|
|||
verifyLoading: false,
|
||||
countdown: 0,
|
||||
isCountingDown: false,
|
||||
needSmsVerify: true
|
||||
needSmsVerify: true,
|
||||
showForgotPasswordDialog: false,
|
||||
forgotPasswordForm: {
|
||||
account: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
verificationCode: ''
|
||||
},
|
||||
forgotPasswordLoading: false,
|
||||
codeCountdown: 0,
|
||||
codeLoading: false
|
||||
})
|
||||
const store = useStore()
|
||||
const pwdRule = computed(() => store.state.app.systemConfig.pwdStrength + ',pswNoSpace' + ',required')
|
||||
const configs = computed(() => store.getters.pageConfig)
|
||||
const loginFormRef = ref(null)
|
||||
const forgotPasswordFormRef = ref(null)
|
||||
let countdownTimer = null
|
||||
|
||||
// 开始倒计时
|
||||
|
|
@ -122,12 +163,15 @@ export default {
|
|||
const route = useRoute()
|
||||
|
||||
// 监听account变化,如果清空则重置needSmsVerify
|
||||
watch(() => state.loginForm.account, (newAccount) => {
|
||||
if (!newAccount.trim()) {
|
||||
state.needSmsVerify = true
|
||||
resetCountdown() // 同时重置倒计时
|
||||
watch(
|
||||
() => state.loginForm.account,
|
||||
(newAccount) => {
|
||||
if (!newAccount.trim()) {
|
||||
state.needSmsVerify = true
|
||||
resetCountdown() // 同时重置倒计时
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const getVertify = () => {
|
||||
if (state.isCountingDown) return // 如果正在倒计时,不允许重复点击
|
||||
|
|
@ -209,6 +253,58 @@ export default {
|
|||
state.capsTooltip = false
|
||||
}
|
||||
}
|
||||
|
||||
function getVerificationCode() {
|
||||
if (!state.forgotPasswordForm.account) {
|
||||
message.error('请先输入用户名')
|
||||
return
|
||||
}
|
||||
state.codeLoading = true
|
||||
getVertifyCode({ account: state.forgotPasswordForm.account })
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
message.success('验证码已发送')
|
||||
state.codeCountdown = 60
|
||||
const timer = setInterval(() => {
|
||||
state.codeCountdown--
|
||||
if (state.codeCountdown <= 0) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
state.codeLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
function openForgotPasswordDialog() {
|
||||
// 将当前登录表单的用户名带入忘记密码表单
|
||||
state.forgotPasswordForm.account = state.loginForm.account
|
||||
state.showForgotPasswordDialog = true
|
||||
}
|
||||
|
||||
function handleForgotPassword() {
|
||||
forgotPasswordFormRef.value.validate().then(() => {
|
||||
const { account, password, confirmPassword, verificationCode } = state.forgotPasswordForm
|
||||
if (confirmPassword !== password) return message.error('两次输入的密码不相同')
|
||||
state.forgotPasswordLoading = true
|
||||
forgetPassword({
|
||||
account,
|
||||
password: encrypt(password),
|
||||
code: verificationCode
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
message.success(res.message)
|
||||
state.showForgotPasswordDialog = false
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
state.forgotPasswordLoading = false
|
||||
})
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
required,
|
||||
|
|
@ -218,7 +314,12 @@ export default {
|
|||
checkCapslock,
|
||||
getVertify,
|
||||
startCountdown,
|
||||
resetCountdown
|
||||
resetCountdown,
|
||||
forgotPasswordFormRef,
|
||||
getVerificationCode,
|
||||
openForgotPasswordDialog,
|
||||
handleForgotPassword,
|
||||
pwdRule
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue