Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
65924bb9
authored
Jan 04, 2025
by
杨宇庆
Committed by
芋道源码
Jan 04, 2025
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
!617 feat: 支持通过短信重置后台密码
* feat: 支持通过短信重置后台密码
parent
791d5902
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
298 additions
and
5 deletions
+298
-5
src/api/login/index.ts
+5
-0
src/locales/en.ts
+4
-1
src/locales/zh-CN.ts
+4
-1
src/views/Login/Login.vue
+3
-1
src/views/Login/components/ForgetPasswordForm.vue
+278
-0
src/views/Login/components/LoginForm.vue
+2
-1
src/views/Login/components/index.ts
+2
-1
No files found.
src/api/login/index.ts
View file @
65924bb9
...
...
@@ -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
})
}
src/locales/en.ts
View file @
65924bb9
...
...
@@ -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'
,
...
...
src/locales/zh-CN.ts
View file @
65924bb9
...
...
@@ -141,7 +141,10 @@ export default {
btnQRCode
:
'二维码登录'
,
qrcode
:
'扫描二维码登录'
,
btnRegister
:
'注册'
,
SmsSendMsg
:
'验证码已发送'
SmsSendMsg
:
'验证码已发送'
,
resetPassword
:
"重置密码"
,
resetPasswordSuccess
:
"重置密码成功"
,
invalidTenantName
:
"无效的租户名称"
},
captcha
:
{
verification
:
'请完成安全验证'
,
...
...
src/views/Login/Login.vue
View file @
65924bb9
...
...
@@ -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'
})
...
...
src/views/Login/components/ForgetPasswordForm.vue
0 → 100644
View file @
65924bb9
<
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
>
src/views/Login/components/LoginForm.vue
View file @
65924bb9
...
...
@@ -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>
...
...
src/views/Login/components/index.ts
View file @
65924bb9
...
...
@@ -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
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment