Files
iboard/docs/V0.2/任务模块/任务模块界面设计.html
T
jif2.zhang 6c9cd3fd99
Docker Build and Push / build-image (push) Failing after 3m51s
feat(V0.2): 任务模块 —— 项目 / 列表与看板 / 列-状态绑定 / 一级子任务
需求 142 条 (T-*), 设计见 docs/V0.2/任务模块/

数据层:
- 新增 6 张表: Project / ProjectMember / BoardColumn / Task / TaskMember / TaskTag
- 看板列是实体(可增删改排序), Task.columnId 外键 RESTRICT 防误删列丢任务
- Task.status(todo/doing/done) 与 columnId 双落库, 二者正交

领域层 server/task-domain/ (唯一口径, 前后端不重复实现):
- resolveStatus: 列决定状态(只看目标列, 无拖出回退); 状态与列不匹配时按列序取第一个绑定该状态的列自动归位, 无匹配列则不移动; 子任务完全豁免
- retention: 逐列 6 档保留窗口(永不显示/当天/3天/本周/本月/永久显示), 以 doneAt 判定
- copyTask: 跨项目深拷贝, 人员按目标项目成员过滤并回报丢弃名单

接口: /api/projects, /api/columns, /api/tasks (均校验项目成员)

前端:
- 底部 Tab 插入「任务」, 位于「打卡」之后; 默认首页仍为打卡
- 列表视图(子任务缩进+折叠) / 看板视图(长按拖拽换列、拖到卡片降为子任务)
- 列设置(列管理+状态绑定+保留选项) / 任务详情(扩展信息卡片默认收起) / 成员管理
- 视图记忆与上次项目存设备端

已验证: 95 文件语法 0 错误、相对导入 0 缺失、领域逻辑用例全部通过
2026-10-24 11:21:16 +08:00

