login.html 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <title>登录 · 门店检测工作台</title>
  7. <style>
  8. :root{
  9. --bg:#fbf7ef; --surface:#fff; --line:#ece0c8; --ink:#211a10; --ink-2:#5b4f3a;
  10. --ink-3:#93876f; --ink-4:#b9ad95; --gold:#eaba4e; --gold-deep:#a97b12;
  11. --gold-bg:#fdf6e4; --grad-gold:linear-gradient(180deg,#f3c95f,#e0a52e);
  12. }
  13. *{box-sizing:border-box;margin:0;padding:0}
  14. body{
  15. font-family:"PingFang SC","Microsoft YaHei",-apple-system,system-ui,sans-serif;
  16. color:var(--ink); min-height:100vh; display:flex; align-items:center; justify-content:center;
  17. padding:24px;
  18. background:
  19. radial-gradient(900px 400px at 15% -120px,rgba(234,185,78,.22),transparent 68%),
  20. radial-gradient(800px 360px at 85% -60px,rgba(234,185,78,.14),transparent 66%),
  21. radial-gradient(700px 500px at 50% 110%,rgba(234,185,78,.08),transparent 70%),
  22. var(--bg);
  23. }
  24. .card{width:100%;max-width:400px;background:var(--surface);border:1px solid var(--line);
  25. border-radius:18px;padding:34px 30px 28px;box-shadow:0 24px 60px rgba(150,110,20,.14)}
  26. .brand{display:flex;align-items:center;gap:10px;margin-bottom:26px}
  27. .logo{width:34px;height:34px;border-radius:10px;background:var(--grad-gold);
  28. display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;font-size:15px;
  29. box-shadow:0 4px 12px rgba(181,126,21,.28)}
  30. .brand h1{font-size:17px;font-weight:600;letter-spacing:-.2px}
  31. .brand p{font-size:11.5px;color:var(--ink-3);margin-top:2px}
  32. label{display:block;font-size:12.5px;color:var(--ink-3);margin-bottom:6px}
  33. input{width:100%;padding:11px 13px;font-size:14.5px;font-family:inherit;color:var(--ink);
  34. background:var(--surface);border:1px solid var(--line);border-radius:10px;outline:none;
  35. transition:border-color .15s,box-shadow .15s}
  36. input:focus{border-color:var(--gold);box-shadow:0 0 0 3px rgba(234,185,78,.16)}
  37. .field{margin-bottom:15px}
  38. button{width:100%;margin-top:8px;padding:12px;font-size:15px;font-family:inherit;font-weight:600;
  39. color:#fff;background:var(--grad-gold);border:1px solid #b57e15;border-radius:10px;cursor:pointer;
  40. box-shadow:0 3px 12px rgba(181,126,21,.28);transition:filter .15s}
  41. button:hover{filter:brightness(1.05)}
  42. button:disabled{opacity:.6;cursor:default}
  43. .err{margin-top:14px;padding:9px 12px;background:#fdf0ea;border:1px solid #f3d4c6;
  44. border-radius:9px;color:#a4462a;font-size:13px;display:none}
  45. .err.on{display:block}
  46. .hint{margin-top:18px;padding:11px 13px;background:var(--gold-bg);border:1px solid #f0dfb4;
  47. border-radius:10px;font-size:12.5px;line-height:1.7;color:var(--ink-2);display:none}
  48. .hint.on{display:block}
  49. .hint b{color:var(--gold-deep)}
  50. .foot{margin-top:22px;text-align:center;font-size:11.5px;color:var(--ink-4);line-height:1.8}
  51. </style>
  52. </head>
  53. <body>
  54. <div class="card">
  55. <div class="brand">
  56. <div class="logo">店</div>
  57. <div>
  58. <h1>门店检测工作台</h1>
  59. <p>怡呵美 · 水光会员店</p>
  60. </div>
  61. </div>
  62. <form id="f" autocomplete="on">
  63. <div class="field">
  64. <label for="u">账号</label>
  65. <input id="u" name="username" autocomplete="username" autocapitalize="off" spellcheck="false" autofocus>
  66. </div>
  67. <div class="field">
  68. <label for="p">密码</label>
  69. <input id="p" name="password" type="password" autocomplete="current-password">
  70. </div>
  71. <button id="btn" type="submit">登 录</button>
  72. <div class="err" id="err"></div>
  73. </form>
  74. <div class="hint" id="hint">
  75. 首次使用:账号 <b>admin</b>,初始密码 <b>admin123</b><br>
  76. 登录后会要求你立刻修改密码。
  77. </div>
  78. <div class="foot">账号由管理员统一分配<br>忘记密码请联系管理员重置</div>
  79. </div>
  80. <script>
  81. const $ = id => document.getElementById(id);
  82. const err = m => { $('err').textContent = m; $('err').classList.add('on'); };
  83. fetch('/api/auth/state').then(r => r.json()).then(s => {
  84. if (s.logged_in) location.replace('/');
  85. if (s.default_admin) $('hint').classList.add('on');
  86. if (s.needs_setup) $('hint').classList.add('on');
  87. }).catch(() => {});
  88. $('f').onsubmit = async e => {
  89. e.preventDefault();
  90. const username = $('u').value.trim(), password = $('p').value;
  91. if (!username || !password) return err('请输入账号和密码');
  92. $('btn').disabled = true; $('btn').textContent = '登录中…';
  93. $('err').classList.remove('on');
  94. try {
  95. const r = await fetch('/api/login', {
  96. method: 'POST', headers: {'Content-Type': 'application/json'},
  97. body: JSON.stringify({username, password}),
  98. });
  99. const d = await r.json();
  100. if (!r.ok) throw new Error(d.error || '登录失败');
  101. location.replace('/');
  102. } catch (e) {
  103. err(e.message);
  104. $('btn').disabled = false; $('btn').textContent = '登 录';
  105. $('p').select();
  106. }
  107. };
  108. </script>
  109. </body>
  110. </html>