Files
docs/悦/注册登录/login-register.html
T

456 lines
16 KiB
HTML
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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虫虫出海 - 用户登录</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', sans-serif;
display: flex;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* ===== 左侧品牌区 ===== */
.brand-side {
width: 50%;
min-width: 420px;
position: relative;
background: linear-gradient(155deg, rgba(30,64,175,0.85) 0%, rgba(37,99,235,0.75) 40%, rgba(59,130,246,0.65) 100%);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
/* 浮动装饰圆圈 */
.brand-side::before {
content: '';
position: absolute;
top: -20%; right: -20%;
width: 80%; height: 80%;
background: radial-gradient(ellipse, rgba(255,255,255,.2) 0%, transparent 70%);
animation: float1 8s ease-in-out infinite;
pointer-events: none;
}
.brand-side::after {
content: '';
position: absolute;
bottom: -15%; left: -15%;
width: 70%; height: 70%;
background: radial-gradient(ellipse, rgba(147,197,253,.3) 0%, transparent 65%);
animation: float2 10s ease-in-out infinite;
pointer-events: none;
}
@keyframes float1 {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(-30px, 30px) scale(1.05); }
}
@keyframes float2 {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(20px, -20px) scale(1.1); }
}
.brand-content {
position: relative;
z-index: 1;
text-align: center;
padding: 40px;
animation: fadeInUp 0.8s ease-out;
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
.logo-wrap {
width: 100px; height: 100px;
margin: 0 auto 24px;
border-radius: 26px;
overflow: hidden;
background: rgba(255,255,255,.95);
padding: 12px;
box-shadow: 0 12px 40px rgba(0,0,0,.15), 0 0 0 1px rgba(255,255,255,.5) inset;
animation: logoFloat 3s ease-in-out infinite;
}
@keyframes logoFloat {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
.logo-wrap img { width: 100%; height: 100%; object-fit: contain; }
.brand-title { font-size: 36px; font-weight: 800; color: #fff; letter-spacing: 4px; text-shadow: 0 4px 20px rgba(0,0,0,.15); }
.brand-subtitle { font-size: 15px; color: rgba(255,255,255,.88); margin-top: 12px; letter-spacing: 2px; }
.feature-list { margin-top: 56px; text-align: left; display: inline-block; }
.feature-item {
color: rgba(255,255,255,.9);
font-size: 15px;
line-height: 2.6;
padding-left: 24px;
position: relative;
opacity: 0;
animation: fadeInLeft 0.6s ease-out forwards;
}
.feature-item:nth-child(1) { animation-delay: 0.2s; }
.feature-item:nth-child(2) { animation-delay: 0.4s; }
.feature-item:nth-child(3) { animation-delay: 0.6s; }
@keyframes fadeInLeft {
from { opacity: 0; transform: translateX(-20px); }
to { opacity: 1; transform: translateX(0); }
}
.feature-item::before {
content: '✓';
position: absolute;
left: 0; top: 2px;
width: 18px; height: 18px;
border-radius: 50%;
background: rgba(255,255,255,.25);
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 700;
}
/* ===== 右侧登录区 ===== */
.login-side {
flex: 1;
min-width: 400px;
display: flex;
align-items: center;
justify-content: center;
padding: 40px;
}
.login-card {
width: 100%;
max-width: 420px;
padding: 52px 44px;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 24px;
box-shadow: 0 25px 80px rgba(0,0,0,.15), 0 0 0 1px rgba(255,255,255,.5) inset;
animation: cardFloat 0.8s ease-out;
}
@keyframes cardFloat {
from { opacity: 0; transform: translateY(40px) scale(0.95); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* 标题区 */
.card-header { margin-bottom: 36px; }
.card-title {
font-size: 30px;
font-weight: 800;
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: 1px;
}
.card-desc {
font-size: 15px;
color: #64748b;
margin-top: 10px;
}
/* 表单 */
.form-group { margin-bottom: 22px; }
.form-input {
width: 100%;
height: 52px;
border: 2px solid #e2e8f0;
border-radius: 14px;
padding: 0 18px;
font-size: 15px;
color: #1e293b;
outline: none;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
background: #f8fafc;
}
.form-input:focus {
border-color: #667eea;
background: #fff;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
transform: translateY(-2px);
}
.form-input::placeholder { color: #94a3b8; }
/* 密码框 */
.password-wrap { position: relative; }
.password-toggle {
position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
border: none; background: none; cursor: pointer;
padding: 6px; color: #64748b; font-size: 18px; line-height: 1;
transition: all .2s;
}
.password-toggle:hover { color: #667eea; transform: translateY(-50%) scale(1.1); }
/* 验证码 */
.captcha-row {
display: flex;
gap: 14px;
align-items: center;
}
.captcha-row .form-input { flex: 1; }
.captcha-img {
width: 120px; height: 52px;
border: 2px solid #e2e8f0;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
user-select: none;
font-size: 22px;
font-weight: 700;
letter-spacing: 6px;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
flex-shrink: 0;
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
}
.captcha-img:hover {
border-color: #667eea;
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
}
/* 按钮 */
.submit-btn {
width: 100%;
height: 54px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
background-size: 200% 200%;
color: #fff;
border: none;
border-radius: 14px;
font-size: 16px;
font-weight: 700;
cursor: pointer;
transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
letter-spacing: 4px;
box-shadow: 0 8px 24px rgba(102, 126, 234, 0.4);
}
.submit-btn:hover {
background-position: 100% 0;
transform: translateY(-3px);
box-shadow: 0 12px 32px rgba(102, 126, 234, 0.5);
}
.submit-btn:active { transform: translateY(-1px); }
/* 底部辅助行 */
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 28px;
}
.remember-me {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: #64748b;
cursor: pointer;
user-select: none;
transition: color .2s;
}
.remember-me:hover { color: #475569; }
.remember-me input { accent-color: #667eea; width: 18px; height: 18px; cursor: pointer; }
.forgot-link {
font-size: 14px;
color: #667eea;
text-decoration: none;
font-weight: 500;
transition: all .2s;
}
.forgot-link:hover { color: #764ba2; text-decoration: underline; }
/* 底部注册链接 */
.register-tip {
text-align: center;
margin-top: 28px;
font-size: 14px;
color: #94a3b8;
}
.register-tip a {
color: #667eea;
text-decoration: none;
font-weight: 600;
transition: all .2s;
}
.register-tip a:hover { color: #764ba2; text-decoration: underline; }
/* 错误提示 */
.error-msg {
font-size: 13px;
color: #ef4444;
margin-top: 6px;
display: none;
padding-left: 4px;
animation: shake 0.3s ease-out;
}
.error-msg.show { display: block; }
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-4px); }
75% { transform: translateX(4px); }
}
/* 响应式 */
@media (max-width: 900px) {
body { flex-direction: column; }
.brand-side { min-width: auto; min-height: 240px; width: 100%; }
.brand-content { padding: 32px; }
.feature-list { display: none; }
.login-side { min-width: auto; padding: 24px 16px; }
.login-card { max-width: 420px; padding: 40px 28px; }
}
</style>
</head>
<body>
<!-- 左侧品牌 -->
<div class="brand-side">
<div class="brand-content">
<div class="logo-wrap">
<img src="logo.png" alt="Logo">
</div>
<h1 class="brand-title">虫虫出海</h1>
<p class="brand-subtitle">一站式跨境物流服务平台</p>
<div class="feature-list">
<div class="feature-item">安全可靠 · 全程可追踪</div>
<div class="feature-item">专业团队 · 快速响应</div>
<div class="feature-item">透明报价 · 无隐藏费用</div>
</div>
</div>
</div>
<!-- 右侧登录 -->
<div class="login-side">
<div class="login-card">
<div class="card-header">
<h2 class="card-title">欢迎回来</h2>
<p class="card-desc">请登录您的账户以继续</p>
</div>
<form id="loginForm" autocomplete="off">
<div class="form-group">
<input type="text" class="form-input" id="loginUsername" placeholder="用户名">
<div class="error-msg" id="loginUserError">请输入用户名</div>
</div>
<div class="form-group">
<div class="password-wrap">
<input type="password" class="form-input" id="loginPassword" placeholder="密码">
<button type="button" class="password-toggle" onclick="togglePassword()">👁</button>
</div>
<div class="error-msg" id="loginPassError">请输入密码</div>
</div>
<div class="form-group">
<div class="captcha-row">
<input type="text" class="form-input" id="loginCaptcha" placeholder="验证码" maxlength="4">
<div class="captcha-img" id="loginCaptchaImg" onclick="refreshCaptcha('login')"></div>
</div>
<div class="error-msg" id="loginCaptchaError">验证码错误</div>
</div>
<div class="form-options">
<label class="remember-me">
<input type="checkbox"> 记住我
</label>
<a href="javascript:void(0)" class="forgot-link">忘记密码?</a>
</div>
<button type="submit" class="submit-btn">登 录</button>
</form>
<div class="register-tip">没有账号?<a href="register.html">立即注册</a></div>
</div>
</div>
<script>
// 验证码
let currentCaptcha = {};
function generateCaptcha() {
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789';
let c = '';
for (let i = 0; i < 4; i++) c += chars.charAt(Math.floor(Math.random() * chars.length));
return c;
}
function refreshCaptcha(type) {
const c = generateCaptcha();
currentCaptcha[type] = c;
const el = document.getElementById(type + 'CaptchaImg');
if (!el) return;
el.textContent = c;
el.style.transform = 'rotate(' + (Math.random() * 8 - 4) + 'deg)';
el.style.color = ['#2563eb','#3b82f6','#1d4ed8','#1e40af'][Math.floor(Math.random()*4)];
}
refreshCaptcha('login');
// 密码显隐
function togglePassword() {
const pw = document.getElementById('loginPassword');
pw.type = pw.type === 'password' ? 'text' : 'password';
}
// 表单提交
document.getElementById('loginForm').addEventListener('submit', function(e) {
e.preventDefault();
var username = document.getElementById('loginUsername').value.trim();
var password = document.getElementById('loginPassword').value;
var captcha = document.getElementById('loginCaptcha').value.trim();
document.querySelectorAll('#loginForm .error-msg').forEach(function(el) { el.classList.remove('show'); });
var hasError = false;
if (!username) { document.getElementById('loginUserError').classList.add('show'); hasError = true; }
if (!password) { document.getElementById('loginPassError').classList.add('show'); hasError = true; }
if (captcha.toUpperCase() !== currentCaptcha['login'].toUpperCase()) {
document.getElementById('loginCaptchaError').classList.add('show');
refreshCaptcha('login');
hasError = true;
}
if (hasError) return;
alert('登录成功!欢迎回来,' + username + '!');
});
// 实时清除错误
document.querySelectorAll('.form-input').forEach(function(input) {
input.addEventListener('input', function() {
var group = this.closest('.form-group');
if (!group) return;
var err = group.querySelector('.error-msg');
if (err) err.classList.remove('show');
});
});
</script>
</body>
</html>