feat(ui): 美化忘记密码页面视觉风格

- 重构整体布局为极光渐变背景 + 居中毛玻璃卡片设计
- 新增浮动极光球光效(aurora-1/2/3)与旋转几何圆环装饰动效
- 卡片采用半透明磨砂玻璃(backdrop-filter: blur(40px)),阴影层次丰富
- 步骤指引改为带渐变编号圆圈的卡片列表,悬停有微动效
- 联系方式区块增加图标 + 悬停高亮交互
- 返回登录按钮增加光泽扫光动画与上浮效果
- 完整适配移动端响应式(max-width: 640px)
This commit is contained in:
Cheng Zhou
2026-06-29 11:31:10 +08:00
parent c7ca97a6d6
commit e242e067f0
+443 -12
View File
@@ -1,23 +1,454 @@
<template> <template>
<div class="forgot-container"> <div class="fp-wrapper">
<ModulePlaceholder <!-- 与登录页一致的极光背景 -->
:title="TEXT.modules.auth.forgotTitle" <div class="aurora aurora-1"></div>
:list-title="TEXT.modules.auth.forgotTitle" <div class="aurora aurora-2"></div>
:empty-title="TEXT.modules.auth.forgotTitle" <div class="aurora aurora-3"></div>
:empty-description="TEXT.modules.auth.forgotDesc" <div class="deco-ring ring-1"></div>
/> <div class="deco-ring ring-2"></div>
<div class="noise-overlay"></div>
<div class="fp-center">
<div class="fp-card">
<!-- 返回链接 -->
<RouterLink to="/login" class="back-link">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M19 12H5M12 19l-7-7 7-7"/>
</svg>
返回登录
</RouterLink>
<!-- 图标 -->
<div class="fp-icon-wrap">
<div class="fp-icon">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</svg>
</div>
<div class="fp-icon-ring"></div>
</div>
<!-- 标题 -->
<h1 class="fp-title">找回密码</h1>
<p class="fp-desc">CTMS 暂不支持自助重置密码请通过以下方式联系系统管理员处理</p>
<!-- 引导步骤 -->
<div class="fp-steps">
<div class="step">
<div class="step-num">1</div>
<div class="step-body">
<div class="step-title">准备您的账号信息</div>
<div class="step-text">记录您的注册邮箱地址以便管理员核实身份</div>
</div>
</div>
<div class="step">
<div class="step-num">2</div>
<div class="step-body">
<div class="step-title">联系系统管理员</div>
<div class="step-text">通过以下任意渠道提交申请说明账号邮箱及重置原因</div>
</div>
</div>
<div class="step">
<div class="step-num">3</div>
<div class="step-body">
<div class="step-title">等待重置并登录</div>
<div class="step-text">管理员将通过邮件发送临时密码收到后请立即修改</div>
</div>
</div>
</div>
<!-- 联系方式 -->
<div class="contact-block">
<div class="contact-label">管理员联系方式</div>
<a href="mailto:admin@huapont.cn" class="contact-item">
<div class="contact-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
<polyline points="22,6 12,13 2,6"/>
</svg>
</div>
<span>admin@huapont.cn</span>
</a>
</div>
<!-- 返回按钮 -->
<RouterLink to="/login" class="back-btn">
<span>返回登录页</span>
<span class="back-btn-arrow"></span>
</RouterLink>
</div>
<p class="fp-tagline">Professional · Compliant · Efficient</p>
</div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import ModulePlaceholder from "../components/ModulePlaceholder.vue"; // 此页面为纯展示页,无需额外逻辑
import { TEXT } from "../locales";
</script> </script>
<style scoped> <style scoped>
.forgot-container { @import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap");
/* ═══════════════ 根容器 ═══════════════ */
.fp-wrapper {
position: relative;
min-height: 100vh; min-height: 100vh;
background-color: var(--ctms-bg-base); display: flex;
padding: 32px; align-items: center;
justify-content: center;
overflow: hidden;
background: #f0f4ff;
font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
}
/* ═══════════════ 极光背景(与登录页一致) ═══════════════ */
.aurora {
position: absolute;
border-radius: 50%;
filter: blur(80px);
pointer-events: none;
z-index: 0;
}
.aurora-1 {
width: 700px; height: 700px;
background: radial-gradient(circle, rgba(99, 102, 241, 0.28) 0%, transparent 70%);
top: -200px; left: -200px;
animation: auroraFloat1 14s ease-in-out infinite alternate;
}
.aurora-2 {
width: 600px; height: 600px;
background: radial-gradient(circle, rgba(6, 182, 212, 0.22) 0%, transparent 70%);
bottom: -150px; right: -150px;
animation: auroraFloat2 18s ease-in-out infinite alternate;
}
.aurora-3 {
width: 400px; height: 400px;
background: radial-gradient(circle, rgba(168, 85, 247, 0.15) 0%, transparent 70%);
top: 40%; left: 50%;
transform: translateX(-50%);
animation: auroraFloat1 12s ease-in-out infinite alternate-reverse;
}
@keyframes auroraFloat1 {
0% { transform: translate(0, 0) scale(1); }
100% { transform: translate(40px, 60px) scale(1.1); }
}
@keyframes auroraFloat2 {
0% { transform: translate(0, 0) scale(1); }
100% { transform: translate(-30px, -50px) scale(1.08); }
}
/* 几何圆环 */
.deco-ring {
position: absolute;
border-radius: 50%;
pointer-events: none;
z-index: 1;
}
.ring-1 {
width: 520px; height: 520px;
border: 1.5px solid rgba(99, 102, 241, 0.12);
top: -200px; left: -180px;
animation: ringRotate 40s linear infinite;
}
.ring-2 {
width: 480px; height: 480px;
border: 1.5px solid rgba(6, 182, 212, 0.1);
bottom: -180px; right: -160px;
animation: ringRotate 36s linear infinite reverse;
}
@keyframes ringRotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* 噪点纹理 */
.noise-overlay {
position: absolute;
inset: 0;
z-index: 0;
pointer-events: none;
opacity: 0.025;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
background-size: 200px;
}
/* ═══════════════ 居中容器 ═══════════════ */
.fp-center {
position: relative;
z-index: 10;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
width: 100%;
max-width: 480px;
padding: 20px;
animation: cardIn 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes cardIn {
from { opacity: 0; transform: translateY(24px) scale(0.97); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* ═══════════════ 卡片 ═══════════════ */
.fp-card {
width: 100%;
background: rgba(255, 255, 255, 0.78);
backdrop-filter: blur(40px);
-webkit-backdrop-filter: blur(40px);
border: 1px solid rgba(255, 255, 255, 0.95);
border-radius: 28px;
padding: 36px 40px 32px;
box-shadow:
0 0 0 1px rgba(99, 102, 241, 0.06) inset,
0 24px 64px -12px rgba(99, 102, 241, 0.18),
0 8px 24px -4px rgba(0, 0, 0, 0.06);
}
/* 返回链接 */
.back-link {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 13px;
font-weight: 600;
text-decoration: none;
color: #9ca3af;
margin-bottom: 28px;
transition: color 0.2s;
}
.back-link:hover { color: #6366f1; }
/* 图标区 */
.fp-icon-wrap {
position: relative;
width: 64px;
height: 64px;
margin: 0 auto 24px;
}
.fp-icon {
width: 64px;
height: 64px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, rgba(99, 102, 241, 0.12), rgba(6, 182, 212, 0.12));
border: 1px solid rgba(99, 102, 241, 0.2);
border-radius: 18px;
color: #6366f1;
box-shadow: 0 8px 24px -6px rgba(99, 102, 241, 0.2);
}
.fp-icon-ring {
position: absolute;
inset: -6px;
border: 1px solid rgba(99, 102, 241, 0.12);
border-radius: 26px;
animation: ringRotate 8s linear infinite;
}
/* 标题 */
.fp-title {
font-size: 26px;
font-weight: 800;
color: #111827;
margin: 0 0 10px;
letter-spacing: -0.5px;
text-align: center;
}
.fp-desc {
font-size: 14px;
color: #9ca3af;
margin: 0 0 28px;
line-height: 1.7;
text-align: center;
}
/* ═══════════════ 步骤 ═══════════════ */
.fp-steps {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 28px;
}
.step {
display: flex;
gap: 14px;
align-items: flex-start;
padding: 14px 16px;
background: rgba(99, 102, 241, 0.03);
border: 1px solid rgba(99, 102, 241, 0.08);
border-radius: 14px;
transition: border-color 0.2s, background 0.2s;
}
.step:hover {
border-color: rgba(99, 102, 241, 0.16);
background: rgba(99, 102, 241, 0.05);
}
.step-num {
flex-shrink: 0;
width: 26px;
height: 26px;
border-radius: 50%;
background: linear-gradient(135deg, #6366f1, #06b6d4);
color: white;
font-size: 12px;
font-weight: 800;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 10px -2px rgba(99, 102, 241, 0.35);
margin-top: 1px;
}
.step-body {
display: flex;
flex-direction: column;
gap: 3px;
}
.step-title {
font-size: 13px;
font-weight: 700;
color: #1f2937;
line-height: 1.4;
}
.step-text {
font-size: 12px;
color: #9ca3af;
line-height: 1.5;
}
/* ═══════════════ 联系方式 ═══════════════ */
.contact-block {
margin-bottom: 28px;
}
.contact-label {
font-size: 12px;
font-weight: 600;
color: #6b7280;
margin-bottom: 10px;
letter-spacing: 0.3px;
}
.contact-item {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
background: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(209, 213, 219, 0.6);
border-radius: 12px;
text-decoration: none;
color: #374151;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
}
.contact-item:hover {
border-color: rgba(99, 102, 241, 0.3);
background: rgba(99, 102, 241, 0.04);
color: #6366f1;
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.08);
}
.contact-icon {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(6, 182, 212, 0.1));
border-radius: 10px;
flex-shrink: 0;
}
.contact-icon svg {
width: 16px;
height: 16px;
color: #6366f1;
}
/* ═══════════════ 返回按钮 ═══════════════ */
.back-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
height: 50px;
border-radius: 14px;
font-size: 15px;
font-weight: 700;
text-decoration: none;
color: white;
background: linear-gradient(135deg, #6366f1, #4f46e5 50%, #0891b2);
box-shadow: 0 8px 24px -6px rgba(99, 102, 241, 0.5);
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.back-btn::before {
content: "";
position: absolute;
top: 0; left: -75%;
width: 50%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.18), transparent);
transform: skewX(-20deg);
transition: left 0.6s ease;
}
.back-btn:hover::before { left: 150%; }
.back-btn:hover {
transform: translateY(-2px);
box-shadow: 0 14px 32px -8px rgba(99, 102, 241, 0.55);
background: linear-gradient(135deg, #818cf8, #6366f1 50%, #06b6d4);
}
.back-btn:active { transform: translateY(0); }
.back-btn-arrow {
font-size: 18px;
transition: transform 0.3s;
}
.back-btn:hover .back-btn-arrow { transform: translateX(4px); }
/* ═══════════════ 底部标语 ═══════════════ */
.fp-tagline {
font-size: 11px;
color: rgba(99, 102, 241, 0.35);
letter-spacing: 3px;
text-transform: uppercase;
font-weight: 600;
margin: 0;
}
/* ═══════════════ 响应式 ═══════════════ */
@media (max-width: 640px) {
.fp-center { padding: 16px; }
.fp-card { padding: 28px 24px 24px; border-radius: 22px; }
.fp-title { font-size: 22px; }
} }
</style> </style>