Files
dudu/todo/todo.html
T
wangjia 40760aa884
ci / server (push) Failing after 14s
ci / design-tokens (push) Failing after 11s
dudu MVP:五端语音输入法初始提交
- server:Go 网关(WS 流式识别中继/计费配额/微信登录支付 mock/反馈/埋点),gummy provider 已真实联调
- desktop:Tauri 2(全局快捷键 push-to-talk/浮层/托盘/设置/登录购买/反馈/首启引导)
- android:Compose 主 App + IME(键盘内录音直传)
- ios:App + 键盘扩展(1A spike 实证键盘内不可录音,走 deep link 听写)
- design/design-pipeline:设计系统 + token 导出 iOS/Android 主题
- doc:前后端设计文档(HTML);web:官网宣传页;todo:任务看板

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 00:38:37 +08:00

1404 lines
69 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>dudu — 项目 TODO</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0; padding: 0 0 80px;
font-family: "Noto Sans SC", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: #1f2933; background: #f7f9fb; line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
header {
background: linear-gradient(135deg, #0A1F3B 0%, #15407D 100%);
color: #fff; padding: 36px 32px 28px;
}
header h1 { margin: 0 0 6px; font-size: 24px; font-weight: 700; }
header .header-meta { color: #ADC9EA; font-size: 13px; margin-top: 4px; }
.stats { display: flex; gap: 16px; margin-top: 14px; flex-wrap: wrap; }
.stat-pill {
background: rgba(255,255,255,0.12); border-radius: 20px;
padding: 4px 14px; font-size: 13px; color: #fff;
}
.stat-pill strong { font-size: 18px; font-weight: 700; margin-right: 2px; }
/* ── 筛选栏 ── */
.filter-bar {
position: sticky; top: 0; z-index: 10;
background: #fff; border-bottom: 1px solid #e4e9ef;
padding: 10px 28px; display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
}
.filter-group { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.filter-label { font-size: 12px; color: #7b8794; white-space: nowrap; }
.filter-chip, .filter-btn {
padding: 3px 12px; border-radius: 14px; border: 1.5px solid #d1d9e6;
background: #f7f9fb; color: #52606d; font-size: 12.5px; cursor: pointer;
transition: all .15s; white-space: nowrap;
}
.filter-chip:hover, .filter-btn:hover { border-color: #2563AC; color: #2563AC; }
.filter-chip.active, .filter-btn.active {
background: #2563AC; border-color: #2563AC; color: #fff;
}
.filter-sep { width: 1px; height: 20px; background: #e4e9ef; margin: 0 4px; }
/* ── 内容区 ── */
.wrap { max-width: 980px; margin: 0 auto; padding: 0 24px; }
.section-block { margin-bottom: 8px; }
.section-title {
font-size: 15px; font-weight: 700;
padding: 10px 14px; border-radius: 8px;
display: flex; align-items: center; gap: 8px; cursor: pointer;
margin: 20px 0 8px; user-select: none;
}
.section-title .s-count {
font-size: 12px; font-weight: 500; padding: 1px 8px; border-radius: 10px;
background: rgba(0,0,0,0.08);
}
.section-title .s-arrow { margin-left: auto; font-size: 12px; color: inherit; opacity: .6; }
/* 状态主题色 */
.st-open { background: #eff6ff; color: #1e40af; border-left: 4px solid #3b82f6; }
.st-doing { background: #fff7ed; color: #9a3412; border-left: 4px solid #f97316; }
.st-done { background: #fefce8; color: #854d0e; border-left: 4px solid #eab308; }
.st-accepted{ background: #f0fdf4; color: #166534; border-left: 4px solid #22c55e; }
ul.todo-list { list-style: none; margin: 0; padding: 0; }
.todo-card {
background: #fff; border: 1px solid #e4e9ef; border-radius: 10px;
padding: 14px 18px; margin-bottom: 10px;
border-left-width: 4px;
}
.todo-card.s-open { border-left-color: #3b82f6; }
.todo-card.s-doing { border-left-color: #f97316; }
.todo-card.s-done { border-left-color: #eab308; }
.todo-card.s-accepted { border-left-color: #22c55e; background: #f0fdf4; opacity: .8; }
.card-header { display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap; }
.item-title { font-weight: 600; font-size: 15px; flex: 1; }
.todo-card.s-accepted .item-title { text-decoration: line-through; color: #52606d; }
.card-badges { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.item-desc { font-size: 13.5px; color: #52606d; margin-top: 6px; }
.item-desc code {
background: #f0f2f5; padding: 1px 5px; border-radius: 3px;
font-family: "JetBrains Mono", monospace; font-size: 12.5px; color: #b91c1c;
}
.card-footer { display: flex; align-items: center; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
.tag-row { display: flex; flex-wrap: wrap; gap: 6px; flex: 1; }
.item-meta { display: flex; flex-wrap: wrap; gap: 8px; font-size: 12px; color: #8aa3c4; }
.meta-date { white-space: nowrap; }
/* ── 标签样式 ── */
.tag { display: inline-block; padding: 2px 9px; border-radius: 10px; font-size: 12px; font-weight: 600; white-space: nowrap; }
.t-block { background: #fde8e8; color: #b91c1c; }
.t-high { background: #fef0d8; color: #9a6700; }
.t-low { background: #e6f0fb; color: #1d4ed8; }
.t-tag { background: #efefef; color: #555; cursor: pointer; transition: .12s; }
.t-tag:hover { background: #d9e8fb; color: #1d4ed8; }
.ver-badge { font-weight: 700; color: #1f7a44; }
.sub-progress-badge { background: #f0f4ff; color: #3730a3; }
/* 状态徽章 */
.status-badge { font-size: 11.5px; }
.s-open { background: #dbeafe; color: #1e40af; }
.s-doing { background: #ffedd5; color: #9a3412; }
.s-done { background: #fef9c3; color: #854d0e; }
.s-accepted { background: #dcfce7; color: #166534; }
/* ── 折叠 ── */
.section-list-wrap.collapsed { display: none; }
.empty-tip { font-size: 14px; color: #8aa3c4; margin: 8px 0 24px; }
.hidden { display: none !important; }
/* ── 改动等级徽章 ── */
.tier-1 { background: #ede9fe; color: #6d28d9; }
.tier-2 { background: #ccfbf1; color: #0f766e; }
.tier-3 { background: #f1f5f9; color: #475569; }
/* ── 拒绝按钮 & 拒绝原因 ── */
.reject-btn {
padding: 3px 10px; border-radius: 6px; border: 1.5px solid #dc2626;
background: #fff; color: #dc2626; font-size: 12px; font-weight: 600;
cursor: pointer; transition: all .15s; white-space: nowrap;
}
.reject-btn:hover { background: #dc2626; color: #fff; }
.reject-note {
margin: 8px 0 4px; padding: 7px 12px; border-radius: 6px;
background: #fef2f2; border: 1px solid #fecaca;
font-size: 13px; color: #b91c1c; line-height: 1.5;
}
.reject-date { color: #ef9999; font-size: 12px; }
/* ── 确认闸(方案/改动说明)── */
.gate-block { margin: 10px 0 4px; padding: 10px 14px; border-radius: 8px; font-size: 13px; }
.gate-pending { background: #fff7ed; border: 1px solid #fdba74; }
.gate-granted { background: #f0fdf4; border: 1px solid #bbf7d0; }
.gate-info { background: #f1f5f9; border: 1px solid #e2e8f0; }
.gate-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
.gate-badge { padding: 2px 9px; border-radius: 10px; font-size: 11.5px; font-weight: 700; white-space: nowrap; }
.gate-badge.pending { background: #f97316; color: #fff; }
.gate-badge.granted { background: #22c55e; color: #fff; }
.gate-badge.info { background: #94a3b8; color: #fff; }
.gate-kind { font-size: 12px; color: #52606d; }
.gate-date { font-size: 12px; color: #8aa3c4; margin-left: auto; }
.gate-note { color: #52606d; margin: 4px 0; white-space: pre-wrap; }
.gate-ref { font-size: 12.5px; color: #52606d; margin-top: 4px; }
.gate-note code, .gate-ref code {
background: #fff; padding: 1px 5px; border-radius: 3px;
font-family: "JetBrains Mono", monospace; font-size: 12px; color: #b91c1c;
}
.approve-btn {
margin-top: 8px; padding: 5px 14px; border-radius: 6px; border: none;
background: #16a34a; color: #fff; font-size: 12.5px; font-weight: 600; cursor: pointer;
transition: background .15s;
}
.approve-btn:hover { background: #15803d; }
.approve-cmd { margin-top: 10px; padding: 10px 12px; background: #1e293b; border-radius: 8px; }
.approve-cmd-label { font-size: 12px; color: #94a3b8; margin-bottom: 6px; }
.approve-cmd-code { font-family: "JetBrains Mono", monospace; font-size: 13px; color: #86efac; display: block; word-break: break-all; }
.approve-copy-btn { margin-top: 8px; padding: 4px 12px; border-radius: 6px; background: #334155; color: #e2e8f0; border: none; font-size: 12px; cursor: pointer; }
.approve-copy-btn:hover { background: #475569; }
.stat-pill.gate-stat { background: #f97316; }
/* ── 子任务区 ── */
.subtask-block {
margin-top: 12px; padding: 10px 14px;
background: #f8fafc; border: 1px solid #e4e9ef; border-radius: 8px;
}
.subtask-header {
display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap;
}
.subtask-label {
font-size: 11px; font-weight: 700; color: #7b8794;
text-transform: uppercase; letter-spacing: .6px;
}
.subtask-progress-text { font-size: 12px; color: #52606d; }
.subtask-progress-bar {
flex: 1; height: 5px; background: #e4e9ef; border-radius: 3px; min-width: 60px;
}
.subtask-progress-fill { height: 100%; background: #22c55e; border-radius: 3px; transition: width .4s; }
.subtask-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.subtask-item {
display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
padding: 6px 10px; border-radius: 6px; font-size: 13px;
background: #fff; border: 1px solid #e8edf2;
}
.subtask-item.s-done { background: #f0fdf4; border-color: #bbf7d0; }
.subtask-item.s-doing { background: #fff7ed; border-color: #fed7aa; }
.subtask-item.s-accepted { background: #f0fdf4; border-color: #bbf7d0; opacity: .75; }
.sub-icon {
width: 16px; text-align: center; font-size: 13px; font-weight: 700; flex-shrink: 0;
}
.sub-icon.s-done { color: #16a34a; }
.sub-icon.s-doing { color: #ea580c; }
.sub-icon.s-open { color: #93aec8; }
.sub-icon.s-accepted { color: #16a34a; }
.sub-sid {
font-family: "JetBrains Mono", monospace; font-size: 11.5px;
color: #52606d; font-weight: 700; min-width: 32px; flex-shrink: 0;
}
.sub-title { flex: 1; font-size: 13px; min-width: 120px; }
.subtask-item.s-done .sub-title,
.subtask-item.s-accepted .sub-title { text-decoration: line-through; color: #52606d; }
.sub-badges { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }
.dep-section { display: flex; align-items: center; gap: 3px; }
.dep-label { font-size: 11px; color: #8aa3c4; margin-right: 2px; }
.dep-badge {
padding: 1px 6px; border-radius: 8px; font-size: 11px;
font-weight: 700; font-family: monospace; cursor: default;
}
.dep-done { background: #dcfce7; color: #166534; }
.dep-pending { background: #fee2e2; color: #b91c1c; }
/* ── 拒绝 Modal ── */
.modal-overlay {
position: fixed; inset: 0; background: rgba(0,0,0,.45);
display: flex; align-items: center; justify-content: center; z-index: 999;
}
.modal-box {
background: #fff; border-radius: 12px; padding: 28px 32px;
width: min(480px, 94vw); box-shadow: 0 20px 60px rgba(0,0,0,.2);
}
.modal-box h3 { margin: 0 0 4px; font-size: 17px; color: #1f2933; }
.modal-subtitle { font-size: 13px; color: #52606d; margin: 0 0 18px; }
.modal-label { font-size: 13px; font-weight: 600; color: #374151; margin-bottom: 6px; display: block; }
.modal-label .req { color: #dc2626; margin-left: 2px; }
.modal-textarea {
width: 100%; border: 1.5px solid #d1d9e6; border-radius: 8px;
padding: 10px 12px; font-size: 14px; font-family: inherit; resize: vertical;
min-height: 88px; outline: none; transition: border-color .15s;
}
.modal-textarea:focus { border-color: #dc2626; }
.modal-textarea.error { border-color: #dc2626; background: #fff8f8; }
.modal-err { font-size: 12px; color: #dc2626; margin-top: 4px; display: none; }
.modal-err.show { display: block; }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; }
.modal-btn { padding: 8px 20px; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; border: none; transition: all .15s; }
.modal-btn-cancel { background: #f3f4f6; color: #374151; }
.modal-btn-cancel:hover { background: #e5e7eb; }
.modal-btn-reject { background: #dc2626; color: #fff; }
.modal-btn-reject:hover { background: #b91c1c; }
.modal-cmd-wrap { margin-top: 16px; padding: 12px 14px; background: #1e293b; border-radius: 8px; }
.modal-cmd-label { font-size: 12px; color: #94a3b8; margin-bottom: 8px; }
.modal-cmd-code { font-family: "JetBrains Mono", "Fira Code", monospace; font-size: 13px; color: #86efac; word-break: break-all; display: block; }
.modal-copy-btn { margin-top: 10px; padding: 5px 14px; border-radius: 6px; background: #334155; color: #e2e8f0; border: none; font-size: 12px; cursor: pointer; }
.modal-copy-btn:hover { background: #475569; }
</style>
</head>
<body>
<header>
<div class="wrap">
<h1>dudu — 项目 TODO</h1>
<div class="header-meta">生成于 2026-06-12 · 真相源 todo/todo.json</div>
<div class="stats">
<div class="stat-pill"><strong>15</strong>全部</div>
<div class="stat-pill"><strong>3</strong>待开始</div>
<div class="stat-pill"><strong>0</strong>开发中</div>
<div class="stat-pill"><strong>12</strong>待验收</div>
<div class="stat-pill"><strong>0</strong>已验收</div>
</div>
</div>
</header>
<div class="filter-bar" id="filterBar">
<div class="filter-group">
<span class="filter-label">重要度</span>
<button class="filter-btn active" data-filter-level="all">全部</button>
<button class="filter-btn" data-filter-level="high">高优</button>
<button class="filter-btn" data-filter-level="mid">重要</button>
<button class="filter-btn" data-filter-level="low">一般</button>
</div>
<div class="filter-sep"></div>
<div class="filter-group">
<span class="filter-label">状态</span>
<button class="filter-btn active" data-filter-status="all">全部</button>
<button class="filter-btn" data-filter-status="open">待开始</button>
<button class="filter-btn" data-filter-status="doing">开发中</button>
<button class="filter-btn" data-filter-status="done">待验收</button>
<button class="filter-btn" data-filter-status="accepted">已验收</button>
</div>
<div class="filter-sep"></div>
<div class="filter-group">
<span class="filter-label">改动等级</span>
<button class="filter-btn active" data-filter-tier="all">全部</button>
<button class="filter-btn" data-filter-tier="1">一级</button>
<button class="filter-btn" data-filter-tier="2">二级</button>
<button class="filter-btn" data-filter-tier="3">三级</button>
</div>
<div class="filter-sep"></div>
<div class="filter-group">
<span class="filter-label">平台 / 标签</span>
<button class="filter-chip" data-filter-tag="Android">Android</button><button class="filter-chip" data-filter-tag="CI/CD">CI/CD</button><button class="filter-chip" data-filter-tag="Web">Web</button><button class="filter-chip" data-filter-tag="Windows">Windows</button><button class="filter-chip" data-filter-tag="iOS">iOS</button><button class="filter-chip" data-filter-tag="mac">mac</button><button class="filter-chip" data-filter-tag="前端">前端</button><button class="filter-chip" data-filter-tag="后端">后端</button><button class="filter-chip" data-filter-tag="外部">外部</button><button class="filter-chip" data-filter-tag="数据库">数据库</button><button class="filter-chip" data-filter-tag="跨端">跨端</button>
</div>
</div>
<div class="wrap">
<div class="section-block" id="section-open">
<div class="section-title st-open" data-toggle="open">
📋 待开始 <span class="s-count">3</span>
<span class="s-arrow">▴ 收起</span>
</div>
<div class="section-list-wrap " id="list-wrap-open">
<ul class="todo-list" id="list-open">
<li class="todo-card s-open"
data-id="1"
data-level="high"
data-status="open"
data-tier="2"
data-tags="跨端">
<div class="card-header">
<span class="item-title">M0 风险验证 spike</span>
<div class="card-badges">
<span class="tag status-badge s-open">待开始</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-2">二级</span>
<span class="tag sub-progress-badge">2/3 子任务</span>
</div>
</div>
<div class="item-desc">三项风险验证并行:iOS 键盘录音、Gummy 流式、macOS 注入。无前置依赖,第一波启动</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">2 / 3 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:67%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="1A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">1A</span>
<span class="sub-title">iOS 键盘扩展内录音可行性 spike(真机验证完全访问下 AVAudioSession;不可行则确认 deep link 降级)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="1B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">1B</span>
<span class="sub-title">Gummy 流式接入 demoGo 直连 DashScope WSwav 推流收 partial/final</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-open" data-sid="1C">
<span class="sub-icon s-open"></span>
<span class="sub-sid">1C</span>
<span class="sub-title">macOS 注入 + 不抢焦点浮层 demo(剪贴板+CGEvent、focusable:false 验证微信/浏览器/IDE</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-open">待开始</span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="跨端">跨端</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-open"
data-id="2"
data-level="high"
data-status="open"
data-tier="3"
data-tags="外部">
<div class="card-header">
<span class="item-title">微信开放平台与商户号申请</span>
<div class="card-badges">
<span class="tag status-badge s-open">待开始</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-3">三级</span>
<span class="tag sub-progress-badge">0/3 子任务</span>
</div>
</div>
<div class="item-desc">人工/外部流程,周期数周,是支付联调(#7)与上架的关键路径,第一天启动</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">0 / 3 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:0%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-open" data-sid="2A">
<span class="sub-icon s-open"></span>
<span class="sub-sid">2A</span>
<span class="sub-title">开放平台网站应用 + 移动应用注册提审</span>
<div class="sub-badges"><span class="tag tier-3">三级</span><span class="tag status-badge s-open">待开始</span></div>
</li>
<li class="subtask-item s-open" data-sid="2B">
<span class="sub-icon s-open"></span>
<span class="sub-sid">2B</span>
<span class="sub-title">微信支付商户号申请 + API 证书/密钥配置(入 Bitwarden</span>
<div class="sub-badges"><span class="tag tier-3">三级</span><span class="tag status-badge s-open">待开始</span></div>
</li>
<li class="subtask-item s-open" data-sid="2C">
<span class="sub-icon s-open"></span>
<span class="sub-sid">2C</span>
<span class="sub-title">软件著作权申请(输入法上架需要)</span>
<div class="sub-badges"><span class="tag tier-3">三级</span><span class="tag status-badge s-open">待开始</span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="外部">外部</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-open"
data-id="12"
data-level="high"
data-status="open"
data-tier="2"
data-tags="mac,Windows">
<div class="card-header">
<span class="item-title">桌面·联调与验收</span>
<div class="card-badges">
<span class="tag status-badge s-open">待开始</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-2">二级</span>
<span class="tag sub-progress-badge">0/3 子任务</span>
</div>
</div>
<div class="item-desc">汇聚点:依赖 #10 #11 全部与后端 #5 #6 #7</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">0 / 3 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:0%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-open" data-sid="12A">
<span class="sub-icon s-open"></span>
<span class="sub-sid">12A</span>
<span class="sub-title">全链路联调:快捷键→采集→流式→浮层→注入(mac+win 双平台)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-open">待开始</span></div>
</li>
<li class="subtask-item s-open" data-sid="12B">
<span class="sub-icon s-open"></span>
<span class="sub-sid">12B</span>
<span class="sub-title">延迟验收:first_partial P95&lt;500ms / release_to_commit&lt;300ms 实测调优</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-open">待开始</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-pending" title="12A 未完成">12A</span></span></div>
</li>
<li class="subtask-item s-open" data-sid="12C">
<span class="sub-icon s-open"></span>
<span class="sub-sid">12C</span>
<span class="sub-title">异常路径:断网重连/QUOTA/RATE_LIMITED/3 分钟截断逐项验证</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-open">待开始</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-pending" title="12A 未完成">12A</span></span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="mac">mac</span> <span class="tag t-tag" data-tag="Windows">Windows</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
</ul>
</div>
</div>
<div class="section-block" id="section-doing">
<div class="section-title st-doing" data-toggle="doing">
🔨 开发中 <span class="s-count">0</span>
<span class="s-arrow">▴ 收起</span>
</div>
<div class="section-list-wrap " id="list-wrap-doing">
<ul class="todo-list" id="list-doing">
<p class="empty-tip">暂无条目</p>
</ul>
</div>
</div>
<div class="section-block" id="section-done">
<div class="section-title st-done" data-toggle="done">
🔍 待验收 <span class="s-count">12</span>
<span class="s-arrow">▴ 收起</span>
</div>
<div class="section-list-wrap " id="list-wrap-done">
<ul class="todo-list" id="list-done">
<li class="todo-card s-done"
data-id="3"
data-level="high"
data-status="done"
data-tier="1"
data-tags="后端,跨端">
<div class="card-header">
<span class="item-title">协议与共享基建</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-1">一级</span>
<span class="tag sub-progress-badge">4/4 子任务</span>
<button class="reject-btn" data-id="3" data-title="协议与共享基建">拒绝验收</button>
</div>
</div>
<div class="item-desc">pkg/protocol 是 5 端对齐的唯一真相源,多数任务前置。设计依据 doc/backend-architecture.html 第四章</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">4 / 4 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="3A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">3A</span>
<span class="sub-title">pkg/protocolWS 帧结构(start/stop/cancel/partial/final/usage/error+ 错误码常量</span>
<div class="sub-badges"><span class="tag tier-1">一级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="3B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">3B</span>
<span class="sub-title">pkg/protocolREST DTOme/packs/orders/feedback/metrics</span>
<div class="sub-badges"><span class="tag tier-1">一级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="3C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">3C</span>
<span class="sub-title">design-pipelinetokens.css 导出 DuduTheme.swift / DuduTheme.kt + CI 校验</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="3D">
<span class="sub-icon s-done"></span>
<span class="sub-sid">3D</span>
<span class="sub-title">monorepo 骨架(server/desktop/android/ios 目录 + 根 README + CI 雏形)</span>
<div class="sub-badges"><span class="tag tier-3">三级</span><span class="tag status-badge s-done">待验收</span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span> <span class="tag t-tag" data-tag="跨端">跨端</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="4"
data-level="high"
data-status="done"
data-tier="1"
data-tags="后端,数据库">
<div class="card-header">
<span class="item-title">后端·工程与数据层</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-1">一级</span>
<span class="tag sub-progress-badge">3/3 子任务</span>
<button class="reject-btn" data-id="4" data-title="后端·工程与数据层">拒绝验收</button>
</div>
</div>
<div class="item-desc">schema 见 doc/backend-architecture.html 第六章</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">3 / 3 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="4A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">4A</span>
<span class="sub-title">Go 工程骨架:gin + 配置加载 + 日志 + Docker composepg/redis</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="4B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">4B</span>
<span class="sub-title">store:全部表 migration + gorm models11 张表,见后端文档第六章)</span>
<div class="sub-badges"><span class="tag tier-1">一级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="4A 已完成">4A</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="4C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">4C</span>
<span class="sub-title">Redis 接入 + Key 封装(quota/authqr/jwt:block/rate 滑动窗口)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="4A 已完成">4A</span></span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span> <span class="tag t-tag" data-tag="数据库">数据库</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="5"
data-level="high"
data-status="done"
data-tier="2"
data-tags="后端">
<div class="card-header">
<span class="item-title">后端·认证</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-2">二级</span>
<span class="tag sub-progress-badge">3/3 子任务</span>
<button class="reject-btn" data-id="5" data-title="后端·认证">拒绝验收</button>
</div>
</div>
<div class="item-desc">跨 epic 依赖:#4 骨架;5C 需 #2A 微信凭证(开发期可用测试号 mock)</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">3 / 3 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="5A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">5A</span>
<span class="sub-title">JWT 签发/校验中间件 + jti 黑名单 + logout</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="5B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">5B</span>
<span class="sub-title">扫码登录状态机(POST/GET /v1/auth/qrRedis state TTL 120s</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="5A 已完成">5A</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="5C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">5C</span>
<span class="sub-title">微信网页授权回调 + 移动端 code 换 token + unionid 关联建号</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="5A 已完成">5A</span></span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="6"
data-level="high"
data-status="done"
data-tier="1"
data-tags="后端">
<div class="card-header">
<span class="item-title">后端·识别网关</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-1">一级</span>
<span class="tag sub-progress-badge">5/5 子任务</span>
<button class="reject-btn" data-id="6" data-title="后端·识别网关">拒绝验收</button>
</div>
</div>
<div class="item-desc">跨 epic 依赖:#3A 协议、#4 骨架。含 Provider 抽象/中继/计量/识别限制</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">5 / 5 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="6A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">6A</span>
<span class="sub-title">ASR Provider 接口 + mock provider(脚本化回放 partial/final 供测试)</span>
<div class="sub-badges"><span class="tag tier-1">一级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="6B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">6B</span>
<span class="sub-title">gummy providerDashScope WS 对接,含断连重建,基于 1B demo)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="6A 已完成">6A</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="6C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">6C</span>
<span class="sub-title">WS 网关:连接鉴权 + 会话状态机 + 上下行双泵中继</span>
<div class="sub-badges"><span class="tag tier-1">一级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="6A 已完成">6A</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="6D">
<span class="sub-icon s-done"></span>
<span class="sub-sid">6D</span>
<span class="sub-title">计量与 usage 帧(实收帧时长累计、provider 时间戳交叉校验、2s 下发)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="6C 已完成">6C</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="6E">
<span class="sub-icon s-done"></span>
<span class="sub-sid">6E</span>
<span class="sub-title">识别限制:3 分钟截断定稿 + 单设备单路 + 30 分钟滑动窗口(次数/时长)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="6C 已完成">6C</span></span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="7"
data-level="high"
data-status="done"
data-tier="1"
data-tags="后端,数据库">
<div class="card-header">
<span class="item-title">后端·计费与配额</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-1">一级</span>
<span class="tag sub-progress-badge">4/4 子任务</span>
<button class="reject-btn" data-id="7" data-title="后端·计费与配额">拒绝验收</button>
</div>
</div>
<div class="item-desc">跨 epic 依赖:#47C/7D 真实支付需 #2B 商户号(可先沙箱)。时长账本设计见后端文档第五章</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">4 / 4 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="7A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">7A</span>
<span class="sub-title">quotaRedis Lua 原子扣减(先试用后余额)+ start 预检 + 扣穿当句不掐断</span>
<div class="sub-badges"><span class="tag tier-1">一级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="7B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">7B</span>
<span class="sub-title">quota:异步落库 ledger/asr_sessions + 余额冗余列 + 每日对账任务</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="7A 已完成">7A</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="7C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">7C</span>
<span class="sub-title">billingGET /v1/packs + 下单(native code_url / app 支付参数)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="7D">
<span class="sub-icon s-done"></span>
<span class="sub-sid">7D</span>
<span class="sub-title">billing:回调验签幂等入账(transaction_id 唯一)+ 订单轮询 + 5 分钟查单兜底</span>
<div class="sub-badges"><span class="tag tier-1">一级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="7C 已完成">7C</span></span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span> <span class="tag t-tag" data-tag="数据库">数据库</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="10"
data-level="high"
data-status="done"
data-tier="2"
data-tags="mac,Windows">
<div class="card-header">
<span class="item-title">桌面·Rust 系统能力</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-2">二级</span>
<span class="tag sub-progress-badge">8/8 子任务</span>
<button class="reject-btn" data-id="10" data-title="桌面·Rust 系统能力">拒绝验收</button>
</div>
</div>
<div class="item-desc">六项系统能力九成可并行;10C 依赖 #3A 协议</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">8 / 8 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="10A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">10A</span>
<span class="sub-title">Tauri 2 工程 + @dudu/design 接入 + data-theme 主题切换</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="10B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">10B</span>
<span class="sub-title">全局快捷键 push-to-talkpress/release 事件 + 自定义改键)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="10C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">10C</span>
<span class="sub-title">WS 客户端:预连接/心跳/指数退避重连 + 协议编解码</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="10D">
<span class="sub-icon s-done"></span>
<span class="sub-sid">10D</span>
<span class="sub-title">cpal 音频采集 + 16k 重采样 + 100ms 分帧 + 设备枚举/切换</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="10E">
<span class="sub-icon s-done"></span>
<span class="sub-sid">10E</span>
<span class="sub-title">macOS 文字注入(剪贴板+CGEvent+恢复)+ 辅助功能权限检测(基于 1C demo)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="10F">
<span class="sub-icon s-done"></span>
<span class="sub-sid">10F</span>
<span class="sub-title">Windows 文字注入(SendInput KEYEVENTF_UNICODE</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="10G">
<span class="sub-icon s-done"></span>
<span class="sub-sid">10G</span>
<span class="sub-title">Rust↔Web 事件桥(hotkey/asr/account/audio 事件 + invoke 命令集)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="10B 已完成">10B</span><span class="dep-badge dep-done" title="10C 已完成">10C</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="10H">
<span class="sub-icon s-done"></span>
<span class="sub-sid">10H</span>
<span class="sub-title">metrics 模块:本地队列(20 条/60s)+ 批量上报 + 漏斗事件汇入</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="10C 已完成">10C</span></span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="mac">mac</span> <span class="tag t-tag" data-tag="Windows">Windows</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="11"
data-level="high"
data-status="done"
data-tier="2"
data-tags="mac,Windows,前端">
<div class="card-header">
<span class="item-title">桌面·界面</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-block">高优 · 紧急</span>
<span class="tag tier-2">二级</span>
<span class="tag sub-progress-badge">6/6 子任务</span>
<button class="reject-btn" data-id="11" data-title="桌面·界面">拒绝验收</button>
</div>
</div>
<div class="item-desc">直接复用 design/ React 组件;可用 mock 事件与 #10 并行,最终联调依赖 10G 事件桥</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">6 / 6 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="11A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">11A</span>
<span class="sub-title">识别浮层窗口(透明/置顶/不抢焦点 + RecognitionOverlay 两态 + 错误态文案)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="11B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">11B</span>
<span class="sub-title">托盘 + 自绘托盘菜单(248px、accent 反白、检查更新入口)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="11C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">11C</span>
<span class="sub-title">设置窗口(四分组:输入/通用/账号与时长/帮助 + 持久化)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="11D">
<span class="sub-icon s-done"></span>
<span class="sub-sid">11D</span>
<span class="sub-title">登录/购买窗口(扫码轮询 → 时长包 → 支付二维码轮询 → 完成)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="11E">
<span class="sub-icon s-done"></span>
<span class="sub-sid">11E</span>
<span class="sub-title">反馈窗口(文字 + 图片粘贴/拖拽 + 诊断 Switch + 成功态)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="11F">
<span class="sub-icon s-done"></span>
<span class="sub-sid">11F</span>
<span class="sub-title">首次启动引导(欢迎 → 权限 → 登录 → 试一试)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="11C 已完成">11C</span></span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="mac">mac</span> <span class="tag t-tag" data-tag="Windows">Windows</span> <span class="tag t-tag" data-tag="前端">前端</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="8"
data-level="mid"
data-status="done"
data-tier="2"
data-tags="后端">
<div class="card-header">
<span class="item-title">后端·用户与周边</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-high">重要</span>
<span class="tag tier-2">二级</span>
<span class="tag sub-progress-badge">4/4 子任务</span>
<button class="reject-btn" data-id="8" data-title="后端·用户与周边">拒绝验收</button>
</div>
</div>
<div class="item-desc">跨 epic 依赖:#4。含 v1.1 新增 feedback/telemetry</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">4 / 4 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="8A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">8A</span>
<span class="sub-title">GET /v1/me 聚合(balance/trial/account_state 判定)+ devices 登记</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="8B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">8B</span>
<span class="sub-title">GET /v1/app/latest 版本检查</span>
<div class="sub-badges"><span class="tag tier-3">三级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="8C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">8C</span>
<span class="sub-title">feedbackmultipart 接收 + magic bytes 校验 + OSS 转存 + 10 条/天限频</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="8D">
<span class="sub-icon s-done"></span>
<span class="sub-sid">8D</span>
<span class="sub-title">telemetrymetrics/batch(白名单/截断/异步入库)+ 每日聚合 P50/P95 + 超标告警</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="9"
data-level="mid"
data-status="done"
data-tier="2"
data-tags="后端,CI/CD">
<div class="card-header">
<span class="item-title">后端·集成测试</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-high">重要</span>
<span class="tag tier-2">二级</span>
<span class="tag sub-progress-badge">2/2 子任务</span>
<button class="reject-btn" data-id="9" data-title="后端·集成测试">拒绝验收</button>
</div>
</div>
<div class="item-desc">汇聚点:依赖 #5 #6 #7 #8 主体完成</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">2 / 2 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="9A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">9A</span>
<span class="sub-title">WS E2Ewav 推流断言 partial/final/usage 序列与扣费正确(mock+gummy 双跑)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="9B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">9B</span>
<span class="sub-title">支付 E2E:沙箱/构造回调测幂等、金额校验、入账 + 限频用例(31 次/超 1800s</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="后端">后端</span> <span class="tag t-tag" data-tag="CI/CD">CI/CD</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="13"
data-level="mid"
data-status="done"
data-tier="2"
data-tags="Android">
<div class="card-header">
<span class="item-title">Android 输入法</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-high">重要</span>
<span class="tag tier-2">二级</span>
<span class="tag sub-progress-badge">6/6 子任务</span>
<button class="reject-btn" data-id="13" data-title="Android 输入法">拒绝验收</button>
</div>
</div>
<div class="item-desc">先于 iOS。UI 依赖 #3C 主题导出;联网依赖 #3A 与后端 #5 #6</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">6 / 6 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="13A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">13A</span>
<span class="sub-title">工程骨架 + DuduTheme.kt 接入(light/dark</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="13B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">13B</span>
<span class="sub-title">主 App:微信登录 + 启用引导三步 + 我的页(权限自检/试用进度/反馈入口)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="13A 已完成">13A</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="13C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">13C</span>
<span class="sub-title">主 App:购买时长页 + 微信 APP 支付</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="13B 已完成">13B</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="13D">
<span class="sub-icon s-done"></span>
<span class="sub-sid">13D</span>
<span class="sub-title">IME Service:键盘 UI 四态(工具条/功能键行/MicBar/partial 文本条)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="13A 已完成">13A</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="13E">
<span class="sub-icon s-done"></span>
<span class="sub-sid">13E</span>
<span class="sub-title">IME:录音 + WS 推流 + commitText 上屏 + 上滑取消</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="13D 已完成">13D</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="13F">
<span class="sub-icon s-done"></span>
<span class="sub-sid">13F</span>
<span class="sub-title">反馈页 + metrics 队列(WorkManager flush</span>
<div class="sub-badges"><span class="tag tier-3">三级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="13B 已完成">13B</span></span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="Android">Android</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="14"
data-level="mid"
data-status="done"
data-tier="2"
data-tags="iOS">
<div class="card-header">
<span class="item-title">iOS 输入法</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-high">重要</span>
<span class="tag tier-2">二级</span>
<span class="tag sub-progress-badge">5/5 子任务</span>
<button class="reject-btn" data-id="14" data-title="iOS 输入法">拒绝验收</button>
</div>
</div>
<div class="item-desc">14D 依赖 #1A spike 结论(主路径或 deep link 降级)。UI 依赖 #3C</div>
<div class="subtask-block">
<div class="subtask-header">
<span class="subtask-label">子任务</span>
<span class="subtask-progress-text">5 / 5 完成</span>
<div class="subtask-progress-bar"><div class="subtask-progress-fill" style="width:100%"></div></div>
</div>
<ul class="subtask-list"><li class="subtask-item s-done" data-sid="14A">
<span class="sub-icon s-done"></span>
<span class="sub-sid">14A</span>
<span class="sub-title">工程骨架(App+Keyboard Extension+App Group+ DuduTheme.swift 接入</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span></div>
</li>
<li class="subtask-item s-done" data-sid="14B">
<span class="sub-icon s-done"></span>
<span class="sub-sid">14B</span>
<span class="sub-title">主 App:微信登录 + 引导(含完全访问步)+ 我的 + 购买(APP 支付)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="14A 已完成">14A</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="14C">
<span class="sub-icon s-done"></span>
<span class="sub-sid">14C</span>
<span class="sub-title">键盘扩展:UI 四态 + textDocumentProxy 上屏框架</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="14A 已完成">14A</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="14D">
<span class="sub-icon s-done"></span>
<span class="sub-sid">14D</span>
<span class="sub-title">键盘扩展:录音 + WS 推流(按 1A 结论实现主路径或 deep link 降级)</span>
<div class="sub-badges"><span class="tag tier-2">二级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="14C 已完成">14C</span></span></div>
</li>
<li class="subtask-item s-done" data-sid="14E">
<span class="sub-icon s-done"></span>
<span class="sub-sid">14E</span>
<span class="sub-title">反馈页 + metricsApp Group 队列)+ iPad 布局适配</span>
<div class="sub-badges"><span class="tag tier-3">三级</span><span class="tag status-badge s-done">待验收</span><span class="dep-section"><span class="dep-label">依赖:</span><span class="dep-badge dep-done" title="14B 已完成">14B</span><span class="dep-badge dep-done" title="14C 已完成">14C</span></span></div>
</li></ul>
</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="iOS">iOS</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
<li class="todo-card s-done"
data-id="15"
data-level="mid"
data-status="done"
data-tier="3"
data-tags="Web,前端">
<div class="card-header">
<span class="item-title">官网宣传页(web/index.html</span>
<div class="card-badges">
<span class="tag status-badge s-done">待验收</span>
<span class="tag t-high">重要</span>
<span class="tag tier-3">三级</span>
<button class="reject-btn" data-id="15" data-title="官网宣传页(web/index.html">拒绝验收</button>
</div>
</div>
<div class="item-desc">单页静态宣传页,复用设计系统品牌语言,含按住说话交互演示;后续接真实下载链接与备案号</div>
<div class="card-footer">
<div class="tag-row"><span class="tag t-tag" data-tag="Web">Web</span> <span class="tag t-tag" data-tag="前端">前端</span></div>
<div class="item-meta">
<span class="meta-date">🕐 2026-06-11</span>
</div>
</div>
</li>
</ul>
</div>
</div>
<div class="section-block" id="section-accepted">
<div class="section-title st-accepted" data-toggle="accepted">
✅ 已验收 <span class="s-count">0</span>
<span class="s-arrow">▾ 展开</span>
</div>
<div class="section-list-wrap collapsed" id="list-wrap-accepted">
<ul class="todo-list" id="list-accepted">
<p class="empty-tip">暂无条目</p>
</ul>
</div>
</div>
</div>
<!-- 拒绝验收 Modal -->
<div id="reject-modal" class="modal-overlay" style="display:none">
<div class="modal-box">
<h3>拒绝验收</h3>
<p class="modal-subtitle" id="reject-modal-subtitle"></p>
<label class="modal-label">拒绝原因<span class="req">*</span></label>
<textarea class="modal-textarea" id="reject-reason-input" rows="3" placeholder="请说明具体问题,Claude 将以此为依据修复…"></textarea>
<div class="modal-err" id="reject-reason-err">请填写拒绝原因</div>
<div id="reject-cmd-wrap" class="modal-cmd-wrap" style="display:none">
<div class="modal-cmd-label">在终端运行以下命令:</div>
<code class="modal-cmd-code" id="reject-cmd-text"></code>
<button class="modal-copy-btn" id="reject-copy-btn">复制命令</button>
</div>
<div class="modal-actions">
<button class="modal-btn modal-btn-cancel" id="reject-cancel-btn">取消</button>
<button class="modal-btn modal-btn-reject" id="reject-confirm-btn">确认拒绝</button>
</div>
</div>
</div>
<script>
(function() {
let curLevel = 'all';
let curStatus = 'all';
let curTier = 'all';
let curTags = new Set();
function applyFilter() {
document.querySelectorAll('.todo-card').forEach(card => {
const lvl = card.dataset.level;
const status = card.dataset.status;
const tier = card.dataset.tier;
const tags = card.dataset.tags ? card.dataset.tags.split(',') : [];
let show = true;
if (curLevel !== 'all' && lvl !== curLevel) show = false;
if (curStatus !== 'all' && status !== curStatus) show = false;
if (curTier !== 'all' && String(tier) !== curTier) show = false;
if (curTags.size > 0 && ![...curTags].some(t => tags.includes(t))) show = false;
card.classList.toggle('hidden', !show);
});
if (curStatus !== 'all') {
const wrap = document.getElementById('list-wrap-' + curStatus);
if (wrap) {
wrap.classList.remove('collapsed');
const title = document.querySelector('[data-toggle="' + curStatus + '"] .s-arrow');
if (title) title.textContent = '▴ 收起';
}
}
}
document.querySelectorAll('[data-filter-level]').forEach(btn => {
btn.addEventListener('click', () => {
curLevel = btn.dataset.filterLevel;
document.querySelectorAll('[data-filter-level]').forEach(b => b.classList.toggle('active', b === btn));
applyFilter();
});
});
document.querySelectorAll('[data-filter-tier]').forEach(btn => {
btn.addEventListener('click', () => {
curTier = btn.dataset.filterTier;
document.querySelectorAll('[data-filter-tier]').forEach(b => b.classList.toggle('active', b === btn));
applyFilter();
});
});
document.querySelectorAll('[data-filter-status]').forEach(btn => {
btn.addEventListener('click', () => {
curStatus = btn.dataset.filterStatus;
document.querySelectorAll('[data-filter-status]').forEach(b => b.classList.toggle('active', b === btn));
applyFilter();
});
});
document.querySelectorAll('[data-filter-tag]').forEach(btn => {
btn.addEventListener('click', () => {
const t = btn.dataset.filterTag;
if (curTags.has(t)) { curTags.delete(t); btn.classList.remove('active'); }
else { curTags.add(t); btn.classList.add('active'); }
applyFilter();
});
});
document.querySelectorAll('.t-tag').forEach(tag => {
tag.addEventListener('click', e => {
e.stopPropagation();
const t = tag.dataset.tag;
const chip = document.querySelector('[data-filter-tag="'+t+'"]');
if (chip) chip.click();
});
});
document.querySelectorAll('.section-title[data-toggle]').forEach(title => {
title.addEventListener('click', () => {
const st = title.dataset.toggle;
const wrap = document.getElementById('list-wrap-' + st);
const arrow = title.querySelector('.s-arrow');
if (!wrap) return;
const collapsed = wrap.classList.toggle('collapsed');
if (arrow) arrow.textContent = collapsed ? '▾ 展开' : '▴ 收起';
});
});
// ── 拒绝验收 Modal ──
const modal = document.getElementById('reject-modal');
const reasonInput = document.getElementById('reject-reason-input');
const reasonErr = document.getElementById('reject-reason-err');
const cmdWrap = document.getElementById('reject-cmd-wrap');
const cmdText = document.getElementById('reject-cmd-text');
const copyBtn = document.getElementById('reject-copy-btn');
let rejectId = null;
document.querySelectorAll('.reject-btn').forEach(btn => {
btn.addEventListener('click', e => {
e.stopPropagation();
rejectId = btn.dataset.id;
document.getElementById('reject-modal-subtitle').textContent = '#' + rejectId + ' ' + btn.dataset.title;
reasonInput.value = '';
reasonInput.classList.remove('error');
reasonErr.classList.remove('show');
cmdWrap.style.display = 'none';
document.getElementById('reject-confirm-btn').style.display = '';
copyBtn.textContent = '复制命令';
modal.style.display = 'flex';
setTimeout(() => reasonInput.focus(), 80);
});
});
document.getElementById('reject-cancel-btn').addEventListener('click', () => {
modal.style.display = 'none';
});
modal.addEventListener('click', e => {
if (e.target === modal) modal.style.display = 'none';
});
document.getElementById('reject-confirm-btn').addEventListener('click', () => {
const reason = reasonInput.value.trim();
if (!reason) {
reasonInput.classList.add('error');
reasonErr.classList.add('show');
reasonInput.focus();
return;
}
const escaped = reason.replace(/\/g, '\\').replace(/"/g, '\"');
const cmd = '/todo reject ' + rejectId + ' ' + escaped;
cmdText.textContent = cmd;
cmdWrap.style.display = 'block';
document.getElementById('reject-confirm-btn').style.display = 'none';
});
reasonInput.addEventListener('input', () => {
if (reasonInput.value.trim()) {
reasonInput.classList.remove('error');
reasonErr.classList.remove('show');
}
});
copyBtn.addEventListener('click', () => {
navigator.clipboard.writeText(cmdText.textContent).then(() => {
copyBtn.textContent = '已复制 ';
});
});
// ── 确认闸:展开命令 + 复制 ──
document.querySelectorAll('.approve-btn').forEach(btn => {
btn.addEventListener('click', e => {
e.stopPropagation();
const box = document.getElementById('approve-cmd-' + btn.dataset.id);
if (box) box.style.display = box.style.display === 'none' ? 'block' : 'none';
});
});
document.querySelectorAll('.approve-copy-btn').forEach(btn => {
btn.addEventListener('click', e => {
e.stopPropagation();
navigator.clipboard.writeText(btn.dataset.cmd).then(() => { btn.textContent = '已复制 '; });
});
});
})();
</script>
</body>
</html>