| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- <!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>绿水青山 · 登录</title>
- <!-- Tailwind CSS(CDN,国内可访问) -->
- <script src="https://cdn.tailwindcss.com"></script>
- <!-- Font Awesome 图标(国内 jsdelivr 镜像) -->
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" />
- <script>
- // Tailwind 主题扩展:品牌色 / 嫩芽色 / 山水色
- tailwind.config = {
- theme: {
- extend: {
- colors: {
- brand: '#368F6F', // 主标题 / 按钮起点(青山绿)
- stream: '#5AB8D0', // 按钮终点(溪流水蓝)
- mist: '#709484', // 副标题(晨雾灰绿)
- sprout: '#9BCB8A', // 嫩芽(卡片边框)
- gold: '#E9C46A', // 金色微光
- },
- fontFamily: {
- sans: ['"PingFang SC"', '"Microsoft YaHei"', '"Hiragino Sans GB"', 'system-ui', 'sans-serif'],
- },
- boxShadow: {
- glass: '0 18px 50px -12px rgba(54, 143, 111, 0.28)',
- btn: '0 14px 30px -8px rgba(54, 143, 111, 0.45)',
- },
- },
- },
- }
- </script>
- <style>
- /* ============ 基础 ============ */
- html, body { height: 100%; }
- body {
- margin: 0;
- -webkit-tap-highlight-color: transparent;
- font-family: "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
- background: #eef4f1;
- }
- /* 手机外壳:移动端竖屏、居中 */
- .phone {
- position: relative;
- width: 100%;
- max-width: 28rem; /* max-w-md */
- min-height: 100vh;
- margin: 0 auto; /* mx-auto */
- overflow: hidden;
- background:
- linear-gradient(180deg, #f7fbf9 0%, #eef6f1 38%, #e7f0ec 100%);
- isolation: isolate;
- }
- /* ============ 顶部浅雾渐变天幕 ============ */
- .sky {
- position: absolute;
- inset: 0 0 auto 0;
- height: 46%;
- background:
- linear-gradient(160deg, #fbfefd 0%, #eaf4ef 45%, #dbe8ec 100%);
- z-index: -3;
- }
- /* 金色微光(标题后方的柔光晕) */
- .gold-glow {
- position: absolute;
- top: 7%;
- left: 50%;
- width: 260px;
- height: 260px;
- transform: translateX(-50%);
- background: radial-gradient(circle, rgba(233,196,106,0.40) 0%, rgba(233,196,106,0.12) 42%, rgba(233,196,106,0) 70%);
- filter: blur(6px);
- z-index: -2;
- animation: breathe 6s ease-in-out infinite;
- }
- @keyframes breathe {
- 0%, 100% { opacity: 0.7; transform: translateX(-50%) scale(1); }
- 50% { opacity: 1; transform: translateX(-50%) scale(1.08); }
- }
- /* 云雾朦胧斑 */
- .mist-blob {
- position: absolute;
- border-radius: 9999px;
- filter: blur(26px);
- z-index: -2;
- opacity: 0.55;
- animation: drift 14s ease-in-out infinite;
- }
- .mist-1 { width: 200px; height: 120px; left: -60px; top: 6%; background: rgba(255,255,255,0.9); }
- .mist-2 { width: 240px; height: 140px; right: -90px; top: 14%; background: rgba(214,235,230,0.9); animation-delay: -4s; }
- .mist-3 { width: 180px; height: 100px; left: 30%; top: 2%; background: rgba(255,255,255,0.7); animation-delay: -8s; }
- @keyframes drift {
- 0%, 100% { transform: translate3d(0, 0, 0); }
- 50% { transform: translate3d(18px, 10px, 0); }
- }
- /* ============ 远山剪影 / 溪流(SVG 共用) ============ */
- .scene { position: absolute; left: 0; right: 0; width: 100%; pointer-events: none; }
- .scene-top { top: 30%; z-index: -1; opacity: 0.5; }
- .scene-bottom { bottom: 0; z-index: -1; }
- /* ============ 飘落绿叶粒子 ============ */
- .leaf {
- position: absolute;
- top: -40px;
- width: 18px;
- height: 18px;
- border-radius: 2px 16px 2px 16px;
- transform: rotate(45deg);
- z-index: 5;
- opacity: 0.85;
- animation: fall linear infinite;
- }
- @keyframes fall {
- 0% { transform: translate3d(0, -40px, 0) rotate(0deg); opacity: 0; }
- 10% { opacity: 0.9; }
- 90% { opacity: 0.8; }
- 100% { transform: translate3d(var(--dx, -30px), 105vh, 0) rotate(540deg); opacity: 0; }
- }
- /* ============ 磨砂玻璃卡片 ============ */
- .glass-card {
- background: rgba(255, 255, 255, 0.80);
- -webkit-backdrop-filter: blur(12px);
- backdrop-filter: blur(12px);
- border: 1px solid rgba(155, 203, 138, 0.30);
- border-radius: 24px;
- box-shadow: 0 18px 50px -12px rgba(54, 143, 111, 0.28);
- }
- /* 输入框 */
- .field {
- display: flex;
- align-items: center;
- height: 52px;
- padding: 0 16px;
- border-radius: 16px;
- background: rgba(246, 250, 247, 0.9);
- border: 1px solid rgba(155, 203, 138, 0.35);
- transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
- }
- .field:focus-within {
- background: #ffffff;
- border-color: #368F6F;
- box-shadow: 0 0 0 4px rgba(54, 143, 111, 0.12);
- }
- .field input {
- flex: 1;
- height: 100%;
- border: none;
- outline: none;
- background: transparent;
- font-size: 15px;
- color: #26403a;
- }
- .field input::placeholder { color: #9fb4aa; }
- .field .fa { width: 20px; text-align: center; color: #7d978c; }
- .field .toggle { color: #9fb4aa; cursor: pointer; padding: 6px; }
- /* ============ 登录按钮(渐变 + 水波纹边缘) ============ */
- .login-btn {
- position: relative;
- height: 56px;
- width: 100%;
- border: none;
- border-radius: 24px;
- color: #ffffff;
- font-size: 17px;
- font-weight: 700;
- letter-spacing: 4px;
- cursor: pointer;
- overflow: hidden;
- background: linear-gradient(135deg, #368F6F 0%, #5AB8D0 100%);
- box-shadow: 0 14px 30px -8px rgba(54, 143, 111, 0.45);
- transition: transform .15s ease, box-shadow .2s ease, opacity .2s ease;
- }
- .login-btn:active { transform: scale(0.985); }
- .login-btn:disabled { opacity: 0.7; cursor: default; }
- /* 持续呼吸的水波纹边缘 */
- .login-btn::before {
- content: "";
- position: absolute;
- inset: -3px;
- border-radius: 26px;
- border: 2px solid rgba(90, 184, 208, 0.55);
- animation: ripple 2.6s ease-out infinite;
- pointer-events: none;
- }
- @keyframes ripple {
- 0% { transform: scale(0.96); opacity: 0.7; }
- 100% { transform: scale(1.08); opacity: 0; }
- }
- /* 点击水波圆斑 */
- .login-btn .ink {
- position: absolute;
- border-radius: 50%;
- transform: scale(0);
- background: rgba(255, 255, 255, 0.45);
- animation: ink .6s ease-out;
- pointer-events: none;
- }
- @keyframes ink {
- to { transform: scale(2.6); opacity: 0; }
- }
- /* ============ 底部草叶浮动 ============ */
- .float-slow { animation: float 6s ease-in-out infinite; }
- .float-slower { animation: float 8s ease-in-out infinite; animation-delay: -2s; }
- @keyframes float {
- 0%, 100% { transform: translateY(0); }
- 50% { transform: translateY(-8px); }
- }
- /* 链接 */
- .link { color: #368F6F; font-size: 13px; }
- .link:active { opacity: 0.7; }
- </style>
- </head>
- <body>
- <!-- ============ 手机容器 ============ -->
- <main class="phone flex flex-col">
- <!-- 天幕 / 光 / 雾(装饰层) -->
- <div class="sky"></div>
- <div class="gold-glow"></div>
- <div class="mist-blob mist-1"></div>
- <div class="mist-blob mist-2"></div>
- <div class="mist-blob mist-3"></div>
- <!-- 顶部远山剪影 -->
- <svg class="scene scene-top" viewBox="0 0 400 120" preserveAspectRatio="none" aria-hidden="true">
- <path d="M0,120 L0,70 Q60,20 120,68 Q180,16 240,66 Q310,30 400,72 L400,120 Z" fill="#7fb3a0" opacity="0.35"/>
- <path d="M0,120 L0,86 Q70,48 140,84 Q210,46 280,86 Q340,58 400,86 L400,120 Z" fill="#5e9c86" opacity="0.40"/>
- </svg>
- <!-- 顶部溪流曲线 -->
- <svg class="scene scene-top" style="top:40%; opacity:0.45" viewBox="0 0 400 60" preserveAspectRatio="none" aria-hidden="true">
- <path d="M0,30 C60,10 90,50 150,30 S260,10 320,30 S380,42 400,30" fill="none" stroke="#5AB8D0" stroke-width="2" opacity="0.5"/>
- <path d="M0,44 C70,26 100,58 160,42 S270,24 400,44" fill="none" stroke="#5AB8D0" stroke-width="1.4" opacity="0.35"/>
- </svg>
- <!-- 飘落绿叶粒子 -->
- <i class="leaf" style="left:8%; --dx:-40px; background:linear-gradient(135deg,#7cc68a,#368F6F); animation-duration:11s; animation-delay:-1s;"></i>
- <i class="leaf" style="left:22%; --dx:30px; background:linear-gradient(135deg,#9BCB8A,#5ab07a); width:14px;height:14px; animation-duration:14s; animation-delay:-6s;"></i>
- <i class="leaf" style="left:40%; --dx:-20px; background:linear-gradient(135deg,#6fbf8f,#2f7f62); width:20px;height:20px; animation-duration:12s; animation-delay:-3s;"></i>
- <i class="leaf" style="left:58%; --dx:40px; background:linear-gradient(135deg,#a9d89c,#368F6F); width:13px;height:13px; animation-duration:15s; animation-delay:-9s;"></i>
- <i class="leaf" style="left:74%; --dx:-34px; background:linear-gradient(135deg,#8bcf9a,#3f9b73); width:16px;height:16px; animation-duration:13s; animation-delay:-4s;"></i>
- <i class="leaf" style="left:90%; --dx:24px; background:linear-gradient(135deg,#9BCB8A,#5ab07a); width:12px;height:12px; animation-duration:16s; animation-delay:-11s;"></i>
- <!-- ============ 内容层 ============ -->
- <div class="relative z-10 flex flex-col flex-1 px-7 pt-16 pb-8">
- <!-- 品牌区 -->
- <header class="flex flex-col items-center">
- <!-- Logo:山形 + 水滴 + 三片叶子 融合 -->
- <div class="w-20 h-20 rounded-[22px] bg-white shadow-glass flex items-center justify-center">
- <svg viewBox="0 0 64 64" width="54" height="54" aria-label="绿水青山">
- <defs>
- <linearGradient id="leafGrad" x1="0" y1="0" x2="1" y2="1">
- <stop offset="0" stop-color="#7fd08a"/>
- <stop offset="1" stop-color="#368F6F"/>
- </linearGradient>
- <linearGradient id="dropGrad" x1="0" y1="0" x2="0" y2="1">
- <stop offset="0" stop-color="#8fd0e0"/>
- <stop offset="1" stop-color="#5AB8D0"/>
- </linearGradient>
- </defs>
- <!-- 山形 -->
- <path d="M6 46 L24 22 L34 34 L44 20 L58 46 Z" fill="#e8f3ec" stroke="#cfe6d6" stroke-width="1.5" stroke-linejoin="round"/>
- <!-- 水滴 -->
- <path d="M32 14 C32 14 24 23 24 30 a8 8 0 0 0 16 0 C40 23 32 14 32 14 Z" fill="url(#dropGrad)" opacity="0.92"/>
- <!-- 三片叶子 -->
- <path d="M32 50 C24 44 20 36 22 28 C30 30 34 38 32 50 Z" fill="url(#leafGrad)"/>
- <path d="M32 50 C40 44 44 36 42 28 C34 30 30 38 32 50 Z" fill="url(#leafGrad)" opacity="0.9"/>
- <path d="M32 52 C30 42 32 34 38 28 C40 36 38 46 32 52 Z" fill="#2f7f62" opacity="0.55"/>
- </svg>
- </div>
- <h1 class="mt-5 text-[32px] font-extrabold tracking-[6px] text-brand">绿水青山</h1>
- <p class="mt-2 text-sm tracking-[3px] text-mist">与自然同行</p>
- </header>
- <!-- 登录卡片 -->
- <section class="glass-card mt-10 px-6 py-7">
- <h2 class="text-center text-lg font-bold text-brand">欢迎回来</h2>
- <form class="mt-6 space-y-4" id="loginForm" novalidate>
- <!-- 账号 -->
- <div class="field">
- <i class="fa fa-user mr-3"></i>
- <input type="text" id="account" name="account" placeholder="请输入账号" autocomplete="username" />
- </div>
- <!-- 密码 -->
- <div>
- <div class="field">
- <i class="fa fa-lock mr-3"></i>
- <input type="password" id="password" name="password" placeholder="请输入密码" autocomplete="current-password" />
- <i class="fa fa-eye toggle" id="togglePwd" aria-label="显示密码"></i>
- </div>
- <div class="mt-2 flex justify-end">
- <a class="link" href="javascript:void(0)" id="forgot">忘记密码?</a>
- </div>
- </div>
- <!-- 登录按钮 -->
- <button type="submit" class="login-btn mt-2" id="loginBtn">登 录</button>
- </form>
- </section>
- <!-- 协议 / 其他入口 -->
- <p class="mt-6 text-center text-xs text-mist/80">
- 登录即代表同意 <span class="link">服务协议</span> 与 <span class="link">隐私政策</span>
- </p>
- <div class="flex-1"></div>
- <p class="mt-6 text-center text-[11px] text-mist/60">v1.0.0 · 绿水青山环境服务</p>
- </div>
- <!-- ============ 底部山水(低透明度 + 浮动) ============ -->
- <svg class="scene scene-bottom float-slower" style="opacity:0.55" viewBox="0 0 400 140" preserveAspectRatio="none" aria-hidden="true">
- <path d="M0,140 L0,78 Q70,30 150,78 Q230,26 320,80 Q360,56 400,82 L400,140 Z" fill="#7fb3a0" opacity="0.30"/>
- <path d="M0,140 L0,98 Q80,64 160,100 Q250,58 400,100 L400,140 Z" fill="#368F6F" opacity="0.22"/>
- </svg>
- <!-- 底部溪流波纹 -->
- <svg class="scene scene-bottom float-slow" style="opacity:0.5" viewBox="0 0 400 70" preserveAspectRatio="none" aria-hidden="true">
- <path d="M0,26 C60,8 100,44 160,26 S280,8 400,30" fill="none" stroke="#5AB8D0" stroke-width="2" opacity="0.45"/>
- <path d="M0,44 C70,26 110,58 180,42 S300,26 400,46" fill="none" stroke="#5AB8D0" stroke-width="1.4" opacity="0.32"/>
- <path d="M0,58 C80,46 120,66 200,56 S320,46 400,60" fill="none" stroke="#5AB8D0" stroke-width="1" opacity="0.22"/>
- </svg>
- <!-- 底部草叶纹理 / 绿叶点缀 -->
- <div class="scene-bottom" style="bottom:14px; z-index:0; opacity:0.8;">
- <i class="leaf float-slow" style="top:auto; bottom:6px; left:24px; position:absolute; width:16px;height:16px; background:linear-gradient(135deg,#9BCB8A,#368F6F);"></i>
- <i class="leaf float-slower" style="top:auto; bottom:2px; right:30px; position:absolute; width:14px;height:14px; background:linear-gradient(135deg,#8bcf9a,#2f7f62);"></i>
- <i class="leaf float-slow" style="top:auto; bottom:22px; right:120px; position:absolute; width:12px;height:12px; background:linear-gradient(135deg,#a9d89c,#5ab07a);"></i>
- </div>
- </main>
- <script>
- // 密码显隐切换
- const pwd = document.getElementById('password')
- const toggle = document.getElementById('togglePwd')
- toggle.addEventListener('click', () => {
- const show = pwd.type === 'password'
- pwd.type = show ? 'text' : 'password'
- toggle.classList.toggle('fa-eye', !show)
- toggle.classList.toggle('fa-eye-slash', show)
- })
- // 忘记密码
- document.getElementById('forgot').addEventListener('click', () => {
- alert('请联系管理员重置密码')
- })
- // 登录提交 + 按钮水波纹 + 加载态
- const form = document.getElementById('loginForm')
- const btn = document.getElementById('loginBtn')
- function spawnInk(x, y) {
- const ink = document.createElement('span')
- ink.className = 'ink'
- const size = 120
- ink.style.width = ink.style.height = size + 'px'
- ink.style.left = (x - size / 2) + 'px'
- ink.style.top = (y - size / 2) + 'px'
- btn.appendChild(ink)
- setTimeout(() => ink.remove(), 600)
- }
- form.addEventListener('submit', (e) => {
- e.preventDefault()
- const account = document.getElementById('account').value.trim()
- if (!account || !pwd.value) {
- // 简单校验反馈
- btn.animate(
- [{ transform: 'translateX(0)' }, { transform: 'translateX(-6px)' }, { transform: 'translateX(6px)' }, { transform: 'translateX(0)' }],
- { duration: 240, iterations: 2 }
- )
- return
- }
- const rect = btn.getBoundingClientRect()
- // 点击位置水波(若来自键盘则居中)
- const x = (e.clientX || 0) ? e.clientX - rect.left : rect.width / 2
- const y = (e.clientY || 0) ? e.clientY - rect.top : rect.height / 2
- spawnInk(x, y)
- btn.disabled = true
- const raw = btn.textContent
- btn.textContent = '登录中…'
- // 模拟登录请求
- setTimeout(() => {
- btn.disabled = false
- btn.textContent = raw
- alert('登录成功,欢迎回来,' + account + '!')
- }, 900)
- })
- </script>
- </body>
- </html>
|