diff --git a/docs/device-session-management-design.html b/docs/device-session-management-design.html index e0bba44..15ff059 100644 --- a/docs/device-session-management-design.html +++ b/docs/device-session-management-design.html @@ -43,6 +43,45 @@ .back{display:inline-block;margin-bottom:24px;font-size:13px} .lvl{font-weight:700} .phase{font-weight:700;color:var(--accent)} + /* —— UI 视觉稿:还原 app 暖色 token(浅色主题),嵌在暗色文档中作截图式预览 —— */ + .mock-wrap{display:flex;flex-wrap:wrap;gap:20px;margin:18px 0 6px} + .mock{--m-bg:#FAF8F4;--m-surface:#FFFFFF;--m-sub:#F2EEE7;--m-fg1:#1F1C18;--m-fg2:#6B6253;--m-fg3:#8C8270; + --m-accent:#B96A3D;--m-accentsub:#FAF3ED;--m-accentbd:#E6C7AC;--m-border:#E6DFD3;--m-ok:#5B8C5A;--m-danger:#C0533B; + background:var(--m-bg);border-radius:20px;padding:18px;width:344px;box-shadow:0 10px 34px rgba(0,0,0,.4);border:1px solid rgba(0,0,0,.15)} + .mock *{box-sizing:border-box} + .mock .cap{font-size:11px;font-weight:700;letter-spacing:.05em;color:#b0a491;margin:0 0 11px;text-transform:uppercase} + .mock .panel{background:var(--m-surface);border:1px solid var(--m-border);border-radius:14px;overflow:hidden} + .mock .row{display:flex;align-items:center;gap:12px;padding:13px 14px;border-bottom:1px solid var(--m-border)} + .mock .row:last-child{border-bottom:none} + .mock .ava{width:38px;height:38px;border-radius:10px;background:var(--m-accentsub);display:flex;align-items:center;justify-content:center;font-size:18px;flex:none} + .mock .meta{flex:1;min-width:0} + .mock .nm{display:flex;align-items:center;gap:7px;font-size:14.5px;font-weight:600;color:var(--m-fg1)} + .mock .badge{font-size:10px;font-weight:700;padding:1px 7px;border-radius:6px;background:var(--m-accentsub);color:var(--m-accent);border:1px solid var(--m-accentbd)} + .mock .sub2{font-size:12px;color:var(--m-fg3);margin-top:3px} + .mock .stat{display:flex;align-items:center;gap:5px;font-size:12px;font-weight:600;flex:none} + .mock .dot{width:7px;height:7px;border-radius:50%} + .mock .on{color:var(--m-ok)} .mock .on .dot{background:var(--m-ok);box-shadow:0 0 0 3px rgba(91,140,90,.18)} + .mock .off{color:#a89e8e} .mock .off .dot{background:#cfc6b8} + .mock .kebab{flex:none;width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;color:var(--m-fg3);font-size:17px} + .mock .kebab.act{background:var(--m-sub);color:var(--m-fg1)} + .mock .foot{font-size:12px;color:var(--m-fg3);margin-top:12px;padding-left:2px} + .mock .foot b{color:var(--m-accent);font-weight:700} + .mock .menu{background:var(--m-surface);border:1px solid var(--m-border);border-radius:13px;padding:6px;box-shadow:0 12px 30px rgba(0,0,0,.16);width:216px;margin-top:6px} + .mock .mi{display:flex;align-items:center;gap:11px;padding:10px 11px;border-radius:9px;font-size:13.5px;font-weight:500;color:var(--m-fg1)} + .mock .mi .ic{font-size:14px;width:17px;text-align:center} + .mock .mi.danger{color:var(--m-danger)} + .mock .mi.sel{background:var(--m-sub)} + .mock.dlg{display:flex;flex-direction:column;justify-content:center;background:linear-gradient(160deg,#efe7dc,#e6dccf)} + .mock .sheet{background:var(--m-surface);border-radius:18px;padding:22px 20px;text-align:center;box-shadow:0 18px 50px rgba(31,28,24,.22)} + .mock .warnico{width:48px;height:48px;border-radius:50%;background:rgba(192,83,59,.12);color:var(--m-danger);display:flex;align-items:center;justify-content:center;font-size:22px;margin:2px auto 13px} + .mock .dt{font-size:16px;font-weight:700;color:var(--m-fg1)} + .mock .dd{font-size:12.5px;color:var(--m-fg2);margin:9px 4px 18px;line-height:1.55} + .mock .dd b{color:var(--m-fg1)} + .mock .btns{display:flex;gap:10px} + .mock .btn{flex:1;padding:11px;border-radius:999px;font-size:13.5px;font-weight:600;text-align:center} + .mock .btn.ghost{background:var(--m-sub);color:var(--m-fg2)} + .mock .btn.danger{background:var(--m-danger);color:#fff} + .mock .pin{display:inline-block;font-size:10px;color:#b0a491;margin-left:6px}
@@ -287,19 +326,78 @@ usage_device_daily(user_id, device_id, date, bytes_up, bytes_down, minutes_used)沿用既有 DevicesScreen 卡片列表,行内信息扩展 + 行尾操作。颜色/字号/间距全走唯一真相源 token(pangolin_theme),不硬编码。
-┌─────────────────────────────────────────────────────────────┐ -│ [▦] MacBook Pro ● 在线 [ ⋯ ] │ ⋯ 菜单: -│ macOS · v1.0.10 · 本机 │ ├ 强制退出 -├─────────────────────────────────────────────────────────────┤ └ 清除登录信息 -│ [▦] iPhone 15 ○ 离线 [ ⋯ ] │ -│ iOS · v1.0.9 · 最后登录 2 小时前 │ -├─────────────────────────────────────────────────────────────┤ -│ [▦] Windows-PC ○ 离线 [ ⋯ ] │ -│ windows · v1.0.10 · 最后登录 3 天前 │ -└─────────────────────────────────────────────────────────────┘ - PRO 套餐最多 5 台设备同时在线 · 已用 3 / 5 -+
↑ 用项目真实 token 配色(clay/sand 暖色浅色主题)的还原稿。三态:A 列表(在线=绿点光晕 / 离线=灰点 + 最后登录;本机带「本机」标)→ B 行尾 ⋯ 弹出菜单(强制退出 / 清除登录信息·危险红)→ C 清除前危险二次确认。强制退出走相同弹窗、文案改为「踢下线、设备保留」。
Device 加 clientVersion / online(bool) / lastLogin(DateTime?)。_kDeviceId='mac-001',首启生成 UUID v4 存 flutter_secure_storage;登录/注册请求体带 device:{id,name,platform,client_version}。