feat(auth): 重构登录页视觉并移除修改密码入口

This commit is contained in:
yelan
2026-09-30 15:56:10 +08:00
parent 35c7b43bb5
commit 60d8c7a800
3 changed files with 126 additions and 82 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

+126 -82
View File
@@ -1,8 +1,9 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { getAuthErrorMessage, getCaptcha } from '@/api/auth'
import hospitalLogo from '@/assets/hospital-logo.png'
import type { CaptchaResponse, LoginRequest } from '@/types/auth'
import { useLoginStore } from '@/stores/login'
@@ -18,7 +19,6 @@ const captchaLoading = ref(false)
const errorMessage = ref('')
const isSubmitting = ref(false)
const passwordChanged = route.query.passwordChanged === '1'
const passwordChangeRequested = computed(() => route.query.redirect === '/change-password')
async function loadCaptcha() {
captchaLoading.value = true
@@ -42,13 +42,6 @@ function getRedirectPath() {
: '/workbench/home'
}
function requestPasswordChange() {
void router.replace({
name: 'login',
query: { ...route.query, redirect: '/change-password' },
})
}
async function handleLogin() {
const normalizedUsername = username.value.trim()
@@ -103,33 +96,42 @@ onMounted(() => {
<template>
<main class="login-page">
<div class="login-visual" aria-hidden="true"></div>
<div class="login-shade" aria-hidden="true"></div>
<div class="login-caption">
<span class="login-badge">
<img :src="hospitalLogo" alt="新华医院" />
</span>
<div class="login-caption-text">
<b>上海交通大学医学院附属新华医院</b>
<span>Xinhua Hospital Affiliated To Shanghai Jiao Tong University School Of Medicine</span>
</div>
</div>
<form class="login-card" novalidate @submit.prevent="handleLogin">
<div class="login-brand">
<div class="login-brand-icon" aria-hidden="true">
<svg width="26" height="26" viewBox="0 0 24 24" fill="none">
<path
d="M14 3v5h5M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5z"
stroke="#fff"
stroke-width="1.7"
stroke-linejoin="round"
/>
<path
d="m9 13.5 2.5 2.5 4-4.5"
d="M5.6 2.6v4.2M3.5 4.7h4.2"
stroke="#fff"
stroke-width="1.7"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path d="M9.7 16.3l1.1-3.1 6.3-6.3a1.41 1.41 0 0 1 2 2l-6.3 6.3-3.1 1.1z" fill="#fff" />
<path d="M15.5 8.5l2 2" stroke="#9bd8e9" stroke-width="1.2" stroke-linecap="round" />
<path
d="M2.8 21.2c1.7 0 1.7-1.3 3.4-1.3s1.7 1.3 3.4 1.3 1.7-1.3 3.4-1.3 1.7 1.3 3.4 1.3 1.7-1.3 3.4-1.3"
stroke="#fff"
stroke-width="1.6"
stroke-linecap="round"
/>
</svg>
</div>
<div>
<h1>医签通</h1>
<p>MEDISIGN · 患者电子签系统</p>
</div>
<h1>医签通</h1>
</div>
<p class="login-subtitle">安全留痕 · 高效签署 · 医患无忧</p>
<p v-if="passwordChanged" class="login-success" role="status">
密码修改成功,请使用新密码重新登录
</p>
@@ -176,11 +178,7 @@ onMounted(() => {
@click="loadCaptcha"
>
<span v-if="captchaLoading" class="captcha-spinner" aria-hidden="true" />
<img
v-else-if="captcha"
:src="captcha.imageBase64"
alt="图形验证码,点击刷新"
/>
<img v-else-if="captcha" :src="captcha.imageBase64" alt="图形验证码,点击刷新" />
<span v-else class="captcha-retry">点击重试</span>
</button>
</div>
@@ -191,15 +189,9 @@ onMounted(() => {
<button class="login-submit" type="submit" :disabled="isSubmitting">
{{ isSubmitting ? '登录中…' : '登 录' }}
</button>
<p v-if="passwordChangeRequested" class="login-change-hint" role="status">
登录后将进入修改密码页面
</p>
<button class="login-change-link" type="button" @click="requestPasswordChange">
修改密码
</button>
</form>
<p class="login-footer">© 2026 医签通 MEDISIGN · 患者电子签署系统 V1.1 原型</p>
<p class="login-footer">© 2026 上海交通大学医学院附属新华医院 · 医签通 MEDISIGN V1.1</p>
</main>
</template>
@@ -210,15 +202,84 @@ onMounted(() => {
display: flex;
align-items: center;
justify-content: center;
background: var(--login-gradient);
background: #0e6e8c;
}
.login-visual {
position: absolute;
inset: 0;
background: url('@/assets/login-bg.jpg') center / cover no-repeat;
}
.login-shade {
position: absolute;
inset: 0;
background: linear-gradient(
180deg,
rgb(6 40 54 / 38%) 0%,
rgb(6 40 54 / 0%) 28%,
rgb(6 40 54 / 0%) 55%,
rgb(6 40 54 / 52%) 100%
);
}
.login-caption {
position: absolute;
top: 28px;
left: 34px;
z-index: 2;
display: flex;
gap: 12px;
align-items: center;
color: #fff;
text-shadow: 0 2px 12px rgb(0 0 0 / 50%);
}
.login-badge {
display: flex;
width: 48px;
height: 48px;
flex: none;
align-items: center;
justify-content: center;
padding: 3px;
background: rgb(255 255 255 / 95%);
border-radius: 50%;
box-shadow: 0 4px 16px rgb(6 40 54 / 40%);
}
.login-badge img {
width: 100%;
height: 100%;
object-fit: contain;
border-radius: 50%;
}
.login-caption-text b {
display: block;
font-size: 19px;
font-weight: 700;
letter-spacing: 1.5px;
}
.login-caption-text span {
display: block;
margin-top: 5px;
font-size: 10.5px;
letter-spacing: 0.4px;
opacity: 0.85;
}
.login-card {
position: relative;
z-index: 2;
width: 380px;
padding: 30px 36px;
padding: 34px 34px 30px;
background: #fff;
border-radius: 14px;
box-shadow: var(--sh-login);
box-shadow:
0 24px 64px rgb(6 40 54 / 38%),
0 4px 16px rgb(6 40 54 / 22%);
}
.login-brand {
@@ -226,13 +287,14 @@ onMounted(() => {
gap: 12px;
align-items: center;
justify-content: center;
margin-bottom: 8px;
margin-bottom: 16px;
}
.login-brand-icon {
display: grid;
width: 46px;
height: 46px;
flex: none;
place-items: center;
border-radius: 12px;
background: linear-gradient(135deg, var(--brand), #18a0c0);
@@ -245,22 +307,8 @@ onMounted(() => {
letter-spacing: 1px;
}
.login-brand p {
margin: 2px 0 0;
color: #8aa7b3;
font-size: 11px;
letter-spacing: 2px;
}
.login-subtitle {
margin: 0 0 20px;
color: var(--mut);
font-size: 12px;
text-align: center;
}
.login-field {
margin-bottom: 10px;
margin-bottom: 14px;
}
.login-field label {
@@ -314,7 +362,6 @@ onMounted(() => {
.captcha-image-button:disabled {
cursor: wait;
opacity: 0.6;
}
.captcha-image-button img {
@@ -342,8 +389,8 @@ onMounted(() => {
.login-submit {
width: 100%;
margin-top: 6px;
padding: 9px;
margin-top: 10px;
padding: 10px;
color: #fff;
font-size: 13px;
font-weight: 700;
@@ -380,41 +427,38 @@ onMounted(() => {
}
}
.login-change-hint {
margin: 8px 0 0;
color: var(--brand);
font-size: 12px;
text-align: center;
}
.login-change-link {
display: block;
padding: 7px 12px;
margin: 5px auto 0;
color: var(--brand);
font-size: 12px;
background: transparent;
border: 0;
}
.login-change-link:hover {
text-decoration: underline;
}
.login-footer {
position: absolute;
bottom: 18px;
bottom: 16px;
z-index: 2;
width: 100%;
margin: 0;
color: rgb(255 255 255 / 55%);
font-size: 12px;
color: rgb(255 255 255 / 82%);
font-size: 11.5px;
text-align: center;
text-shadow: 0 1px 6px rgb(0 0 0 / 45%);
}
@media (max-width: 820px) {
.login-caption-text span {
display: none;
}
}
@media (max-width: 520px) {
.login-caption {
top: 18px;
left: 18px;
}
.login-caption-text b {
font-size: 16px;
letter-spacing: 1px;
}
.login-card {
width: calc(100% - 32px);
padding: 32px 24px;
padding: 28px 22px;
}
}
</style>