Files
xiaotutongxue/docs/prototype/teacher-app.html
T
lovife 63aec55329 docs: 产品文档与交互原型(P1-P7 交付物)
一期范围:学校收集 + 自主认定(4 类材料全部有实测样本)
- 主 PRD 190KB:125 条 FR / 21 条 VAL / 20 张表 DDL / 121 个接口
- 功能逻辑卷 88KB:不含代码模块
- 接口设计 116KB:58 个错误码 / 12 个 VO
- 核心模块设计:M1 命名 / M2 压缩 / M3 识别 / M4 门禁 / M5 校验 / M6 导出
- 开发任务拆解:100 任务 / 387 人日 / 15 周
- 验收测试清单:36 条 Golden 断言 / 111 条功能验收
- PostgreSQL DDL:已在 PG 16.15 实测零错误
- 交互原型 31 屏:学生端 11 / 班主任端 9 / 管理端 11
2026-09-28 16:19:19 +08:00

1073 lines
63 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>填报通 · 班主任端交互原型</title>
<style>
:root{
--ink:#1b2430; --ink2:#4a5768; --ink3:#8b95a3;
--paper:#f4f1ea; --paper2:#fbfaf7; --card:#ffffff;
--line:#e0dbd0; --line2:#cfc8b8;
--seal:#c0392b; --seal-soft:#f9ece9;
--jade:#2f6b4f; --jade-soft:#e8f0eb;
--amber:#a9761f; --amber-soft:#f8f1de;
--slate:#5b6879; --slate-soft:#eceff3;
--font-display:"Songti SC","STSong","SimSun","Noto Serif SC",serif;
--font-body:"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Source Han Sans SC",sans-serif;
--font-mono:"SF Mono","JetBrains Mono","Cascadia Mono",Consolas,monospace;
--r:14px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{
font-family:var(--font-body);color:var(--ink);background:var(--paper);
background-image:
linear-gradient(rgba(207,200,184,.28) 1px,transparent 1px),
linear-gradient(90deg,rgba(207,200,184,.28) 1px,transparent 1px);
background-size:26px 26px;-webkit-font-smoothing:antialiased;padding:0 0 80px;
}
/* ── 图标 ── */
.ico{width:1em;height:1em;flex:none;display:inline-block;vertical-align:-.14em;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.ico.lg{width:1.35em;height:1.35em;vertical-align:-.28em}
.ico.xl{width:1.9em;height:1.9em;vertical-align:-.42em}
/* ── 页头 ── */
.masthead{padding:38px 40px 26px;border-bottom:1px solid var(--line2);background:linear-gradient(180deg,var(--paper2),transparent);position:relative}
.masthead::after{content:"";position:absolute;left:0;right:0;bottom:3px;height:1px;background:var(--line)}
.kicker{font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--ink3);font-family:var(--font-mono);margin-bottom:10px}
h1{font-family:var(--font-display);font-size:32px;font-weight:600;letter-spacing:.04em;line-height:1.25}
h1 em{font-style:normal;color:var(--seal)}
.sub{margin-top:10px;color:var(--ink2);font-size:13.5px;line-height:1.75;max-width:800px}
.sub code{font-family:var(--font-mono);font-size:12px;background:#fff;border:1px solid var(--line);border-radius:4px;padding:1px 5px}
.compare{
display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:20px;max-width:800px;
}
.compare>div{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:13px 15px;font-size:12.5px;line-height:1.7;color:var(--ink2)}
.compare h5{font-size:12.5px;color:var(--ink);margin-bottom:7px;font-weight:600;display:flex;align-items:center;gap:7px}
/* ── 画廊 ── */
.gallery{display:grid;grid-template-columns:repeat(auto-fit,minmax(348px,1fr));gap:36px 30px;padding:44px 40px;max-width:1560px;margin:0 auto}
figure{margin:0;display:flex;flex-direction:column;align-items:center}
figcaption{margin-top:16px;max-width:340px;text-align:center;font-size:12.5px;line-height:1.7;color:var(--ink2)}
figcaption b{display:block;font-family:var(--font-display);font-size:15px;color:var(--ink);letter-spacing:.03em;margin-bottom:5px;font-weight:600}
figcaption .tag{display:inline-block;font-family:var(--font-mono);font-size:10px;letter-spacing:.1em;color:var(--seal);border:1px solid var(--seal);border-radius:3px;padding:1px 6px;margin-bottom:7px;opacity:.85}
/* ── 手机 ── */
.device{width:348px;height:752px;flex:none;background:#0e1319;border-radius:44px;padding:11px;box-shadow:0 26px 48px -18px rgba(27,36,48,.42),0 2px 6px rgba(27,36,48,.14);position:relative;transition:transform .4s cubic-bezier(.2,.8,.3,1),box-shadow .4s}
.device:hover{transform:translateY(-6px);box-shadow:0 36px 62px -20px rgba(27,36,48,.5)}
.screen{width:100%;height:100%;background:var(--paper2);border-radius:34px;overflow:hidden;display:flex;flex-direction:column;position:relative}
.statusbar{height:40px;flex:none;display:flex;align-items:center;justify-content:space-between;padding:0 20px;font-size:12px;font-family:var(--font-mono);color:var(--ink);font-weight:500}
.statusbar .icons{display:flex;gap:5px;align-items:center;opacity:.85;font-size:13px}
.bat{width:20px;height:10px;border:1.2px solid var(--ink);border-radius:2.5px;position:relative;flex:none}
.bat::after{content:"";position:absolute;left:1.5px;top:1.5px;bottom:1.5px;width:11px;background:var(--ink);border-radius:1px}
.bat::before{content:"";position:absolute;right:-3px;top:3px;width:2px;height:4px;background:var(--ink);border-radius:0 1px 1px 0}
.navbar{flex:none;height:46px;display:flex;align-items:center;gap:10px;padding:0 18px;border-bottom:1px solid var(--line);font-size:15px;font-weight:600;letter-spacing:.02em;background:var(--paper2)}
.navbar .back{width:17px;height:17px;flex:none;opacity:.55}
.navbar .back .ico{stroke-width:2.4}
.navbar .navact{margin-left:auto;font-size:12px;color:var(--ink3);font-weight:400;display:flex;align-items:center;gap:5px}
.body{flex:1;overflow-y:auto;padding:18px;scrollbar-width:thin}
.body::-webkit-scrollbar{width:4px}
.body::-webkit-scrollbar-thumb{background:var(--line2);border-radius:2px}
.body.flush{padding:0}
.foot{flex:none;padding:13px 18px 20px;border-top:1px solid var(--line);background:var(--paper2)}
/* ── 通用 ── */
.panel{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:15px;margin-bottom:13px}
.panel.flush{padding:0;overflow:hidden}
.ptitle{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--ink3);letter-spacing:.06em;margin-bottom:11px;font-family:var(--font-mono)}
.badge{font-size:10px;padding:1.5px 6px;border-radius:3px;letter-spacing:.04em;font-family:var(--font-body);font-weight:600;display:inline-flex;align-items:center;gap:4px}
.badge .ico{font-size:11px}
.badge.lock{background:#eef1f4;color:var(--ink2);border:1px solid var(--line2)}
.badge.crit{background:var(--seal-soft);color:var(--seal);border:1px solid #eed5cf}
.badge.warn{background:var(--amber-soft);color:var(--amber);border:1px solid #e8d9b5}
.badge.ok{background:var(--jade-soft);color:var(--jade);border:1px solid #cfe0d6}
.btn{display:block;width:100%;border:0;border-radius:11px;font-family:var(--font-body);font-size:15px;font-weight:600;letter-spacing:.04em;padding:14px;cursor:pointer;transition:.22s;text-align:center}
.btn.primary{background:var(--ink);color:#fff}
.btn.primary:hover{background:#2a3646}
.btn.seal{background:var(--seal);color:#fff}
.btn.seal:hover{background:#a93022}
.btn.jade{background:var(--jade);color:#fff}
.btn.ghost{background:transparent;color:var(--ink2);border:1px solid var(--line2)}
.btn.ghost:hover{background:#fff;color:var(--ink)}
.btn.sm{padding:9px 14px;font-size:13px;width:auto;border-radius:9px}
.btnrow{display:flex;gap:10px}
.btnrow .btn{margin:0}
/* 状态点 */
.sdot{width:8px;height:8px;border-radius:50%;flex:none;display:inline-block}
.sdot.pass{background:var(--jade)} .sdot.audit{background:var(--ink)}
.sdot.warn{background:var(--amber)} .sdot.crit{background:var(--seal)}
.sdot.none{background:#fff;border:1.5px solid var(--line2)}
/* ── 班级看板头部 ── */
.dashhead{padding:15px 17px 13px;background:#fff;border-bottom:1px solid var(--line)}
.dh-top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.dh-name{font-family:var(--font-display);font-size:20px;font-weight:600;letter-spacing:.04em}
.dh-sub{font-size:11.5px;color:var(--ink3);font-family:var(--font-mono);margin-top:5px}
.dh-sub .urgent{color:var(--seal);font-weight:600}
.rate{display:flex;align-items:baseline;gap:3px;flex:none}
.rate .n{font-family:var(--font-mono);font-size:26px;font-weight:700;color:var(--jade);line-height:1}
.rate .d{font-family:var(--font-mono);font-size:13px;color:var(--ink3)}
.bar{height:7px;border-radius:4px;background:#e8e4db;overflow:hidden;margin-top:12px;display:flex}
.bar i{height:100%;display:block}
.bar .b-pass{background:var(--jade)} .bar .b-audit{background:var(--ink)}
.bar .b-warn{background:var(--amber)} .bar .b-crit{background:var(--seal)}
.statrow{display:flex;gap:14px;margin-top:11px;font-size:11.5px;color:var(--ink2);flex-wrap:wrap}
.statrow span{display:flex;align-items:center;gap:6px}
/* ── 花名册网格(核心)── */
.roster{padding:13px 14px 16px;background:var(--paper2)}
.roster .rhead{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.roster .rtitle{font-size:11px;font-family:var(--font-mono);letter-spacing:.1em;color:var(--ink3)}
.grid{display:grid;grid-template-columns:repeat(5,1fr);gap:6px}
.cell{
height:52px;border-radius:8px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
font-size:11.5px;font-weight:600;letter-spacing:.01em;cursor:pointer;transition:.18s;position:relative;
border:1px solid var(--line);background:#fff;color:var(--ink2);
}
.cell:hover{transform:translateY(-2px);box-shadow:0 6px 14px -6px rgba(27,36,48,.3);z-index:2}
.cell .nm{line-height:1;white-space:nowrap}
.cell .st{font-size:9px;font-weight:400;letter-spacing:.03em;font-family:var(--font-mono);opacity:.75}
.cell.pass{background:var(--jade-soft);border-color:#c3d8ca;color:#245341}
.cell.audit{background:var(--ink);border-color:var(--ink);color:#fff}
.cell.audit .st{opacity:.6}
.cell.warn{background:var(--amber-soft);border-color:#e8d9b5;color:#7d5815}
.cell.crit{background:var(--seal);border-color:var(--seal);color:#fff;animation:pulse 2.4s ease-in-out infinite}
.cell.none{background:#fff;border:1px dashed var(--line2);color:var(--ink3)}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(192,57,43,.34)}50%{box-shadow:0 0 0 5px rgba(192,57,43,0)}}
.legend2{display:flex;gap:13px;flex-wrap:wrap;margin-top:12px;font-size:10.5px;color:var(--ink3)}
.legend2 span{display:flex;align-items:center;gap:5px}
/* ── 学生卡片流 ── */
.filters{display:flex;gap:7px;padding:11px 15px;background:#fff;border-bottom:1px solid var(--line);overflow-x:auto}
.filters::-webkit-scrollbar{display:none}
.chip{
flex:none;font-size:12px;padding:6px 12px;border-radius:20px;border:1px solid var(--line2);
background:#fff;color:var(--ink2);cursor:pointer;transition:.18s;white-space:nowrap;display:flex;align-items:center;gap:6px;
}
.chip:hover{border-color:var(--ink3)}
.chip.on{background:var(--ink);border-color:var(--ink);color:#fff}
.chip .cnt{font-family:var(--font-mono);font-size:10.5px;opacity:.7}
.stu{display:flex;gap:12px;padding:13px 15px;background:var(--card);border-bottom:1px solid var(--line);cursor:pointer;transition:.18s;position:relative}
.stu:hover{background:#fdfcfa}
.stu .avatar{
width:42px;height:42px;border-radius:10px;flex:none;display:flex;align-items:center;justify-content:center;
font-family:var(--font-display);font-size:17px;font-weight:600;background:var(--paper);border:1px solid var(--line);color:var(--ink2);
}
.stu.crit .avatar{background:var(--seal-soft);border-color:#eed5cf;color:var(--seal)}
.stu.warn .avatar{background:var(--amber-soft);border-color:#e8d9b5;color:var(--amber)}
.stu .sinfo{flex:1;min-width:0}
.stu .sname{font-size:14.5px;font-weight:600;display:flex;align-items:center;gap:7px}
.stu .sissue{font-size:11.5px;color:var(--ink3);margin-top:5px;line-height:1.5;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.stu.crit .sissue{color:var(--seal)}
.stu.warn .sissue{color:var(--amber)}
.stu .chev{width:15px;height:15px;flex:none;align-self:center;opacity:.35}
/* 材料缩略条 */
.mstrip{display:flex;gap:5px;margin-top:7px}
.mstrip i{
width:26px;height:26px;border-radius:6px;flex:none;display:flex;align-items:center;justify-content:center;
font-size:14px;border:1px solid var(--line);background:#fff;color:var(--jade);font-style:normal;
}
.mstrip i.miss{border-style:dashed;color:var(--line2);background:transparent}
.mstrip i.bad{border-color:#eed5cf;background:var(--seal-soft);color:var(--seal)}
.mstrip i.warn2{border-color:#e8d9b5;background:var(--amber-soft);color:var(--amber)}
/* ── 审核详情 ── */
.preview{
background:#141a22;border-radius:var(--r);overflow:hidden;margin-bottom:13px;position:relative;height:290px;
display:flex;align-items:center;justify-content:center;
}
.preview .fake{
width:200px;height:126px;border-radius:6px;background:linear-gradient(135deg,#f0ece3,#ddd7c9);
border:1px solid #b9b2a2;display:flex;flex-direction:column;justify-content:center;padding:13px;gap:7px;position:relative;
}
.preview .fake b{font-size:9.5px;color:#5a5348;letter-spacing:.13em}
.preview .fake span{height:6px;background:#c8c0b0;border-radius:2px;display:block}
.preview .fake span.s{width:62%}
.preview .badge-tr{position:absolute;top:11px;right:11px;font-size:10.5px;font-family:var(--font-mono);color:#fff;background:rgba(255,255,255,.14);padding:3px 9px;border-radius:20px;letter-spacing:.04em}
.preview .dots{position:absolute;bottom:11px;left:0;right:0;display:flex;justify-content:center;gap:6px}
.preview .dots i{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.3);display:block}
.preview .dots i.on{background:#fff;width:16px;border-radius:3px}
/* 问题清单 */
.issue{display:flex;gap:10px;padding:11px 0;border-top:1px dashed var(--line);font-size:12.5px;line-height:1.65;align-items:flex-start}
.issue:first-child{border-top:0;padding-top:2px}
.issue .ii{flex:none;font-size:15px;margin-top:1px}
.issue.crit .ii{color:var(--seal)} .issue.warn .ii{color:var(--amber)} .issue.ok .ii{color:var(--jade)}
.issue .it{flex:1;color:var(--ink2)}
.issue .it b{color:var(--ink);font-weight:600}
.issue .it .mono{font-family:var(--font-mono);font-size:11.5px}
.issue .ia{flex:none;font-size:11.5px;color:var(--seal);text-decoration:underline;text-underline-offset:3px;cursor:pointer;white-space:nowrap}
/* 对比条 */
.compare-bar{display:flex;gap:8px;margin-bottom:12px}
.cbtn{
flex:1;font-size:11.5px;padding:8px;border-radius:8px;border:1px solid var(--line2);background:#fff;
color:var(--ink2);cursor:pointer;text-align:center;transition:.18s;
}
.cbtn.on{background:var(--ink);border-color:var(--ink);color:#fff}
/* ── 批量通过 ── */
.batch{display:flex;align-items:center;gap:12px;padding:12px 15px;background:var(--card);border-bottom:1px solid var(--line)}
.cbx{width:20px;height:20px;flex:none;accent-color:var(--jade);cursor:pointer}
.batch .binfo{flex:1;min-width:0}
.batch .bname{font-size:13.5px;font-weight:600}
.batch .bsub{font-size:11px;color:var(--ink3);margin-top:3px;font-family:var(--font-mono)}
.batch.skipped{background:#fafaf8;opacity:.62}
.batch.skipped .bname{color:var(--ink3)}
.skipnote{
display:flex;gap:9px;align-items:flex-start;padding:11px 15px;background:var(--seal-soft);
border-bottom:1px solid #eed5cf;font-size:11.5px;color:#8e2d20;line-height:1.6;
}
.skipnote .ico{margin-top:2px}
/* ── 驳回原因 ── */
.reasons{display:flex;flex-wrap:wrap;gap:8px}
.rchip{
font-size:12.5px;padding:9px 13px;border-radius:9px;border:1px solid var(--line2);background:#fff;
color:var(--ink2);cursor:pointer;transition:.18s;
}
.rchip:hover{border-color:var(--seal);color:var(--seal)}
.rchip.on{background:var(--seal);border-color:var(--seal);color:#fff}
.ta{
width:100%;min-height:76px;border:1.5px solid var(--line2);border-radius:11px;padding:11px 13px;
font-family:var(--font-body);font-size:13px;line-height:1.65;resize:none;color:var(--ink);background:var(--card);
}
.ta:focus{outline:0;border-color:var(--ink)}
.ta::placeholder{color:#b3b9c1}
/* ── 催报 ── */
.quota{
display:flex;align-items:center;gap:10px;padding:12px 14px;border-radius:11px;
background:var(--amber-soft);border:1px solid #e8d9b5;font-size:12px;color:#7d5815;line-height:1.6;margin-bottom:13px;
}
.quota .ico{flex:none;margin-top:2px}
.quota b{font-weight:600}
.person{display:flex;align-items:center;gap:11px;padding:11px 15px;border-bottom:1px solid var(--line);background:var(--card)}
.person .pn{flex:1;font-size:13.5px;font-weight:500}
.person .pt{font-size:10.5px;font-family:var(--font-mono);color:var(--ink3)}
.person .pact{font-size:11.5px;color:var(--ink3);text-decoration:underline;text-underline-offset:3px;cursor:pointer}
/* ── 消息 ── */
.msg{display:flex;gap:11px;padding:13px 15px;border-bottom:1px solid var(--line);background:var(--card);cursor:pointer;transition:.18s}
.msg:hover{background:#fdfcfa}
.msg .micon{
width:34px;height:34px;border-radius:9px;flex:none;display:flex;align-items:center;justify-content:center;font-size:17px;
background:var(--slate-soft);border:1px solid var(--line);color:var(--slate);
}
.msg.crit .micon{background:var(--seal-soft);border-color:#eed5cf;color:var(--seal)}
.msg.warn .micon{background:var(--amber-soft);border-color:#e8d9b5;color:var(--amber)}
.msg.ok .micon{background:var(--jade-soft);border-color:#cfe0d6;color:var(--jade)}
.msg .mc{flex:1;min-width:0}
.msg .mt{font-size:13.5px;font-weight:600;display:flex;align-items:center;gap:7px}
.msg .mt .time{margin-left:auto;font-size:10.5px;font-family:var(--font-mono);color:var(--ink3);font-weight:400}
.msg .mb{font-size:11.5px;color:var(--ink3);margin-top:4px;line-height:1.55;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.unread{width:7px;height:7px;border-radius:50%;background:var(--seal);flex:none}
/* 底部 tab */
.tabbar{
flex:none;display:flex;border-top:1px solid var(--line);background:var(--paper2);padding:8px 0 16px;
}
.tabbar a{
flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;font-size:10px;color:var(--ink3);
text-decoration:none;cursor:pointer;position:relative;
}
.tabbar a.on{color:var(--ink);font-weight:600}
.tabbar a .ico{font-size:19px}
.tabbar a .nb{
position:absolute;top:-3px;right:50%;margin-right:-19px;background:var(--seal);color:#fff;
font-size:9px;font-family:var(--font-mono);padding:0 4px;border-radius:8px;line-height:14px;min-width:14px;text-align:center;
}
/* ── 滑动通过 ── */
.swipe-wrap{position:relative;border-radius:12px;overflow:hidden;margin-bottom:9px}
.swipe-bg{
position:absolute;inset:0;background:var(--jade);display:flex;align-items:center;
padding-left:20px;gap:9px;color:#fff;font-size:14px;font-weight:600;letter-spacing:.06em;
}
.swipe-bg .ico{font-size:20px;stroke-width:2.2}
.swipe-card{
position:relative;background:var(--card);border:1px solid var(--line);border-radius:12px;
padding:14px;display:flex;gap:12px;align-items:center;
transform:translateX(104px);box-shadow:-6px 0 18px -8px rgba(27,36,48,.3);
}
.swipe-card .avatar{
width:42px;height:42px;border-radius:10px;flex:none;display:flex;align-items:center;justify-content:center;
font-family:var(--font-display);font-size:17px;font-weight:600;background:var(--paper);border:1px solid var(--line);color:var(--ink2);
}
.swipe-card .sc-i{flex:1;min-width:0}
.swipe-card .sc-n{font-size:14.5px;font-weight:600}
.swipe-card .sc-s{font-size:11.5px;color:var(--ink3);margin-top:4px}
.swipe-hint{
display:flex;align-items:center;gap:9px;padding:11px 14px;border-radius:11px;
background:var(--jade-soft);border:1px solid #cfe0d6;font-size:11.5px;color:#245341;line-height:1.6;margin-bottom:13px;
}
.swipe-hint .ico{flex:none;font-size:16px}
.swipe-hint b{font-weight:600}
/* 二次确认弹层 */
.confirm{
position:absolute;left:14px;right:14px;bottom:14px;z-index:20;background:var(--paper2);
border-radius:16px;box-shadow:0 -12px 40px -10px rgba(27,36,48,.42);padding:20px 18px 18px;
}
.confirm h4{font-family:var(--font-display);font-size:17px;font-weight:600;letter-spacing:.04em;text-align:center;margin-bottom:9px}
.confirm p{font-size:12.5px;color:var(--ink2);line-height:1.7;text-align:center;margin-bottom:17px}
.confirm .cbtns{display:flex;gap:10px}
.confirm .cbtns .btn{margin:0}
/* 说明区 */
.apron{max-width:1560px;margin:0 auto;padding:0 40px}
.apron h3{font-family:var(--font-display);font-size:19px;letter-spacing:.05em;margin:44px 0 16px;padding-bottom:10px;border-bottom:1px solid var(--line2)}
.aside-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(290px,1fr));gap:20px}
.aside-card{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:17px;font-size:12.5px;line-height:1.8;color:var(--ink2)}
.aside-card h4{font-size:13.5px;color:var(--ink);margin-bottom:9px;letter-spacing:.03em;display:flex;align-items:center;gap:8px;font-weight:600}
.aside-card h4 .n{font-family:var(--font-mono);font-size:10.5px;color:var(--seal);border:1px solid var(--seal);border-radius:3px;padding:0 5px}
.aside-card code{font-family:var(--font-mono);font-size:11px;background:var(--paper);border:1px solid var(--line);border-radius:3px;padding:1px 4px}
</style>
</head>
<body>
<!-- ══ 图标库 ══ -->
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
<symbol id="i-back" viewBox="0 0 24 24"><path d="M15 18l-6-6 6-6"/></symbol>
<symbol id="i-chev" viewBox="0 0 24 24"><path d="M9 6l6 6-6 6"/></symbol>
<symbol id="i-signal" viewBox="0 0 24 24"><path d="M4 18v-2M9 18v-5M14 18v-8M19 18V7"/></symbol>
<symbol id="i-wifi" viewBox="0 0 24 24"><path d="M4 9.6a12.5 12.5 0 0 1 16 0M7 13a8 8 0 0 1 10 0"/><circle cx="12" cy="17.2" r="1.1"/></symbol>
<symbol id="i-users" viewBox="0 0 24 24"><circle cx="9" cy="8.4" r="3.4"/><path d="M3 19.2c0-3.1 2.7-5.2 6-5.2s6 2.1 6 5.2"/><path d="M16.2 5.6a3.4 3.4 0 0 1 0 6.4M17.6 14.4c2 .6 3.4 2.3 3.4 4.8"/></symbol>
<symbol id="i-mega" viewBox="0 0 24 24"><path d="M4 10.2v3.6a1.4 1.4 0 0 0 1.4 1.4h1.9L14 19.4V4.6L7.3 8.8H5.4A1.4 1.4 0 0 0 4 10.2z"/><path d="M17.4 9.2a4 4 0 0 1 0 5.6M19.8 6.8a7.4 7.4 0 0 1 0 10.4"/></symbol>
<symbol id="i-check" viewBox="0 0 24 24"><path d="M5 12.6l4.5 4.5L19 7.4"/></symbol>
<symbol id="i-check-circle" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M8.2 12.2l2.6 2.6 5-5.2"/></symbol>
<symbol id="i-alert" viewBox="0 0 24 24"><path d="M12 4.3l8.8 15.2H3.2z"/><path d="M12 10v3.9M12 16.9v.5"/></symbol>
<symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.4V12l3 2"/></symbol>
<symbol id="i-image" viewBox="0 0 24 24"><rect x="3.5" y="4.5" width="17" height="15" rx="2.2"/><circle cx="8.8" cy="9.8" r="1.6"/><path d="M4 17.5l4.5-4.5 3.5 3.5 3-3 4.5 4.5"/></symbol>
<symbol id="i-idcard" viewBox="0 0 24 24"><rect x="2.5" y="5" width="19" height="14" rx="2.2"/><circle cx="8.5" cy="11.4" r="2.1"/><path d="M5.2 16.4c.6-1.5 1.8-2.3 3.3-2.3s2.7.8 3.3 2.3"/><path d="M14.5 10.2h4.3M14.5 13.6h4.3"/></symbol>
<symbol id="i-file" viewBox="0 0 24 24"><path d="M13.5 3.5H7A1.8 1.8 0 0 0 5.2 5.3v13.4A1.8 1.8 0 0 0 7 20.5h10a1.8 1.8 0 0 0 1.8-1.8V9z"/><path d="M13.5 3.5V9h5.3"/></symbol>
<symbol id="i-stamp" viewBox="0 0 24 24"><circle cx="12" cy="8.8" r="5.4"/><path d="M9.4 13.4L8 20.5h8l-1.4-7.1"/></symbol>
<symbol id="i-bell" viewBox="0 0 24 24"><path d="M17.4 16.4V11a5.4 5.4 0 0 0-10.8 0v5.4L5.2 18.4h13.6z"/><path d="M10 18.4a2 2 0 0 0 4 0"/></symbol>
<symbol id="i-bulb" viewBox="0 0 24 24"><path d="M12 3.5a5.4 5.4 0 0 0-3.2 9.8c.5.4.8 1 .8 1.6v1.1h4.8v-1.1c0-.6.3-1.2.8-1.6A5.4 5.4 0 0 0 12 3.5z"/><path d="M9.8 18.6h4.4M10.4 21h3.2"/></symbol>
<symbol id="i-mic" viewBox="0 0 24 24"><rect x="9" y="3.4" width="6" height="10.4" rx="3"/><path d="M5.6 11.6a6.4 6.4 0 0 0 12.8 0M12 18v2.6"/></symbol>
<symbol id="i-filter" viewBox="0 0 24 24"><path d="M3.8 5.6h16.4l-6.4 7.5v5.6l-3.6 1.9v-7.5z"/></symbol>
<symbol id="i-swap" viewBox="0 0 24 24"><path d="M4 8.4h13M14 4.6l3.8 3.8-3.8 3.8M20 15.6H7M10 11.8L6.2 15.6l3.8 3.8"/></symbol>
<symbol id="i-lock" viewBox="0 0 24 24"><rect x="4.5" y="10.5" width="15" height="10" rx="2.2"/><path d="M8 10.5V7.5a4 4 0 0 1 8 0v3"/><path d="M12 14.5v2.5"/></symbol>
<symbol id="i-home" viewBox="0 0 24 24"><path d="M3.8 10.4L12 4l8.2 6.4v9.2a1.4 1.4 0 0 1-1.4 1.4H5.2a1.4 1.4 0 0 1-1.4-1.4z"/></symbol>
<symbol id="i-inbox" viewBox="0 0 24 24"><path d="M3.8 13.4h4.2l1.4 2.6h5.2l1.4-2.6h4.2"/><path d="M5.6 5.2h12.8l1.8 8.2v4.4a1.6 1.6 0 0 1-1.6 1.6H5.4a1.6 1.6 0 0 1-1.6-1.6v-4.4z"/></symbol>
<symbol id="i-zoom" viewBox="0 0 24 24"><circle cx="11" cy="11" r="6.4"/><path d="M15.7 15.7l4.8 4.8M8.6 11h4.8M11 8.6v4.8"/></symbol>
</svg>
<header class="masthead">
<div class="kicker">Prototype · 班主任端 · V1.1</div>
<h1>填报通 · <em>班主任端</em>交互原型</h1>
<p class="sub">
9 屏:<strong>花名册看板 → 待审列表 → 学生详情 → 批量通过 / 右滑通过 / 驳回 → 催报 → 消息 → 代传</strong>。<br>
视觉隐喻为「<strong>电子花名册</strong>」——把全班排成网格,一眼扫完;与学生端共用「档案室 / 电子卷宗」的设计语言。
</p>
<div class="compare">
<div>
<h5><svg class="ico"><use href="#i-users"/></svg>学生端:极简</h5>
几乎不用打字。校对着点两下 + 传文件,一屏搞定。目标:<b>一次填对、不返工</b>。
</div>
<div>
<h5><svg class="ico"><use href="#i-inbox"/></svg>班主任端:高密度</h5>
一屏看完全班 40 人、3 次点击处理一个学生、批量操作。<b>手机单手可操作</b>——通常在通勤路上处理。
</div>
</div>
</header>
<main class="gallery">
<!-- ① 班级看板 -->
<figure>
<div class="device"><div class="screen">
<div class="statusbar"><span>9:41</span><span class="icons"><svg class="ico"><use href="#i-signal"/></svg><svg class="ico"><use href="#i-wifi"/></svg><i class="bat"></i></span></div>
<div class="navbar">
<span class="back"><svg class="ico"><use href="#i-back"/></svg></span>我的班级
<span class="navact"><svg class="ico"><use href="#i-bell"/></svg></span>
</div>
<div class="body flush" style="overflow-y:auto">
<div class="dashhead">
<div class="dh-top">
<div>
<div class="dh-name">24中技数控1班</div>
<div class="dh-sub">2026年9月机电认定 · 截止 <span class="urgent">10-15</span> 剩 3 天</div>
</div>
<div class="rate" style="flex-direction:column;align-items:flex-end;gap:4px">
<div style="display:flex;align-items:baseline;gap:3px">
<span class="n">82</span><span class="d">%</span>
</div>
<span style="font-size:10px;font-family:var(--font-mono);color:var(--ink3);letter-spacing:.05em">已提交率 23/28</span>
</div>
</div>
<div class="bar">
<i class="b-pass" style="width:53.6%"></i>
<i class="b-audit" style="width:14.3%"></i>
<i class="b-warn" style="width:10.7%"></i>
<i class="b-crit" style="width:3.6%"></i>
</div>
<div class="statrow">
<span><i class="sdot pass"></i>已通过 15</span>
<span><i class="sdot audit"></i>待我审 4</span>
<span><i class="sdot warn"></i>待核对 3</span>
<span><i class="sdot crit"></i>有问题 1</span>
<span><i class="sdot none"></i>未提交 5</span>
</div>
</div>
<div style="padding:13px 15px 0">
<button class="btn seal" style="font-size:14px;padding:12px">
<svg class="ico"><use href="#i-mega"/></svg> 一键催报 5 位未提交
</button>
</div>
<div class="roster">
<div class="rhead">
<span class="rtitle">花名册 · 28 人</span>
<span class="rtitle" style="color:var(--seal)">点格子看详情</span>
</div>
<div class="grid">
<div class="cell crit"><span class="nm">陈子文</span><span class="st">待处理</span></div>
<div class="cell warn"><span class="nm">杨晨</span><span class="st">低清</span></div>
<div class="cell warn"><span class="nm">曹文锋</span><span class="st">待核对</span></div>
<div class="cell warn"><span class="nm">黎思明</span><span class="st">待核对</span></div>
<div class="cell audit"><span class="nm">李绍康</span><span class="st">待审</span></div>
<div class="cell audit"><span class="nm">何天宇</span><span class="st">待审</span></div>
<div class="cell audit"><span class="nm">曾云天</span><span class="st">待审</span></div>
<div class="cell pass"><span class="nm">熊宇豪</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">魏航</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">余饶平</span><span class="st">已通过</span></div>
<div class="cell audit"><span class="nm">曾伊豪</span><span class="st">待审</span></div>
<div class="cell pass"><span class="nm">卢宇俊</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">于豪</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">杜明韬</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">朱彬宇</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">刘俊宇</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">何森辉</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">江训坚</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">涂子峰</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">郑志滔</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">廖俊杰</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">刘羿江</span><span class="st">已通过</span></div>
<div class="cell pass"><span class="nm">唐昊宇</span><span class="st">已通过</span></div>
<div class="cell none"><span class="nm">谭宇峰</span><span class="st">未交</span></div>
<div class="cell none"><span class="nm">邱文俊</span><span class="st">未交</span></div>
<div class="cell none"><span class="nm">张仕勋</span><span class="st">未交</span></div>
<div class="cell none"><span class="nm">宋应兴</span><span class="st">未交</span></div>
<div class="cell none"><span class="nm">徐程宇</span><span class="st">未交</span></div>
</div>
<div class="legend2">
<span><i class="sdot crit"></i>有问题须处理</span>
<span><i class="sdot warn"></i>待核对</span>
<span><i class="sdot audit"></i>待我审</span>
<span><i class="sdot pass"></i>已通过</span>
<span><i class="sdot none"></i>未提交</span>
</div>
</div>
</div>
<div class="tabbar">
<a class="on"><svg class="ico"><use href="#i-home"/></svg>看板</a>
<a><svg class="ico"><use href="#i-inbox"/></svg>待审<span class="nb">4</span></a>
<a><svg class="ico"><use href="#i-mega"/></svg>催报</a>
<a><svg class="ico"><use href="#i-bell"/></svg>消息<span class="nb">2</span></a>
</div>
</div></div>
<figcaption>
<span class="tag">STEP 01 · 核心屏</span>
<b>班级看板:电子花名册,一屏扫完 28 人</b>
用<b style="display:inline">网格</b>而不是列表——列表必须滚动才能看全,网格可以一屏扫完。每个格子就是一个人,颜色即状态。<br>
「陈子文」那格是<b style="display:inline;color:var(--seal)">唯一红色的</b>,带呼吸动画——它需要我做决定,其余都是看一眼就过的。
</figcaption>
</figure>
<!-- ② 待审列表 -->
<figure>
<div class="device"><div class="screen">
<div class="statusbar"><span>9:41</span><span class="icons"><svg class="ico"><use href="#i-signal"/></svg><svg class="ico"><use href="#i-wifi"/></svg><i class="bat"></i></span></div>
<div class="navbar"><span class="back"><svg class="ico"><use href="#i-back"/></svg></span>待我审核
<span class="navact"><svg class="ico"><use href="#i-filter"/></svg>筛选</span>
</div>
<div class="filters">
<span class="chip on">全部 <span class="cnt">8</span></span>
<span class="chip">有问题 <span class="cnt">1</span></span>
<span class="chip">待核对 <span class="cnt">3</span></span>
<span class="chip">可批量 <span class="cnt">4</span></span>
</div>
<div class="body flush">
<div class="stu crit">
<div class="avatar">陈</div>
<div class="sinfo">
<div class="sname">陈子文 <span class="badge crit"><svg class="ico"><use href="#i-alert"/></svg>需处理</span></div>
<div class="sissue">一寸照片的证件号和其他材料对不上,疑似传错人</div>
<div class="mstrip">
<i class="bad"><svg class="ico"><use href="#i-image"/></svg></i>
<i><svg class="ico"><use href="#i-idcard"/></svg></i>
<i><svg class="ico"><use href="#i-file"/></svg></i>
<i><svg class="ico"><use href="#i-stamp"/></svg></i>
</div>
</div>
<span class="chev"><svg class="ico"><use href="#i-chev"/></svg></span>
</div>
<div class="stu warn">
<div class="avatar">杨</div>
<div class="sinfo">
<div class="sname">杨晨 <span class="badge warn"><svg class="ico"><use href="#i-alert"/></svg>待核对</span></div>
<div class="sissue">姓名已纠正(扬晨 → 杨晨);身份证图偏小 558×745</div>
<div class="mstrip">
<i><svg class="ico"><use href="#i-image"/></svg></i>
<i class="warn2"><svg class="ico"><use href="#i-idcard"/></svg></i>
<i><svg class="ico"><use href="#i-file"/></svg></i>
<i><svg class="ico"><use href="#i-stamp"/></svg></i>
</div>
</div>
<span class="chev"><svg class="ico"><use href="#i-chev"/></svg></span>
</div>
<div class="stu warn">
<div class="avatar">曹</div>
<div class="sinfo">
<div class="sname">曹文锋 <span class="badge warn"><svg class="ico"><use href="#i-alert"/></svg>待核对</span></div>
<div class="sissue">一寸照片证件号仅 17 位,已按名单补齐,请确认</div>
<div class="mstrip">
<i class="warn2"><svg class="ico"><use href="#i-image"/></svg></i>
<i><svg class="ico"><use href="#i-idcard"/></svg></i>
<i><svg class="ico"><use href="#i-file"/></svg></i>
<i><svg class="ico"><use href="#i-stamp"/></svg></i>
</div>
</div>
<span class="chev"><svg class="ico"><use href="#i-chev"/></svg></span>
</div>
<div class="stu warn">
<div class="avatar">黎</div>
<div class="sinfo">
<div class="sname">黎思明 <span class="badge warn"><svg class="ico"><use href="#i-alert"/></svg>待核对</span></div>
<div class="sissue">身份证证件号仅 17 位,已按名单补齐,请确认</div>
<div class="mstrip">
<i><svg class="ico"><use href="#i-image"/></svg></i>
<i class="warn2"><svg class="ico"><use href="#i-idcard"/></svg></i>
<i><svg class="ico"><use href="#i-file"/></svg></i>
<i><svg class="ico"><use href="#i-stamp"/></svg></i>
</div>
</div>
<span class="chev"><svg class="ico"><use href="#i-chev"/></svg></span>
</div>
<div class="stu">
<div class="avatar">曾</div>
<div class="sinfo">
<div class="sname">曾伊豪 <span class="badge ok"><svg class="ico"><use href="#i-check"/></svg>可批量</span></div>
<div class="sissue">刚提交 · 4 项材料齐全,无问题</div>
<div class="mstrip">
<i><svg class="ico"><use href="#i-image"/></svg></i>
<i><svg class="ico"><use href="#i-idcard"/></svg></i>
<i><svg class="ico"><use href="#i-file"/></svg></i>
<i><svg class="ico"><use href="#i-stamp"/></svg></i>
</div>
</div>
<span class="chev"><svg class="ico"><use href="#i-chev"/></svg></span>
</div>
<div class="stu">
<div class="avatar">李</div>
<div class="sinfo">
<div class="sname">李绍康 <span class="badge ok"><svg class="ico"><use href="#i-check"/></svg>可批量</span></div>
<div class="sissue">4 项材料齐全,无问题</div>
<div class="mstrip">
<i><svg class="ico"><use href="#i-image"/></svg></i>
<i><svg class="ico"><use href="#i-idcard"/></svg></i>
<i><svg class="ico"><use href="#i-file"/></svg></i>
<i><svg class="ico"><use href="#i-stamp"/></svg></i>
</div>
</div>
<span class="chev"><svg class="ico"><use href="#i-chev"/></svg></span>
</div>
<div class="stu">
<div class="avatar">何</div>
<div class="sinfo">
<div class="sname">何天宇 <span class="badge ok"><svg class="ico"><use href="#i-check"/></svg>可批量</span></div>
<div class="sissue">4 项材料齐全,无问题</div>
<div class="mstrip">
<i><svg class="ico"><use href="#i-image"/></svg></i>
<i><svg class="ico"><use href="#i-idcard"/></svg></i>
<i><svg class="ico"><use href="#i-file"/></svg></i>
<i><svg class="ico"><use href="#i-stamp"/></svg></i>
</div>
</div>
<span class="chev"><svg class="ico"><use href="#i-chev"/></svg></span>
</div>
<div class="stu">
<div class="avatar">曾</div>
<div class="sinfo">
<div class="sname">曾云天 <span class="badge ok"><svg class="ico"><use href="#i-check"/></svg>可批量</span></div>
<div class="sissue">4 项材料齐全,无问题</div>
<div class="mstrip">
<i><svg class="ico"><use href="#i-image"/></svg></i>
<i><svg class="ico"><use href="#i-idcard"/></svg></i>
<i><svg class="ico"><use href="#i-file"/></svg></i>
<i><svg class="ico"><use href="#i-stamp"/></svg></i>
</div>
</div>
<span class="chev"><svg class="ico"><use href="#i-chev"/></svg></span>
</div>
</div>
<div class="foot">
<button class="btn jade">批量通过 4 人(仅无问题)</button>
</div>
</div></div>
<figcaption>
<span class="tag">STEP 02</span>
<b>待审列表:异常优先 + 材料缩略条</b>
默认按<b style="display:inline">异常优先</b>排序——红色排最前,绿色的沉到底部。<br>
每条右侧那条「缩略条」是 4 项材料的状态速览:<b style="display:inline">虚线=没交、琥珀=有疑点、朱红=有问题</b>。不用点进去就知道哪里不对。<br>
绿色项还支持<b style="display:inline">右滑直接通过</b>(见 STEP 09);有疑点的项滑不动,必须点进去逐个判断。
</figcaption>
</figure>
<!-- ③ 学生详情 -->
<figure>
<div class="device"><div class="screen">
<div class="statusbar"><span>9:41</span><span class="icons"><svg class="ico"><use href="#i-signal"/></svg><svg class="ico"><use href="#i-wifi"/></svg><i class="bat"></i></span></div>
<div class="navbar"><span class="back"><svg class="ico"><use href="#i-back"/></svg></span>陈子文
<span class="navact"><svg class="ico"><use href="#i-zoom"/></svg>放大</span>
</div>
<div class="body">
<div class="compare-bar">
<div class="cbtn on">一寸照片 1/4</div>
<div class="cbtn">原图 / 处理后</div>
</div>
<div class="preview">
<div class="badge-tr">295 × 413 · 96KB</div>
<div class="fake">
<b>证件照</b>
<span></span><span class="s"></span>
<span class="s"></span>
</div>
<div class="dots"><i class="on"></i><i></i><i></i><i></i></div>
</div>
<div class="panel">
<div class="ptitle">系统发现 1 个问题 <span class="badge crit">需你判断</span></div>
<div class="issue crit">
<span class="ii"><svg class="ico"><use href="#i-alert"/></svg></span>
<div class="it">
<b>这张「一寸照片」的证件号,和陈子文其他材料对不上</b><br>
<span class="mono">照片文件名:360122200902044232</span><br>
<span class="mono">其他材料:36010520090817121X</span><br>
两个号码校验位都通过 → <b>是两个不同的人</b>,不是打字错误。
</div>
</div>
</div>
<div class="panel">
<div class="ptitle">其他 3 项材料</div>
<div class="issue ok"><span class="ii"><svg class="ico"><use href="#i-check-circle"/></svg></span>
<div class="it">身份证 <span class="mono">已规范 · 810KB</span></div></div>
<div class="issue ok"><span class="ii"><svg class="ico"><use href="#i-check-circle"/></svg></span>
<div class="it">学籍表 <span class="mono">已规范 · 41KB</span></div></div>
<div class="issue ok"><span class="ii"><svg class="ico"><use href="#i-check-circle"/></svg></span>
<div class="it">工作证明 <span class="mono">已规范 · 806KB</span></div></div>
</div>
</div>
<div class="foot">
<div class="btnrow">
<button class="btn ghost">驳回</button>
<button class="btn jade">通过</button>
</div>
</div>
</div></div>
<figcaption>
<span class="tag">STEP 03</span>
<b>学生详情:给结论,也给我依据</b>
不只说"有问题",而是把<b style="display:inline">两个号码并列摆出来</b>,并指出<b style="display:inline">校验位都通过 = 是两个人而不是打字错误</b>。<br>
班主任不需要懂身份证算法,只需要看懂这个结论——<b style="display:inline">判断依据由系统给出,判断权交给人</b>。
</figcaption>
</figure>
<!-- ④ 批量通过 -->
<figure>
<div class="device"><div class="screen">
<div class="statusbar"><span>9:41</span><span class="icons"><svg class="ico"><use href="#i-signal"/></svg><svg class="ico"><use href="#i-wifi"/></svg><i class="bat"></i></span></div>
<div class="navbar"><span class="back"><svg class="ico"><use href="#i-back"/></svg></span>批量通过</div>
<div class="body flush">
<div style="padding:14px 15px;background:#fff;border-bottom:1px solid var(--line)">
<div style="font-size:13.5px;font-weight:600">将通过的 4 人</div>
<div style="font-size:11.5px;color:var(--ink3);margin-top:5px;line-height:1.6">
只包含<b style="color:var(--ink)">全部材料无问题</b>的填报单。有疑点的已自动排除,不会被批量带过。
</div>
</div>
<div class="batch">
<input type="checkbox" class="cbx" checked>
<div class="binfo"><div class="bname">曾伊豪</div><div class="bsub">4/4 项 · 无问题</div></div>
<span class="badge ok"><svg class="ico"><use href="#i-check"/></svg>可批量</span>
</div>
<div class="batch">
<input type="checkbox" class="cbx" checked>
<div class="binfo"><div class="bname">李绍康</div><div class="bsub">4/4 项 · 无问题</div></div>
<span class="badge ok"><svg class="ico"><use href="#i-check"/></svg>可批量</span>
</div>
<div class="batch">
<input type="checkbox" class="cbx" checked>
<div class="binfo"><div class="bname">何天宇</div><div class="bsub">4/4 项 · 无问题</div></div>
<span class="badge ok"><svg class="ico"><use href="#i-check"/></svg>可批量</span>
</div>
<div class="batch">
<input type="checkbox" class="cbx" checked>
<div class="binfo"><div class="bname">曾云天</div><div class="bsub">4/4 项 · 无问题</div></div>
<span class="badge ok"><svg class="ico"><use href="#i-check"/></svg>可批量</span>
</div>
<div class="skipnote">
<svg class="ico"><use href="#i-alert"/></svg>
<div><b>已自动排除 4 人</b>(陈子文 / 杨晨 / 曹文锋 / 黎思明)——他们有疑点需要你逐个判断,系统不会替你放行。</div>
</div>
<div class="batch skipped">
<input type="checkbox" class="cbx" disabled>
<div class="binfo"><div class="bname">陈子文</div><div class="bsub">1 项有问题</div></div>
<span class="badge crit">已排除</span>
</div>
<div class="batch skipped">
<input type="checkbox" class="cbx" disabled>
<div class="binfo"><div class="bname">杨晨</div><div class="bsub">2 项待核对</div></div>
<span class="badge warn">已排除</span>
</div>
<div class="batch skipped">
<input type="checkbox" class="cbx" disabled>
<div class="binfo"><div class="bname">曹文锋</div><div class="bsub">1 项待核对</div></div>
<span class="badge warn">已排除</span>
</div>
<div class="batch skipped">
<input type="checkbox" class="cbx" disabled>
<div class="binfo"><div class="bname">黎思明</div><div class="bsub">1 项待核对</div></div>
<span class="badge warn">已排除</span>
</div>
</div>
<div class="foot">
<button class="btn jade">通过 4 人</button>
<div style="text-align:center;font-size:11.5px;color:var(--ink3);margin-top:11px;line-height:1.6">
通过后进入管理员终审,你仍可在终审前撤回
</div>
</div>
</div></div>
<figcaption>
<span class="tag">STEP 04 · 安全闸门</span>
<b>批量通过:只带无问题的,红黄一律排除</b>
展开后把两种人<b style="display:inline">并列展示</b>:上面是可批量的(默认勾选),下面是已排除的(置灰 + 写明原因)。<br>
<b style="display:inline;color:var(--seal)">这是防"手快全选"的关键设计</b>——如果只显示可批量的 4 人,班主任不会意识到自己放过了 4 个有疑点的。让他看见被排除了谁,他才会去想"为什么"。
</figcaption>
</figure>
<!-- ⑤ 驳回 -->
<figure>
<div class="device"><div class="screen">
<div class="statusbar"><span>9:41</span><span class="icons"><svg class="ico"><use href="#i-signal"/></svg><svg class="ico"><use href="#i-wifi"/></svg><i class="bat"></i></span></div>
<div class="navbar"><span class="back"><svg class="ico"><use href="#i-back"/></svg></span>驳回 陈子文</div>
<div class="body">
<div class="panel">
<div class="ptitle">驳回哪一项</div>
<div class="reasons">
<span class="rchip on">一寸照片</span>
<span class="rchip">身份证</span>
<span class="rchip">学籍表</span>
<span class="rchip">工作证明</span>
</div>
</div>
<div class="panel">
<div class="ptitle">驳回原因 <span class="badge lock">必选</span></div>
<div class="reasons">
<span class="rchip on">材料不是本人</span>
<span class="rchip">照片模糊,请重新提供</span>
<span class="rchip">身份证号与名单不符</span>
<span class="rchip">文件超过 1M</span>
<span class="rchip">工作证明未盖公章</span>
<span class="rchip">缺少材料</span>
<span class="rchip">其他(手填)</span>
</div>
</div>
<div class="panel">
<div class="ptitle">补充说明 <span class="badge lock">选填</span></div>
<textarea class="ta" placeholder="还可以补充一句说明,学生打开就能看到…">这张照片上的身份证号不是你,请核对后重新上传你本人的一寸照片。</textarea>
<div style="display:flex;align-items:center;gap:8px;margin-top:11px;font-size:12px;color:var(--ink3)">
<svg class="ico lg"><use href="#i-mic"/></svg>长按说话,自动转文字
</div>
</div>
<div class="notice info" style="margin-bottom:0">
<svg class="ico lg"><use href="#i-bulb"/></svg>
<div>学生收到通知后修改重传,会<b>回到你的待办</b>。这是第 <b>1</b> 次驳回。</div>
</div>
</div>
<div class="foot">
<div class="btnrow">
<button class="btn ghost">取消</button>
<button class="btn seal">确认驳回</button>
</div>
</div>
</div></div>
<figcaption>
<span class="tag">STEP 05</span>
<b>驳回:原因必选,但不必打字</b>
常用原因做成<b style="display:inline">快捷标签</b>——80% 的驳回一句话就够。文字框是补充,不是必填。<br>
支持<b style="display:inline">语音转文字</b>:班主任常在通勤路上,单手打字很痛苦。
</figcaption>
</figure>
<!-- ⑥ 催报 -->
<figure>
<div class="device"><div class="screen">
<div class="statusbar"><span>9:41</span><span class="icons"><svg class="ico"><use href="#i-signal"/></svg><svg class="ico"><use href="#i-wifi"/></svg><i class="bat"></i></span></div>
<div class="navbar"><span class="back"><svg class="ico"><use href="#i-back"/></svg></span>催报</div>
<div class="body">
<div class="quota">
<svg class="ico lg"><use href="#i-bulb"/></svg>
<div>微信订阅消息<b>每人只剩 2 次额度</b>。系统会在额度用尽时自动改用短信,但短信按条计费——建议<b>合并催报</b>,不要一天催三次。</div>
</div>
<div class="panel flush">
<div style="padding:15px 15px 11px">
<div class="ptitle" style="margin:0">未提交 5 人 <span class="badge crit">剩 3 天截止</span></div>
</div>
<div class="person"><span class="pn">谭宇峰</span><span class="pt">178****3238</span><span class="pact">单独催</span></div>
<div class="person"><span class="pn">邱文俊</span><span class="pt">136****1102</span><span class="pact">单独催</span></div>
<div class="person"><span class="pn">张仕勋</span><span class="pt">158****1859</span><span class="pact">单独催</span></div>
<div class="person"><span class="pn">宋应兴</span><span class="pt">139****0016</span><span class="pact">单独催</span></div>
<div class="person"><span class="pn">徐程宇</span><span class="pt">187****2334</span><span class="pact">单独催</span></div>
</div>
<div class="panel">
<div class="ptitle">催报记录</div>
<div class="issue" style="border-top:0;padding-top:2px">
<span class="ii"><svg class="ico"><use href="#i-mega"/></svg></span>
<div class="it">今天 09:12 群发 5 人<br><span style="font-size:11px;color:var(--ink3)">微信订阅消息 · 4 人送达 · 1 人额度不足</span></div>
</div>
<div class="issue">
<span class="ii"><svg class="ico"><use href="#i-mega"/></svg></span>
<div class="it">昨天 10:30 群发 8 人<br><span style="font-size:11px;color:var(--ink3)">微信订阅消息 · 8 人送达 · 3 人已提交</span></div>
</div>
</div>
</div>
<div class="foot"><button class="btn seal"><svg class="ico"><use href="#i-mega"/></svg> 再催一次 5 人</button></div>
</div></div>
<figcaption>
<span class="tag">STEP 06</span>
<b>催报:先说清代价,再让人决定</b>
微信订阅消息<b style="display:inline">是有额度的</b>——一次授权只能发一条,用尽就得走短信(要花钱)。<br>
所以这里不藏这个事实,把<b style="display:inline">剩余额度</b>和<b style="display:inline">每条历史记录的实际送达情况</b>摆出来,让班主任自己权衡。
</figcaption>
</figure>
<!-- ⑦ 消息 -->
<figure>
<div class="device"><div class="screen">
<div class="statusbar"><span>9:41</span><span class="icons"><svg class="ico"><use href="#i-signal"/></svg><svg class="ico"><use href="#i-wifi"/></svg><i class="bat"></i></span></div>
<div class="navbar"><span class="back"><svg class="ico"><use href="#i-back"/></svg></span>消息</div>
<div class="body flush">
<div class="msg crit">
<div class="micon"><svg class="ico"><use href="#i-alert"/></svg></div>
<div class="mc"><div class="mt">陈子文 的材料有疑点<span class="time">09:41</span></div>
<div class="mb">一寸照片证件号与他其他材料不一致,需要你判断</div></div>
<i class="unread"></i>
</div>
<div class="msg warn">
<div class="micon"><svg class="ico"><use href="#i-clock"/></svg></div>
<div class="mc"><div class="mt">你有 3 份待审超过 24 小时<span class="time">08:00</span></div>
<div class="mb">李绍康、何天宇、曾云天 的填报单等待初审</div></div>
<i class="unread"></i>
</div>
<div class="msg ok">
<div class="micon"><svg class="ico"><use href="#i-check-circle"/></svg></div>
<div class="mc"><div class="mt">曾伊豪 已提交材料<span class="time">昨天</span></div>
<div class="mb">4 项材料齐全,系统未发现问题,可直接通过</div></div>
</div>
<div class="msg">
<div class="micon"><svg class="ico"><use href="#i-mega"/></svg></div>
<div class="mc"><div class="mt">催报已送达 4 人<span class="time">昨天</span></div>
<div class="mb">谭宇峰 的订阅额度不足,已改用短信</div></div>
</div>
<div class="msg">
<div class="micon"><svg class="ico"><use href="#i-file"/></svg></div>
<div class="mc"><div class="mt">管理员导出完成<span class="time">昨天</span></div>
<div class="mb">24中技数控1班 汇总包已生成,共 22.4MB</div></div>
</div>
<div class="msg">
<div class="micon"><svg class="ico"><use href="#i-bulb"/></svg></div>
<div class="mc"><div class="mt">距离截止还有 3 天<span class="time">前天</span></div>
<div class="mb">还有 5 人未提交,建议今天催一次</div></div>
</div>
</div>
</div></div>
<figcaption>
<span class="tag">STEP 07</span>
<b>消息:只推需要我做决定的事</b>
优先级严格排序:<b style="display:inline;color:var(--seal)">要判断的</b> → <b style="display:inline;color:var(--amber)">快超时的</b> → 完成通知 → 系统提醒。<br>
每条消息都带<b style="display:inline">下一步动作的暗示</b>("可直接通过"、"建议今天催一次"),而不是只报事实。
</figcaption>
</figure>
<!-- ⑧ 代传材料 -->
<figure>
<div class="device"><div class="screen">
<div class="statusbar"><span>9:41</span><span class="icons"><svg class="ico"><use href="#i-signal"/></svg><svg class="ico"><use href="#i-wifi"/></svg><i class="bat"></i></span></div>
<div class="navbar"><span class="back"><svg class="ico"><use href="#i-back"/></svg></span>代传材料</div>
<div class="body">
<div class="notice warn">
<svg class="ico lg"><use href="#i-swap"/></svg>
<div>你是<b>代替学生上传</b>。系统会记录<b>代传人是你</b>,审核界面会标注出来。</div>
</div>
<div class="panel">
<div class="ptitle">选择学生</div>
<div class="row"><span class="k">学生</span><span class="v">谭宇峰 · 未提交</span></div>
<div class="row"><span class="k">联系电话</span><span class="v mono">178****3238</span></div>
</div>
<div class="panel flush">
<div style="padding:15px 15px 11px"><div class="ptitle" style="margin:0">要代传哪一项</div></div>
<div class="person" style="cursor:pointer"><svg class="ico lg" style="color:var(--ink2)"><use href="#i-image"/></svg><span class="pn">一寸照片</span><span class="pact">选择</span></div>
<div class="person" style="cursor:pointer"><svg class="ico lg" style="color:var(--ink2)"><use href="#i-idcard"/></svg><span class="pn">身份证</span><span class="pact">选择</span></div>
<div class="person" style="cursor:pointer"><svg class="ico lg" style="color:var(--ink2)"><use href="#i-file"/></svg><span class="pn">学籍表</span><span class="pact">选择</span></div>
<div class="person" style="cursor:pointer"><svg class="ico lg" style="color:var(--ink2)"><use href="#i-stamp"/></svg><span class="pn">工作证明</span><span class="pact">选择</span></div>
</div>
<div class="notice info" style="margin-bottom:0">
<svg class="ico lg"><use href="#i-bulb"/></svg>
<div>代传的材料<b>同样会自动改名、压缩、校验</b>——和学生自己传走完全一样的流程。</div>
</div>
</div>
<div class="foot"><button class="btn primary" disabled>请先选择材料类型</button></div>
</div></div>
<figcaption>
<span class="tag">STEP 08</span>
<b>代传:兜底通道,但必须留痕</b>
总有学生就是不会操作(老旧手机、不在身边、沟通不畅)。<b style="display:inline">代传是必须有的兜底</b>。<br>
但代传会让"谁交的"变模糊,所以<b style="display:inline">记录代传人并在审核界面标注</b>——责任可追溯,也避免老师被误解。
</figcaption>
</figure>
<!-- ⑨ 右滑通过 -->
<figure>
<div class="device"><div class="screen">
<div class="statusbar"><span>9:41</span><span class="icons"><svg class="ico"><use href="#i-signal"/></svg><svg class="ico"><use href="#i-wifi"/></svg><i class="bat"></i></span></div>
<div class="navbar"><span class="back"><svg class="ico"><use href="#i-back"/></svg></span>待我审核
<span class="navact"><svg class="ico"><use href="#i-filter"/></svg>筛选</span>
</div>
<div class="body">
<div class="swipe-hint">
<svg class="ico"><use href="#i-check-circle"/></svg>
<div><b>右滑可通过</b>(松手后需二次确认)。驳回请点进详情——驳回要选原因,不能滑。</div>
</div>
<div class="swipe-wrap">
<div class="swipe-bg">
<svg class="ico"><use href="#i-check"/></svg>通过
</div>
<div class="swipe-card">
<div class="avatar">曾</div>
<div class="sc-i">
<div class="sc-n">曾伊豪</div>
<div class="sc-s">4/4 项材料齐全 · 无问题</div>
</div>
</div>
</div>
<div class="swipe-wrap">
<div class="swipe-bg">
<svg class="ico"><use href="#i-check"/></svg>通过
</div>
<div class="swipe-card" style="transform:translateX(0);box-shadow:none">
<div class="avatar">李</div>
<div class="sc-i">
<div class="sc-n">李绍康</div>
<div class="sc-s">4/4 项材料齐全 · 无问题</div>
</div>
</div>
</div>
<div class="swipe-wrap">
<div class="swipe-bg" style="background:#eef1f4;color:var(--ink3)">
<svg class="ico"><use href="#i-lock"/></svg>需逐个判断
</div>
<div class="swipe-card" style="transform:translateX(0);box-shadow:none">
<div class="avatar" style="background:var(--seal-soft);border-color:#eed5cf;color:var(--seal)">陈</div>
<div class="sc-i">
<div class="sc-n">陈子文</div>
<div class="sc-s" style="color:var(--seal)">1 项有问题 · 不可滑动通过</div>
</div>
</div>
</div>
<div class="swipe-wrap">
<div class="swipe-bg" style="background:#eef1f4;color:var(--ink3)">
<svg class="ico"><use href="#i-lock"/></svg>需逐个判断
</div>
<div class="swipe-card" style="transform:translateX(0);box-shadow:none">
<div class="avatar" style="background:var(--amber-soft);border-color:#e8d9b5;color:var(--amber)">杨</div>
<div class="sc-i">
<div class="sc-n">杨晨</div>
<div class="sc-s" style="color:var(--amber)">2 项待核对 · 不可滑动通过</div>
</div>
</div>
</div>
</div>
<div class="mask" style="background:rgba(27,36,48,.34)"></div>
<div class="confirm">
<h4>确认通过 曾伊豪?</h4>
<p>通过后进入管理员终审。<br>在终审完成前,你仍可撤回。</p>
<div class="cbtns">
<button class="btn ghost">取消</button>
<button class="btn jade">确认通过</button>
</div>
</div>
</div></div>
<figcaption>
<span class="tag">STEP 09 · 已确认的设计决策</span>
<b>只做「右滑通过」,不做「左滑驳回」</b>
通过是<b style="display:inline">正向动作</b>、可撤回,适合低阻力的滑动;驳回是<b style="display:inline">负向动作</b>、要选原因、代价高(学生重传 + 班主任重审)。<br>
<b style="display:inline;color:var(--seal)">两者误触的后果不对称</b>,所以驳回必须点按钮完成。<br>
注意<b style="display:inline">有疑点的卡片滑动层是灰的、写着"需逐个判断"</b>——它根本滑不动,从交互层面堵死"手快滑过"。
</figcaption>
</figure>
</main>
<section class="apron">
<h3>设计依据 · 每一条都对着 PRD 里的约束</h3>
<div class="aside-grid">
<div class="aside-card">
<h4><span class="n">01</span>为什么用网格而不是列表</h4>
PRD §9.4 要求"<b>一屏能看完整班状态,40 人无需滚动超过 2 屏</b>"。列表逐行 60px,40 人要 2400px;网格每格 52px、5 列,40 人只要 8 行 ≈ 420px——<b>真正的一屏看完</b>。
</div>
<div class="aside-card">
<h4><span class="n">02</span>为什么批量通过要显示"被排除了谁"</h4>
PRD 明确"<b>批量通过只带绿色项</b>"。但如果只显示可批量的 4 人,班主任不会意识到还有 4 个疑点被跳过——<b>把排除名单并列展示,是在提醒他"为什么"</b>。
</div>
<div class="aside-card">
<h4><span class="n">03</span>为什么审批动作要 ≤3 次点击</h4>
PRD §9.4 的硬性约束。路径是:<b>列表点人 → 看问题 → 通过/驳回</b>,正好 3 次。详情页不做多层展开、不做标签页切换。
</div>
<div class="aside-card">
<h4><span class="n">04</span>为什么要把"校验位都通过"写出来</h4>
陈子文那单,两个号码<b>各自都合法</b>——这说明是两个人而不是打字错误。<b>班主任不需要懂算法,但需要这个结论</b>才能正确判断该驳回还是该通过。
</div>
<div class="aside-card">
<h4><span class="n">05</span>为什么催报要先说额度</h4>
微信订阅消息<b>发一条消耗一次授权</b>。如果不告知额度,班主任会频繁催报,第 3 次就发不出去了,还会以为系统坏了。<b>把约束前置,比事后解释便宜</b>。
</div>
<div class="aside-card">
<h4><span class="n">06</span>为什么学生端极简、班主任端高密度</h4>
学生是<b>一年用一两次</b>的偶发用户,必须零学习成本;班主任是<b>一学期用几十次</b>的高频用户,愿意为效率接受更密的界面。<b>同一个人群用同一套设计是错的。</b>
</div>
<div class="aside-card">
<h4><span class="n">07</span>为什么只做右滑通过、不做左滑驳回</h4>
通过是<b>正向动作且可撤回</b>,适合低阻力滑动;驳回是<b>负向动作</b>、要选原因、代价高(学生重传 +班主任重审)。<b>误触后果不对称</b>:滑错一个通过最多撤回,滑错一个驳回会打断学生。<br>
有疑点的卡片<b>滑动层是灰的、根本滑不动</b>——从交互层面堵死"手快滑过"。
</div>
</div>
</section>
<script>
const figs=[...document.querySelectorAll('figure')];
figs.forEach(f=>{f.style.opacity='0';f.style.transform='translateY(22px)';
f.style.transition='opacity .6s cubic-bezier(.2,.8,.3,1),transform .6s cubic-bezier(.2,.8,.3,1)';});
const io=new IntersectionObserver(es=>{es.forEach(e=>{if(e.isIntersecting){
const i=figs.indexOf(e.target);
setTimeout(()=>{e.target.style.opacity='1';e.target.style.transform='translateY(0)';},(i%3)*110);
io.unobserve(e.target);}});},{threshold:.12});
figs.forEach(f=>io.observe(f));
document.querySelectorAll('.chip').forEach(c=>c.addEventListener('click',()=>{
c.parentElement.querySelectorAll('.chip').forEach(x=>x.classList.remove('on'));c.classList.add('on');}));
document.querySelectorAll('.rchip').forEach(c=>c.addEventListener('click',()=>c.classList.toggle('on')));
document.querySelectorAll('.cbtn').forEach(c=>c.addEventListener('click',()=>{
c.parentElement.querySelectorAll('.cbtn').forEach(x=>x.classList.remove('on'));c.classList.add('on');}));
</script>
</body>
</html>