feat(auth): 重构登录页视觉并移除修改密码入口
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 93 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
@@ -1,8 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
import { getAuthErrorMessage, getCaptcha } from '@/api/auth'
|
import { getAuthErrorMessage, getCaptcha } from '@/api/auth'
|
||||||
|
import hospitalLogo from '@/assets/hospital-logo.png'
|
||||||
import type { CaptchaResponse, LoginRequest } from '@/types/auth'
|
import type { CaptchaResponse, LoginRequest } from '@/types/auth'
|
||||||
import { useLoginStore } from '@/stores/login'
|
import { useLoginStore } from '@/stores/login'
|
||||||
|
|
||||||
@@ -18,7 +19,6 @@ const captchaLoading = ref(false)
|
|||||||
const errorMessage = ref('')
|
const errorMessage = ref('')
|
||||||
const isSubmitting = ref(false)
|
const isSubmitting = ref(false)
|
||||||
const passwordChanged = route.query.passwordChanged === '1'
|
const passwordChanged = route.query.passwordChanged === '1'
|
||||||
const passwordChangeRequested = computed(() => route.query.redirect === '/change-password')
|
|
||||||
|
|
||||||
async function loadCaptcha() {
|
async function loadCaptcha() {
|
||||||
captchaLoading.value = true
|
captchaLoading.value = true
|
||||||
@@ -42,13 +42,6 @@ function getRedirectPath() {
|
|||||||
: '/workbench/home'
|
: '/workbench/home'
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestPasswordChange() {
|
|
||||||
void router.replace({
|
|
||||||
name: 'login',
|
|
||||||
query: { ...route.query, redirect: '/change-password' },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleLogin() {
|
async function handleLogin() {
|
||||||
const normalizedUsername = username.value.trim()
|
const normalizedUsername = username.value.trim()
|
||||||
|
|
||||||
@@ -103,32 +96,41 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main class="login-page">
|
<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">
|
<form class="login-card" novalidate @submit.prevent="handleLogin">
|
||||||
<div class="login-brand">
|
<div class="login-brand">
|
||||||
<div class="login-brand-icon" aria-hidden="true">
|
<div class="login-brand-icon" aria-hidden="true">
|
||||||
<svg width="26" height="26" viewBox="0 0 24 24" fill="none">
|
<svg width="26" height="26" viewBox="0 0 24 24" fill="none">
|
||||||
<path
|
<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"
|
d="M5.6 2.6v4.2M3.5 4.7h4.2"
|
||||||
stroke="#fff"
|
|
||||||
stroke-width="1.7"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="m9 13.5 2.5 2.5 4-4.5"
|
|
||||||
stroke="#fff"
|
stroke="#fff"
|
||||||
stroke-width="1.7"
|
stroke-width="1.7"
|
||||||
stroke-linecap="round"
|
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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<h1>医签通</h1>
|
<h1>医签通</h1>
|
||||||
<p>MEDISIGN · 患者电子签系统</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="login-subtitle">安全留痕 · 高效签署 · 医患无忧</p>
|
|
||||||
|
|
||||||
<p v-if="passwordChanged" class="login-success" role="status">
|
<p v-if="passwordChanged" class="login-success" role="status">
|
||||||
密码修改成功,请使用新密码重新登录
|
密码修改成功,请使用新密码重新登录
|
||||||
@@ -176,11 +178,7 @@ onMounted(() => {
|
|||||||
@click="loadCaptcha"
|
@click="loadCaptcha"
|
||||||
>
|
>
|
||||||
<span v-if="captchaLoading" class="captcha-spinner" aria-hidden="true" />
|
<span v-if="captchaLoading" class="captcha-spinner" aria-hidden="true" />
|
||||||
<img
|
<img v-else-if="captcha" :src="captcha.imageBase64" alt="图形验证码,点击刷新" />
|
||||||
v-else-if="captcha"
|
|
||||||
:src="captcha.imageBase64"
|
|
||||||
alt="图形验证码,点击刷新"
|
|
||||||
/>
|
|
||||||
<span v-else class="captcha-retry">点击重试</span>
|
<span v-else class="captcha-retry">点击重试</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -191,15 +189,9 @@ onMounted(() => {
|
|||||||
<button class="login-submit" type="submit" :disabled="isSubmitting">
|
<button class="login-submit" type="submit" :disabled="isSubmitting">
|
||||||
{{ isSubmitting ? '登录中…' : '登 录' }}
|
{{ isSubmitting ? '登录中…' : '登 录' }}
|
||||||
</button>
|
</button>
|
||||||
<p v-if="passwordChangeRequested" class="login-change-hint" role="status">
|
|
||||||
登录后将进入修改密码页面
|
|
||||||
</p>
|
|
||||||
<button class="login-change-link" type="button" @click="requestPasswordChange">
|
|
||||||
修改密码
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p class="login-footer">© 2026 医签通 MEDISIGN · 患者电子签署系统 V1.1 原型</p>
|
<p class="login-footer">© 2026 上海交通大学医学院附属新华医院 · 医签通 MEDISIGN V1.1</p>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -210,15 +202,84 @@ onMounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: 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 {
|
.login-card {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
width: 380px;
|
width: 380px;
|
||||||
padding: 30px 36px;
|
padding: 34px 34px 30px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 14px;
|
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 {
|
.login-brand {
|
||||||
@@ -226,13 +287,14 @@ onMounted(() => {
|
|||||||
gap: 12px;
|
gap: 12px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-brand-icon {
|
.login-brand-icon {
|
||||||
display: grid;
|
display: grid;
|
||||||
width: 46px;
|
width: 46px;
|
||||||
height: 46px;
|
height: 46px;
|
||||||
|
flex: none;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
background: linear-gradient(135deg, var(--brand), #18a0c0);
|
background: linear-gradient(135deg, var(--brand), #18a0c0);
|
||||||
@@ -245,22 +307,8 @@ onMounted(() => {
|
|||||||
letter-spacing: 1px;
|
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 {
|
.login-field {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-field label {
|
.login-field label {
|
||||||
@@ -314,7 +362,6 @@ onMounted(() => {
|
|||||||
|
|
||||||
.captcha-image-button:disabled {
|
.captcha-image-button:disabled {
|
||||||
cursor: wait;
|
cursor: wait;
|
||||||
opacity: 0.6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.captcha-image-button img {
|
.captcha-image-button img {
|
||||||
@@ -342,8 +389,8 @@ onMounted(() => {
|
|||||||
|
|
||||||
.login-submit {
|
.login-submit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 6px;
|
margin-top: 10px;
|
||||||
padding: 9px;
|
padding: 10px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 700;
|
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 {
|
.login-footer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 18px;
|
bottom: 16px;
|
||||||
|
z-index: 2;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: rgb(255 255 255 / 55%);
|
color: rgb(255 255 255 / 82%);
|
||||||
font-size: 12px;
|
font-size: 11.5px;
|
||||||
text-align: center;
|
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) {
|
@media (max-width: 520px) {
|
||||||
|
.login-caption {
|
||||||
|
top: 18px;
|
||||||
|
left: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-caption-text b {
|
||||||
|
font-size: 16px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.login-card {
|
.login-card {
|
||||||
width: calc(100% - 32px);
|
width: calc(100% - 32px);
|
||||||
padding: 32px 24px;
|
padding: 28px 22px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user