361 lines
19 KiB
HTML
361 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<title>可乐 - 忘记密码 (Apple 极简白 V2)</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Noto+Sans+SC:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
<style>
|
|
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
|
|
body{font-family:'Inter',-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;-webkit-font-smoothing:antialiased}
|
|
.page{min-height:100vh;display:flex;flex-direction:column;align-items:center;padding:0;position:relative;overflow:hidden}
|
|
.page.light{background:#f5f5f7;color:#1d1d1f}
|
|
.page.dark{background:#000;color:#f5f5f7}
|
|
|
|
/* Theme switcher */
|
|
.theme-switch{position:fixed;top:16px;right:16px;z-index:100;display:flex;background:#e5e5ea;border-radius:10px;padding:3px}
|
|
.page.dark .theme-switch{background:#2c2c2e}
|
|
.theme-btn{padding:6px 14px;border:none;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;font-family:inherit;transition:all .25s}
|
|
.page.light .theme-btn{background:transparent;color:#86868b}
|
|
.page.light .theme-btn.active{background:#fff;color:#1d1d1f;box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
|
.page.dark .theme-btn{background:transparent;color:rgba(255,255,255,.35)}
|
|
.page.dark .theme-btn.active{background:#3a3a3c;color:#fff}
|
|
|
|
.content{width:100%;padding:48px 32px 0;position:relative;z-index:1}
|
|
.logo{width:56px;height:56px;border-radius:16px;display:inline-flex;align-items:center;justify-content:center;font-size:28px}
|
|
.page.light .logo{background:#1d1d1f}
|
|
.page.dark .logo{background:rgba(255,255,255,.1)}
|
|
.header{text-align:center;margin-bottom:32px}
|
|
.title{font-size:28px;font-weight:800;letter-spacing:-.5px;margin-top:16px}
|
|
.subtitle{font-size:15px;margin-top:6px}
|
|
.page.light .title{color:#1d1d1f}.page.light .subtitle{color:#86868b}
|
|
.page.dark .title{color:#fff}.page.dark .subtitle{color:rgba(255,255,255,.4)}
|
|
|
|
/* ===== Segmented Steps ===== */
|
|
.steps-container{width:100%;margin-bottom:36px}
|
|
.steps-track{display:flex;position:relative;height:56px;border-radius:14px;padding:6px;overflow:hidden}
|
|
.page.light .steps-track{background:#e8e8ed}
|
|
.page.dark .steps-track{background:rgba(255,255,255,.06)}
|
|
.steps-track .slide{position:absolute;top:6px;bottom:6px;left:6px;width:calc(50% - 6px);border-radius:10px;transition:transform .4s cubic-bezier(.4,0,.2,1)}
|
|
.page.light .steps-track .slide{background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.06)}
|
|
.page.dark .steps-track .slide{background:#2c2c2e;box-shadow:0 1px 4px rgba(0,0,0,.3)}
|
|
.steps-track .slide.pos-1{transform:translateX(calc(100% + 0px))}
|
|
.steps-track .slide.pos-2{transform:translateX(calc(200% + 6px))}
|
|
.step-btn{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;border:none;background:none;cursor:pointer;font-family:inherit;position:relative;z-index:2;transition:all .3s}
|
|
.step-btn .num{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;transition:all .3s}
|
|
.step-btn .text{font-size:12px;font-weight:600;transition:color .3s}
|
|
.page.light .step-btn .num{background:#d1d1d6;color:#aeaeb2}
|
|
.page.light .step-btn .text{color:#aeaeb2}
|
|
.page.dark .step-btn .num{background:rgba(255,255,255,.1);color:rgba(255,255,255,.25)}
|
|
.page.dark .step-btn .text{color:rgba(255,255,255,.25)}
|
|
.steps-track .slide.pos-0 ~ .step-btn:first-child .num,
|
|
.steps-track .slide.pos-0 ~ .step-btn:first-child .text{position:relative;z-index:3}
|
|
/* Active step colors */
|
|
.page.light .step-btn.active .num{background:#1d1d1f;color:#fff}
|
|
.page.light .step-btn.active .text{color:#1d1d1f}
|
|
.page.dark .step-btn.active .num{background:#667eea;color:#fff}
|
|
.page.dark .step-btn.active .text{color:#fff}
|
|
.page.light .step-btn.done .num{background:#34d399;color:#fff}
|
|
.page.light .step-btn.done .text{color:#34d399}
|
|
.page.dark .step-btn.done .num{background:#34d399;color:#fff}
|
|
.page.dark .step-btn.done .text{color:#34d399}
|
|
|
|
/* Tabs */
|
|
.tabs{display:flex;border-radius:12px;padding:4px;margin-bottom:28px;width:100%}
|
|
.page.light .tabs{background:#f0f0f2}
|
|
.page.dark .tabs{background:#1c1c1e}
|
|
.tab{flex:1;padding:11px 0;text-align:center;border-radius:10px;font-size:14px;font-weight:600;border:none;cursor:pointer;transition:all .3s;font-family:inherit}
|
|
.page.light .tab{background:transparent;color:#86868b}
|
|
.page.light .tab.active{background:#fff;color:#1d1d1f;box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
|
.page.dark .tab{background:transparent;color:rgba(255,255,255,.35)}
|
|
.page.dark .tab.active{background:#2c2c2e;color:#fff}
|
|
|
|
/* Form */
|
|
.form-step{display:none;width:100%}
|
|
.form-step.active{display:flex;flex-direction:column;animation:fadeSlide .35s ease}
|
|
@keyframes fadeSlide{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
|
|
.field{margin-bottom:16px}
|
|
.field label{display:block;font-size:13px;font-weight:600;margin-bottom:8px}
|
|
.page.light .field label{color:#333}
|
|
.page.dark .field label{color:rgba(255,255,255,.6)}
|
|
.input{width:100%;height:52px;border-radius:12px;padding:0 16px;font-size:16px;outline:none;transition:all .25s;font-family:inherit}
|
|
.page.light .input{border:1.5px solid #e5e5ea;background:#fff;color:#1d1d1f}
|
|
.page.light .input::placeholder{color:#c7c7cc}
|
|
.page.light .input:focus{border-color:#667eea;box-shadow:0 0 0 3px rgba(102,126,234,.12)}
|
|
.page.dark .input{border:1.5px solid rgba(255,255,255,.1);background:#1c1c1e;color:#fff}
|
|
.page.dark .input::placeholder{color:rgba(255,255,255,.25)}
|
|
.page.dark .input:focus{border-color:rgba(102,126,234,.6);box-shadow:0 0 0 3px rgba(102,126,234,.12)}
|
|
|
|
/* Code row */
|
|
.code-row{display:flex;gap:10px;margin-bottom:16px;align-items:stretch}
|
|
.code-row .input{flex:1;margin-bottom:0}
|
|
.code-btn{flex-shrink:0;height:52px;padding:0 18px;border-radius:12px;font-size:13px;font-weight:600;cursor:pointer;transition:all .2s;font-family:inherit;white-space:nowrap}
|
|
.page.light .code-btn{border:1.5px solid #e5e5ea;background:#fafafa;color:#667eea}
|
|
.page.dark .code-btn{border:1.5px solid rgba(255,255,255,.1);background:#1c1c1e;color:#667eea}
|
|
.code-btn:disabled{opacity:.5;cursor:not-allowed}
|
|
|
|
/* Buttons */
|
|
.btn-primary{width:100%;height:54px;border-radius:14px;border:none;font-size:17px;font-weight:600;cursor:pointer;transition:all .3s;margin-top:8px;font-family:inherit}
|
|
.btn-primary:active{transform:scale(.97);opacity:.9}
|
|
.page.light .btn-primary{background:#1d1d1f;color:#fff}
|
|
.page.dark .btn-primary{background:#fff;color:#000}
|
|
.btn-ghost{width:100%;height:54px;border-radius:14px;font-size:15px;font-weight:600;cursor:pointer;margin-top:12px;transition:all .3s;font-family:inherit}
|
|
.page.light .btn-ghost{border:1.5px solid #e5e5ea;background:#fff;color:#1d1d1f}
|
|
.page.dark .btn-ghost{border:1.5px solid rgba(255,255,255,.12);background:transparent;color:rgba(255,255,255,.8)}
|
|
|
|
.back-link{display:inline-flex;align-items:center;gap:6px;font-size:14px;cursor:pointer;margin-bottom:20px;font-weight:500;font-family:inherit;border:none;background:none;padding:0}
|
|
.page.light .back-link{color:#667eea}
|
|
.page.dark .back-link{color:#667eea}
|
|
|
|
.email-badge{display:inline-flex;align-items:center;gap:8px;padding:12px 16px;border-radius:12px;margin-bottom:20px;font-size:14px;font-weight:500}
|
|
.page.light .email-badge{background:#f0f0f2;color:#667eea}
|
|
.page.dark .email-badge{background:rgba(102,126,234,.1);color:#8b9cf7;border:1px solid rgba(255,255,255,.08)}
|
|
|
|
/* Password strength */
|
|
.strength{display:flex;gap:4px;margin-top:-8px;margin-bottom:16px}
|
|
.strength-bar{flex:1;height:3px;border-radius:2px;transition:all .3s}
|
|
.page.light .strength-bar{background:#e5e5ea}
|
|
.page.dark .strength-bar{background:rgba(255,255,255,.08)}
|
|
.strength-bar.active-weak{background:#ff3b30}
|
|
.strength-bar.active-medium{background:#ff9500}
|
|
.strength-bar.active-strong{background:#34d399}
|
|
.strength-text{font-size:12px;margin-top:4px;margin-bottom:12px;font-weight:500}
|
|
.page.light .strength-text{color:#86868b}
|
|
.page.dark .strength-text{color:rgba(255,255,255,.35)}
|
|
|
|
.rules{padding:14px 16px;border-radius:12px;margin-top:10px;margin-bottom:8px}
|
|
.page.light .rules{background:#f8f8fa;border:1px solid #e5e5ea}
|
|
.page.dark .rules{background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.08)}
|
|
.rules p{font-size:13px;line-height:2}
|
|
.page.light .rules p{color:#86868b}
|
|
.page.dark .rules p{color:rgba(255,255,255,.35)}
|
|
.rules strong{font-weight:600}
|
|
.page.light .rules strong{color:#1d1d1f}
|
|
.page.dark .rules strong{color:rgba(255,255,255,.6)}
|
|
|
|
.success{display:none;text-align:center;padding:48px 0}
|
|
.success.active{display:block;animation:fadeSlide .4s ease}
|
|
.success .check{width:72px;height:72px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:36px;margin-bottom:20px}
|
|
.page.light .success .check{background:#f0fff4}
|
|
.page.dark .success .check{background:rgba(52,211,153,.1)}
|
|
.success h2{font-size:22px;font-weight:800;margin-bottom:8px}
|
|
.page.light .success h2{color:#1d1d1f}
|
|
.page.dark .success h2{color:#fff}
|
|
.success p{font-size:15px;margin-bottom:32px}
|
|
.page.light .success p{color:#86868b}
|
|
.page.dark .success p{color:rgba(255,255,255,.4)}
|
|
|
|
.divider{display:flex;align-items:center;gap:16px;margin:24px 0 20px;width:100%}
|
|
.divider::before,.divider::after{content:'';flex:1;height:.5px}
|
|
.page.light .divider::before,.page.light .divider::after{background:#d2d2d7}
|
|
.page.dark .divider::before,.page.dark .divider::after{background:rgba(255,255,255,.08)}
|
|
.divider span{font-size:13px;white-space:nowrap;font-weight:500}
|
|
.page.light .divider span{color:#86868b}
|
|
.page.dark .divider span{color:rgba(255,255,255,.3)}
|
|
|
|
.agreement{text-align:center;font-size:12px;line-height:1.7;padding:16px 20px 32px;margin-top:12px}
|
|
.page.light .agreement{color:#aeaeb2}
|
|
.page.dark .agreement{color:rgba(255,255,255,.2)}
|
|
.agree-link{background:none;border:none;font-size:12px;cursor:pointer;padding:0;font-weight:500;font-family:inherit}
|
|
.page.light .agree-link{color:#8e8e93}
|
|
.page.dark .agree-link{color:rgba(255,255,255,.35)}
|
|
|
|
@media(max-width:480px){.content{padding-left:24px!important;padding-right:24px!important}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- Light -->
|
|
<div class="page light" id="lightPage">
|
|
<div class="theme-switch">
|
|
<button class="theme-btn active" onclick="switchTheme('light')">☀️ 浅色</button>
|
|
<button class="theme-btn" onclick="switchTheme('dark')">🌙 深色</button>
|
|
</div>
|
|
<div class="content">
|
|
<div class="header">
|
|
<div class="logo">🥤</div>
|
|
<h1 class="title">找回密码</h1>
|
|
<p class="subtitle">别担心,几步就能重置密码</p>
|
|
</div>
|
|
|
|
<!-- Segmented Steps -->
|
|
<div class="steps-container">
|
|
<div class="steps-track" id="lightTrack">
|
|
<div class="slide pos-0"></div>
|
|
<button class="step-btn active" id="lightBtn0"><div class="num">1</div><div class="text">验证身份</div></button>
|
|
<button class="step-btn" id="lightBtn1"><div class="num">2</div><div class="text">重置密码</div></button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 1 -->
|
|
<div class="form-step active" id="lightStep0">
|
|
<div class="field">
|
|
<label>邮箱地址</label>
|
|
<input class="input" type="email" placeholder="请输入注册邮箱" id="lightEmail">
|
|
</div>
|
|
<div class="code-row">
|
|
<input class="input" type="text" placeholder="验证码" maxlength="8">
|
|
<button class="code-btn" onclick="sendCode(this)">获取验证码</button>
|
|
</div>
|
|
<button class="btn-primary" onclick="goStep(1,'light')">下一步</button>
|
|
<div class="divider"><span>或</span></div>
|
|
<button class="btn-ghost" onclick="window.location.href='/login'">返回登录</button>
|
|
</div>
|
|
|
|
<!-- Step 2 -->
|
|
<div class="form-step" id="lightStep1">
|
|
<button class="back-link" onclick="goStep(0,'light')">← 返回验证</button>
|
|
<div class="email-badge" id="lightEmailDisplay">✉️ user@example.com</div>
|
|
<div class="field">
|
|
<label>验证码</label>
|
|
<input class="input" type="text" placeholder="请输入验证码" maxlength="8">
|
|
</div>
|
|
<div class="field">
|
|
<label>新密码</label>
|
|
<input class="input" type="password" placeholder="至少8位,包含字母和数字" oninput="checkStrength(this.value,'light')">
|
|
<div class="strength" id="lightStrength"><div class="strength-bar"></div><div class="strength-bar"></div><div class="strength-bar"></div></div>
|
|
<div class="strength-text" id="lightStrengthText"></div>
|
|
</div>
|
|
<div class="field">
|
|
<label>确认密码</label>
|
|
<input class="input" type="password" placeholder="请再次输入新密码">
|
|
</div>
|
|
<div class="rules">
|
|
<p><strong>•</strong> 至少8个字符</p>
|
|
<p><strong>•</strong> 包含字母和数字</p>
|
|
<p><strong>•</strong> 建议12位以上更安全</p>
|
|
</div>
|
|
<button class="btn-primary" onclick="resetPwd('light')">重置密码</button>
|
|
</div>
|
|
|
|
<div class="success" id="lightSuccess">
|
|
<div class="check">✅</div>
|
|
<h2>密码重置成功!</h2>
|
|
<p>你的密码已更新,现在可以使用新密码登录了</p>
|
|
<button class="btn-primary" onclick="location.reload()">返回登录</button>
|
|
</div>
|
|
|
|
<div class="agreement">
|
|
继续即表示你同意 <button class="agree-link">用户协议</button> 和 <button class="agree-link">隐私政策</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dark -->
|
|
<div class="page dark" id="darkPage" style="display:none">
|
|
<div class="theme-switch">
|
|
<button class="theme-btn" onclick="switchTheme('light')">☀️ 浅色</button>
|
|
<button class="theme-btn active" onclick="switchTheme('dark')">🌙 深色</button>
|
|
</div>
|
|
<div class="content">
|
|
<div class="header">
|
|
<div class="logo">🥤</div>
|
|
<h1 class="title">找回密码</h1>
|
|
<p class="subtitle">别担心,几步就能重置密码</p>
|
|
</div>
|
|
|
|
<div class="steps-container">
|
|
<div class="steps-track" id="darkTrack">
|
|
<div class="slide pos-0"></div>
|
|
<button class="step-btn active" id="darkBtn0"><div class="num">1</div><div class="text">验证身份</div></button>
|
|
<button class="step-btn" id="darkBtn1"><div class="num">2</div><div class="text">重置密码</div></button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-step active" id="darkStep0">
|
|
<div class="field">
|
|
<label>邮箱地址</label>
|
|
<input class="input" type="email" placeholder="请输入注册邮箱" id="darkEmail">
|
|
</div>
|
|
<div class="code-row">
|
|
<input class="input" type="text" placeholder="验证码" maxlength="8">
|
|
<button class="code-btn" onclick="sendCode(this)">获取验证码</button>
|
|
</div>
|
|
<button class="btn-primary" onclick="goStep(1,'dark')">下一步</button>
|
|
<div class="divider"><span>或</span></div>
|
|
<button class="btn-ghost" onclick="window.location.href='/login'">返回登录</button>
|
|
</div>
|
|
|
|
<div class="form-step" id="darkStep1">
|
|
<button class="back-link" onclick="goStep(0,'dark')">← 返回验证</button>
|
|
<div class="email-badge" id="darkEmailDisplay">✉️ user@example.com</div>
|
|
<div class="field">
|
|
<label>验证码</label>
|
|
<input class="input" type="text" placeholder="请输入验证码" maxlength="8">
|
|
</div>
|
|
<div class="field">
|
|
<label>新密码</label>
|
|
<input class="input" type="password" placeholder="至少8位,包含字母和数字" oninput="checkStrength(this.value,'dark')">
|
|
<div class="strength" id="darkStrength"><div class="strength-bar"></div><div class="strength-bar"></div><div class="strength-bar"></div></div>
|
|
<div class="strength-text" id="darkStrengthText"></div>
|
|
</div>
|
|
<div class="field">
|
|
<label>确认密码</label>
|
|
<input class="input" type="password" placeholder="请再次输入新密码">
|
|
</div>
|
|
<div class="rules">
|
|
<p><strong>•</strong> 至少8个字符</p>
|
|
<p><strong>•</strong> 包含字母和数字</p>
|
|
<p><strong>•</strong> 建议12位以上更安全</p>
|
|
</div>
|
|
<button class="btn-primary" onclick="resetPwd('dark')">重置密码</button>
|
|
</div>
|
|
|
|
<div class="success" id="darkSuccess">
|
|
<div class="check">✅</div>
|
|
<h2>密码重置成功!</h2>
|
|
<p>你的密码已更新,现在可以使用新密码登录了</p>
|
|
<button class="btn-primary" onclick="location.reload()">返回登录</button>
|
|
</div>
|
|
|
|
<div class="agreement">
|
|
继续即表示你同意 <button class="agree-link">用户协议</button> 和 <button class="agree-link">隐私政策</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function switchTheme(t){
|
|
document.getElementById('lightPage').style.display=t==='light'?'flex':'none';
|
|
document.getElementById('darkPage').style.display=t==='dark'?'flex':'none';
|
|
document.querySelectorAll('.theme-btn').forEach(function(b){b.classList.remove('active')});
|
|
document.querySelectorAll('.theme-btn').forEach(function(b){
|
|
if((t==='light'&&b.textContent.includes('浅色'))||(t==='dark'&&b.textContent.includes('深色')))b.classList.add('active');
|
|
});
|
|
}
|
|
function sendCode(btn){var s=60;btn.disabled=true;var iv=setInterval(function(){s--;btn.textContent=s+'s';if(s<=0){clearInterval(iv);btn.disabled=false;btn.textContent='获取验证码'}},1000)}
|
|
function goStep(n,theme){
|
|
var track=document.getElementById(theme+'Track');
|
|
var slide=track.querySelector('.slide');
|
|
slide.className='slide pos-'+n;
|
|
var btns=[document.getElementById(theme+'Btn0'),document.getElementById(theme+'Btn1')];
|
|
btns.forEach(function(b,i){b.classList.remove('active','done');if(i<n)b.classList.add('done');if(i===n)b.classList.add('active')});
|
|
for(var i=0;i<2;i++){var el=document.getElementById(theme+'Step'+i);if(el)el.classList.remove('active')}
|
|
document.getElementById(theme+'Step'+n).classList.add('active');
|
|
if(n===1){var em=document.getElementById(theme+'Email').value||'user@example.com';document.getElementById(theme+'EmailDisplay').textContent='✉️ '+em}
|
|
}
|
|
function checkStrength(pwd,theme){
|
|
var bars=document.getElementById(theme+'Strength').querySelectorAll('.strength-bar');
|
|
var txt=document.getElementById(theme+'StrengthText');
|
|
bars.forEach(function(b){b.className='strength-bar'});
|
|
if(!pwd){txt.textContent='';return}
|
|
var score=0;
|
|
if(pwd.length>=8)score++;
|
|
if(/[a-zA-Z]/.test(pwd)&&/\d/.test(pwd))score++;
|
|
if(pwd.length>=12&&/[A-Z]/.test(pwd))score++;
|
|
var cls=score<=1?'active-weak':score===2?'active-medium':'active-strong';
|
|
var label=score<=1?'弱 - 建议增加字符':score===2?'中等 - 不错':'强 - 安全';
|
|
for(var i=0;i<=score&&i<3;i++)bars[i].classList.add(cls);
|
|
txt.textContent=label;txt.className='strength-text';txt.style.color=score<=1?'#ff3b30':score===2?'#ff9500':'#34d399';
|
|
}
|
|
function resetPwd(theme){
|
|
document.getElementById(theme+'Step1').classList.remove('active');
|
|
document.getElementById(theme+'Success').classList.add('active');
|
|
var btns=[document.getElementById(theme+'Btn0'),document.getElementById(theme+'Btn1')];
|
|
btns.forEach(function(b){b.classList.remove('active');b.classList.add('done')});
|
|
var slide=document.getElementById(theme+'Track').querySelector('.slide');
|
|
slide.className='slide pos-2';
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |