Docker Build and Push / build-image (push) Successful in 4m14s
界面设计.html - 新增 2.12「V0.2.1 界面调整」章节: 头部统一 / 日历·打卡合并 / 模板分类 / 宏观 tab 溢出 - 已实现部分 (①③④) 与待确认草案 (②) 分别标注 - 2.9 宏观截图同步新 tab 顺序与右侧透支提示; 2.3 / 2.7 清单补「模板」分段 - 全部原型头部改用 23px 紧凑头部, 「我」页去掉头部条 设计文档.md - 新增 §11 界面调整: 变更清单、头部统一对照表、模板接口与排序口径、宏观 tab 顺序与溢出实现、 待确认的日历+打卡合并方案 (含确认后需改动的文件与样式段)
1705 lines
124 KiB
HTML
1705 lines
124 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>iBoard V0.2 界面设计 · 打卡 / 日历 / 清单</title>
|
||
<style>
|
||
:root{
|
||
--bg:#f0f2f5; --page:#ffffff; --card:#ffffff;
|
||
--text:#333333; --muted:#666666; --weak:#999999; --line:#eeeeee;
|
||
--primary:#1677ff; --success:#00b578; --warn:#ffc53d; --over:#a855f7;
|
||
--danger:#ff3141; --orange:#ff8f1f; --teal:#14b8a6; --pink:#f43f9e;
|
||
--nav-h:45px; --tab-h:72px;
|
||
}
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
body{
|
||
background:var(--bg); color:#1f2328; font-size:14px; line-height:1.6;
|
||
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Hiragino Sans GB','Microsoft YaHei',Roboto,sans-serif;
|
||
-webkit-font-smoothing:antialiased;
|
||
}
|
||
.wrap{max-width:1400px;margin:0 auto;padding:36px 24px 72px}
|
||
.doc-head{border-bottom:1px solid #e3e6ea;padding-bottom:20px;margin-bottom:28px}
|
||
.doc-head h1{font-size:26px;font-weight:700;letter-spacing:.5px}
|
||
.doc-head p{color:var(--muted);font-size:13px;margin-top:6px}
|
||
.meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}
|
||
.meta span{font-size:12px;background:#fff;border:1px solid #e3e6ea;border-radius:999px;padding:3px 12px;color:var(--muted)}
|
||
h2{font-size:19px;font-weight:700;margin:40px 0 6px;display:flex;align-items:center;gap:10px}
|
||
h2::before{content:"";width:4px;height:17px;background:var(--primary);border-radius:2px}
|
||
h2 .sub{font-size:12px;font-weight:400;color:var(--weak)}
|
||
h3{font-size:15px;font-weight:700;margin:22px 0 10px;color:#24292f}
|
||
p.desc{color:var(--muted);font-size:13px;margin-bottom:16px}
|
||
|
||
/* ---------- 设计规范 ---------- */
|
||
.tokens{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:18px}
|
||
.panel{background:#fff;border:1px solid #e6e8eb;border-radius:12px;padding:16px 18px}
|
||
.panel h4{font-size:13px;color:var(--muted);font-weight:600;margin-bottom:12px;letter-spacing:.4px}
|
||
.swatches{display:flex;flex-wrap:wrap;gap:10px}
|
||
.sw{width:88px;text-align:center}
|
||
.sw i{display:block;height:44px;border-radius:8px;border:1px solid rgba(0,0,0,.06)}
|
||
.sw b{display:block;font-size:11px;font-weight:600;margin-top:5px}
|
||
.sw em{display:block;font-size:10px;font-style:normal;color:var(--weak)}
|
||
.kv{display:grid;grid-template-columns:96px 1fr;gap:6px 12px;font-size:12px}
|
||
.kv span{color:var(--weak)}
|
||
.kv b{font-weight:600}
|
||
.type-row{display:flex;align-items:baseline;gap:12px;padding:6px 0;border-bottom:1px dashed var(--line);font-size:12px}
|
||
.type-row:last-child{border-bottom:none}
|
||
.type-row em{font-style:normal;color:var(--weak);width:132px;flex-shrink:0}
|
||
.type-row span{color:#444}
|
||
|
||
/* ---------- 手机 ---------- */
|
||
.stage{display:grid;grid-template-columns:repeat(auto-fit,minmax(420px,1fr));gap:30px 26px;justify-items:center}
|
||
.shot{width:420px}
|
||
.phone{
|
||
width:420px;height:820px;background:var(--page);position:relative;overflow:hidden;
|
||
border:1px solid #d8dde3;border-radius:22px;box-shadow:0 10px 24px rgba(15,23,42,.08);
|
||
display:flex;flex-direction:column;
|
||
}
|
||
.phone::after{content:"";position:absolute;top:8px;left:50%;transform:translateX(-50%);width:118px;height:20px;background:#111827;border-radius:12px;opacity:.9}
|
||
.navbar{height:var(--nav-h);margin-top:28px;flex-shrink:0;display:flex;align-items:center;justify-content:center;
|
||
font-size:17px;font-weight:600;border-bottom:1px solid var(--line);background:#fff}
|
||
.body{flex:1;min-height:0;overflow:hidden;background:var(--bg);padding:0 0 8px}
|
||
.tabbar{height:var(--tab-h);flex-shrink:0;background:#fff;border-top:1px solid var(--line);
|
||
display:flex;align-items:flex-start;padding-top:7px}
|
||
.tab{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;color:var(--weak);font-size:11px}
|
||
.tab.on{color:var(--primary)}
|
||
.tab svg{width:23px;height:23px}
|
||
.caption{margin-top:10px;background:#fff;border:1px solid #e6e8eb;border-radius:10px;padding:10px 14px}
|
||
.caption b{font-size:13px}
|
||
.caption p{font-size:12px;color:var(--muted);margin-top:3px}
|
||
.tag{display:inline-block;font-size:11px;color:var(--primary);background:#f0f5ff;border-radius:4px;padding:1px 6px;margin-left:6px}
|
||
|
||
/* ---------- 打卡视图 ---------- */
|
||
.habit-head{display:flex;justify-content:space-between;align-items:flex-end;padding:12px 14px 8px}
|
||
.habit-date{font-size:18px;font-weight:700}
|
||
.habit-summary{font-size:12px;color:var(--muted);margin-top:2px}
|
||
.habit-summary strong{color:var(--primary);font-size:14px}
|
||
.badge{font-size:11px;color:#ad6800;background:#fff7e6;border-radius:4px;padding:1px 5px;margin-left:6px}
|
||
.mini-btn{font-size:11px;border:1px solid var(--primary);color:var(--primary);border-radius:999px;padding:3px 10px;background:#fff}
|
||
.mini-btn.solid{background:var(--primary);color:#fff;border-color:var(--primary)}
|
||
.mini-btn.grey{border-color:#dcdcdc;color:var(--muted)}
|
||
.head-right{display:flex;gap:6px}
|
||
.habit-list{padding:0 12px;display:flex;flex-direction:column;gap:10px}
|
||
.habit-card{position:relative;background:#fff;border-radius:10px;padding:12px;box-shadow:0 1px 2px rgba(0,0,0,.04);
|
||
display:grid;grid-template-columns:auto 1fr auto;grid-template-areas:"ring main actions" "foot foot foot";gap:8px 12px}
|
||
.habit-card.done{background:#f7fbf8}
|
||
.ring{grid-area:ring;width:58px;height:58px;position:relative;display:flex;align-items:center;justify-content:center}
|
||
.ring svg{display:block}
|
||
.ring-center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:16px;font-weight:700}
|
||
.ring-center em{font-style:normal;font-size:10px;color:var(--muted);font-weight:400}
|
||
.ring-over{position:absolute;top:-4px;right:-10px;font-size:10px;color:#fff;background:var(--orange);border-radius:999px;padding:0 5px}
|
||
.habit-main{grid-area:main;min-width:0}
|
||
.habit-name{font-size:15px;font-weight:600}
|
||
.habit-meta{font-size:12px;color:var(--muted);margin-top:3px}
|
||
.streak{margin-left:8px;color:var(--orange);background:rgba(255,143,31,.12);border-radius:4px;padding:1px 6px}
|
||
.habit-range{font-size:11px;color:var(--muted);margin-top:3px}
|
||
.over-txt{margin-left:8px;color:var(--orange)}
|
||
.habit-actions{grid-area:actions;display:flex;align-items:center}
|
||
.habit-foot{grid-area:foot;display:flex;gap:14px;padding-top:8px;border-top:1px dashed var(--line)}
|
||
.link{font-size:12px;color:var(--primary)}
|
||
.link.danger{color:var(--danger)}
|
||
|
||
/* ---------- 日历视图 ---------- */
|
||
.cal-month-bar{display:flex;align-items:center;gap:10px;padding:12px 14px 6px}
|
||
.cal-month{font-size:16px;font-weight:700}
|
||
.cal-arrow{font-size:20px;color:var(--muted);padding:0 4px;line-height:1}
|
||
.cal-today{margin-left:auto;font-size:12px;color:var(--primary)}
|
||
.seg{display:flex;margin:4px 14px 10px;background:#f2f3f5;border-radius:8px;padding:3px}
|
||
.seg div{flex:1;text-align:center;font-size:13px;padding:5px 0;border-radius:6px;color:var(--muted)}
|
||
.seg div.on{background:#fff;color:var(--text);font-weight:600;box-shadow:0 1px 2px rgba(0,0,0,.06)}
|
||
.cal-grid{margin:0 12px;background:#fff;border-radius:10px;padding:8px 6px 10px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
|
||
.grid7{display:grid;grid-template-columns:repeat(7,1fr)}
|
||
.wd span{text-align:center;font-size:11px;color:var(--muted);padding:4px 0}
|
||
.day{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:5px 0;border-radius:8px}
|
||
.day .num{font-size:13px}
|
||
.day.out .num{color:#c8c8c8}
|
||
.day.future .num{color:#b0b0b0}
|
||
.day.today .num{color:var(--primary);font-weight:700}
|
||
.day.sel{background:var(--primary)}
|
||
.day.sel .num{color:#fff;font-weight:600}
|
||
.dot{width:5px;height:5px;border-radius:50%;margin-top:3px}
|
||
.dot.partial{background:var(--warn)} .dot.full{background:var(--success)} .dot.over{background:var(--over)}
|
||
.day.sel .dot{background:#fff}
|
||
.cal-rate{font-size:12px;color:var(--muted);padding:8px 14px}
|
||
.cal-rate strong{color:var(--primary)}
|
||
.cal-detail-title{font-size:14px;font-weight:600;padding:6px 14px 8px}
|
||
.cal-item{display:flex;align-items:center;gap:8px;background:#fff;border-radius:8px;padding:10px 12px;margin:0 12px 8px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
|
||
.cal-item.done{background:#f7fbf8}
|
||
.cdot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
||
.cname{font-size:14px;font-weight:600}
|
||
.cmeta{font-size:11px;color:var(--muted);flex:1;text-align:right}
|
||
.cplan{font-size:12px;color:var(--muted)}
|
||
|
||
/* ---------- 清单视图 ---------- */
|
||
.list-head{display:flex;align-items:center;gap:8px;padding:12px 14px 10px}
|
||
.list-head .seg{flex:1;margin:0}
|
||
.checklist-card{background:#fff;border-radius:10px;padding:12px;margin:0 12px 10px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
|
||
.checklist-card.done{background:#f7fbf8}
|
||
.cl-title-row{display:flex;align-items:center;gap:8px}
|
||
.cl-title{font-size:15px;font-weight:600}
|
||
.cl-scene{font-size:11px;color:var(--primary);background:#f0f5ff;border-radius:4px;padding:1px 6px}
|
||
.progress-row{display:flex;align-items:center;gap:8px;margin-top:8px}
|
||
.bar{flex:1;height:6px;border-radius:3px;background:#f0f0f0;overflow:hidden}
|
||
.bar i{display:block;height:100%;border-radius:3px;background:var(--success)}
|
||
.count{font-size:12px;color:var(--muted)}
|
||
.arrow{color:var(--muted);transform:rotate(90deg)}
|
||
.cl-body{margin-top:10px;padding-top:8px;border-top:1px dashed var(--line)}
|
||
.cl-item{display:flex;align-items:center;gap:8px;padding:7px 0}
|
||
.box{width:20px;height:20px;border-radius:50%;border:1.5px solid #d0d0d0;display:flex;align-items:center;justify-content:center;flex-shrink:0}
|
||
.cl-item.done .box{background:var(--success);border-color:var(--success)}
|
||
.box svg{opacity:0} .cl-item.done .box svg{opacity:1}
|
||
.cl-item-title{flex:1;font-size:14px}
|
||
.cl-item.done .cl-item-title{color:#a0a0a0;text-decoration:line-through}
|
||
.cl-del{color:#ccc;font-size:18px;line-height:1;padding:0 4px}
|
||
.cl-add{display:flex;gap:8px;margin-top:8px}
|
||
.cl-add .inp{flex:1;border:1px solid var(--line);border-radius:6px;padding:6px 8px;font-size:13px;color:var(--weak);background:#fff}
|
||
.cl-actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:10px}
|
||
|
||
/* ---------- 弹窗 ---------- */
|
||
.mask{position:absolute;inset:28px 0 0 0;background:rgba(0,0,0,.45);z-index:9}
|
||
.sheet{position:absolute;left:0;right:0;bottom:0;background:#fff;border-radius:12px 12px 0 0;padding:16px 16px 12px;z-index:10;max-height:560px;overflow:hidden}
|
||
.sheet-title{font-size:16px;font-weight:700;margin-bottom:12px}
|
||
.field{margin-bottom:13px}
|
||
.field label{display:block;font-size:12px;color:var(--muted);margin-bottom:6px}
|
||
.inp{border:1px solid var(--line);border-radius:8px;padding:8px 10px;font-size:14px;background:#fff;color:var(--text)}
|
||
.inp.ph{color:#b8bcc4}
|
||
.chips{display:flex;gap:8px}
|
||
.chip{flex:1;text-align:center;font-size:13px;padding:6px 0;border-radius:8px;background:#f5f6f8;color:var(--muted)}
|
||
.chip.on{background:var(--primary);color:#fff;font-weight:600}
|
||
.stepper{display:inline-flex;align-items:center;gap:10px}
|
||
.stepper span{width:28px;height:28px;border-radius:6px;background:#f5f6f8;display:flex;align-items:center;justify-content:center;color:var(--muted)}
|
||
.stepper span.act{background:var(--primary);color:#fff}
|
||
.stepper b{font-size:16px;min-width:24px;text-align:center}
|
||
.colors{display:flex;gap:10px;flex-wrap:wrap}
|
||
.cd{width:26px;height:26px;border-radius:50%;border:2px solid transparent}
|
||
.cd.on{border-color:rgba(0,0,0,.25);transform:scale(1.12)}
|
||
.btn-primary{display:block;text-align:center;background:var(--primary);color:#fff;border-radius:8px;padding:10px 0;font-size:15px;font-weight:600;margin-top:18px}
|
||
.btn-ghost{display:block;text-align:center;border:1px solid var(--line);border-radius:8px;padding:9px 0;font-size:15px;color:var(--muted);margin-top:8px;background:#fff}
|
||
|
||
/* ---------- 特效 ---------- */
|
||
.fx{position:absolute;inset:0;pointer-events:none}
|
||
.fx .halo{position:absolute;left:50%;top:50%;width:88px;height:88px;margin:-44px 0 0 -44px;border-radius:50%;border:2px solid var(--success);opacity:.55}
|
||
.fx .halo2{width:108px;height:108px;margin:-54px 0 0 -54px;opacity:.25}
|
||
.fx i{position:absolute;left:50%;top:50%;width:6px;height:6px;border-radius:50%;}
|
||
|
||
/* ---------- 空态 ---------- */
|
||
.empty{text-align:center;padding:70px 20px;color:var(--weak)}
|
||
.empty .ico{width:64px;height:64px;margin:0 auto 12px;border-radius:50%;background:#f2f3f5;display:flex;align-items:center;justify-content:center;color:#c4c8ce;font-size:30px}
|
||
.empty p{font-size:13px;margin-bottom:12px}
|
||
|
||
/* ---------- 统一主 Tab 头部(V0.2.1 调整:高度减半,标题主色小字) ---------- */
|
||
.navbar-sm{height:23px;margin-top:28px;flex-shrink:0;display:flex;align-items:center;justify-content:center;
|
||
font-size:12px;font-weight:600;letter-spacing:1px;color:var(--primary);background:var(--bg)}
|
||
/* 「我」页:不设头部,头像区直接顶到状态栏下方 */
|
||
.me-head.flush{padding-top:24px}
|
||
|
||
/* ---------- 打卡 · 日历与打卡合并视图(V0.2.1 草案) ---------- */
|
||
.mv-cal{background:#fff;border-radius:10px;margin:8px 12px 0;padding:6px 6px 8px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
|
||
.mv-month{display:flex;align-items:center;gap:8px;padding:2px 4px 6px}
|
||
.mv-month b{font-size:14px}
|
||
.mv-month .arrow{font-size:17px;color:var(--muted);line-height:1;padding:0 3px}
|
||
.mv-month .today{margin-left:auto;font-size:11px;color:var(--primary)}
|
||
.mv-grid{display:grid;grid-template-columns:repeat(7,1fr)}
|
||
.mv-wd span{text-align:center;font-size:10px;color:var(--muted);padding:1px 0 3px;display:block}
|
||
.mv-day{height:31px;margin:1px 0;display:flex;flex-direction:column;align-items:center;justify-content:center;
|
||
border-radius:6px;font-size:12px;line-height:1.15;color:var(--text)}
|
||
.mv-day.out{color:#c8c8c8}
|
||
.mv-day.future{color:#b0b0b0}
|
||
.mv-day.today{color:var(--primary);font-weight:700}
|
||
.mv-day.sel{background:var(--primary);color:#fff;font-weight:600}
|
||
.mv-day i{width:4px;height:4px;border-radius:50%;margin-top:2px}
|
||
.mv-day i.partial{background:var(--warn)} .mv-day i.full{background:var(--success)} .mv-day i.over{background:var(--over)}
|
||
.mv-day.sel i{background:#fff}
|
||
.mv-rate{display:flex;justify-content:space-between;align-items:center;font-size:11px;color:var(--muted);padding:7px 6px 0}
|
||
.mv-rate b{color:var(--primary)}
|
||
.mv-daybar{display:flex;align-items:center;gap:8px;padding:10px 14px 2px;font-size:13px;font-weight:600}
|
||
.mv-daybar .badge{font-weight:400}
|
||
.mv-daybar .sum{margin-left:auto;font-size:11px;color:var(--muted);font-weight:400}
|
||
.mv-groups{padding-bottom:12px}
|
||
.mv-ghead{display:flex;align-items:center;gap:6px;padding:9px 14px 5px;font-size:11px;font-weight:600;color:var(--muted)}
|
||
.mv-ghead::before{content:"";width:3px;height:11px;border-radius:2px;background:var(--primary)}
|
||
.mv-ghead .cnt{margin-left:auto;font-weight:400;color:var(--weak)}
|
||
.mv-card{position:relative;display:flex;align-items:center;gap:9px;background:#fff;border-radius:9px;
|
||
padding:8px 10px;margin:0 12px 7px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
|
||
.mv-card.done{background:#f7fbf8}
|
||
.mv-ring{width:42px;height:42px;position:relative;display:flex;align-items:center;justify-content:center;flex-shrink:0}
|
||
.mv-ring svg{display:block}
|
||
.mv-ring .c{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700}
|
||
.mv-ring .c em{font-style:normal;font-size:9px;color:var(--muted);font-weight:400}
|
||
.mv-ring .ov{position:absolute;top:-3px;right:-5px;font-size:9px;color:#fff;background:var(--orange);border-radius:999px;padding:0 4px}
|
||
.mv-main{flex:1;min-width:0}
|
||
.mv-name{font-size:14px;font-weight:600;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.mv-meta{font-size:10px;color:var(--muted);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.mv-meta .st{color:var(--orange);background:rgba(255,143,31,.12);border-radius:3px;padding:0 4px;margin-left:5px}
|
||
.mv-btn{font-size:11px;border-radius:999px;padding:4px 12px;background:var(--primary);color:#fff;flex-shrink:0;white-space:nowrap}
|
||
.mv-btn.grey{background:#f2f3f5;color:var(--muted)}
|
||
.mv-more{color:#c0c4cc;font-size:15px;line-height:1;padding:4px 2px 4px 6px;flex-shrink:0}
|
||
/* 操作面板(⋯ 触发) */
|
||
.mv-sheet .sheet-title{font-size:15px;margin-bottom:8px}
|
||
.mv-sheet-row{display:flex;align-items:center;justify-content:space-between;padding:12px 4px;border-top:1px solid var(--line);font-size:14px}
|
||
.mv-sheet-row.danger{color:var(--danger)}
|
||
.mv-sheet-row .k{font-size:11px;color:var(--weak)}
|
||
|
||
/* ---------- 清单 · 模板分类(V0.2.1 草案) ---------- */
|
||
.tpl-card{background:#fff;border-radius:10px;padding:11px 12px;margin:0 12px 10px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
|
||
.tpl-row{display:flex;align-items:center;gap:7px}
|
||
.tpl-name{font-size:14px;font-weight:600}
|
||
.tpl-badge{font-size:10px;color:var(--muted);background:#f2f3f5;border-radius:4px;padding:1px 5px}
|
||
.tpl-num{margin-left:auto;font-size:11px;color:var(--muted)}
|
||
.tpl-chips{display:flex;flex-wrap:wrap;gap:5px;margin-top:7px}
|
||
.tpl-chip{font-size:10px;color:var(--muted);background:#f7f8fa;border-radius:4px;padding:2px 6px}
|
||
.tpl-chip.more{color:var(--primary);background:#f0f5ff}
|
||
.tpl-acts{display:flex;gap:14px;margin-top:9px;padding-top:7px;border-top:1px dashed var(--line)}
|
||
/* 新建清单(无场景,模板从右侧滑出选择) */
|
||
.pick-row{display:flex;align-items:center;gap:8px;border:1px solid var(--line);border-radius:8px;padding:8px 10px;font-size:14px;color:var(--weak)}
|
||
.pick-row .meta{margin-left:auto;display:flex;align-items:center;gap:4px;font-size:11px;color:var(--muted)}
|
||
.side-panel{position:absolute;top:28px;right:0;bottom:0;width:78%;background:#fff;z-index:11;
|
||
box-shadow:-6px 0 18px rgba(15,23,42,.12);display:flex;flex-direction:column;padding:14px 0 0}
|
||
.side-head{display:flex;align-items:center;padding:0 16px 4px}
|
||
.side-head b{font-size:16px}
|
||
.side-head .x{margin-left:auto;font-size:20px;color:#c8c8c8;line-height:1}
|
||
.side-tip{font-size:11px;color:var(--muted);padding:0 16px 8px}
|
||
.side-item{display:flex;align-items:baseline;gap:8px;padding:11px 16px}
|
||
.side-item.on{background:#f0f5ff}
|
||
.side-item .nm{flex:1;font-size:14px;font-weight:600;display:flex;align-items:center;gap:6px}
|
||
.side-item.on .nm{color:var(--primary)}
|
||
.side-item .sub{font-size:11px;color:var(--muted)}
|
||
|
||
/* ---------- 宏观 · tab 溢出提示(V0.2.1 草案) ---------- */
|
||
.mtabs-wrap{position:relative;background:#fff;border-bottom:1px solid var(--line)}
|
||
.mtabs-wrap .mtabs{border-bottom:none}
|
||
.mtabs-fade{position:absolute;top:0;right:0;bottom:0;width:52px;display:flex;align-items:center;justify-content:flex-end;
|
||
padding-right:8px;background:linear-gradient(to right,rgba(255,255,255,0),#fff 55%,#fff)}
|
||
.mtabs-fade .hint{width:19px;height:19px;border-radius:50%;background:#fff;border:1px solid #e3e6ea;
|
||
display:flex;align-items:center;justify-content:center;color:var(--primary);font-size:13px;font-weight:700;
|
||
box-shadow:0 1px 4px rgba(0,0,0,.14)}
|
||
|
||
/* ---------- 表格 ---------- */ table{width:100%;border-collapse:collapse;background:#fff;border:1px solid #e6e8eb;border-radius:10px;overflow:hidden;font-size:13px}
|
||
th,td{border-bottom:1px solid var(--line);padding:9px 12px;text-align:left;vertical-align:middle}
|
||
th{background:#fafbfc;font-weight:600;color:#444;white-space:nowrap}
|
||
tr:last-child td{border-bottom:none}
|
||
td code{background:#f4f6f8;border-radius:4px;padding:1px 5px;font-size:12px}
|
||
.legend{display:flex;flex-wrap:wrap;gap:18px;font-size:12px;color:var(--muted);margin:10px 0 0}
|
||
.legend span{display:flex;align-items:center;gap:6px}
|
||
.note{font-size:12px;color:var(--weak);margin-top:8px}
|
||
.flow{background:#fff;border:1px solid #e6e8eb;border-radius:12px;padding:16px 18px;font-size:13px;color:#333;white-space:pre;overflow-x:auto;line-height:1.7}
|
||
|
||
/* ---------- 宏观子 Tab(6 项,可横向滚动) ---------- */
|
||
.mtabs{display:flex;gap:18px;padding:10px 14px 8px;overflow-x:auto;background:#fff;border-bottom:1px solid var(--line);font-size:13px;color:var(--muted);white-space:nowrap}
|
||
.mtabs::-webkit-scrollbar{display:none}
|
||
.mtabs .on{color:var(--primary);font-weight:600;position:relative}
|
||
.mtabs .on::after{content:"";position:absolute;left:50%;transform:translateX(-50%);bottom:-9px;width:22px;height:3px;border-radius:2px;background:var(--primary)}
|
||
.mtabs .badge-dot{display:inline-block;min-width:15px;height:15px;line-height:15px;padding:0 4px;margin-left:3px;
|
||
background:var(--danger);color:#fff;font-size:10px;border-radius:8px;text-align:center;vertical-align:1px}
|
||
|
||
/* ---------- 资讯卡片(报警 / 新闻) ---------- */
|
||
.feed{padding:10px 14px 14px;display:flex;flex-direction:column;gap:8px}
|
||
.feed-card{background:#fff;border:1px solid #eef0f2;border-radius:10px;padding:10px 12px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
|
||
.feed-title{font-size:14px;font-weight:600;line-height:1.45;color:var(--text)}
|
||
.feed-sub{font-size:12px;color:var(--muted);margin-top:4px;line-height:1.5}
|
||
.feed-meta{display:flex;gap:10px;font-size:11px;color:var(--weak);margin-top:6px}
|
||
.feed-meta .rk{color:var(--primary)}
|
||
.alert-name{color:var(--danger);font-weight:600}
|
||
|
||
/* ---------- 我的页 ---------- */
|
||
.me-head{display:flex;flex-direction:column;align-items:center;gap:4px;padding:18px 0 16px;background:#fff}
|
||
.me-avatar{width:60px;height:60px;border-radius:50%;background:#e8effd;color:var(--primary);
|
||
display:flex;align-items:center;justify-content:center;font-size:22px;font-weight:600}
|
||
.me-name{font-size:16px;font-weight:600}
|
||
.me-mail{font-size:12px;color:var(--weak)}
|
||
.me-group{margin:10px 12px 0;background:#fff;border-radius:10px;overflow:hidden;border:1px solid #eef0f2}
|
||
.me-group .g-head{font-size:12px;color:var(--weak);padding:9px 14px 6px}
|
||
.me-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:11px 14px;border-top:1px solid var(--line);font-size:14px}
|
||
.me-group .g-head + .me-row{border-top:none}
|
||
.me-row .val{font-size:12px;color:var(--weak)}
|
||
.me-row .hint{font-size:11px;color:var(--weak);margin-top:2px;line-height:1.45}
|
||
.sw{width:42px;height:25px;border-radius:999px;background:#e5e7eb;position:relative;flex-shrink:0;transition:background .2s}
|
||
.sw::after{content:"";position:absolute;top:2px;left:2px;width:21px;height:21px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.2)}
|
||
.sw.on{background:var(--success)}
|
||
.sw.on::after{left:19px}
|
||
.me-actions{display:flex;gap:8px;padding:12px 14px;border-top:1px solid var(--line)}
|
||
.me-actions .mini-btn{flex:1;text-align:center;padding:7px 0;font-size:13px}
|
||
.me-actions .mini-btn.ghost{border-color:#e5e7eb;color:var(--muted)}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
|
||
<div class="doc-head">
|
||
<h1>iBoard V0.2 · 界面设计</h1>
|
||
<p>打卡 / 日历 / 清单 —— 移动端静态高保真原型(设计基线 420 × 820,适配 375~430px)</p>
|
||
<div class="meta">
|
||
<span>版本 V0.2(0.2.0)</span><span>分支 dev-0.2</span><span>antd-mobile 风格</span>
|
||
<span>底部 4 Tab(打卡默认)</span><span>时区 Asia/Shanghai</span><span>文档日期 2026-10-22 · 修订 2026-10-23</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ 1 设计规范 ============ -->
|
||
<h2>1 设计规范<span class="sub">Design Tokens</span></h2>
|
||
<p class="desc">沿用项目既有 <code>:root</code> 变量(<code>src/styles/globals.css</code>),本模块不引入新主题。</p>
|
||
<div class="tokens">
|
||
<div class="panel">
|
||
<h4>语义色</h4>
|
||
<div class="swatches">
|
||
<div class="sw"><i style="background:#1677ff"></i><b>#1677ff</b><em>主色 / 今日 / 链接</em></div>
|
||
<div class="sw"><i style="background:#00b578"></i><b>#00b578</b><em>完成 / 进度条</em></div>
|
||
<div class="sw"><i style="background:#ffc53d"></i><b>#ffc53d</b><em>部分完成 / 粒子</em></div>
|
||
<div class="sw"><i style="background:#a855f7"></i><b>#a855f7</b><em>超额完成</em></div>
|
||
<div class="sw"><i style="background:#ff8f1f"></i><b>#ff8f1f</b><em>连续天数 / 超额徽标</em></div>
|
||
<div class="sw"><i style="background:#ff3141"></i><b>#ff3141</b><em>危险操作</em></div>
|
||
<div class="sw"><i style="background:#f5f5f5"></i><b>#f5f5f5</b><em>页面底色</em></div>
|
||
<div class="sw"><i style="background:#f7fbf8"></i><b>#f7fbf8</b><em>已完成卡片底</em></div>
|
||
</div>
|
||
<div class="legend" style="margin-top:14px">
|
||
<span><i class="dot full"></i>日历·全部完成</span>
|
||
<span><i class="dot partial"></i>日历·部分完成</span>
|
||
<span><i class="dot over"></i>日历·超额</span>
|
||
</div>
|
||
</div>
|
||
<div class="panel">
|
||
<h4>布局与圆角</h4>
|
||
<div class="kv">
|
||
<span>视口</span><b>420 × 820(375~430 自适应)</b>
|
||
<span>NavBar 高</span><b>45px</b>
|
||
<span>TabBar 高</span><b>72px(含安全区)</b>
|
||
<span>页面内边距</span><b>左右 12px</b>
|
||
<span>卡片圆角</span><b>10px</b>
|
||
<span>卡片间距</span><b>10px 纵向</b>
|
||
<span>卡片阴影</span><b>0 1px 2px rgba(0,0,0,.04)</b>
|
||
<span>环形尺寸</span><b>58 × 58,环宽 6px</b>
|
||
<span>最小点按区</span><b>≥ 40 × 40</b>
|
||
</div>
|
||
</div>
|
||
<div class="panel">
|
||
<h4>字号层级</h4>
|
||
<div class="type-row"><em>18 / 700</em><span style="font-size:18px;font-weight:700">日期标题「10月22日」</span></div>
|
||
<div class="type-row"><em>17 / 600</em><span style="font-size:17px;font-weight:600">NavBar 标题「打卡」</span></div>
|
||
<div class="type-row"><em>16 / 700</em><span style="font-size:16px;font-weight:700">环形中心数字 / 弹窗标题</span></div>
|
||
<div class="type-row"><em>15 / 600</em><span style="font-size:15px;font-weight:600">打卡项名 / 清单标题</span></div>
|
||
<div class="type-row"><em>13 / 400</em><span style="font-size:13px">正文 / 日历日期数字</span></div>
|
||
<div class="type-row"><em>12 / 400</em><span style="font-size:12px;color:#666">次要信息 / 操作链接</span></div>
|
||
<div class="type-row"><em>11 / 400</em><span style="font-size:11px;color:#999">备注 / 周期范围 / 徽标</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ 2 主界面 ============ -->
|
||
<h2>2 主界面<span class="sub">三个子视图(V0.2 现状;合并方案见 2.12 ②)</span></h2>
|
||
|
||
<div class="stage">
|
||
|
||
<!-- ---------- 2.1 打卡视图 ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="habit-head">
|
||
<div>
|
||
<div class="habit-date">10月22日 周四</div>
|
||
<div class="habit-summary">已完成 <strong>2</strong> / 4</div>
|
||
</div>
|
||
<div class="head-right">
|
||
<div class="mini-btn solid">+ 新建</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="habit-list">
|
||
<!-- 未完成:每天 2 次,0/2 -->
|
||
<div class="habit-card">
|
||
<div class="ring">
|
||
<svg width="58" height="58" viewBox="0 0 58 58">
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ececf0" stroke-width="6"/>
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#1677ff" stroke-width="6" stroke-linecap="round"
|
||
stroke-dasharray="163.4" stroke-dashoffset="163.4" transform="rotate(-90 29 29)"/>
|
||
</svg>
|
||
<div class="ring-center">0<em>/2</em></div>
|
||
</div>
|
||
<div class="habit-main">
|
||
<div class="habit-name">喝水</div>
|
||
<div class="habit-meta">每天 2 次<span class="streak">连续 12</span></div>
|
||
<div class="habit-range">今日</div>
|
||
</div>
|
||
<div class="habit-actions"><div class="mini-btn solid">打卡</div></div>
|
||
<div class="habit-foot"><span class="link">编辑</span><span class="link danger">归档</span></div>
|
||
</div>
|
||
|
||
<!-- 未完成:每周 3 次,1/3 = 33.3% -->
|
||
<div class="habit-card">
|
||
<div class="ring">
|
||
<svg width="58" height="58" viewBox="0 0 58 58">
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ececf0" stroke-width="6"/>
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ff8f1f" stroke-width="6" stroke-linecap="round"
|
||
stroke-dasharray="163.4" stroke-dashoffset="108.9" transform="rotate(-90 29 29)"/>
|
||
</svg>
|
||
<div class="ring-center">1<em>/3</em></div>
|
||
</div>
|
||
<div class="habit-main">
|
||
<div class="habit-name">健身</div>
|
||
<div class="habit-meta">每周 3 次<span class="streak">连续 5</span></div>
|
||
<div class="habit-range">10-19 ~ 10-25</div>
|
||
</div>
|
||
<div class="habit-actions"><div class="mini-btn solid">打卡</div></div>
|
||
<div class="habit-foot"><span class="link">撤销</span><span class="link">编辑</span><span class="link danger">归档</span></div>
|
||
</div>
|
||
|
||
<!-- 已完成:每月 12 次,12/12 闭合 -->
|
||
<div class="habit-card done">
|
||
<div class="ring">
|
||
<svg width="58" height="58" viewBox="0 0 58 58">
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ececf0" stroke-width="6"/>
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#00b578" stroke-width="6" stroke-linecap="round"
|
||
stroke-dasharray="163.4" stroke-dashoffset="0" transform="rotate(-90 29 29)"/>
|
||
</svg>
|
||
<div class="ring-center">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||
<path d="M4 12.5l5 5L20 6.5" stroke="#00b578" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
<div class="habit-main">
|
||
<div class="habit-name">读书</div>
|
||
<div class="habit-meta">每月 12 次<span class="streak">连续 3</span></div>
|
||
<div class="habit-range">10-01 ~ 10-31</div>
|
||
</div>
|
||
<div class="habit-actions"><div class="mini-btn grey">再打一次</div></div>
|
||
<div class="habit-foot"><span class="link">撤销</span><span class="link">编辑</span><span class="link danger">归档</span></div>
|
||
</div>
|
||
|
||
<!-- 已完成 + 超额:每天 1 次,打了 2 次 -->
|
||
<div class="habit-card done">
|
||
<div class="ring">
|
||
<svg width="58" height="58" viewBox="0 0 58 58">
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ececf0" stroke-width="6"/>
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#a855f7" stroke-width="6" stroke-linecap="round"
|
||
stroke-dasharray="163.4" stroke-dashoffset="0" transform="rotate(-90 29 29)"/>
|
||
</svg>
|
||
<div class="ring-center">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||
<path d="M4 12.5l5 5L20 6.5" stroke="#a855f7" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||
</svg>
|
||
</div>
|
||
<span class="ring-over">+1</span>
|
||
</div>
|
||
<div class="habit-main">
|
||
<div class="habit-name">吃药</div>
|
||
<div class="habit-meta">每天 1 次<span class="streak">连续 30</span></div>
|
||
<div class="habit-range">今日<span class="over-txt">超额 1</span></div>
|
||
</div>
|
||
<div class="habit-actions"><div class="mini-btn grey">再打一次</div></div>
|
||
<div class="habit-foot"><span class="link">撤销</span><span class="link">编辑</span><span class="link danger">归档</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.1 打卡视图 · 今天<span class="tag">默认进入</span></b>
|
||
<p>头部日期 + 完成数;未完成卡片排在前面。环形中心未达标显示 <code>done/target</code>,达标显示对勾(每天 1 次打完即刻闭合);超额在右上角显示 <code>+n</code>。点环或「打卡」按钮均可打卡,卡片底部提供撤销 / 编辑 / 归档。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.2 日历视图 ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px">
|
||
<div>打卡</div><div class="on">日历</div><div>清单</div>
|
||
</div>
|
||
<div class="cal-month-bar">
|
||
<span class="cal-arrow">‹</span><span class="cal-month">2026年10月</span><span class="cal-arrow">›</span>
|
||
<span class="cal-today">回到今天</span>
|
||
</div>
|
||
<div class="seg">
|
||
<div>昨天</div><div class="on">今天</div><div>明天</div>
|
||
</div>
|
||
|
||
<div class="cal-grid">
|
||
<div class="grid7 wd"><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span><span>日</span></div>
|
||
<div class="grid7">
|
||
<div class="day out"><span class="num">28</span></div>
|
||
<div class="day out"><span class="num">29</span></div>
|
||
<div class="day out"><span class="num">30</span></div>
|
||
<div class="day"><span class="num">1</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">2</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">3</span><i class="dot partial"></i></div>
|
||
<div class="day"><span class="num">4</span><i class="dot full"></i></div>
|
||
|
||
<div class="day"><span class="num">5</span></div>
|
||
<div class="day"><span class="num">6</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">7</span><i class="dot over"></i></div>
|
||
<div class="day"><span class="num">8</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">9</span><i class="dot partial"></i></div>
|
||
<div class="day"><span class="num">10</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">11</span><i class="dot full"></i></div>
|
||
|
||
<div class="day"><span class="num">12</span></div>
|
||
<div class="day"><span class="num">13</span></div>
|
||
<div class="day"><span class="num">14</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">15</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">16</span><i class="dot partial"></i></div>
|
||
<div class="day"><span class="num">17</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">18</span><i class="dot full"></i></div>
|
||
|
||
<div class="day"><span class="num">19</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">20</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">21</span><i class="dot full"></i></div>
|
||
<div class="day today sel"><span class="num">22</span><i class="dot partial"></i></div>
|
||
<div class="day future"><span class="num">23</span></div>
|
||
<div class="day future"><span class="num">24</span></div>
|
||
<div class="day future"><span class="num">25</span></div>
|
||
|
||
<div class="day future"><span class="num">26</span></div>
|
||
<div class="day future"><span class="num">27</span></div>
|
||
<div class="day future"><span class="num">28</span></div>
|
||
<div class="day future"><span class="num">29</span></div>
|
||
<div class="day future"><span class="num">30</span></div>
|
||
<div class="day future"><span class="num">31</span></div>
|
||
<div class="day out"><span class="num">1</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cal-rate">本月完成率 <strong>82%</strong></div>
|
||
<div class="cal-detail-title">今天 · 2026-10-22</div>
|
||
|
||
<div class="cal-item done">
|
||
<i class="cdot" style="background:#1677ff"></i><span class="cname">喝水</span>
|
||
<span class="cmeta">每天 2 次 · 当日 2/2</span>
|
||
<span class="mini-btn grey">已达标</span>
|
||
</div>
|
||
<div class="cal-item">
|
||
<i class="cdot" style="background:#ff8f1f"></i><span class="cname">健身</span>
|
||
<span class="cmeta">每周 3 次 · 当日 0/1</span>
|
||
<span class="mini-btn solid">打卡</span>
|
||
</div>
|
||
<div class="cal-item done">
|
||
<i class="cdot" style="background:#00b578"></i><span class="cname">读书</span>
|
||
<span class="cmeta">每月 12 次 · 当日 1/1</span>
|
||
<span class="mini-btn grey">已达标</span>
|
||
</div>
|
||
<div class="cal-item done">
|
||
<i class="cdot" style="background:#a855f7"></i><span class="cname">吃药</span>
|
||
<span class="cmeta">每天 1 次 · 当日 2/1</span>
|
||
<span class="mini-btn grey">已达标</span>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.2 日历视图 · 今天选中</b>
|
||
<p>周一起始月历 + 「昨天 / 今天 / 明天」快捷分段;日期下方状态点:绿=全部完成、黄=部分完成、紫=超额、无点=未完成或未来。今天用主色数字并选中高亮,未来日期数字弱化。下方为该日明细,可直接打卡;底部展示本月完成率。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.3 清单视图 ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px">
|
||
<div>打卡</div><div>日历</div><div class="on">清单</div>
|
||
</div>
|
||
<div class="list-head">
|
||
<div class="seg"><div class="on">进行中</div><div>已归档</div><div>模板</div></div>
|
||
<div class="mini-btn solid">+ 新建</div>
|
||
</div>
|
||
|
||
<div class="checklist-card">
|
||
<div class="cl-title-row"><span class="cl-title">出差 · 杭州</span><span class="cl-scene">出差</span></div>
|
||
<div class="progress-row">
|
||
<div class="bar"><i style="width:66.7%"></i></div><span class="count">8/12</span><span class="arrow">›</span>
|
||
</div>
|
||
<div class="cl-body">
|
||
<div class="cl-item done"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">身份证 / 证件</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item done"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">手机充电器 + 充电宝</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item done"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">笔记本电脑 + 电源</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item done"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">耳机</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item done"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">换洗衣物</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item done"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">洗漱包</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item done"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">常用药</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item done"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">车票 / 机票 / 酒店确认</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">雨伞</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">工牌 / 名片</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">报销单据</span><span class="cl-del">×</span></div>
|
||
<div class="cl-item"><span class="box"><svg viewBox="0 0 24 24" width="14" height="14" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span class="cl-item-title">现金零钱</span><span class="cl-del">×</span></div>
|
||
|
||
<div class="cl-add"><div class="inp ph">添加检查项</div><div class="mini-btn solid">添加</div></div>
|
||
<div class="cl-actions">
|
||
<span class="link">全选</span><span class="link">全不选</span><span class="link">复制</span>
|
||
<span class="link">存为模板</span><span class="link">归档</span><span class="link danger">删除</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="checklist-card">
|
||
<div class="cl-title-row"><span class="cl-title">回老家 · 国庆</span><span class="cl-scene">回老家</span></div>
|
||
<div class="progress-row">
|
||
<div class="bar"><i style="width:0%"></i></div><span class="count">0/12</span><span class="arrow" style="transform:none">›</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.3 清单视图 · 展开态</b>
|
||
<p>卡片头部常显标题、场景标签、进度条与 <code>8/12</code>;点击展开逐条勾选(勾选后绿色圆底、文字加删除线并弱化)。底部可继续添加检查项,并提供全选 / 全不选 / 复制 / 存为模板 / 归档 / 删除。收起态只保留头部一行。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.4 新建打卡项弹窗 ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="habit-head">
|
||
<div>
|
||
<div class="habit-date">10月22日 周四</div>
|
||
<div class="habit-summary">已完成 <strong>2</strong> / 4</div>
|
||
</div>
|
||
<div class="head-right"><div class="mini-btn solid">+ 新建</div></div>
|
||
</div>
|
||
<div class="habit-list">
|
||
<div class="habit-card">
|
||
<div class="ring">
|
||
<svg width="58" height="58" viewBox="0 0 58 58">
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ececf0" stroke-width="6"/>
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#1677ff" stroke-width="6" stroke-linecap="round" stroke-dasharray="163.4" stroke-dashoffset="163.4" transform="rotate(-90 29 29)"/>
|
||
</svg><div class="ring-center">0<em>/2</em></div>
|
||
</div>
|
||
<div class="habit-main"><div class="habit-name">喝水</div><div class="habit-meta">每天 2 次</div><div class="habit-range">今日</div></div>
|
||
<div class="habit-actions"><div class="mini-btn solid">打卡</div></div>
|
||
<div class="habit-foot"><span class="link">编辑</span><span class="link danger">归档</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="mask"></div>
|
||
<div class="sheet">
|
||
<div class="sheet-title">新建打卡项</div>
|
||
<div class="field"><label>名称</label><div class="inp ph">例如:喝水 / 健身 / 读书</div></div>
|
||
<div class="field"><label>周期</label>
|
||
<div class="chips"><div class="chip on">每天</div><div class="chip">每周</div><div class="chip">每月</div><div class="chip">每年</div></div>
|
||
</div>
|
||
<div class="field"><label>目标次数(周期内)</label>
|
||
<div class="stepper"><span>−</span><b>1</b><span class="act">+</span></div>
|
||
</div>
|
||
<div class="field"><label>颜色</label>
|
||
<div class="colors">
|
||
<span class="cd on" style="background:#1677ff"></span><span class="cd" style="background:#00b578"></span>
|
||
<span class="cd" style="background:#ff8f1f"></span><span class="cd" style="background:#ff3141"></span>
|
||
<span class="cd" style="background:#a855f7"></span><span class="cd" style="background:#14b8a6"></span>
|
||
<span class="cd" style="background:#f43f9e"></span>
|
||
</div>
|
||
</div>
|
||
<div class="field"><label>备注(可选)</label><div class="inp ph">补充说明</div></div>
|
||
<div class="btn-primary">保存</div>
|
||
<div class="btn-ghost">取消</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.4 新建 / 编辑打卡项(底部弹层)</b>
|
||
<p>名称 ≤20 字;周期四选一(每天 / 每周 / 每月 / 每年);目标次数用 Stepper,最小 1;颜色 7 色预设;备注可选。编辑态标题变为「编辑打卡项」并回填当前值。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.5 完成特效 ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="habit-head">
|
||
<div><div class="habit-date">10月22日 周四</div><div class="habit-summary">已完成 <strong>3</strong> / 4</div></div>
|
||
<div class="head-right"><div class="mini-btn solid">+ 新建</div></div>
|
||
</div>
|
||
<div class="habit-list">
|
||
<div class="habit-card done" style="overflow:visible">
|
||
<div class="ring">
|
||
<!-- 特效层:光环 + 14 颗粒子(静态呈现 t=250ms 时的形态) -->
|
||
<div class="fx">
|
||
<div class="halo"></div><div class="halo halo2"></div>
|
||
<i style="background:#ffc53d;transform:translate(-50%,-50%) rotate(0deg) translateY(-34px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(26deg) translateY(-40px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(52deg) translateY(-34px)"></i>
|
||
<i style="background:#ffc53d;transform:translate(-50%,-50%) rotate(78deg) translateY(-46px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(104deg) translateY(-34px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(130deg) translateY(-40px)"></i>
|
||
<i style="background:#ffc53d;transform:translate(-50%,-50%) rotate(156deg) translateY(-34px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(182deg) translateY(-46px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(208deg) translateY(-34px)"></i>
|
||
<i style="background:#ffc53d;transform:translate(-50%,-50%) rotate(234deg) translateY(-40px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(260deg) translateY(-34px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(286deg) translateY(-46px)"></i>
|
||
<i style="background:#ffc53d;transform:translate(-50%,-50%) rotate(312deg) translateY(-34px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(338deg) translateY(-40px)"></i>
|
||
</div>
|
||
<svg width="58" height="58" viewBox="0 0 58 58">
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ececf0" stroke-width="6"/>
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#00b578" stroke-width="6" stroke-linecap="round" stroke-dasharray="163.4" stroke-dashoffset="0" transform="rotate(-90 29 29)"/>
|
||
</svg>
|
||
<div class="ring-center">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#00b578" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||
</div>
|
||
</div>
|
||
<div class="habit-main"><div class="habit-name">吃药</div><div class="habit-meta">每天 1 次<span class="streak">连续 30</span></div><div class="habit-range">今日</div></div>
|
||
<div class="habit-actions"><div class="mini-btn grey">再打一次</div></div>
|
||
<div class="habit-foot"><span class="link">撤销</span><span class="link">编辑</span><span class="link danger">归档</span></div>
|
||
</div>
|
||
<div class="habit-card">
|
||
<div class="ring">
|
||
<svg width="58" height="58" viewBox="0 0 58 58">
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ececf0" stroke-width="6"/>
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ff8f1f" stroke-width="6" stroke-linecap="round" stroke-dasharray="163.4" stroke-dashoffset="108.9" transform="rotate(-90 29 29)"/>
|
||
</svg><div class="ring-center">1<em>/3</em></div>
|
||
</div>
|
||
<div class="habit-main"><div class="habit-name">健身</div><div class="habit-meta">每周 3 次</div><div class="habit-range">10-19 ~ 10-25</div></div>
|
||
<div class="habit-actions"><div class="mini-btn solid">打卡</div></div>
|
||
<div class="habit-foot"><span class="link">撤销</span><span class="link">编辑</span><span class="link danger">归档</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.5 达标瞬间 · 完成特效</b>
|
||
<p>环形闭合 + 对勾缩放入场(0.32s);同时 14 颗粒子沿圆周扩散(26~58px,交替主色与金色)+ 主色光环脉冲(0.7s),总时长 ≤900ms,<code>pointer-events:none</code> 不阻塞后续操作;并触发 18ms 轻震动。<b>特效恒开</b>(V0.2 设计变更:头部不再有开关)。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.6 日历·明天(计划) ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px"><div>打卡</div><div class="on">日历</div><div>清单</div></div>
|
||
<div class="cal-month-bar"><span class="cal-arrow">‹</span><span class="cal-month">2026年10月</span><span class="cal-arrow">›</span><span class="cal-today">回到今天</span></div>
|
||
<div class="seg"><div>昨天</div><div>今天</div><div class="on">明天</div></div>
|
||
<div class="cal-grid">
|
||
<div class="grid7 wd"><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span><span>日</span></div>
|
||
<div class="grid7">
|
||
<div class="day out"><span class="num">28</span></div><div class="day out"><span class="num">29</span></div><div class="day out"><span class="num">30</span></div>
|
||
<div class="day"><span class="num">1</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">2</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">3</span><i class="dot partial"></i></div>
|
||
<div class="day"><span class="num">4</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">5</span></div>
|
||
<div class="day"><span class="num">6</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">7</span><i class="dot over"></i></div>
|
||
<div class="day"><span class="num">8</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">9</span><i class="dot partial"></i></div>
|
||
<div class="day"><span class="num">10</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">11</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">12</span></div><div class="day"><span class="num">13</span></div>
|
||
<div class="day"><span class="num">14</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">15</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">16</span><i class="dot partial"></i></div>
|
||
<div class="day"><span class="num">17</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">18</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">19</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">20</span><i class="dot full"></i></div>
|
||
<div class="day today"><span class="num">21</span><i class="dot full"></i></div>
|
||
<div class="day"><span class="num">22</span><i class="dot partial"></i></div>
|
||
<div class="day future sel"><span class="num">23</span></div>
|
||
<div class="day future"><span class="num">24</span></div>
|
||
<div class="day future"><span class="num">25</span></div>
|
||
<div class="day future"><span class="num">26</span></div><div class="day future"><span class="num">27</span></div>
|
||
<div class="day future"><span class="num">28</span></div><div class="day future"><span class="num">29</span></div>
|
||
<div class="day future"><span class="num">30</span></div><div class="day future"><span class="num">31</span></div>
|
||
<div class="day out"><span class="num">1</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="cal-rate">本月完成率 <strong>82%</strong></div>
|
||
<div class="cal-detail-title">明天 · 2026-10-23<span class="badge">计划(不可打卡)</span></div>
|
||
<div class="cal-item"><i class="cdot" style="background:#1677ff"></i><span class="cname">喝水</span><span class="cmeta">每天 2 次 · 当日 0/2</span><span class="cplan">待办</span></div>
|
||
<div class="cal-item"><i class="cdot" style="background:#ff8f1f"></i><span class="cname">健身</span><span class="cmeta">每周 3 次 · 当日 0/1</span><span class="cplan">待办</span></div>
|
||
<div class="cal-item"><i class="cdot" style="background:#00b578"></i><span class="cname">读书</span><span class="cmeta">每月 12 次 · 当日 0/1</span><span class="cplan">待办</span></div>
|
||
<div class="cal-item"><i class="cdot" style="background:#a855f7"></i><span class="cname">吃药</span><span class="cmeta">每天 1 次 · 当日 0/1</span><span class="cplan">待办</span></div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.6 日历 · 明天(计划,只读)</b>
|
||
<p>未来日期不允许打卡:标题右侧显示「计划(不可打卡)」徽标,条目右侧只显示「待办」文案而不渲染按钮,月历上未来日期数字弱化且不打点。昨天视图则相反——可补打最近 7 天内的漏打卡。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.7 清单完成 + 空态 ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px"><div>打卡</div><div>日历</div><div class="on">清单</div></div>
|
||
<div class="list-head">
|
||
<div class="seg"><div class="on">进行中</div><div>已归档</div><div>模板</div></div>
|
||
<div class="mini-btn solid">+ 新建</div>
|
||
</div>
|
||
<div class="checklist-card done" style="position:relative;overflow:visible">
|
||
<div class="cl-title-row"><span class="cl-title">出差 · 杭州</span><span class="cl-scene">出差</span></div>
|
||
<div class="progress-row"><div class="bar"><i style="width:100%"></i></div><span class="count">12/12</span><span class="arrow">›</span></div>
|
||
<div class="fx" style="left:50%;top:34px;right:auto;bottom:auto;width:0;height:0">
|
||
<div class="halo" style="border-color:#00b578"></div>
|
||
<i style="background:#ffc53d;transform:translate(-50%,-50%) rotate(10deg) translateY(-46px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(46deg) translateY(-56px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(92deg) translateY(-46px)"></i>
|
||
<i style="background:#ffc53d;transform:translate(-50%,-50%) rotate(140deg) translateY(-62px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(190deg) translateY(-46px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(240deg) translateY(-56px)"></i>
|
||
<i style="background:#ffc53d;transform:translate(-50%,-50%) rotate(300deg) translateY(-46px)"></i>
|
||
<i style="background:#00b578;transform:translate(-50%,-50%) rotate(340deg) translateY(-62px)"></i>
|
||
</div>
|
||
</div>
|
||
<div class="checklist-card">
|
||
<div class="cl-title-row"><span class="cl-title">回老家 · 国庆</span><span class="cl-scene">回老家</span></div>
|
||
<div class="progress-row"><div class="bar"><i style="width:0%"></i></div><span class="count">0/12</span><span class="arrow" style="transform:none">›</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.7 清单全部完成(12/12)</b>
|
||
<p>进度条 100%、计数变为 <code>12/12</code>、卡片底色转 <code>#f7fbf8</code>,并播放与打卡一致的完成特效。清单完成后用户通常选择「归档」或「复制」复用。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.8 空态与归档 ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="habit-head">
|
||
<div><div class="habit-date">10月22日 周四</div><div class="habit-summary">已完成 <strong>0</strong> / 0</div></div>
|
||
<div class="head-right"><div class="mini-btn solid">+ 新建</div></div>
|
||
</div>
|
||
<div class="empty">
|
||
<div class="ico">○</div>
|
||
<p>还没有打卡项</p>
|
||
<div style="display:inline-block" class="mini-btn solid">创建第一个打卡项</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.8 空态</b>
|
||
<p>三个视图均具备加载中 / 空态 / 错误(带重试)三态。空态给出明确引导按钮。<b>V0.2 设计变更</b>:打卡页头部不再有「特效开 / 特效关」开关,完成特效与触感反馈<b>恒开</b>,没有任何关闭入口。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.9 宏观(原首页报警/新闻并入) ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">宏观</div>
|
||
<div class="body">
|
||
<div class="mtabs-wrap">
|
||
<div class="mtabs">
|
||
<div>报警<span class="badge-dot">3</span></div><div class="on">新闻</div>
|
||
<div>油价</div><div>经济数据</div><div>策略研究</div><div>经济文章</div>
|
||
</div>
|
||
<div class="mtabs-fade"><span class="hint">›</span></div>
|
||
</div>
|
||
<div class="feed">
|
||
<div class="feed-card">
|
||
<div class="feed-title">央行开展 5000 亿元 MLF 操作,中标利率持平</div>
|
||
<div class="feed-sub">本月 MLF 净投放 2000 亿元,市场流动性保持合理充裕…</div>
|
||
<div class="feed-meta"><span>妙想财经</span><span>2026-10-22</span><span class="rk">#1</span></div>
|
||
</div>
|
||
<div class="feed-card">
|
||
<div class="feed-title">9 月社零同比增长 3.2%,服务消费延续回暖</div>
|
||
<div class="feed-sub">餐饮收入增速回升至 5.1%,可选消费分化明显…</div>
|
||
<div class="feed-meta"><span>妙想财经</span><span>2026-10-21</span><span class="rk">#2</span></div>
|
||
</div>
|
||
<div class="feed-card">
|
||
<div class="feed-title">美联储会议纪要偏鹰,美元指数小幅走强</div>
|
||
<div class="feed-sub">点阵图显示年内或仍有一次降息空间,但分歧加大…</div>
|
||
<div class="feed-meta"><span>妙想财经</span><span>2026-10-21</span><span class="rk">#3</span></div>
|
||
</div>
|
||
<div class="feed-card">
|
||
<div class="feed-title">OPEC+ 维持减产节奏,国际油价日内涨逾 1%</div>
|
||
<div class="feed-sub">布伦特原油重回 78 美元上方,化工链成本端承压…</div>
|
||
<div class="feed-meta"><span>妙想财经</span><span>2026-10-20</span><span class="rk">#4</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.9 宏观 · 原「首页」报警/新闻并入<span class="tag">设计变更</span></b>
|
||
<p>「首页」Tab 取消,报警与新闻并入宏观。<b>2026-10-23 调整</b>:两者移到<b>最左</b>(报警 → 新闻 → 油价 → 经济数据 → 策略研究 → 经济文章),<b>默认选中「新闻」</b>;共 6 个子 Tab 可横向滚动,当前项底部有 3px 主色指示条;报警数量以红色角标挂在子 Tab 上。tab 条右侧增加<b>渐变遮罩 + 箭头</b>,提示还有未展示的 tab(详见 2.12 ④)。新闻详情为 <code>/macro/news/:id</code>,底部「宏观」保持高亮。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.10 我的 · OTA(开发版本 关 = 默认) ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="body">
|
||
<div class="me-head flush">
|
||
<div class="me-avatar">C</div>
|
||
<div class="me-name">Cheney</div>
|
||
<div class="me-mail">qian.huang@sunyard.com</div>
|
||
</div>
|
||
<div class="me-group">
|
||
<div class="g-head">前端升级 (OTA)</div>
|
||
<div class="me-row"><span>当前版本</span><span class="val">v0.2.0 · 20261022.1530</span></div>
|
||
<div class="me-row"><span>运行资源</span><span class="val">内置</span></div>
|
||
<div class="me-row">
|
||
<div>
|
||
<div>开发版本</div>
|
||
<div class="hint">按版本号判新:仅当服务端版本号更高时才提示更新</div>
|
||
</div>
|
||
<div class="sw"></div>
|
||
</div>
|
||
<div class="me-actions">
|
||
<div class="mini-btn solid">检查更新</div>
|
||
<div class="mini-btn ghost">立即升级</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.10 我的 · OTA「开发版本」关闭(默认)<span class="tag">新功能</span></b>
|
||
<p>开关默认关闭 = <b>按版本号判新</b>:取服务端 <code>latest.json</code> 的 <code>version</code>(如 <code>0.2.0-ota</code>),与当前运行版本按数字字段逐段比较,<b>更高</b>才提示更新。用于生产,避免旧分支被重建(sequence 变大但版本更小)把设备拉回旧版。开关值保存在设备端 <code>localStorage.iboard_ota_dev_mode</code>。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ---------- 2.11 我的 · OTA(开发版本 开) ---------- -->
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="body">
|
||
<div class="me-head flush">
|
||
<div class="me-avatar">C</div>
|
||
<div class="me-name">Cheney</div>
|
||
<div class="me-mail">qian.huang@sunyard.com</div>
|
||
</div>
|
||
<div class="me-group">
|
||
<div class="g-head">前端升级 (OTA)</div>
|
||
<div class="me-row"><span>当前版本</span><span class="val">v0.2.0 · 20261022.1530</span></div>
|
||
<div class="me-row"><span>运行资源</span><span class="val">内置</span></div>
|
||
<div class="me-row">
|
||
<div>
|
||
<div>开发版本</div>
|
||
<div class="hint">按 build sequence 判新:每次构建都算新版本,便于开发联调</div>
|
||
</div>
|
||
<div class="sw on"></div>
|
||
</div>
|
||
<div class="me-row"><span>新版本</span><span class="val">v0.2.0-ota (288 KB)</span></div>
|
||
<div class="me-actions">
|
||
<div class="mini-btn solid">立即升级</div>
|
||
<div class="mini-btn ghost">回滚</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab on">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>2.11 我的 · OTA「开发版本」打开</b>
|
||
<p>开关打开 = <b>按 build sequence 判新</b>:走 hotswap 插件的 <code>checkUpdate()</code>,只要服务端 <code>sequence</code> 比本地大就算新版本——每次 CI 构建 sequence 都会变(默认取时间戳),所以任何一次提交都能推到设备上,适合开发联调。切换开关会清空上一次的检查结果,避免上一种口径的结论误导。</p>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ============ 2.12 V0.2.1 界面调整草案 ============ -->
|
||
<h2>2.12 V0.2.1 界面调整<span class="sub">头部统一 / 日历·打卡合并 / 模板分类 / 宏观 tab 溢出</span></h2>
|
||
<p class="desc">本节为 2026-10-23 提出的调整方案。其中 <b>①头部统一 / ③模板分类 / ④宏观 tab 溢出</b> 已按本节实现;
|
||
<b>②日历与打卡合并</b> 为待确认草案,<b>确认后再改代码</b>。</p>
|
||
|
||
<h3>① 四个主 Tab 头部统一</h3>
|
||
<table>
|
||
<tr><th>页</th><th>调整前</th><th>调整后</th></tr>
|
||
<tr><td>打卡</td><td>NavBar 45px,标题「打卡」17px 深色</td><td><b>23px</b>,标题「打卡」12px 主色加粗,字距 1px</td></tr>
|
||
<tr><td>宏观</td><td>NavBar 45px,<b>无标题</b>(空白)</td><td>23px + 标题「宏观」(同打卡规格)</td></tr>
|
||
<tr><td>监控</td><td>NavBar 45px,<b>无标题</b>(空白)</td><td>23px + 标题「监控」(同打卡规格)</td></tr>
|
||
<tr><td>我</td><td>NavBar 45px 空白条</td><td><b>整条去掉</b>,蓝色头像区直接顶到状态栏下方</td></tr>
|
||
</table>
|
||
<p class="note">实现为独立组件 <code>PageHeader</code>,只被打卡 / 宏观 / 监控 引用;「我」页不引用,因此三者互不影响。
|
||
头部背景取页面底色 <code>#f5f5f5</code>(不再是卡片白),视觉上更轻。</p>
|
||
|
||
<div class="stage">
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="habit-head">
|
||
<div><div class="habit-date">10月23日 周五</div><div class="habit-summary">已完成 <strong>2</strong> / 10</div></div>
|
||
<div class="head-right"><div class="mini-btn solid">+ 新建</div></div>
|
||
</div>
|
||
<div class="habit-list">
|
||
<div class="habit-card">
|
||
<div class="ring">
|
||
<svg width="58" height="58" viewBox="0 0 58 58">
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ececf0" stroke-width="6"/>
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#1677ff" stroke-width="6" stroke-linecap="round" stroke-dasharray="163.4" stroke-dashoffset="81.7" transform="rotate(-90 29 29)"/>
|
||
</svg><div class="ring-center">1<em>/2</em></div>
|
||
</div>
|
||
<div class="habit-main"><div class="habit-name">喝水</div><div class="habit-meta">每天 2 次<span class="streak">连续 12</span></div><div class="habit-range">今日</div></div>
|
||
<div class="habit-actions"><div class="mini-btn solid">打卡</div></div>
|
||
<div class="habit-foot"><span class="link">撤销</span><span class="link">编辑</span><span class="link danger">归档</span></div>
|
||
</div>
|
||
<div class="habit-card">
|
||
<div class="ring">
|
||
<svg width="58" height="58" viewBox="0 0 58 58">
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ececf0" stroke-width="6"/>
|
||
<circle cx="29" cy="29" r="26" fill="none" stroke="#ff8f1f" stroke-width="6" stroke-linecap="round" stroke-dasharray="163.4" stroke-dashoffset="163.4" transform="rotate(-90 29 29)"/>
|
||
</svg><div class="ring-center">0<em>/1</em></div>
|
||
</div>
|
||
<div class="habit-main"><div class="habit-name">俯卧撑</div><div class="habit-meta">每周 1 次</div><div class="habit-range">10-19 ~ 10-25</div></div>
|
||
<div class="habit-actions"><div class="mini-btn solid">打卡</div></div>
|
||
<div class="habit-foot"><span class="link">编辑</span><span class="link danger">归档</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>①-a 打卡(头部已缩至 23px)<span class="tag">已实现</span></b>
|
||
<p>原 45px 白色 NavBar 换成 23px 底色条 + 主色标题,页面上移,首屏多出一张卡片的高度。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">宏观</div>
|
||
<div class="body">
|
||
<div class="mtabs-wrap">
|
||
<div class="mtabs">
|
||
<div>报警<span class="badge-dot">1</span></div><div class="on">新闻</div><div>油价</div>
|
||
<div>经济数据</div><div>策略研究</div><div>经济文章</div>
|
||
</div>
|
||
<div class="mtabs-fade"><span class="hint">›</span></div>
|
||
</div>
|
||
<div class="feed">
|
||
<div class="feed-card">
|
||
<div class="feed-title">央行开展 5000 亿元 MLF 操作,中标利率持平</div>
|
||
<div class="feed-sub">本月 MLF 净投放 2000 亿元,市场流动性保持合理充裕…</div>
|
||
<div class="feed-meta"><span>妙想财经</span><span>2026-10-22</span><span class="rk">#1</span></div>
|
||
</div>
|
||
<div class="feed-card">
|
||
<div class="feed-title">9 月社零同比增长 3.2%,服务消费延续回暖</div>
|
||
<div class="feed-sub">餐饮收入增速回升至 5.1%,可选消费分化明显…</div>
|
||
<div class="feed-meta"><span>妙想财经</span><span>2026-10-21</span><span class="rk">#2</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>①-b + ④ 宏观:头部标题化 · 报警/新闻置最左 · 右侧溢出提示<span class="tag">已实现</span></b>
|
||
<p><b>顺序</b>:报警 → 新闻 → 油价 → 经济数据 → 策略研究 → 经济文章,<b>默认选中「新闻」</b>(<code>/macro</code> 自动跳 <code>/macro/news</code>)。<br>
|
||
<b>溢出提示</b>:tab 条仍可向右滚动时,右边缘出现白色渐变遮罩 + 主色圆底箭头「›」(1.5s 轻微左右摆动,可点击向右翻页),滚到末尾自动消失;切换 tab 时自动把激活项滚到可视区中间。<br>
|
||
antd-mobile Tabs 自带的右侧渐变遮罩只有 30px 且无箭头,用户难以察觉,故叠加此提示层。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>② 打卡:日历 + 打卡合并(<span style="color:var(--danger)">待确认草案</span>)</h3>
|
||
<p class="desc">把原来的「打卡」「日历」两个 tab 合成一个:<b>上半部日历,下半部打卡卡片</b>。取舍按下述规则:</p>
|
||
<table>
|
||
<tr><th>项</th><th>规则</th></tr>
|
||
<tr><td>页面结构</td><td>SwipeTabs 从 3 个减为 <b>2 个</b>:<b>日历(含打卡)</b> / <b>清单</b></td></tr>
|
||
<tr><td>上方日历</td><td>保留月历网格 + 月份左右切换 + 「回到今天」;<b>去掉</b>「昨天 / 今天 / 明天」分段控件(点日期即可,节省 38px 高度)</td></tr>
|
||
<tr><td>日历高度</td><td>日期格子 38px → <b>31px</b>,去掉 6 行补位中的空行;整块约 240px</td></tr>
|
||
<tr><td>下方打卡</td><td>沿用现有打卡卡片样式,但<b>紧凑化</b>:内边距 12px → 8px,环形 58px → <b>42px</b>(环宽 6 → 5),行高压缩,卡片间距 10 → 7px</td></tr>
|
||
<tr><td>卡片内容</td><td>保留环形进度(含达标对勾 / 超额 +n)、名称、周期与目标、连续天数、打卡按钮;<b>撤销 / 编辑 / 归档收进「⋯」</b>,减少一行高度</td></tr>
|
||
<tr><td>分组</td><td>按周期类型分组:<b>每天 → 每周 → 每月</b>,每组一个小标题(左侧主色竖条 + 组名 + 条数);<b>去掉「每年」分组</b>(已有年目标项并入「每月」区末尾的「其他周期」小标题,或建议直接隐藏年视图)</td></tr>
|
||
<tr><td>联动</td><td>点日历某日 → 下方卡片即该日数据(进度仍按该日所属周期算);未来日期只读,按钮变灰显示「计划」</td></tr>
|
||
<tr><td>空态</td><td>日历下方直接显示「该日没有打卡项」+「+ 新建」引导</td></tr>
|
||
</table>
|
||
|
||
<div class="stage">
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px">
|
||
<div class="on">日历</div><div>清单</div>
|
||
</div>
|
||
|
||
<div class="mv-cal">
|
||
<div class="mv-month">
|
||
<span class="arrow">‹</span><b>2026年10月</b><span class="arrow">›</span>
|
||
<span class="today">回到今天</span>
|
||
</div>
|
||
<div class="mv-grid mv-wd"><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span><span>日</span></div>
|
||
<div class="mv-grid">
|
||
<div class="mv-day out">29</div><div class="mv-day out">30</div>
|
||
<div class="mv-day">1<i class="full"></i></div><div class="mv-day">2<i class="full"></i></div>
|
||
<div class="mv-day">3<i class="partial"></i></div><div class="mv-day">4<i class="full"></i></div><div class="mv-day">5</div>
|
||
<div class="mv-day">6<i class="full"></i></div><div class="mv-day">7<i class="over"></i></div>
|
||
<div class="mv-day">8<i class="full"></i></div><div class="mv-day">9<i class="partial"></i></div>
|
||
<div class="mv-day">10<i class="full"></i></div><div class="mv-day">11<i class="full"></i></div><div class="mv-day">12</div>
|
||
<div class="mv-day">13</div><div class="mv-day">14<i class="full"></i></div><div class="mv-day">15<i class="full"></i></div>
|
||
<div class="mv-day">16<i class="partial"></i></div><div class="mv-day">17<i class="full"></i></div><div class="mv-day">18<i class="full"></i></div><div class="mv-day">19<i class="full"></i></div>
|
||
<div class="mv-day">20<i class="full"></i></div><div class="mv-day">21<i class="full"></i></div>
|
||
<div class="mv-day today sel">22<i class="partial"></i></div><div class="mv-day future">23</div><div class="mv-day future">24</div><div class="mv-day future">25</div>
|
||
<div class="mv-day future">26</div><div class="mv-day future">27</div><div class="mv-day future">28</div>
|
||
<div class="mv-day future">29</div><div class="mv-day future">30</div><div class="mv-day future">31</div><div class="mv-day out">1</div>
|
||
</div>
|
||
<div class="mv-rate"><span>本月完成率 <b>82%</b></span><span>今天 · 2026-10-22</span></div>
|
||
</div>
|
||
|
||
<div class="mv-daybar">今天<span class="badge">已完成 2 / 4</span><span class="sum">点环即打卡</span></div>
|
||
|
||
<div class="mv-groups">
|
||
<div class="mv-ghead">每天<span class="cnt">2 项</span></div>
|
||
|
||
<div class="mv-card">
|
||
<div class="mv-ring">
|
||
<svg width="42" height="42" viewBox="0 0 42 42">
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ececf0" stroke-width="5"/>
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#1677ff" stroke-width="5" stroke-linecap="round" stroke-dasharray="116.2" stroke-dashoffset="58.1" transform="rotate(-90 21 21)"/>
|
||
</svg>
|
||
<div class="c">1<em>/2</em></div>
|
||
</div>
|
||
<div class="mv-main">
|
||
<div class="mv-name">喝水</div>
|
||
<div class="mv-meta">每天 2 次 · 今日 1/2<span class="st">连续 12</span></div>
|
||
</div>
|
||
<div class="mv-btn">打卡</div>
|
||
<div class="mv-more">⋯</div>
|
||
</div>
|
||
|
||
<div class="mv-card done">
|
||
<div class="mv-ring">
|
||
<svg width="42" height="42" viewBox="0 0 42 42">
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ececf0" stroke-width="5"/>
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#a855f7" stroke-width="5" stroke-linecap="round" stroke-dasharray="116.2" stroke-dashoffset="0" transform="rotate(-90 21 21)"/>
|
||
</svg>
|
||
<div class="c"><svg width="15" height="15" viewBox="0 0 24 24" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#a855f7" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||
<span class="ov">+1</span>
|
||
</div>
|
||
<div class="mv-main">
|
||
<div class="mv-name">吃药</div>
|
||
<div class="mv-meta">每天 1 次 · 今日 2/1<span class="st">连续 30</span></div>
|
||
</div>
|
||
<div class="mv-btn grey">再打一次</div>
|
||
<div class="mv-more">⋯</div>
|
||
</div>
|
||
|
||
<div class="mv-ghead">每周<span class="cnt">1 项</span></div>
|
||
<div class="mv-card">
|
||
<div class="mv-ring">
|
||
<svg width="42" height="42" viewBox="0 0 42 42">
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ececf0" stroke-width="5"/>
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ff8f1f" stroke-width="5" stroke-linecap="round" stroke-dasharray="116.2" stroke-dashoffset="77.5" transform="rotate(-90 21 21)"/>
|
||
</svg>
|
||
<div class="c">1<em>/3</em></div>
|
||
</div>
|
||
<div class="mv-main">
|
||
<div class="mv-name">健身</div>
|
||
<div class="mv-meta">每周 3 次 · 本周 1/3<span class="st">连续 5</span></div>
|
||
</div>
|
||
<div class="mv-btn">打卡</div>
|
||
<div class="mv-more">⋯</div>
|
||
</div>
|
||
|
||
<div class="mv-ghead">每月<span class="cnt">1 项</span></div>
|
||
<div class="mv-card">
|
||
<div class="mv-ring">
|
||
<svg width="42" height="42" viewBox="0 0 42 42">
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ececf0" stroke-width="5"/>
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#00b578" stroke-width="5" stroke-linecap="round" stroke-dasharray="116.2" stroke-dashoffset="116.2" transform="rotate(-90 21 21)"/>
|
||
</svg>
|
||
<div class="c">0<em>/12</em></div>
|
||
</div>
|
||
<div class="mv-main">
|
||
<div class="mv-name">读书</div>
|
||
<div class="mv-meta">每月 12 次 · 本月 0/12</div>
|
||
</div>
|
||
<div class="mv-btn">打卡</div>
|
||
<div class="mv-more">⋯</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>②-a 合并后的主视图(日历在上 · 打卡在下,按天 / 周 / 月分组)<span class="tag" style="background:#fff1f0;color:#ff3141">待确认</span></b>
|
||
<p>卡片整体压缩:环形 42px、内边距 8px、行距 7px,单卡高度约 58px(原 92px),一屏可看 4~5 项。分组顺序固定为 <b>每天 → 每周 → 每月</b>,
|
||
组标题左侧 3px 主色竖条;<b>无「每年」分组</b>。日历顶部的「昨天 / 今天 / 明天」分段已去掉,直接点日期切换,选中日靠「今天」主色数字与蓝色实心块识别。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px"><div class="on">日历</div><div>清单</div></div>
|
||
<div class="mv-cal">
|
||
<div class="mv-month"><span class="arrow">‹</span><b>2026年10月</b><span class="arrow">›</span><span class="today">回到今天</span></div>
|
||
<div class="mv-grid mv-wd"><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span><span>日</span></div>
|
||
<div class="mv-grid">
|
||
<div class="mv-day out">29</div><div class="mv-day out">30</div>
|
||
<div class="mv-day">1<i class="full"></i></div><div class="mv-day">2<i class="full"></i></div>
|
||
<div class="mv-day">3<i class="partial"></i></div><div class="mv-day">4<i class="full"></i></div><div class="mv-day">5</div>
|
||
<div class="mv-day">6<i class="full"></i></div><div class="mv-day">7<i class="over"></i></div>
|
||
<div class="mv-day">8<i class="full"></i></div><div class="mv-day">9<i class="partial"></i></div>
|
||
<div class="mv-day">10<i class="full"></i></div><div class="mv-day">11<i class="full"></i></div><div class="mv-day">12</div>
|
||
<div class="mv-day">13</div><div class="mv-day">14<i class="full"></i></div><div class="mv-day">15<i class="full"></i></div>
|
||
<div class="mv-day">16<i class="partial"></i></div><div class="mv-day">17<i class="full"></i></div><div class="mv-day">18<i class="full"></i></div><div class="mv-day">19<i class="full"></i></div>
|
||
<div class="mv-day">20<i class="full"></i></div><div class="mv-day">21<i class="full"></i></div>
|
||
<div class="mv-day today">22<i class="partial"></i></div><div class="mv-day future sel">23</div><div class="mv-day future">24</div><div class="mv-day future">25</div>
|
||
<div class="mv-day future">26</div><div class="mv-day future">27</div><div class="mv-day future">28</div>
|
||
<div class="mv-day future">29</div><div class="mv-day future">30</div><div class="mv-day future">31</div><div class="mv-day out">1</div>
|
||
</div>
|
||
<div class="mv-rate"><span>本月完成率 <b>82%</b></span><span>明天 · 2026-10-23</span></div>
|
||
</div>
|
||
<div class="mv-daybar">明天<span class="badge">计划(不可打卡)</span></div>
|
||
<div class="mv-groups">
|
||
<div class="mv-ghead">每天<span class="cnt">2 项</span></div>
|
||
<div class="mv-card">
|
||
<div class="mv-ring">
|
||
<svg width="42" height="42" viewBox="0 0 42 42">
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ececf0" stroke-width="5"/>
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#1677ff" stroke-width="5" stroke-linecap="round" stroke-dasharray="116.2" stroke-dashoffset="116.2" transform="rotate(-90 21 21)"/>
|
||
</svg><div class="c">0<em>/2</em></div>
|
||
</div>
|
||
<div class="mv-main"><div class="mv-name">喝水</div><div class="mv-meta">每天 2 次 · 当日 0/2</div></div>
|
||
<div class="mv-btn grey">计划</div><div class="mv-more">⋯</div>
|
||
</div>
|
||
<div class="mv-card">
|
||
<div class="mv-ring">
|
||
<svg width="42" height="42" viewBox="0 0 42 42">
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ececf0" stroke-width="5"/>
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#a855f7" stroke-width="5" stroke-linecap="round" stroke-dasharray="116.2" stroke-dashoffset="116.2" transform="rotate(-90 21 21)"/>
|
||
</svg><div class="c">0<em>/1</em></div>
|
||
</div>
|
||
<div class="mv-main"><div class="mv-name">吃药</div><div class="mv-meta">每天 1 次 · 当日 0/1</div></div>
|
||
<div class="mv-btn grey">计划</div><div class="mv-more">⋯</div>
|
||
</div>
|
||
<div class="mv-ghead">每周<span class="cnt">1 项</span></div>
|
||
<div class="mv-card">
|
||
<div class="mv-ring">
|
||
<svg width="42" height="42" viewBox="0 0 42 42">
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ececf0" stroke-width="5"/>
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ff8f1f" stroke-width="5" stroke-linecap="round" stroke-dasharray="116.2" stroke-dashoffset="77.5" transform="rotate(-90 21 21)"/>
|
||
</svg><div class="c">1<em>/3</em></div>
|
||
</div>
|
||
<div class="mv-main"><div class="mv-name">健身</div><div class="mv-meta">每周 3 次 · 本周 1/3</div></div>
|
||
<div class="mv-btn grey">计划</div><div class="mv-more">⋯</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>②-b 未来日期(计划态)</b>
|
||
<p>选中未来日期时,打卡按钮统一变灰显示「计划」,点击不生效;环形仍显示该日所属周期的既有进度(此处举例为周期初)。
|
||
补打窗口仍是最近 7 天,超出时同样只读。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px"><div class="on">日历</div><div>清单</div></div>
|
||
<div class="mv-cal">
|
||
<div class="mv-month"><span class="arrow">‹</span><b>2026年10月</b><span class="arrow">›</span><span class="today">回到今天</span></div>
|
||
<div class="mv-grid mv-wd"><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span><span>日</span></div>
|
||
<div class="mv-grid">
|
||
<div class="mv-day out">29</div><div class="mv-day out">30</div>
|
||
<div class="mv-day">1<i class="full"></i></div><div class="mv-day">2<i class="full"></i></div>
|
||
<div class="mv-day">3<i class="partial"></i></div><div class="mv-day">4<i class="full"></i></div><div class="mv-day">5</div>
|
||
<div class="mv-day">6<i class="full"></i></div><div class="mv-day">7<i class="over"></i></div>
|
||
<div class="mv-day">8<i class="full"></i></div><div class="mv-day">9<i class="partial"></i></div>
|
||
<div class="mv-day">10<i class="full"></i></div><div class="mv-day">11<i class="full"></i></div><div class="mv-day">12</div>
|
||
<div class="mv-day">13</div><div class="mv-day">14<i class="full"></i></div><div class="mv-day">15<i class="full"></i></div>
|
||
<div class="mv-day">16<i class="partial"></i></div><div class="mv-day">17<i class="full"></i></div><div class="mv-day">18<i class="full"></i></div><div class="mv-day">19<i class="full"></i></div>
|
||
<div class="mv-day">20<i class="full"></i></div><div class="mv-day">21<i class="full"></i></div>
|
||
<div class="mv-day today">22<i class="partial"></i></div><div class="mv-day future">23</div><div class="mv-day future">24</div><div class="mv-day future">25</div>
|
||
<div class="mv-day future">26</div><div class="mv-day future">27</div><div class="mv-day future">28</div>
|
||
<div class="mv-day future">29</div><div class="mv-day future">30</div><div class="mv-day future">31</div><div class="mv-day out">1</div>
|
||
</div>
|
||
<div class="mv-rate"><span>本月完成率 <b>82%</b></span><span>今天 · 2026-10-22</span></div>
|
||
</div>
|
||
<div class="mv-daybar">今天<span class="badge">已完成 2 / 4</span><span class="sum">点环即打卡</span></div>
|
||
<div class="mv-groups">
|
||
<div class="mv-ghead">每天<span class="cnt">2 项</span></div>
|
||
<div class="mv-card">
|
||
<div class="mv-ring">
|
||
<svg width="42" height="42" viewBox="0 0 42 42">
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ececf0" stroke-width="5"/>
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#1677ff" stroke-width="5" stroke-linecap="round" stroke-dasharray="116.2" stroke-dashoffset="58.1" transform="rotate(-90 21 21)"/>
|
||
</svg><div class="c">1<em>/2</em></div>
|
||
</div>
|
||
<div class="mv-main"><div class="mv-name">喝水</div><div class="mv-meta">每天 2 次 · 今日 1/2</div></div>
|
||
<div class="mv-btn">打卡</div><div class="mv-more">⋯</div>
|
||
</div>
|
||
<div class="mv-card done">
|
||
<div class="mv-ring">
|
||
<svg width="42" height="42" viewBox="0 0 42 42">
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#ececf0" stroke-width="5"/>
|
||
<circle cx="21" cy="21" r="18.5" fill="none" stroke="#a855f7" stroke-width="5" stroke-linecap="round" stroke-dasharray="116.2" stroke-dashoffset="0" transform="rotate(-90 21 21)"/>
|
||
</svg>
|
||
<div class="c"><svg width="15" height="15" viewBox="0 0 24 24" fill="none"><path d="M4 12.5l5 5L20 6.5" stroke="#a855f7" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||
<span class="ov">+1</span>
|
||
</div>
|
||
<div class="mv-main"><div class="mv-name">吃药</div><div class="mv-meta">每天 1 次 · 今日 2/1</div></div>
|
||
<div class="mv-btn grey">再打一次</div><div class="mv-more">⋯</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="mask" style="inset:28px 0 0 0"></div>
|
||
<div class="sheet mv-sheet">
|
||
<div class="sheet-title">吃药 · 每天 1 次</div>
|
||
<div class="mv-sheet-row"><span>撤销上次打卡</span><span class="k">今日 2 次</span></div>
|
||
<div class="mv-sheet-row"><span>编辑打卡项</span><span class="k">名称 / 周期 / 目标</span></div>
|
||
<div class="mv-sheet-row danger"><span>归档</span><span class="k">历史记录保留</span></div>
|
||
<div class="btn-ghost" style="margin-top:10px">取消</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>②-c 卡片「⋯」操作面板</b>
|
||
<p>紧凑化后卡片不再常显三个文字链接,改由右上角「⋯」唤出底部面板:撤销 / 编辑 / 归档。面板项 44px 高,
|
||
「归档」用危险色;撤销仅在当日有记录时可用,否则置灰。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>③ 清单:新增「模板」分类(与进行中 / 已归档并列)<span class="tag">已实现</span></h3>
|
||
<p class="desc">清单页分段从 2 个变为 <b>3 个</b>:<b>进行中 / 已归档 / 模板</b>。模板拥有独立的增删改查,<b>按名称字母顺序</b>(中文按拼音、数字按数值)排序;
|
||
新建清单时<b>只保留名称</b>,<b>去掉场景</b>,模板改为点击后在<b>右侧滑出</b>的面板里选择。</p>
|
||
|
||
<div class="stage">
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px"><div>日历</div><div class="on">清单</div></div>
|
||
<div class="list-head">
|
||
<div class="seg"><div>进行中</div><div>已归档</div><div class="on">模板</div></div>
|
||
<div class="mini-btn solid">+ 新建模板</div>
|
||
</div>
|
||
|
||
<div class="tpl-card">
|
||
<div class="tpl-row"><span class="tpl-name">出差</span><span class="tpl-badge">预置</span><span class="tpl-num">11 项</span></div>
|
||
<div class="tpl-chips">
|
||
<span class="tpl-chip">身份证 / 证件</span><span class="tpl-chip">手机充电器 + 充电宝</span>
|
||
<span class="tpl-chip">笔记本电脑 + 电源</span><span class="tpl-chip">耳机</span><span class="tpl-chip more">+7</span>
|
||
</div>
|
||
<div class="tpl-acts"><span class="link">由此新建</span></div>
|
||
</div>
|
||
|
||
<div class="tpl-card">
|
||
<div class="tpl-row"><span class="tpl-name">回老家</span><span class="tpl-badge">预置</span><span class="tpl-num">12 项</span></div>
|
||
<div class="tpl-chips">
|
||
<span class="tpl-chip">身份证 / 证件</span><span class="tpl-chip">钥匙</span>
|
||
<span class="tpl-chip">手机充电器 + 充电宝</span><span class="tpl-chip">换洗衣物</span><span class="tpl-chip more">+8</span>
|
||
</div>
|
||
<div class="tpl-acts"><span class="link">由此新建</span></div>
|
||
</div>
|
||
|
||
<div class="tpl-card">
|
||
<div class="tpl-row"><span class="tpl-name">露营装备</span><span class="tpl-num">2 项</span></div>
|
||
<div class="tpl-chips"><span class="tpl-chip">帐篷</span><span class="tpl-chip">睡袋</span></div>
|
||
<div class="tpl-acts"><span class="link">由此新建</span><span class="link">编辑</span><span class="link danger">删除</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>③-a 模板分类<span class="tag">已实现</span></b>
|
||
<p>模板卡片:名称 + 「预置」标记 + 项数;下方最多展示 4 个检查项摘要(超出折叠为 <code>+n</code>);底部操作「由此新建 / 编辑 / 删除」。
|
||
<b>系统预置模板不可编辑、不可删除</b>(只保留「由此新建」)。右上角按钮随分段切换:模板页为「+ 新建模板」,其余为「+ 新建」。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px"><div>日历</div><div class="on">清单</div></div>
|
||
<div class="mask" style="inset:28px 0 0 0"></div>
|
||
<div class="sheet">
|
||
<div class="sheet-title">新建检查清单</div>
|
||
<div class="field"><label>名称</label><div class="inp">周末露营</div></div>
|
||
<div class="field">
|
||
<label>模板</label>
|
||
<div class="pick-row">露营装备<span class="meta">2 项 <span style="color:#c8c8c8;font-size:15px">›</span></span></div>
|
||
</div>
|
||
<div class="btn-primary">创建</div>
|
||
<div class="btn-ghost">取消</div>
|
||
</div>
|
||
<div class="side-panel">
|
||
<div class="side-head"><b>选择模板</b><span class="x">×</span></div>
|
||
<div class="side-tip">按名称字母顺序排列</div>
|
||
<div class="side-item"><span class="nm">不使用模板</span><span class="sub">空白清单</span></div>
|
||
<div class="side-item"><span class="nm">出差<span class="tpl-badge">预置</span></span><span class="sub">11 项</span></div>
|
||
<div class="side-item"><span class="nm">回老家<span class="tpl-badge">预置</span></span><span class="sub">12 项</span></div>
|
||
<div class="side-item on"><span class="nm">露营装备</span><span class="sub">2 项</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>③-b 新建清单 + 模板右侧滑出面板<span class="tag">已实现</span></b>
|
||
<p>表单只剩两项:<b>名称</b>(≤20 字,必填)与 <b>模板</b>(可空)。<b>场景选择器已移除</b>——场景不再由用户填写,新建时沿用所选模板自带的场景(无模板则为空),历史数据仍正常展示场景标签。<br>
|
||
点模板行从<b>右侧滑出 78% 宽面板</b>:首项固定为「不使用模板」,其后按字母顺序列出全部模板(预置带标记、右侧显示项数),选中项主色高亮,点遮罩或 × 关闭。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="shot">
|
||
<div class="phone">
|
||
<div class="navbar-sm">打卡</div>
|
||
<div class="body">
|
||
<div class="seg" style="width:calc(100% - 28px);margin-left:14px"><div>日历</div><div class="on">清单</div></div>
|
||
<div class="mask" style="inset:28px 0 0 0"></div>
|
||
<div class="sheet">
|
||
<div class="sheet-title">编辑模板</div>
|
||
<div class="field"><label>模板名称</label><div class="inp">露营装备</div></div>
|
||
<div class="field">
|
||
<label>检查项(3)</label>
|
||
<div style="display:flex;flex-direction:column;gap:6px">
|
||
<div style="display:flex;align-items:center;gap:8px"><span style="width:16px;text-align:right;font-size:11px;color:#999">1</span><div class="inp" style="flex:1">帐篷</div><span style="color:#ccc;font-size:17px">×</span></div>
|
||
<div style="display:flex;align-items:center;gap:8px"><span style="width:16px;text-align:right;font-size:11px;color:#999">2</span><div class="inp" style="flex:1">睡袋</div><span style="color:#ccc;font-size:17px">×</span></div>
|
||
<div style="display:flex;align-items:center;gap:8px"><span style="width:16px;text-align:right;font-size:11px;color:#999">3</span><div class="inp ph" style="flex:1">检查项内容</div><span style="color:#ccc;font-size:17px">×</span></div>
|
||
</div>
|
||
<div style="margin-top:8px;border:1px solid var(--line);border-radius:7px;text-align:center;padding:6px 0;font-size:12px;color:var(--muted)">+ 添加检查项</div>
|
||
</div>
|
||
<div class="btn-primary">保存</div>
|
||
<div class="btn-ghost">取消</div>
|
||
</div>
|
||
</div>
|
||
<div class="tabbar">
|
||
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="8.5"/><path d="M8 12.4l2.6 2.6L16.5 9.5" stroke-linecap="round" stroke-linejoin="round"/></svg>打卡</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9m5 10V5m5 14v-7m5 7V8"/></svg>宏观</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><circle cx="7" cy="7.5" r="1"/><circle cx="7" cy="16.5" r="1"/></svg>监控</div>
|
||
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="3.6"/><path d="M4.5 20c1.4-3.6 4.1-5.4 7.5-5.4S18.1 16.4 19.5 20"/></svg>我</div>
|
||
</div>
|
||
</div>
|
||
<div class="caption">
|
||
<b>③-c 模板编辑(增删改)<span class="tag">已实现</span></b>
|
||
<p>新建 / 编辑共用同一弹层:模板名称(≤20 字)+ 检查项列表(逐条 ≤40 字,可删除、可追加)。保存时至少需 1 条有效检查项,名称为空或全空则拦截并 Toast 提示。
|
||
删除模板需二次确认,且不影响已用该模板创建过的清单。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>④ 补充:模板接口</h3>
|
||
<table>
|
||
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
|
||
<tr><td>GET</td><td><code>/api/checklists/templates</code></td><td>模板列表(含预置),<b>服务端按名称字母顺序排序</b></td></tr>
|
||
<tr><td>GET</td><td><code>/api/checklists/templates/:id</code></td><td>模板详情</td></tr>
|
||
<tr><td>POST</td><td><code>/api/checklists/templates</code></td><td>新建模板 <code>{ name, items[] }</code></td></tr>
|
||
<tr><td>PUT</td><td><code>/api/checklists/templates/:id</code></td><td>改名称 / 检查项(预置模板拒绝)</td></tr>
|
||
<tr><td>DELETE</td><td><code>/api/checklists/templates/:id</code></td><td>删自建模板(预置模板拒绝)</td></tr>
|
||
</table>
|
||
<p class="note">排序口径:<code>Intl.Collator('zh-Hans-CN', { numeric: true, sensitivity: 'base' })</code>,中文按拼音、数字按数值比较,前后端一致。</p>
|
||
|
||
<!-- ============ 3 组件状态 ============ -->
|
||
<h2>3 组件状态定义<span class="sub">Component States</span></h2>
|
||
|
||
<h3>3.0 页面头部(PageHeader)</h3>
|
||
<table>
|
||
<tr><th>项</th><th>取值</th></tr>
|
||
<tr><td>高度</td><td>23px(原 NavBar 45px 的一半),<code>flex: 0 0 23px</code> 不参与压缩</td></tr>
|
||
<tr><td>标题字号 / 字重</td><td>12px / 600</td></tr>
|
||
<tr><td>标题颜色</td><td>主色 <code>#1677ff</code></td></tr>
|
||
<tr><td>背景</td><td>页面底色 <code>#f5f5f5</code></td></tr>
|
||
<tr><td>适用范围</td><td>打卡 / 宏观 / 监控;<b>「我」页不使用</b></td></tr>
|
||
</table>
|
||
<p class="note">实现为独立组件 <code>src/components/PageHeader.jsx</code>,三页各自引用、互不影响;「我」页移除 NavBar 后头像区直接贴顶。</p>
|
||
|
||
<h3>3.1 环形进度(尺寸 58,环宽 6,r=26,周长 163.4)</h3>
|
||
<table>
|
||
<tr><th>状态</th><th>条件</th><th>环形</th><th>中心</th><th>卡片底</th><th>按钮</th></tr>
|
||
<tr><td>未开始</td><td><code>done = 0</code></td><td>仅灰底环</td><td><code>0/2</code></td><td>白</td><td>打卡(主色)</td></tr>
|
||
<tr><td>进行中</td><td><code>0 < done < target</code></td><td>按 <code>done/target</code> 填充(45°…330°)</td><td><code>1/3</code></td><td>白</td><td>打卡(主色)</td></tr>
|
||
<tr><td>已达标</td><td><code>done = target</code></td><td>闭合整圈</td><td>对勾(主色)</td><td><code>#f7fbf8</code></td><td>再打一次(灰)</td></tr>
|
||
<tr><td>超额</td><td><code>done > target</code></td><td>闭合 + 右上角 <code>+n</code> 橙标</td><td>对勾</td><td><code>#f7fbf8</code></td><td>再打一次(灰)</td></tr>
|
||
<tr><td>每日 1 次达标</td><td><code>target = 1</code> 且已打卡</td><td><b>直接整圈闭合</b>,不做渐增生长期</td><td>对勾</td><td><code>#f7fbf8</code></td><td>再打一次</td></tr>
|
||
</table>
|
||
<p class="note">环形进度 = 周期完成度(<code>done / n</code>);日历日标记 = 当日份额(<code>当日次数 / 日均期望</code>),两者口径不同,互不影响。</p>
|
||
|
||
<h3>3.2 日历日期</h3>
|
||
<table>
|
||
<tr><th>状态</th><th>判定</th><th>视觉</th></tr>
|
||
<tr><td>全部完成 <code>full</code></td><td>所有打卡项当日次数 ≥ 日均期望,且无超额</td><td>绿色圆点</td></tr>
|
||
<tr><td>超额 <code>over</code></td><td>全部达标且存在任一打卡项当日次数 > 期望</td><td>紫色圆点</td></tr>
|
||
<tr><td>部分完成 <code>partial</code></td><td>有完成但未全部完成</td><td>黄色圆点</td></tr>
|
||
<tr><td>无 <code>empty</code></td><td>无记录 / 当天无打卡项 / 未来日期</td><td>不显示圆点</td></tr>
|
||
<tr><td>今天</td><td><code>date = today</code></td><td>数字主色加粗</td></tr>
|
||
<tr><td>选中</td><td>用户点击</td><td>主色实心底,数字与圆点转白</td></tr>
|
||
<tr><td>非本月 / 未来</td><td>月份不符 / <code>date > today</code></td><td>数字弱化(#c8c8c8 / #b0b0b0)</td></tr>
|
||
</table>
|
||
|
||
<h3>3.3 清单检查项</h3>
|
||
<table>
|
||
<tr><th>状态</th><th>勾选框</th><th>文字</th><th>触发</th></tr>
|
||
<tr><td>未完成</td><td>1.5px 灰边圆圈,对勾透明</td><td>#333</td><td>点击圆圈或文字切换</td></tr>
|
||
<tr><td>已完成</td><td>绿底绿边,白色对勾显现(0.2s)</td><td>#a0a0a0 + 删除线</td><td>同上,写 <code>doneAt</code></td></tr>
|
||
<tr><td>整单完成</td><td>—</td><td>进度条 100%、卡片转绿</td><td>最后一项勾选时播放特效</td></tr>
|
||
</table>
|
||
|
||
<!-- ============ 4 交互与动效 ============ -->
|
||
<h2>4 交互与动效<span class="sub">Motion</span></h2>
|
||
<table>
|
||
<tr><th>动效</th><th>时长</th><th>曲线 / 实现</th><th>说明</th></tr>
|
||
<tr><td>环形增长</td><td>450ms</td><td><code>cubic-bezier(.4,0,.2,1)</code>,<code>stroke-dashoffset</code> 过渡</td><td>12 点方向顺时针增长</td></tr>
|
||
<tr><td>对勾入场</td><td>320ms</td><td><code>scale(.4) → 1</code> + 透明度</td><td>达标瞬间出现</td></tr>
|
||
<tr><td>完成粒子</td><td>≤900ms</td><td>14 颗粒子按角度 <code>--a</code>、距离 <code>--d</code> 扩散,交错 40ms 延迟</td><td>不阻塞点击</td></tr>
|
||
<tr><td>光环脉冲</td><td>700ms</td><td>主色圆环放大淡出</td><td>与粒子同时开始</td></tr>
|
||
<tr><td>触感反馈</td><td>18ms</td><td><code>navigator.vibrate(18)</code></td><td>WebView 不支持则静默跳过</td></tr>
|
||
<tr><td>进度条填充</td><td>400ms</td><td><code>width</code> 过渡</td><td>清单勾选后更新</td></tr>
|
||
<tr><td>视图切换</td><td>—</td><td>SwipeTabs 跟手横滑</td><td>与既有模块一致</td></tr>
|
||
</table>
|
||
|
||
<h3>4.1 打卡时序</h3>
|
||
<div class="flow">用户点环 / 点「打卡」
|
||
└─ 前端乐观更新:done+1,重算 percent / completed / over,环形立即增长
|
||
└─ POST /api/checkin/habits/:id/check
|
||
├─ 200 → 用服务端 item 覆盖本地;若 completed → 触发特效 + 震动
|
||
├─ 400 → 回滚 + Toast(未来日期 / 超出 7 天补打窗口)
|
||
├─ 409 → 视为已打卡,刷新一次(幂等)
|
||
└─ 网络失败 → 回滚 + Toast「打卡失败」</div>
|
||
|
||
<!-- ============ 5 适配与可达性 ============ -->
|
||
<h2>5 适配与可达性</h2>
|
||
<table>
|
||
<tr><th>项</th><th>约定</th></tr>
|
||
<tr><td>视口</td><td>设计稿 420×820;375~430px 内元素不换行、不裁切;底部 TabBar 4 项每项 ≥ 44px 可点宽度</td></tr>
|
||
<tr><td>安全区</td><td>TabBar 使用 antd-mobile <code>safeArea</code>,页面底部留出 <code>tabbar-h + safe-bottom</code></td></tr>
|
||
<tr><td>动效</td><td><b>特效恒开</b>(V0.2 设计变更,无开关):单次 ≤900ms、<code>pointer-events:none</code>,不阻塞连续打卡;不再响应 <code>prefers-reduced-motion</code></td></tr>
|
||
<tr><td>大字号</td><td>卡片采用 grid 自适应列宽,文字超长换行不截断;名称限制 20 字、检查项 40 字</td></tr>
|
||
<tr><td>深色模式</td><td>V0.2 沿用现有浅色主题,暂不适配</td></tr>
|
||
</table>
|
||
|
||
<p class="note" style="margin-top:26px">本文档为静态设计稿,不含脚本逻辑;实现对应 <code>src/pages/checkin/*.jsx</code>、<code>src/components/RingProgress.jsx</code> 与样式段(<code>src/styles/globals.css</code>)。接口与数据口径见《设计文档.md》与《数据库设计文档.md》。</p>
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|