Files
cmroubao/docs/design/android-login.html
T

77 lines
6.1 KiB
HTML

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>App 登录与设备绑定 - 低保真原型</title>
<style>
:root{color-scheme:light;--ink:#17212b;--muted:#5e6b76;--line:#cdd4da;--surface:#fff;--bg:#eef1f3;--primary:#176b52;--primary-dark:#0f5540;--danger:#a13a32;--focus:#c57414}
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 system-ui,-apple-system,"Segoe UI","Microsoft YaHei",sans-serif;letter-spacing:0;padding-top:38px}
.prototype{position:fixed;z-index:20;top:0;left:0;right:0;height:38px;display:grid;place-items:center;background:#2d343a;color:#fff;font-size:12px;font-weight:700}
.phone{width:min(100%,420px);min-height:calc(100vh - 38px);margin:auto;background:#f8f9fa;border-inline:1px solid var(--line)}
header{height:58px;display:flex;align-items:center;padding:0 20px;background:var(--surface);border-bottom:1px solid var(--line)}h1{font-size:20px;margin:0}
main{padding:24px 20px 32px}.eyebrow{margin:0 0 6px;color:var(--primary);font-size:13px;font-weight:700}.intro{margin:0 0 24px;color:var(--muted)}
form{display:grid;gap:18px}.field{display:grid;gap:7px}label{font-weight:650}.hint{color:var(--muted);font-size:13px}.input-wrap{display:flex}
input,select,button{font:inherit}input,select{width:100%;min-height:48px;padding:10px 12px;border:1px solid #8f9aa3;border-radius:6px;background:#fff;color:var(--ink)}
input:focus,select:focus,button:focus-visible,a:focus-visible{outline:3px solid color-mix(in srgb,var(--focus) 45%,transparent);outline-offset:2px}
.input-wrap input{border-radius:6px 0 0 6px}.icon-button{width:54px;min-height:48px;border:1px solid #8f9aa3;border-left:0;border-radius:0 6px 6px 0;background:#fff;font-weight:700}
.device{padding:14px;border-left:4px solid var(--primary);background:#e9f3ef}.device strong,.device span{display:block}.device span{margin-top:3px;color:var(--muted);font-size:13px}
.error{display:none;padding:12px;border:1px solid #d9a09a;background:#fff1ef;color:#76271f}.error.show{display:block}
.primary{min-height:50px;border:0;border-radius:6px;background:var(--primary);color:#fff;font-weight:750}.primary:hover{background:var(--primary-dark)}button:disabled{opacity:.58;cursor:not-allowed}
.privacy{margin:18px 0 0;color:var(--muted);font-size:12px}.status{min-height:24px;margin:0;color:var(--primary);font-weight:650}
@media(max-width:420px){.phone{border:0}main{padding-inline:18px}}
</style>
</head>
<body>
<div class="prototype">PROTOTYPE - 仅供确认布局和交互,不是生产实现</div>
<div class="phone">
<header><h1>采购执行</h1></header>
<main>
<p class="eyebrow">人员与设备身份</p>
<p class="intro">登录后将绑定当前测试设备,并检查采购所需能力。</p>
<form id="loginForm" novalidate>
<div class="field">
<label for="account">采购账号</label>
<input id="account" autocomplete="username" value="buyer.demo" required>
</div>
<div class="field">
<label for="password">密码</label>
<div class="input-wrap">
<input id="password" type="password" autocomplete="current-password" required>
<button class="icon-button" id="togglePassword" type="button" aria-label="显示密码">显示</button>
</div>
</div>
<div class="field">
<label for="device">设备身份</label>
<select id="device">
<option>测试设备 A · 后端已预授权</option>
</select>
<div class="device" aria-label="设备状态">
<strong>设备身份待验证</strong>
<span>未预授权或绑定冲突时请联系管理员,不在 App 内重新登记</span>
</div>
</div>
<div class="field">
<label for="scenario">原型提交结果</label>
<select id="scenario">
<option value="success">登录成功</option>
<option value="invalid">账号或密码不正确</option>
<option value="network">网络连接失败</option>
<option value="disabled">账号或设备已停用</option>
</select>
</div>
<div class="error" id="error" role="alert">请输入账号和密码。</div>
<button class="primary" id="submit" type="submit">登录并绑定设备</button>
<p class="status" id="status" role="status" aria-live="polite"></p>
</form>
<p class="privacy">登录凭据由 Android 安全存储处理。原型不保存任何输入。</p>
</main>
</div>
<script>
const form=document.querySelector("#loginForm"),password=document.querySelector("#password"),account=document.querySelector("#account"),error=document.querySelector("#error"),submit=document.querySelector("#submit"),status=document.querySelector("#status"),scenario=document.querySelector("#scenario");
document.querySelector("#togglePassword").addEventListener("click",e=>{const hidden=password.type==="password";password.type=hidden?"text":"password";e.currentTarget.textContent=hidden?"隐藏":"显示";e.currentTarget.setAttribute("aria-label",hidden?"隐藏密码":"显示密码")});
form.addEventListener("submit",e=>{e.preventDefault();error.classList.remove("show");if(!account.value.trim()||!password.value){error.textContent="请输入账号和密码。";error.classList.add("show");(!account.value.trim()?account:password).focus();return}submit.disabled=true;submit.textContent="正在登录";status.textContent="正在建立人员与设备身份…";setTimeout(()=>{if(scenario.value==="success"){status.textContent="身份已建立,即将进入任务主页。";submit.textContent="已登录";location.hash="success";return}password.value="";submit.disabled=false;submit.textContent="登录并绑定设备";status.textContent="";error.textContent=scenario.value==="invalid"?"账号或密码不正确。":scenario.value==="network"?"网络连接失败,账号已保留,请重试。":"账号或设备已停用,请联系管理员。";error.classList.add("show");password.focus()},650)});
</script>
</body>
</html>