1281 lines
78 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" />
<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}
table{width:100%;border-collapse:collapse;background:#fff;border:1px solid #e6e8eb;border-radius:10px;overflow:hidden;font-size:12.5px}
th{background:#f7f8fa;text-align:left;font-weight:600;color:var(--muted);padding:9px 12px;border-bottom:1px solid #e6e8eb}
td{padding:9px 12px;border-bottom:1px solid var(--line);vertical-align:top}
tr:last-child td{border-bottom:none}
code{background:#f4f5f7;border-radius:4px;padding:1px 5px;font-size:11.5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:#c7254e}
.note{background:#fff;border-left:3px solid var(--primary);border-radius:0 8px 8px 0;padding:11px 14px;font-size:12.5px;color:var(--muted)}
/* ---------- 设计规范 ---------- */
.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}
/* ---------- 手机 ---------- */
.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}
.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)}
.navbar-sub{height:44px;flex-shrink:0;display:flex;align-items:center;gap:10px;padding:0 14px;background:#fff;border-bottom:1px solid var(--line)}
.navbar-sub .back{font-size:18px;color:var(--muted);line-height:1}
.navbar-sub .title{font-size:16px;font-weight:700}
.navbar-sub .right{margin-left:auto;display:flex;gap:8px}
.body{flex:1;min-height:0;overflow:hidden;background:var(--bg);padding:0 0 8px}
.body.scroll{overflow-y:auto}
.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}
.tag.grey{color:var(--muted);background:#f2f3f5}
/* ---------- 通用组件 ---------- */
.mini-btn{font-size:11px;border:1px solid var(--primary);color:var(--primary);border-radius:999px;padding:3px 10px;background:#fff;white-space:nowrap}
.mini-btn.solid{background:var(--primary);color:#fff;border-color:var(--primary)}
.mini-btn.grey{border-color:#dcdcdc;color:var(--muted)}
.seg{display:flex;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)}
.link{font-size:12px;color:var(--primary)}
.link.danger{color:var(--danger)}
/* 状态点:未开始 / 执行中 / 完成 */
.sdot{width:8px;height:8px;border-radius:50%;flex-shrink:0;display:inline-block}
.sdot.todo{background:#c9ced6}
.sdot.doing{background:var(--primary)}
.sdot.done{background:var(--success)}
.sdot.pill{width:auto;height:auto;border-radius:999px;font-size:10px;padding:1px 6px;color:#fff;line-height:14px}
.sdot.pill.todo{background:#a8b0ba} .sdot.pill.doing{background:var(--primary)} .sdot.pill.done{background:var(--success)}
/* ---------- 项目列表 ---------- */
.proj-head{padding:12px 14px 8px;display:flex;align-items:center}
.proj-head b{font-size:18px;font-weight:700}
.proj-head .right{margin-left:auto;display:flex;gap:6px}
.proj-group{font-size:11px;color:var(--weak);letter-spacing:.5px;padding:10px 16px 6px}
.proj-item{display:flex;align-items:center;gap:12px;background:#fff;border-radius:10px;padding:13px 14px;margin:0 12px 8px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
.proj-item .pico{width:34px;height:34px;border-radius:9px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:14px;font-weight:700;flex-shrink:0}
.proj-item .pmain{flex:1;min-width:0}
.proj-item .ptitle{font-size:14.5px;font-weight:600;display:flex;align-items:center;gap:6px}
.proj-item .psub{font-size:11.5px;color:var(--muted);margin-top:2px}
.proj-item .pcount{font-size:11px;color:var(--weak);text-align:right;flex-shrink:0}
.badge{font-size:10px;color:#ad6800;background:#fff7e6;border-radius:4px;padding:0 5px;font-weight:400}
/* ---------- 列表视图 ---------- */
.pv-head{padding:10px 14px 8px;display:flex;align-items:center;gap:10px;background:var(--bg)}
.pv-head .seg{flex:0 0 112px}
.pv-head .right{margin-left:auto;display:flex;gap:6px}
.filter-bar{display:flex;gap:6px;padding:0 14px 8px;overflow:hidden}
.fchip{font-size:11px;color:var(--muted);background:#fff;border:1px solid #e6e8eb;border-radius:999px;padding:2px 9px;white-space:nowrap}
.fchip.on{color:var(--primary);border-color:var(--primary);background:#f0f5ff}
.group-title{display:flex;align-items:center;gap:7px;padding:12px 16px 6px;font-size:12px;color:var(--muted);font-weight:600}
.group-title::before{content:"";width:3px;height:12px;border-radius:2px;background:var(--primary)}
.group-title .cnt{color:var(--weak);font-weight:400}
.task-row{display:flex;align-items:flex-start;gap:9px;background:#fff;border-radius:9px;padding:10px 12px;margin:0 12px 7px;box-shadow:0 1px 2px rgba(0,0,0,.04)}
.task-row.done{background:#fafbfa}
.task-row .box{width:19px;height:19px;border-radius:50%;border:1.5px solid #d0d0d0;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:1px}
.task-row.done .box{background:var(--success);border-color:var(--success)}
.box svg{opacity:0} .task-row.done .box svg{opacity:1}
.task-main{flex:1;min-width:0}
.task-title{font-size:14px;display:flex;align-items:center;gap:6px}
.task-row.done .task-title{color:#a0a0a0;text-decoration:line-through}
.task-meta{display:flex;align-items:center;gap:8px;margin-top:4px;font-size:11px;color:var(--weak);flex-wrap:wrap}
.task-meta .col{color:var(--primary);background:#f0f5ff;border-radius:4px;padding:0 5px}
.task-meta .assignee{color:var(--text);font-size:12px;font-weight:600}
.task-meta .members{font-size:10.5px;color:var(--weak)}
.task-right{display:flex;align-items:center;gap:6px;flex-shrink:0;margin-top:1px}
.more{color:#c2c7cf;font-size:16px;line-height:1;padding:0 2px}
.sub-row{display:flex;align-items:center;gap:8px;background:#fff;border-radius:8px;padding:8px 12px 8px 30px;margin:-2px 12px 7px 26px;
box-shadow:0 1px 2px rgba(0,0,0,.03);position:relative}
.sub-row::before{content:"";position:absolute;left:14px;top:0;bottom:0;width:1px;background:#e9ecf0}
.sub-row .box{width:16px;height:16px;border-radius:50%;border:1.5px solid #d0d0d0;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.sub-row.done .box{background:var(--success);border-color:var(--success)}
.sub-row .box svg{opacity:0} .sub-row.done .box svg{opacity:1}
.sub-title{flex:1;font-size:13px;color:#444}
.sub-row.done .sub-title{color:#a8a8a8;text-decoration:line-through}
.collapse{font-size:11px;color:var(--primary);padding:4px 0 8px 30px;margin:0 12px}
/* ---------- 看板视图 ---------- */
.board-wrap{display:flex;gap:10px;padding:4px 12px 8px;overflow-x:auto;overflow-y:hidden;height:100%}
.bcol{flex:0 0 186px;display:flex;flex-direction:column;min-height:0}
.bcol-head{display:flex;align-items:center;gap:5px;padding:2px 2px 7px}
.bcol-name{font-size:12px;font-weight:700;color:#3d4450;letter-spacing:.3px}
.bcol-cnt{font-size:11px;color:var(--weak);background:#e8ebef;border-radius:999px;padding:0 6px;line-height:15px}
.bcol-bind{font-size:10px;color:var(--primary);background:#f0f5ff;border-radius:4px;padding:0 4px;margin-left:auto}
.bcol-bind.off{color:var(--weak);background:#f2f3f5}
.bcol-body{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:7px;padding-bottom:8px}
.bcard{background:#fff;border-radius:8px;padding:9px 10px;box-shadow:0 1px 2px rgba(0,0,0,.05)}
.bcard .brow1{display:flex;align-items:flex-start;gap:6px}
.bcard .btitle{flex:1;font-size:12.5px;font-weight:600;line-height:1.45}
.bcard .bmeta{display:flex;align-items:center;gap:6px;margin-top:6px;font-size:10.5px;color:var(--weak)}
.bcard .bassignee{font-size:11px;font-weight:600;color:#4a5160}
.bcard .bmembers{font-size:10px;color:#a7adb6}
.bsub{display:flex;align-items:center;gap:5px;margin-top:5px;padding-top:5px;border-top:1px dashed #eef0f3;font-size:11px;color:#5a616b}
.bsub .sbox{width:13px;height:13px;border-radius:50%;border:1.3px solid #d0d0d0;flex-shrink:0}
.bsub.done .sbox{background:var(--success);border-color:var(--success)}
.bsub .stitle{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bsub.done .stitle{color:#a8a8a8;text-decoration:line-through}
.bsub .sdot{width:6px;height:6px}
.bmore{color:var(--weak);font-size:10px;margin-left:2px}
.badd{background:rgba(255,255,255,.6);border:1px dashed #d5dae1;border-radius:8px;padding:8px;text-align:center;font-size:11.5px;color:var(--weak)}
.bcol.dragover .bcol-body{background:#eaf2ff;border-radius:8px;outline:1.5px dashed var(--primary)}
.dragging{opacity:.55;transform:scale(.97) rotate(-1deg);box-shadow:0 8px 18px rgba(15,23,42,.16)}
/* ---------- 设置 / 弹窗 ---------- */
.set-row{display:flex;align-items:center;gap:10px;background:#fff;padding:12px 14px;margin-bottom:1px}
.set-row .sname{font-size:13.5px;font-weight:600;width:64px;flex-shrink:0}
.set-row .sctrl{flex:1;display:flex;align-items:center;gap:6px;justify-content:flex-end;flex-wrap:wrap}
.set-hint{font-size:11px;color:var(--weak);padding:8px 14px 14px;line-height:1.7}
.drop{border:1px solid var(--line);border-radius:7px;padding:4px 9px;font-size:12px;color:var(--text);background:#fff;min-width:92px;display:flex;align-items:center;gap:6px}
.drop .cv{margin-left:auto;font-size:9px;color:var(--weak)}
.drop.off{color:var(--weak);background:#f7f8fa}
.sw-toggle{width:38px;height:21px;border-radius:999px;background:#dfe3e8;position:relative;flex-shrink:0}
.sw-toggle::after{content:"";position:absolute;top:2px;left:2px;width:17px;height:17px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.15)}
.sw-toggle.on{background:var(--primary)}
.sw-toggle.on::after{left:19px}
.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 14px;z-index:10;max-height:640px;overflow:hidden}
.sheet-title{font-size:16px;font-weight:700;margin-bottom:4px}
.sheet-sub{font-size:11.5px;color:var(--weak);margin-bottom:14px}
.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);display:block;width:100%}
.inp.ph{color:#b8bcc4}
.section-h{font-size:11px;color:var(--weak);letter-spacing:.5px;margin:14px 0 8px;display:flex;align-items:center;gap:6px}
.section-h::after{content:"";flex:1;height:1px;background:var(--line)}
.extras-head{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:600;padding:9px 10px;background:#f7f8fa;border-radius:8px}
.extras-head .cv{margin-left:auto;color:var(--weak);font-size:10px}
.extra-row{display:flex;gap:8px;margin-top:8px}
.extra-row .k{flex:0 0 86px}
.extra-row .v{flex:1}
.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}
.btn-danger{display:block;text-align:center;border:1px solid var(--danger);border-radius:8px;padding:9px 0;font-size:15px;color:var(--danger);margin-top:8px;background:#fff}
.pick-row{display:flex;align-items:center;gap:10px;padding:10px 4px;border-bottom:1px solid var(--line)}
.pick-row:last-child{border-bottom:none}
.avatar{width:26px;height:26px;border-radius:50%;background:#dfe6f0;color:#5a6a80;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.avatar.sm{width:20px;height:20px;font-size:9.5px}
.pick-row .pn{flex:1;font-size:13.5px}
.ck{width:18px;height:18px;border-radius:50%;border:1.5px solid #d0d0d0;flex-shrink:0}
.ck.on{background:var(--primary);border-color:var(--primary);position:relative}
.ck.on::after{content:"";position:absolute;left:5px;top:3px;width:4px;height:8px;border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}
/* 空态 */
.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}
.empty .mini-btn.solid{display:inline-block;padding:6px 18px;font-size:13px}
/* 骨架屏 */
.skel{background:#fff;border-radius:9px;padding:12px;margin:0 12px 8px}
.skel i{display:block;height:10px;border-radius:5px;background:linear-gradient(90deg,#eef0f3 25%,#f6f7f9 37%,#eef0f3 63%);background-size:400% 100%;animation:sk 1.2s ease infinite}
.skel i+i{margin-top:8px;width:60%}
@keyframes sk{0%{background-position:100% 50%}100%{background-position:0 50%}}
/* 退场动画示意 */
.leaving{opacity:.35;transform:scale(.96);filter:grayscale(.5)}
.toast{position:absolute;left:50%;bottom:96px;transform:translateX(-50%);background:rgba(0,0,0,.78);color:#fff;font-size:12px;border-radius:8px;padding:8px 14px;white-space:nowrap;z-index:12}
.hl{outline:2px solid var(--primary);outline-offset:1px;border-radius:8px}
</style>
</head>
<body>
<div class="wrap">
<div class="doc-head">
<h1>iBoard V0.2 界面设计 · 任务模块</h1>
<p>轻量任务 / 项目管理 —— 列表与看板双视图 · 列-状态绑定 · 按列保留选项 · 一级子任务</p>
<div class="meta">
<span>版本 V0.2</span><span>视口 420 × 820</span><span>移动端优先</span>
<span>风格沿用《界面设计.html》</span><span>需求编号 T-*</span>
</div>
</div>
<h2>1 设计规范 <span class="sub">沿用主文档 token,仅新增任务模块语义色</span></h2>
<p class="desc">任务模块不引入新主色,全部复用 V0.2 既有色板;只在「任务状态」「列绑定」两处新增语义映射。</p>
<div class="tokens">
<div class="panel">
<h4>主色 / 语义色</h4>
<div class="swatches">
<div class="sw"><i style="background:#1677ff"></i><b>Primary</b><em>#1677ff</em></div>
<div class="sw"><i style="background:#00b578"></i><b>Success</b><em>#00b578</em></div>
<div class="sw"><i style="background:#ffc53d"></i><b>Warn</b><em>#ffc53d</em></div>
<div class="sw"><i style="background:#ff3141"></i><b>Danger</b><em>#ff3141</em></div>
<div class="sw"><i style="background:#c9ced6"></i><b>Idle</b><em>#c9ced6</em></div>
</div>
</div>
<div class="panel">
<h4>任务状态映射</h4>
<div class="type-row"><em><span class="sdot todo"></span> 未开始 todo</em><span>灰点 #c9ced6,与「空闲/未启用」同色</span></div>
<div class="type-row"><em><span class="sdot doing"></span> 执行中 doing</em><span>主色点 #1677ff,与选中态一致</span></div>
<div class="type-row"><em><span class="sdot done"></span> 完成 done</em><span>成功绿 #00b578,勾选态一致</span></div>
</div>
<div class="panel">
<h4>尺寸 / 间距</h4>
<div class="kv">
<span>页面边距</span><b>12px</b>
<span>卡片圆角</span><b>8~10px</b>
<span>看板列宽</span><b>186px(固定,横向滚动)</b>
<span>列表行高</span><b>≈ 58px(含子任务元信息)</b>
<span>子任务缩进</span><b>28px + 层级线 1px</b>
<span>点击热区</span><b>≥ 44 × 44px</b>
<span>标题字号</span><b>14px / 600(列表)· 12.5px / 600(卡片)</b>
<span>负责人</span><b>12px / 600(突出)</b>
<span>任务成员</span><b>10.5px / 400 · #999(弱化)</b>
</div>
</div>
<div class="panel">
<h4>布局约定</h4>
<div class="type-row"><em>TabBar</em><span>5 项:打卡 / <b>任务</b> / 宏观 / 监控 / 我(任务在打卡之后,T-PM-06)</span></div>
<div class="type-row"><em>头部</em><span>项目页用 <code>navbar-sub</code>(44px,左返回 + 标题 + 右侧操作)</span></div>
<div class="type-row"><em>视图切换</em><span>列表 / 看板 用 <code>seg</code> 分段,切换不刷新</span></div>
<div class="type-row"><em>看板</em><span>列横向滚动,列体纵向滚动,两轴分离</span></div>
</div>
</div>
<h2>2 项目列表 <span class="sub">入口 · 个人默认项目 · 归档分组</span></h2>
<p class="desc">顶级 Tab「任务」的第一屏。个人默认项目置顶且不可删除、不可加成员(T-PJ-01~04);普通协作项目可增删成员(T-PJ-05/06)。</p>
<div class="stage">
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="body">
<div class="proj-head">
<b>我的项目</b>
<div class="right">
<div class="mini-btn">+ 归档</div>
<div class="mini-btn solid">+ 新建</div>
</div>
</div>
<div class="proj-item">
<div class="pico" style="background:#1677ff">张</div>
<div class="pmain">
<div class="ptitle">张三的任务 <span class="badge">个人</span></div>
<div class="psub">12 个任务 · 3 个进行中</div>
</div>
<div class="pcount">›</div>
</div>
<div class="proj-group">协作项目(3)</div>
<div class="proj-item">
<div class="pico" style="background:#00b578">APP</div>
<div class="pmain">
<div class="ptitle">APP 改版</div>
<div class="psub">28 个任务 · 4 人 · 6 个子任务</div>
</div>
<div class="pcount">›</div>
</div>
<div class="proj-item">
<div class="pico" style="background:#ff8f1f">二期</div>
<div class="pmain">
<div class="ptitle">APP 二期</div>
<div class="psub">9 个任务 · 2 人</div>
</div>
<div class="pcount">›</div>
</div>
<div class="proj-item">
<div class="pico" style="background:#a855f7">运</div>
<div class="pmain">
<div class="ptitle">运维排期</div>
<div class="psub">5 个任务 · 1 人</div>
</div>
<div class="pcount">›</div>
</div>
<div class="proj-group">已归档(1)</div>
<div class="proj-item" style="opacity:.65">
<div class="pico" style="background:#a8b0ba">旧</div>
<div class="pmain">
<div class="ptitle">2025 遗留</div>
<div class="psub">已归档 · 14 个任务</div>
</div>
<div class="pcount">›</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>说明</b>
<p>个人默认项目带「个人」徽标,无删除入口;归档项目降透明并单独分组。Tab 共 5 项,<b>任务位于打卡之后</b>(T-PM-06),默认首页仍为打卡。</p>
</div>
</div>
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="body">
<div class="empty" style="padding-top:120px">
<div class="ico">▤</div>
<p>还没有协作项目</p>
<div 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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>空状态(T-UI-08)</b>
<p>无协作项目时展示空态与 CTA;个人默认项目始终存在,故不会出现完全空白。</p>
</div>
</div>
</div>
<h2>3 列表视图 <span class="sub">Todoist 风格 · 一级子任务缩进折叠</span></h2>
<p class="desc">默认视图(T-VW-05)。子任务缩进 28px 并带层级线(T-ST-04),可折叠(T-ST-05);已完成任务按<b>所属列</b>的保留选项隐藏(T-FL-11)。</p>
<div class="stage">
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">APP 改版</span>
<div class="right">
<div class="mini-btn">⋯</div>
<div class="mini-btn solid">+ 新增</div>
</div>
</div>
<div class="body scroll">
<div class="pv-head">
<div class="seg"><div class="on">列表</div><div>看板</div></div>
<div class="right"><div class="mini-btn grey">过滤</div><div class="mini-btn grey">成员</div></div>
</div>
<div class="group-title">Doing <span class="cnt">2</span></div>
<div class="task-row">
<div class="box"><svg viewBox="0 0 14 14" width="11" height="11"><path d="M2.5 7.2l3 3 6-6.4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round"/></svg></div>
<div class="task-main">
<div class="task-title">登录接口返回 500</div>
<div class="task-meta">
<span class="sdot doing"></span><span>执行中</span>
<span class="col">Doing</span>
<span class="assignee">张三</span>
<span class="members">+ 李四、王五</span>
</div>
</div>
<div class="task-right"><span class="more">›</span></div>
</div>
<div class="sub-row">
<div class="box"><svg viewBox="0 0 14 14" width="10" height="10"><path d="M2.5 7.2l3 3 6-6.4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round"/></svg></div>
<span class="sub-title">复现环境搭建</span>
<span class="sdot done pill">完成</span>
</div>
<div class="sub-row">
<div class="box"><svg viewBox="0 0 14 14" width="10" height="10"><path d="M2.5 7.2l3 3 6-6.4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round"/></svg></div>
<span class="sub-title">补单元测试</span>
<span class="sdot doing pill">执行中</span>
</div>
<div class="collapse">收起 2 个子任务 ⌃</div>
<div class="task-row">
<div class="box"><svg viewBox="0 0 14 14" width="11" height="11"><path d="M2.5 7.2l3 3 6-6.4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round"/></svg></div>
<div class="task-main">
<div class="task-title">首页改版视觉走查</div>
<div class="task-meta">
<span class="sdot doing"></span><span>执行中</span>
<span class="col">Doing</span>
<span class="assignee">李四</span>
</div>
</div>
<div class="task-right"><span class="more">›</span></div>
</div>
<div class="collapse">展开 1 个子任务 ⌄</div>
<div class="group-title">Plan <span class="cnt">1</span></div>
<div class="task-row">
<div class="box"><svg viewBox="0 0 14 14" width="11" height="11"><path d="M2.5 7.2l3 3 6-6.4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round"/></svg></div>
<div class="task-main">
<div class="task-title">接入埋点上报</div>
<div class="task-meta">
<span class="sdot todo"></span><span>未开始</span>
<span class="col">Plan</span>
<span class="assignee">未指派</span>
</div>
</div>
<div class="task-right"><span class="more">›</span></div>
</div>
<div class="group-title">Done <span class="cnt">1</span></div>
<div class="task-row done">
<div class="box"><svg viewBox="0 0 14 14" width="11" height="11"><path d="M2.5 7.2l3 3 6-6.4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round"/></svg></div>
<div class="task-main">
<div class="task-title">需求评审</div>
<div class="task-meta">
<span class="sdot done"></span><span>完成</span>
<span class="col">Done</span>
<span class="assignee">王五</span>
</div>
</div>
<div class="task-right"><span class="more">›</span></div>
</div>
<div style="height:6px"></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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>列表视图</b>
<p>按看板列分组显示(列名可关闭)。负责人 12px/600 突出,任务成员 10.5px 弱化并置于下方(T-AS-01/02)。子任务带<b>独立状态小标记</b>(T-ST-09),可与父任务不一致。</p>
</div>
</div>
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">APP 改版</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body scroll">
<div class="pv-head">
<div class="seg"><div class="on">列表</div><div>看板</div></div>
<div class="right"><div class="mini-btn grey">过滤</div><div class="mini-btn grey">成员</div></div>
</div>
<div class="group-title">Done <span class="cnt">3</span></div>
<div class="task-row done">
<div class="box"><svg viewBox="0 0 14 14" width="11" height="11"><path d="M2.5 7.2l3 3 6-6.4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round"/></svg></div>
<div class="task-main">
<div class="task-title">接口联调</div>
<div class="task-meta"><span class="sdot done"></span><span>完成于 今天</span><span class="col">Done</span><span class="assignee">张三</span></div>
</div>
<div class="task-right"><span class="more">›</span></div>
</div>
<!-- 正在退场:保留选项跨日触发,当场淡出并重排 -->
<div class="task-row done leaving" style="position:relative">
<div class="box"><svg viewBox="0 0 14 14" width="11" height="11"><path d="M2.5 7.2l3 3 6-6.4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round"/></svg></div>
<div class="task-main">
<div class="task-title">旧任务 · 超出保留期</div>
<div class="task-meta"><span class="sdot done"></span><span>完成于 昨天</span><span class="col">Done</span></div>
</div>
<div class="task-right"><span class="more">›</span></div>
</div>
<div class="task-row done">
<div class="box"><svg viewBox="0 0 14 14" width="11" height="11"><path d="M2.5 7.2l3 3 6-6.4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round"/></svg></div>
<div class="task-main">
<div class="task-title">修复打包脚本</div>
<div class="task-meta"><span class="sdot done"></span><span>完成于 今天</span><span class="col">Done</span><span class="assignee">李四</span></div>
</div>
<div class="task-right"><span class="more">›</span></div>
</div>
<div class="toast">已隐藏 1 条超出保留期的任务</div>
<div class="note" style="margin:16px 12px 0">
<b>退场动画(T-EX-18)</b><br>
跨日 / 跨周 / 跨月边界到点后,超出所属列保留选项(如「当天」)的已完成任务:透明度与高度在 <b>240ms</b> 内收缩至 0 → 移除节点 → 其余条目平滑重排。不做整页刷新。
</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>保留选项 · 当场消失</b>
<p>该列保留选项为「当天」,昨日完成的任务在跨日后进入退场态并移除,其余任务重排(T-FL-05/09、T-EX-18)。</p>
</div>
</div>
</div>
<h2>4 看板视图 <span class="sub">列-状态绑定 · 卡片内嵌子任务 · 长按拖拽</span></h2>
<p class="desc">列头显示列名、数量与绑定标记(<span class="tag">↔ 完成</span> 表示该列绑定「完成」状态,<span class="tag grey">未绑定</span> 表示不参与状态联动)。</p>
<div class="stage">
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">APP 改版</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body" style="padding-top:8px">
<div class="pv-head" style="padding-bottom:6px">
<div class="seg"><div>列表</div><div class="on">看板</div></div>
<div class="right"><div class="mini-btn grey">列设置</div></div>
</div>
<div class="board-wrap" style="height:calc(100% - 44px)">
<!-- Plan -->
<div class="bcol">
<div class="bcol-head">
<span class="bcol-name">Plan</span><span class="bcol-cnt">2</span>
<span class="bcol-bind">↔ 未开始</span>
</div>
<div class="bcol-body">
<div class="bcard">
<div class="brow1"><span class="btitle">接入埋点上报</span><span class="sdot todo"></span></div>
<div class="bmeta"><span class="bassignee">未指派</span></div>
</div>
<div class="bcard">
<div class="brow1"><span class="btitle">整理 0.3 需求清单</span><span class="sdot todo"></span></div>
<div class="bmeta"><span class="bassignee">张三</span><span class="bmembers">+ 王五</span></div>
<div class="bsub"><span class="sbox"></span><span class="stitle">收集各方诉求</span><span class="sdot todo"></span></div>
</div>
<div class="badd">+ 添加任务</div>
</div>
</div>
<!-- Doing 拖拽目标高亮 -->
<div class="bcol dragover">
<div class="bcol-head">
<span class="bcol-name">Doing</span><span class="bcol-cnt">2</span>
<span class="bcol-bind">↔ 执行中</span>
</div>
<div class="bcol-body">
<div class="bcard dragging">
<div class="brow1"><span class="btitle">登录接口返回 500</span><span class="sdot doing"></span></div>
<div class="bmeta"><span class="bassignee">张三</span><span class="bmembers">+ 李四、王五</span></div>
</div>
<div class="bcard">
<div class="brow1"><span class="btitle">首页改版视觉走查</span><span class="sdot doing"></span></div>
<div class="bmeta"><span class="bassignee">李四</span></div>
<div class="bsub"><span class="sbox"></span><span class="stitle">确认色板与字号</span><span class="sdot done"></span></div>
<div class="bsub"><span class="sbox"></span><span class="stitle">产出走查清单</span><span class="sdot doing"></span></div>
<div class="bmore">+1 个子任务</div>
</div>
<div class="badd">+ 添加任务</div>
</div>
</div>
<!-- Action 不绑定 -->
<div class="bcol">
<div class="bcol-head">
<span class="bcol-name">Action</span><span class="bcol-cnt">1</span>
<span class="bcol-bind off">未绑定</span>
</div>
<div class="bcol-body">
<div class="bcard">
<div class="brow1"><span class="btitle">待产品确认的 3 个问题</span><span class="sdot doing"></span></div>
<div class="bmeta"><span class="bassignee">王五</span></div>
</div>
<div class="badd">+ 添加任务</div>
</div>
</div>
<!-- Done -->
<div class="bcol">
<div class="bcol-head">
<span class="bcol-name">Done</span><span class="bcol-cnt">1</span>
<span class="bcol-bind">↔ 完成</span>
</div>
<div class="bcol-body">
<div class="bcard">
<div class="brow1"><span class="btitle">需求评审</span><span class="sdot done"></span></div>
<div class="bmeta"><span class="bassignee">王五</span></div>
<div class="bsub done"><span class="sbox"></span><span class="stitle">会前材料准备</span><span class="sdot done"></span></div>
</div>
<div class="badd">+ 添加任务</div>
</div>
</div>
</div>
<div class="toast">拖入 Doing,状态将改为「执行中」</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>看板视图 + 拖拽中</b>
<p>卡片轻量化(T-UI-02):标题 + 状态点 + 负责人(小字)+ 成员(更弱)+ 子任务摘要。拖拽中卡片半透明抬起,目标列蓝色虚线高亮。<b>子任务内嵌展示并可勾选</b>(T-ST-06/07),带自身状态点(T-ST-09)。</p>
</div>
</div>
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">APP 改版</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body" style="padding-top:8px">
<div class="pv-head" style="padding-bottom:6px">
<div class="seg"><div>列表</div><div class="on">看板</div></div>
<div class="right"><div class="mini-btn grey">列设置</div></div>
</div>
<div class="board-wrap" style="height:calc(100% - 44px)">
<div class="bcol">
<div class="bcol-head"><span class="bcol-name">Plan</span><span class="bcol-cnt">1</span><span class="bcol-bind">↔ 未开始</span></div>
<div class="bcol-body">
<div class="bcard">
<div class="brow1"><span class="btitle">接入埋点上报</span><span class="sdot todo"></span></div>
<div class="bmeta"><span class="bassignee">未指派</span></div>
</div>
</div>
</div>
<div class="bcol">
<div class="bcol-head"><span class="bcol-name">Doing</span><span class="bcol-cnt">1</span><span class="bcol-bind">↔ 执行中</span></div>
<div class="bcol-body">
<!-- 拖拽落点:另一张卡片上 → 降为该卡片的子任务 -->
<div class="bcard" style="margin-bottom:7px"><span class="btitle" style="font-size:12.5px">首页改版视觉走查</span></div>
<div class="bcard hl" style="position:relative">
<div class="brow1"><span class="btitle">登录接口返回 500</span><span class="sdot doing"></span></div>
<div class="bmeta"><span class="bassignee">张三</span></div>
<div class="bcard" style="border:1.5px dashed var(--primary);background:#f5f9ff;box-shadow:none;margin-top:6px;padding:5px 7px">
<span style="font-size:11px;color:var(--primary)">松手 → 成为子任务</span>
</div>
</div>
</div>
</div>
<div class="bcol">
<div class="bcol-head"><span class="bcol-name">Action</span><span class="bcol-cnt">0</span><span class="bcol-bind off">未绑定</span></div>
<div class="bcol-body"><div class="badd">+ 添加任务</div></div>
</div>
<div class="bcol">
<div class="bcol-head"><span class="bcol-name">Done</span><span class="bcol-cnt">1</span><span class="bcol-bind">↔ 完成</span></div>
<div class="bcol-body">
<div class="bcard">
<div class="brow1"><span class="btitle">需求评审</span><span class="sdot done"></span></div>
<div class="bmeta"><span class="bassignee">王五</span></div>
</div>
</div>
</div>
</div>
<div class="toast">仅支持一级子任务</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>拖拽降为子任务(T-ST-12)</b>
<p>长按卡片拖到<b>另一张卡片</b>上松手即成为其一级子任务。目标本身是子任务、或被拖任务已有子任务,均拒绝并 Toast「仅支持一级子任务」(T-ST-13/14)。</p>
</div>
</div>
</div>
<h2>5 列设置 <span class="sub">列管理 + 状态绑定 + 保留选项</span></h2>
<p class="desc">本模块的配置中枢:每列一行,包含<b>重命名</b>、<b>状态绑定</b>(T-BD-02)与<b>保留选项</b>(T-FL-02)。列可拖动排序(T-COL-05)、增删(T-COL-02/04),数量 1~10。</p>
<div class="stage">
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">列设置</span>
<div class="right"><div class="mini-btn solid">保存</div></div>
</div>
<div class="body scroll">
<div class="set-hint" style="padding-top:12px">
拖动左侧手柄调整列顺序;顺序决定「改状态时自动归位」的目标列(取第一个匹配列)。
</div>
<div class="set-row">
<span style="color:#c2c7cf">≡</span>
<span class="sname">Plan</span>
<div class="sctrl">
<div class="drop">未开始 <span class="cv">▾</span></div>
</div>
</div>
<div class="set-row">
<span style="color:#c2c7cf">≡</span>
<span class="sname">Doing</span>
<div class="sctrl">
<div class="drop">执行中 <span class="cv">▾</span></div>
</div>
</div>
<div class="set-row">
<span style="color:#c2c7cf">≡</span>
<span class="sname">Action</span>
<div class="sctrl">
<div class="drop off">不绑定状态 <span class="cv">▾</span></div>
</div>
</div>
<div class="set-row">
<span style="color:#c2c7cf">≡</span>
<span class="sname">Done</span>
<div class="sctrl">
<div class="drop">完成 <span class="cv">▾</span></div>
</div>
</div>
<div style="padding:12px 14px">
<div class="mini-btn" style="display:inline-block;padding:6px 14px;font-size:12px">+ 新增列</div>
<div class="mini-btn grey" style="display:inline-block;padding:6px 14px;font-size:12px;margin-left:6px">删除列</div>
</div>
<div class="section-h" style="margin:6px 14px 8px">已完成任务保留</div>
<div class="set-row">
<span class="sname" style="width:82px">Plan</span>
<div class="sctrl"><div class="drop">永久显示 <span class="cv">▾</span></div></div>
</div>
<div class="set-row">
<span class="sname" style="width:82px">Doing</span>
<div class="sctrl"><div class="drop">本月 <span class="cv">▾</span></div></div>
</div>
<div class="set-row">
<span class="sname" style="width:82px">Action</span>
<div class="sctrl"><div class="drop">3 天 <span class="cv">▾</span></div></div>
</div>
<div class="set-row">
<span class="sname" style="width:82px">Done</span>
<div class="sctrl"><div class="drop">当天 <span class="cv">▾</span></div></div>
</div>
<div class="set-hint">
保留选项:<b>永不显示 / 当天 / 3 天 / 本周 / 本月 / 永久显示</b>。<br>
仅影响已完成任务;未完成任务始终展示。列表与看板按同一规则过滤。
</div>
<div style="padding:0 14px 20px">
<div class="btn-primary">保存</div>
<div class="btn-ghost">取消</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>列设置</b>
<p>上半区是「列 → 状态」绑定,下半区是「列 → 保留选项」。<code>Action</code> 显示为「不绑定状态」灰态;保存后看板与列表即时生效,不批量改写已有任务(T-BD-11/12)。</p>
</div>
</div>
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">APP 改版</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body" style="padding-top:8px">
<div class="pv-head" style="padding-bottom:6px">
<div class="seg"><div>列表</div><div class="on">看板</div></div>
<div class="right"><div class="mini-btn grey">列设置</div></div>
</div>
<div class="board-wrap" style="height:calc(100% - 44px)">
<div class="bcol">
<div class="bcol-head"><span class="bcol-name">Plan</span><span class="bcol-cnt">0</span><span class="bcol-bind">↔ 未开始</span></div>
<div class="bcol-body"><div class="badd">+ 添加任务</div></div>
</div>
<div class="bcol">
<div class="bcol-head"><span class="bcol-name">Doing</span><span class="bcol-cnt">0</span><span class="bcol-bind">↔ 执行中</span></div>
<div class="bcol-body"><div class="badd">+ 添加任务</div></div>
</div>
<div class="bcol">
<div class="bcol-head"><span class="bcol-name">Action</span><span class="bcol-cnt">1</span><span class="bcol-bind off">未绑定</span></div>
<div class="bcol-body">
<div class="bcard hl">
<div class="brow1"><span class="btitle">待产品确认的 3 个问题</span><span class="sdot done"></span></div>
<div class="bmeta"><span class="bassignee">王五</span><span class="bmembers">+ 李四</span></div>
</div>
</div>
</div>
<div class="bcol">
<div class="bcol-head"><span class="bcol-name">Done</span><span class="bcol-cnt">0</span><span class="bcol-bind">↔ 完成</span></div>
<div class="bcol-body"><div class="badd">+ 添加任务</div></div>
</div>
</div>
<div class="toast">状态已改为「完成」,Action 未绑定完成,任务保留在原列</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>自动归位 · 无匹配列</b>
<p>任务在未绑定的 <code>Action</code> 中被勾成「完成」。若其他列绑定了「完成」→ 自动移入第一个匹配列;<b>若全部列都未绑定「完成」→ 不移动</b>,保留在原列(T-BD-14/16)。此屏即后者。</p>
</div>
</div>
</div>
<h2>6 任务详情 <span class="sub">字段 + 扩展信息卡片(默认收起)</span></h2>
<p class="desc">底部弹层。源码等扩展信息放在<b>可折叠卡片</b>内,默认收起、全部非必填(T-TK-04~07),不占用主字段空间。</p>
<div class="stage">
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">APP 改版</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body" style="position:relative">
<div class="mask"></div>
<div class="sheet">
<div class="sheet-title">登录接口返回 500</div>
<div class="sheet-sub">APP 改版 · Doing · 执行中 · 创建于 10-22</div>
<div class="field">
<label>标题</label>
<div class="inp">登录接口返回 500</div>
</div>
<div class="field">
<label>描述</label>
<div class="inp ph">补充说明…</div>
</div>
<div class="field">
<label>状态</label>
<div class="seg"><div>未开始</div><div class="on">执行中</div><div>完成</div></div>
</div>
<div class="field">
<label>负责人</label>
<div class="pick-row" style="padding:6px 0">
<div class="avatar">张</div>
<span class="pn">张三</span>
<span class="link">更换</span>
</div>
</div>
<div class="field">
<label>任务成员</label>
<div class="pick-row" style="padding:6px 0">
<div class="avatar sm">李</div><div class="avatar sm" style="margin-left:-8px">王</div>
<span class="pn" style="font-size:12px;color:var(--weak)">李四、王五</span>
<span class="link">编辑</span>
</div>
</div>
<!-- 扩展信息卡片:默认收起 -->
<div class="extras-head">
<span>▸</span><span>扩展信息</span>
<span class="tag">2</span>
<span class="cv">默认收起 · 全部非必填</span>
</div>
<div style="margin-top:12px">
<div class="btn-primary">保存</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>详情(扩展信息收起)</b>
<p>负责人默认填入创建者本人,可清空为「未指派」(T-TK-09/10)。扩展信息卡片默认收起,右侧标出条目数。</p>
</div>
</div>
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">APP 改版</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body" style="position:relative">
<div class="mask"></div>
<div class="sheet" style="padding-bottom:8px">
<div class="sheet-title">登录接口返回 500</div>
<div class="sheet-sub">APP 改版 · Doing · 执行中</div>
<div class="field">
<label>负责人</label>
<div class="pick-row" style="padding:6px 0">
<div class="avatar">张</div>
<span class="pn">张三</span>
<span class="link">更换</span>
</div>
</div>
<div class="extras-head">
<span>▾</span><span>扩展信息</span>
<span class="tag">2</span>
<span class="cv">可自由增删条目</span>
</div>
<div class="extra-row">
<div class="inp k">仓库</div>
<div class="inp v">gitlab/app-web</div>
</div>
<div class="extra-row">
<div class="inp k">分支</div>
<div class="inp v">fix/login-500</div>
</div>
<div class="extra-row">
<div class="inp k">相关链接</div>
<div class="inp v" style="color:var(--primary)">https://…/issues/128</div>
</div>
<div style="margin-top:10px">
<span class="link">+ 添加一条</span>
</div>
<div class="section-h">子任务 <span class="tag">2</span></div>
<div class="pick-row">
<span class="ck on"></span>
<span class="pn">复现环境搭建</span>
<span class="sdot done pill">完成</span>
</div>
<div class="pick-row">
<span class="ck"></span>
<span class="pn">补单元测试</span>
<span class="sdot doing pill">执行中</span>
</div>
<div class="pick-row" style="border-bottom:none">
<span style="color:#c2c7cf;font-size:16px">+</span>
<span class="pn" style="color:var(--weak);font-size:13px">添加子任务</span>
</div>
<div class="btn-primary" style="margin-top:12px">保存</div>
<div class="btn-danger">删除任务<span style="font-size:11px;font-weight:400">(将一并删除 2 条子任务)</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>详情(扩展信息展开)</b>
<p>扩展条目为<b>任意名称 + 值</b>,不限固定字段(T-TK-05),值可为文本或链接。子任务在此可增删改,状态与父任务互相独立(T-ST-03)。删除任务会提示级联条数(T-EX-07)。</p>
</div>
</div>
</div>
<h2>7 成员与跨项目拷贝 <span class="sub">项目成员唯一选人源 · 拷贝非移动</span></h2>
<p class="desc">负责人与任务成员只能从<b>当前项目成员</b>中选择(T-AS-03/04);跨项目操作是<b>拷贝</b>(T-CP-01),新任务创建人为操作者(T-CP-04)。</p>
<div class="stage">
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">APP 改版</span>
<div class="right"><div class="mini-btn solid">+ 添加</div></div>
</div>
<div class="body scroll">
<div class="set-hint" style="padding-top:12px">
项目内所有成员<b>权限均等、全读写</b>;负责人与成员只是信息标记,不影响权限(T-AS-07、T-PM-02)。
</div>
<div class="set-row" style="padding:12px 14px">
<div class="avatar">张</div>
<span class="pn" style="flex:1;font-size:13.5px">张三 <span class="tag grey">创建人</span></span>
<span class="link" style="color:var(--weak)">退出</span>
</div>
<div class="set-row" style="padding:12px 14px">
<div class="avatar">李</div>
<span class="pn" style="flex:1;font-size:13.5px">李四</span>
<span class="link danger">移除</span>
</div>
<div class="set-row" style="padding:12px 14px">
<div class="avatar">王</div>
<span class="pn" style="flex:1;font-size:13.5px">王五</span>
<span class="link danger">移除</span>
</div>
<div class="set-row" style="padding:12px 14px;opacity:.7">
<div class="avatar" style="background:#f2f3f5;color:#b6bcc4">赵</div>
<span class="pn" style="flex:1;font-size:13.5px">赵六 <span class="badge">已退出</span></span>
<span class="link" style="color:var(--weak)">—</span>
</div>
<div class="note" style="margin:14px 12px 0">
成员被移出项目后,其担任的负责人 / 成员标记<b>保留历史</b>并显示「已退出」灰标,不清空、不报错(T-EX-06)。
</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>项目成员</b>
<p>创建人可主动退出(T-PJ-07);成员清空后项目静默保留、前端不报错(T-PJ-08、T-EX-11)。</p>
</div>
</div>
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span>
<span class="title">APP 改版</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body" style="position:relative">
<div class="mask"></div>
<div class="sheet" style="padding-bottom:8px">
<div class="sheet-title">跨项目拷贝</div>
<div class="sheet-sub">将「登录接口返回 500」复制到另一个项目;源任务保持不变</div>
<div class="field">
<label>目标项目</label>
<div class="drop" style="width:100%">APP 二期 <span class="cv">▾</span></div>
</div>
<div class="field">
<label>将会复制</label>
<div style="font-size:12.5px;color:var(--muted);line-height:1.9">
标题、描述、状态、看板列、标签<br>
负责人与任务成员(仅保留目标项目成员)<br>
<b>2 条子任务</b> · <b>2 条扩展信息</b>
</div>
</div>
<div class="field">
<label>人员处理</label>
<div style="font-size:12px;color:var(--orange);background:#fff7e6;border-radius:8px;padding:8px 10px;line-height:1.7">
王五 不是「APP 二期」的成员,拷贝后将<b>不保留</b>其任务成员标记。
</div>
</div>
<div class="btn-primary">确认拷贝</div>
<div class="btn-ghost">取消</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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption">
<b>拷贝确认</b>
<p>明确列出复制内容与被丢弃的人员(T-EX-08),避免静默丢数据。拷贝后新旧任务<b>完全独立</b>(T-CP-05)。</p>
</div>
</div>
</div>
<h2>8 交互与状态 <span class="sub">长按拖拽 · 三态 · 边界</span></h2>
<h3>8.1 拖拽与落点</h3>
<table>
<tr><th style="width:150px">操作</th><th>落点</th><th>结果</th></tr>
<tr><td>长按卡片 ≥ 300ms</td><td>—</td><td>卡片抬起(缩 0.97 + 倾斜 1°),进入拖拽态,锁定滚动</td></tr>
<tr><td>拖到另一列空白</td><td>列体</td><td>换列;目标列<b>绑定状态则状态跟随</b>,<b>未绑定则保留原状态</b>(T-BD-07)</td></tr>
<tr><td>拖到另一张卡片上</td><td>顶层任务卡</td><td>降为该任务的一级子任务;<b>原列与状态保持不变</b>(T-ST-15)</td></tr>
<tr><td>拖到子任务 / 自身 / 后代</td><td>非法落点</td><td>拒绝并 Toast,卡片回弹(T-ST-13、T-EX-15)</td></tr>
<tr><td>被拖任务有子任务</td><td>任何卡片</td><td>拒绝,避免二级嵌套(T-ST-14)</td></tr>
<tr><td>无需拖拽时</td><td>卡片「⋯」</td><td>「移动到列 / 移动到子任务」等价入口(T-UI-07)</td></tr>
</table>
<h3>8.2 三态与反馈</h3>
<div class="stage" style="margin-top:8px">
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span><span class="title">APP 二期</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body">
<div class="pv-head"><div class="seg"><div class="on">列表</div><div>看板</div></div></div>
<div class="skel"><i></i><i></i></div>
<div class="skel"><i></i><i></i></div>
<div class="skel"><i></i><i></i></div>
<div class="skel"><i></i><i></i></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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption"><b>加载态(T-UI-09)</b><p>骨架屏,避免白屏与布局跳动。</p></div>
</div>
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span><span class="title">APP 二期</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body">
<div class="pv-head"><div class="seg"><div class="on">列表</div><div>看板</div></div></div>
<div class="empty" style="padding-top:120px">
<div class="ico">✓</div>
<p>这个项目还没有任务</p>
<div 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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption"><b>空态(T-UI-08)</b><p>带明确 CTA;某列因保留选项隐藏全部已完成任务时,展示该列空态而非报错(T-EX-10)。</p></div>
</div>
<div class="shot">
<div class="phone">
<div class="navbar-sm">任务</div>
<div class="navbar-sub">
<span class="back">‹</span><span class="title">APP 二期</span>
<div class="right"><div class="mini-btn">⋯</div><div class="mini-btn solid">+ 新增</div></div>
</div>
<div class="body">
<div class="pv-head"><div class="seg"><div class="on">列表</div><div>看板</div></div></div>
<div class="empty" style="padding-top:110px">
<div class="ico" style="background:#fff1f0;color:#ff7875">!</div>
<p>数据加载失败,请检查网络</p>
<div 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="9"/><path d="M8 12h8M12 8v8"/></svg>打卡</div>
<div class="tab on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M8 10h8M8 14h5"/><path d="M9 5V3M15 5V3"/></svg>任务</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 19V9M10 19V5M16 19v-7M22 19H2"/></svg>宏观</div>
<div class="tab"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 13h4l2-5 3 10 2-5h7"/></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.2"/><path d="M5 20c1.2-4 4-6 7-6s5.8 2 7 6"/></svg>我</div>
</div>
</div>
<div class="caption"><b>异常态(T-UI-10)</b><p>乐观更新失败时回滚并 Toast,可重试(T-EX-02)。</p></div>
</div>
</div>
<h2>9 需求点对照 <span class="sub">界面稿 ↔ 需求编号</span></h2>
<table>
<tr><th style="width:120px">界面</th><th>对应需求点</th></tr>
<tr><td>2 项目列表</td><td><code>T-PJ-01~10</code>、<code>T-PM-06</code>、<code>T-PM-07</code>、<code>T-UI-08</code></td></tr>
<tr><td>3 列表视图</td><td><code>T-VW-01~07</code>、<code>T-ST-04/05/09</code>、<code>T-AS-01/02</code>、<code>T-FL-11</code>、<code>T-TK-12</code></td></tr>
<tr><td>3′ 保留退场</td><td><code>T-FL-05/09</code>、<code>T-EX-18</code></td></tr>
<tr><td>4 看板视图</td><td><code>T-BD-01~16</code>、<code>T-UI-02/07</code>、<code>T-ST-06/07/09</code>、<code>T-ST-12~15</code></td></tr>
<tr><td>5 列设置</td><td><code>T-COL-01~10</code>、<code>T-BD-02/09/10</code>、<code>T-FL-01~15</code></td></tr>
<tr><td>5′ 自动归位</td><td><code>T-BD-14/16</code>、<code>T-EX-04/05</code></td></tr>
<tr><td>6 任务详情</td><td><code>T-TK-01~13</code>、<code>T-ST-03</code>、<code>T-AS-05</code>、<code>T-EX-07</code></td></tr>
<tr><td>7 成员 / 拷贝</td><td><code>T-AS-03/04/06/07</code>、<code>T-PM-01~05</code>、<code>T-CP-01~09</code>、<code>T-EX-06/08</code></td></tr>
<tr><td>8 三态</td><td><code>T-UI-08/09/10</code>、<code>T-EX-02/10</code></td></tr>
</table>
<h2>10 适配与可达性</h2>
<table>
<tr><th style="width:120px">项</th><th>约定</th></tr>
<tr><td>视口</td><td>设计稿 420×820;375~430px 内元素不换行、不裁切;底部 TabBar <b>5 项</b>每项 ≥ 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>列宽固定 186px,超出横向滚动;列头吸顶,列体独立纵向滚动</td></tr>
<tr><td>触控</td><td>长按 300ms 进入拖拽;点击热区 ≥ 44×44;拖拽中禁用页面滚动</td></tr>
<tr><td>动效</td><td>退场 240ms、拖动抬起 150ms、Toast 2s 自动消失;均 <code>pointer-events:none</code> 不阻塞后续操作</td></tr>
<tr><td>大字号</td><td>任务标题超长换行不截断(卡片内最多 2 行省略);列名 ≤ 12 字</td></tr>
<tr><td>深色模式</td><td>V0.2 沿用现有浅色主题,暂不适配</td></tr>
<tr><td>数量上限</td><td>看板列 <b>1~10</b>(上限待确认);扩展信息条目建议 ≤ 20</td></tr>
</table>
<p class="note" style="margin-top:26px">本文档为静态设计稿,不含脚本逻辑;实现对应 <code>src/pages/task/*.jsx</code>、<code>src/components/task/*.jsx</code> 与样式段(<code>src/styles/globals.css</code> 的 <code>.task-*</code>)。接口与数据口径见《任务模块设计文档-框架设计.md》《任务模块功能设计.md》与《任务模块数据库设计文档.md》。</p>
</div>
</body>
</html>