Files
xh-medical-sign-web/clinical-web/src/views/auth/ChangePasswordView.vue
T

221 lines
5.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useLoginStore } from '@/stores/login'
const route = useRoute()
const router = useRouter()
const loginStore = useLoginStore()
const currentPassword = ref('')
const newPassword = ref('')
const confirmPassword = ref('')
const errorMessage = ref('')
const isSubmitting = ref(false)
function getAfterChangeRedirect() {
const redirect = route.query.redirect
if (
typeof redirect === 'string' &&
redirect.startsWith('/') &&
!redirect.startsWith('//') &&
redirect !== '/change-password'
) {
return redirect
}
return '/workbench/home'
}
function validatePassword() {
if (!currentPassword.value || !newPassword.value || !confirmPassword.value) {
return '请完整填写当前密码、新密码和确认密码'
}
if (newPassword.value.length < 12 || newPassword.value.length > 128) {
return '新密码长度必须为 12 至 128 位'
}
if (
!/[A-Z]/.test(newPassword.value) ||
!/[a-z]/.test(newPassword.value) ||
!/\d/.test(newPassword.value) ||
!/[^A-Za-z0-9]/.test(newPassword.value)
) {
return '新密码必须包含大写字母、小写字母、数字和特殊字符'
}
if (newPassword.value !== confirmPassword.value) {
return '两次输入的新密码不一致'
}
if (newPassword.value === currentPassword.value) {
return '新密码不能与当前密码相同'
}
return ''
}
async function handleSubmit() {
const validationMessage = validatePassword()
if (validationMessage) {
errorMessage.value = validationMessage
return
}
errorMessage.value = ''
isSubmitting.value = true
try {
await loginStore.changePassword({
currentPassword: currentPassword.value,
newPassword: newPassword.value,
})
await router.replace({
name: 'login',
query: { passwordChanged: '1', redirect: getAfterChangeRedirect() },
})
} catch (error: unknown) {
errorMessage.value =
error instanceof Error && error.message ? error.message : '密码修改失败,请稍后重试'
} finally {
isSubmitting.value = false
}
}
async function handleLogout() {
try {
await loginStore.logout()
} catch {
loginStore.clearSession()
}
await router.replace({ name: 'login' })
}
</script>
<template>
<main class="password-page">
<form class="password-card" novalidate @submit.prevent="handleSubmit">
<div class="password-brand">医签通</div>
<h1>{{ loginStore.user?.passwordChangeRequired ? '首次登录,请修改密码' : '修改密码' }}</h1>
<p class="password-description">
{{
loginStore.user?.passwordChangeRequired
? '为保护患者信息,设置新密码后需要重新登录。'
: '修改密码后需要重新登录。'
}}
</p>
<label>
<span>当前密码</span>
<input v-model="currentPassword" type="password" autocomplete="current-password" />
</label>
<label>
<span>新密码</span>
<input v-model="newPassword" type="password" autocomplete="new-password" />
</label>
<label>
<span>确认新密码</span>
<input v-model="confirmPassword" type="password" autocomplete="new-password" />
</label>
<p class="password-policy">12–128 位,须同时包含大小写字母、数字和特殊字符。</p>
<p v-if="errorMessage" class="password-error" role="alert">{{ errorMessage }}</p>
<button class="password-submit" type="submit" :disabled="isSubmitting">
{{ isSubmitting ? '修改中…' : '修改密码并重新登录' }}
</button>
<button class="password-logout" type="button" :disabled="isSubmitting" @click="handleLogout">
退出当前账号
</button>
</form>
</main>
</template>
<style scoped>
.password-page {
position: fixed;
inset: 0;
display: grid;
place-items: center;
background: var(--login-gradient);
}
.password-card {
width: min(420px, calc(100% - 32px));
padding: 32px 36px;
background: #fff;
border-radius: 14px;
box-shadow: var(--sh-login);
}
.password-brand {
color: var(--brand);
font-size: 15px;
font-weight: 800;
text-align: center;
}
h1 {
margin: 8px 0;
color: var(--ink);
font-size: 22px;
text-align: center;
}
.password-description,
.password-policy {
color: var(--mut);
font-size: 12px;
line-height: 1.6;
text-align: center;
}
label {
display: block;
margin-top: 14px;
}
label span {
display: block;
margin-bottom: 6px;
color: var(--mut);
font-size: 12px;
}
input {
width: 100%;
padding: 9px 10px;
border: 1px solid var(--line);
border-radius: 6px;
outline: none;
}
input:focus {
border-color: var(--brand);
}
.password-error {
color: var(--err);
font-size: 12px;
}
.password-submit,
.password-logout {
width: 100%;
padding: 10px;
border-radius: 7px;
}
.password-submit {
color: #fff;
font-weight: 700;
background: var(--brand);
}
.password-logout {
margin-top: 8px;
color: var(--mut);
background: transparent;
}
button:disabled {
cursor: wait;
opacity: 0.65;
}
</style>