mirror of
https://gitee.com/hhyykk/ipms-sjy-ui.git
synced 2025-02-01 19:24:58 +08:00
parent
791d59020a
commit
65924bb921
@ -85,3 +85,8 @@ export const getCode = (data) => {
|
||||
export const reqCheck = (data) => {
|
||||
return request.postOriginal({ url: 'system/captcha/check', data })
|
||||
}
|
||||
|
||||
// 通过短信重置密码
|
||||
export const smsResetPassword = (data) => {
|
||||
return request.post({ url: '/system/auth/sms-reset-password', data })
|
||||
}
|
||||
|
@ -140,7 +140,10 @@ export default {
|
||||
btnQRCode: 'QR code sign in',
|
||||
qrcode: 'Scan the QR code to log in',
|
||||
btnRegister: 'Sign up',
|
||||
SmsSendMsg: 'code has been sent'
|
||||
SmsSendMsg: 'code has been sent',
|
||||
resetPassword: "Reset Password",
|
||||
resetPasswordSuccess: "Reset Password Success",
|
||||
invalidTenantName:"Invalid Tenant Name"
|
||||
},
|
||||
captcha: {
|
||||
verification: 'Please complete security verification',
|
||||
|
@ -141,7 +141,10 @@ export default {
|
||||
btnQRCode: '二维码登录',
|
||||
qrcode: '扫描二维码登录',
|
||||
btnRegister: '注册',
|
||||
SmsSendMsg: '验证码已发送'
|
||||
SmsSendMsg: '验证码已发送',
|
||||
resetPassword: "重置密码",
|
||||
resetPasswordSuccess: "重置密码成功",
|
||||
invalidTenantName: "无效的租户名称"
|
||||
},
|
||||
captcha: {
|
||||
verification: '请完成安全验证',
|
||||
|
@ -59,6 +59,8 @@
|
||||
<RegisterForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
|
||||
<!-- 三方登录 -->
|
||||
<SSOLoginVue class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
|
||||
<!-- 忘记密码 -->
|
||||
<ForgetPasswordForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
@ -73,7 +75,7 @@ import { useAppStore } from '@/store/modules/app'
|
||||
import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
|
||||
import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
|
||||
|
||||
import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue } from './components'
|
||||
import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue, ForgetPasswordForm } from './components'
|
||||
|
||||
defineOptions({ name: 'Login' })
|
||||
|
||||
|
278
src/views/Login/components/ForgetPasswordForm.vue
Normal file
278
src/views/Login/components/ForgetPasswordForm.vue
Normal file
@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<el-form
|
||||
v-show="getShow"
|
||||
ref="formSmsResetPassword"
|
||||
:model="resetPasswordData"
|
||||
:rules="rules"
|
||||
class="login-form"
|
||||
label-position="top"
|
||||
label-width="120px"
|
||||
size="large"
|
||||
>
|
||||
<el-row style="margin-right: -10px; margin-left: -10px">
|
||||
<!-- 租户名 -->
|
||||
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
|
||||
<el-form-item>
|
||||
<LoginFormTitle style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
|
||||
<el-form-item v-if="resetPasswordData.tenantEnable === 'true'" prop="tenantName">
|
||||
<el-input
|
||||
v-model="resetPasswordData.tenantName"
|
||||
:placeholder="t('login.tenantNamePlaceholder')"
|
||||
:prefix-icon="iconHouse"
|
||||
type="primary"
|
||||
link
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 手机号 -->
|
||||
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
|
||||
<el-form-item prop="mobile">
|
||||
<el-input
|
||||
v-model="resetPasswordData.mobile"
|
||||
:placeholder="t('login.mobileNumberPlaceholder')"
|
||||
:prefix-icon="iconCellphone"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<Verify
|
||||
ref="verify"
|
||||
:captchaType="captchaType"
|
||||
:imgSize="{ width: '400px', height: '200px' }"
|
||||
mode="pop"
|
||||
@success="getSmsCode"
|
||||
/>
|
||||
<!-- 验证码 -->
|
||||
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
|
||||
<el-form-item prop="code">
|
||||
<el-row :gutter="5" justify="space-between" style="width: 100%">
|
||||
<el-col :span="24">
|
||||
<el-input
|
||||
v-model="resetPasswordData.code"
|
||||
:placeholder="t('login.codePlaceholder')"
|
||||
:prefix-icon="iconCircleCheck"
|
||||
>
|
||||
<template #append>
|
||||
<span
|
||||
v-if="mobileCodeTimer <= 0"
|
||||
class="getMobileCode"
|
||||
style="cursor: pointer"
|
||||
@click="getCode"
|
||||
>
|
||||
{{ t('login.getSmsCode') }}
|
||||
</span>
|
||||
<span v-if="mobileCodeTimer > 0" class="getMobileCode" style="cursor: pointer">
|
||||
{{ mobileCodeTimer }}秒后可重新获取
|
||||
</span>
|
||||
</template>
|
||||
</el-input>
|
||||
<!-- </el-button> -->
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
|
||||
<el-form-item prop="password">
|
||||
<InputPassword
|
||||
v-model="resetPasswordData.password"
|
||||
:placeholder="t('login.passwordPlaceholder')"
|
||||
style="width: 100%"
|
||||
strength="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
|
||||
<el-form-item prop="check_password">
|
||||
<InputPassword
|
||||
v-model="resetPasswordData.check_password"
|
||||
:placeholder="t('login.checkPassword')"
|
||||
style="width: 100%"
|
||||
strength="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 登录按钮 / 返回按钮 -->
|
||||
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
|
||||
<el-form-item>
|
||||
<XButton
|
||||
:loading="loginLoading"
|
||||
:title="t('login.resetPassword')"
|
||||
class="w-[100%]"
|
||||
type="primary"
|
||||
@click="resetPassword()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
|
||||
<el-form-item>
|
||||
<XButton
|
||||
:loading="loginLoading"
|
||||
:title="t('login.backLogin')"
|
||||
class="w-[100%]"
|
||||
@click="handleBackLogin()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
|
||||
import { useIcon } from '@/hooks/web/useIcon'
|
||||
|
||||
import { sendSmsCode, smsResetPassword } from '@/api/login'
|
||||
import LoginFormTitle from './LoginFormTitle.vue'
|
||||
import { LoginStateEnum, useFormValid, useLoginState } from './useLogin'
|
||||
import { ElLoading } from 'element-plus'
|
||||
import * as authUtil from '@/utils/auth'
|
||||
import * as LoginApi from '@/api/login'
|
||||
defineOptions({ name: 'ForgetPasswordForm' })
|
||||
const verify = ref()
|
||||
|
||||
const { t } = useI18n()
|
||||
const message = useMessage()
|
||||
const { currentRoute, push } = useRouter()
|
||||
const formSmsResetPassword = ref()
|
||||
const loginLoading = ref(false)
|
||||
const iconHouse = useIcon({ icon: 'ep:house' })
|
||||
const iconCellphone = useIcon({ icon: 'ep:cellphone' })
|
||||
const iconCircleCheck = useIcon({ icon: 'ep:circle-check' })
|
||||
const { validForm } = useFormValid(formSmsResetPassword)
|
||||
const { handleBackLogin, getLoginState, setLoginState } = useLoginState()
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.RESET_PASSWORD)
|
||||
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
|
||||
|
||||
const validatePass2 = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请再次输入密码'))
|
||||
} else if (value !== resetPasswordData.password) {
|
||||
callback(new Error('两次输入密码不一致!'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const rules = {
|
||||
tenantName: [{ required: true, min: 2, max: 20, trigger: 'blur', message: '长度为4到16位' }],
|
||||
mobile: [{ required: true, min: 11, max: 11, trigger: 'blur', message: '手机号长度为11位' }],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
min: 4,
|
||||
max: 16,
|
||||
validator: validatePass2,
|
||||
trigger: 'blur',
|
||||
message: '密码长度为4到16位'
|
||||
}
|
||||
],
|
||||
check_password: [{ required: true, validator: validatePass2, trigger: 'blur' }],
|
||||
code: [required]
|
||||
}
|
||||
|
||||
const resetPasswordData = reactive({
|
||||
captchaEnable: import.meta.env.VITE_APP_CAPTCHA_ENABLE,
|
||||
tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE,
|
||||
tenantName: '',
|
||||
username: '',
|
||||
password: '',
|
||||
check_password: '',
|
||||
mobile: '',
|
||||
code: ''
|
||||
})
|
||||
|
||||
const smsVO = reactive({
|
||||
tenantName: '',
|
||||
mobile: '',
|
||||
captchaVerification: '',
|
||||
scene: 23
|
||||
})
|
||||
const mobileCodeTimer = ref(0)
|
||||
const redirect = ref<string>('')
|
||||
|
||||
// 获取验证码
|
||||
const getCode = async () => {
|
||||
// 情况一,未开启:则直接发送验证码
|
||||
if (resetPasswordData.captchaEnable === 'false') {
|
||||
await getSmsCode({})
|
||||
} else {
|
||||
// 情况二,已开启:则展示验证码;只有完成验证码的情况,才进行发送验证码
|
||||
// 弹出验证码
|
||||
verify.value.show()
|
||||
}
|
||||
}
|
||||
|
||||
const getSmsCode = async (params) => {
|
||||
if (resetPasswordData.tenantEnable === 'true') {
|
||||
await getTenantId()
|
||||
}
|
||||
smsVO.captchaVerification = params.captchaVerification
|
||||
smsVO.mobile = resetPasswordData.mobile
|
||||
await sendSmsCode(smsVO).then(async () => {
|
||||
message.success(t('login.SmsSendMsg'))
|
||||
// 设置倒计时
|
||||
mobileCodeTimer.value = 60
|
||||
let msgTimer = setInterval(() => {
|
||||
mobileCodeTimer.value = mobileCodeTimer.value - 1
|
||||
if (mobileCodeTimer.value <= 0) {
|
||||
clearInterval(msgTimer)
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
watch(
|
||||
() => currentRoute.value,
|
||||
(route: RouteLocationNormalizedLoaded) => {
|
||||
redirect.value = route?.query?.redirect as string
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
const getTenantId = async () => {
|
||||
if (resetPasswordData.tenantEnable === 'true') {
|
||||
const res = await LoginApi.getTenantIdByName(resetPasswordData.tenantName)
|
||||
if (res == null) {
|
||||
message.error(t('login.invalidTenantName'))
|
||||
throw t('login.invalidTenantName')
|
||||
}
|
||||
authUtil.setTenantId(res)
|
||||
}
|
||||
}
|
||||
|
||||
// 重置密码
|
||||
const resetPassword = async () => {
|
||||
const data = await validForm()
|
||||
if (!data) return
|
||||
await getTenantId()
|
||||
loginLoading.value = true
|
||||
await smsResetPassword(resetPasswordData)
|
||||
.then(async () => {
|
||||
message.success(t('login.resetPasswordSuccess'))
|
||||
setLoginState(LoginStateEnum.LOGIN)
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
loginLoading.value = false
|
||||
setTimeout(() => {
|
||||
const loadingInstance = ElLoading.service()
|
||||
loadingInstance.close()
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.anticon) {
|
||||
&:hover {
|
||||
color: var(--el-color-primary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.smsbtn {
|
||||
margin-top: 33px;
|
||||
}
|
||||
</style>
|
@ -59,7 +59,8 @@
|
||||
</el-checkbox>
|
||||
</el-col>
|
||||
<el-col :offset="6" :span="12">
|
||||
<el-link style="float: right" type="primary">{{ t('login.forgetPassword') }}</el-link>
|
||||
<el-link style="float: right" type="primary" @click="setLoginState(LoginStateEnum.RESET_PASSWORD)">{{
|
||||
t('login.forgetPassword') }}</el-link>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
@ -4,5 +4,6 @@ import LoginFormTitle from './LoginFormTitle.vue'
|
||||
import RegisterForm from './RegisterForm.vue'
|
||||
import QrCodeForm from './QrCodeForm.vue'
|
||||
import SSOLoginVue from './SSOLogin.vue'
|
||||
import ForgetPasswordForm from './ForgetPasswordForm.vue'
|
||||
|
||||
export { LoginForm, MobileForm, LoginFormTitle, RegisterForm, QrCodeForm, SSOLoginVue }
|
||||
export { LoginForm, MobileForm, LoginFormTitle, RegisterForm, QrCodeForm, SSOLoginVue, ForgetPasswordForm }
|
||||
|
Loading…
Reference in New Issue
Block a user