b5ab92a57e
来自 xhigh code review 的正确性/健壮性修复,覆盖全部五端: - server:鉴权 fail-closed、计量交叉校验与配额扣穿处理、WS 网关并发与关闭顺序、 billing 行锁、redis Lua 过期与设备槽刷新、config 解析 - desktop:会话 epoch 防串话、WS 重连与 401 处理、api 客户端复用、统一 usePoll 轮询 - android:握手时序、请求头封装、账户状态派生、按需重组 - ios:finalize 宽限、串行采集、错误文案服务端优先、删除死代码 CommitController Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1915 lines
95 KiB
HTML
1915 lines
95 KiB
HTML
<!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>22</strong>全部</div>
|
||
<div class="stat-pill"><strong>4</strong>待开始</div>
|
||
<div class="stat-pill"><strong>0</strong>开发中</div>
|
||
<div class="stat-pill"><strong>18</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><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">4</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 流式接入 demo(Go 直连 DashScope WS,wav 推流收 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<500ms / release_to_commit<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>
|
||
|
||
<li class="todo-card s-open"
|
||
data-id="22"
|
||
data-level="mid"
|
||
data-status="open"
|
||
data-tier="1"
|
||
data-tags="跨端,文档">
|
||
<div class="card-header">
|
||
<span class="item-title">跨端架构改进 backlog(评审后再做)</span>
|
||
<div class="card-badges">
|
||
<span class="tag status-badge s-open">待开始</span>
|
||
<span class="tag t-high">重要</span>
|
||
<span class="tag tier-1">一级</span>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item-desc">本轮不改代码,仅记录待评审:限制常量(180s/30次/1800s)服务端下发、gummy 断连重建分层、三端 WS 连接策略统一、错误码文案服务端下发、web 价格表第三份副本与 SeedPacks 单源、设备准入校验防随机 device_id 绕过限流</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-12</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">18</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/protocol:WS 帧结构(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/protocol:REST DTO(me/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-pipeline:tokens.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 compose(pg/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 models(11 张表,见后端文档第六章)</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/qr,Redis 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 provider(DashScope 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 依赖:#4;7C/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">quota:Redis 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">billing:GET /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-talk(press/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="16"
|
||
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">7/7 子任务</span>
|
||
<button class="reject-btn" data-id="16" data-title="后端·网关与计费正确性修复">拒绝验收</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item-desc">code-review 发现的网关/计费严重 bug:截断或 provider 死亡后仍扣费、WriteJSON 无写超时致 goroutine 泄漏、WaitGroup Add 竞态、finish 漏在途扣费、扣穿当句未掐断致白嫖、GORM v2 锁失效、usage 帧 omitempty 吞合法 0 值</div>
|
||
|
||
<div class="subtask-block">
|
||
<div class="subtask-header">
|
||
<span class="subtask-label">子任务</span>
|
||
<span class="subtask-progress-text">7 / 7 完成</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="16A">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">16A</span>
|
||
<span class="sub-title">feed 先判截断再累计;provider 死亡/截断后终结会话停止扣费</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="16B">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">16B</span>
|
||
<span class="sub-title">wsConn 写超时(SetWriteDeadline)+finish 的 Wait 加超时+修 defer 顺序避免 goroutine 泄漏</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="16C">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">16C</span>
|
||
<span class="sub-title">resultsDone.Add(1) 移到 go 语句之前,消除 WaitGroup 竞态</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="16D">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">16D</span>
|
||
<span class="sub-title">finish 等待在途 consumeDelta 完成后再取 settle 快照,避免漏账</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="16E">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">16E</span>
|
||
<span class="sub-title">扣穿当句不掐断:consumeDelta 扣穿后置标志,本句 final 后下发 QUOTA_EXCEEDED 结束会话</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="16F">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">16F</span>
|
||
<span class="sub-title">billing.MarkPaid 改用 GORM v2 Clauses(锁)写法,恢复行锁</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="16G">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">16G</span>
|
||
<span class="sub-title">usage 帧 SessionSeconds/BalanceSeconds/TrialRemaining 去掉 omitempty,让 0 显式下发</span>
|
||
<div class="sub-badges"><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-12</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card s-done"
|
||
data-id="17"
|
||
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">9/9 子任务</span>
|
||
<button class="reject-btn" data-id="17" data-title="后端·认证限流与依赖装配修复">拒绝验收</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item-desc">JWT 黑名单 fail-open、logout TTL 硬编码 8 天、滑动窗口 seq 键永不过期、设备槽 4min TTL 不续期、pickProvider 永远 mock(gummy 永不装配)、/v1/pay/notify 无鉴权+pickPay 永远 mock=免费充值、metrics/batch 无可选鉴权 user_id 恒空、AppLatest 裸读 env、死代码清理</div>
|
||
|
||
<div class="subtask-block">
|
||
<div class="subtask-header">
|
||
<span class="subtask-label">子任务</span>
|
||
<span class="subtask-progress-text">9 / 9 完成</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="17A">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">17A</span>
|
||
<span class="sub-title">JWT 黑名单检查 fail-closed:Redis Exists 出错时拒绝并记录,不放行</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="17B">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">17B</span>
|
||
<span class="sub-title">logout Revoke TTL 用 token 实际过期时间(claims.ExpiresAt),不硬编码 8 天</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="17C">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">17C</span>
|
||
<span class="sub-title">滑动窗口 Lua 给 key:seq 计数器设 EXPIRE,消除永久泄漏键</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="17D">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">17D</span>
|
||
<span class="sub-title">设备槽会话期间续期 TTL(usageLoop 里 EXPIRE),避免长会话槽过期致多路</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="17E">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">17E</span>
|
||
<span class="sub-title">pickProvider 真正按 ASR_PROVIDER 装配 gummy(有 key 用 gummy),启动日志打印 real/mock</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="17F">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">17F</span>
|
||
<span class="sub-title">metrics/batch 挂可选鉴权中间件,注入 user_id</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="17G">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">17G</span>
|
||
<span class="sub-title">AppLatest 配置进 config.Load 启动校验,避免每请求裸读 env</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="17H">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">17H</span>
|
||
<span class="sub-title">清理死代码:AllowAudioSeconds、fmt 占位行、gummy lastText 字段</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="17I">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">17I</span>
|
||
<span class="sub-title">pay/notify 鉴权与验签:MockPay 加共享密钥校验或文档标注部署前必换真实验签</span>
|
||
<div class="sub-badges"><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-12</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card s-done"
|
||
data-id="18"
|
||
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="18" data-title="桌面 Rust 客户端正确性修复">拒绝验收</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item-desc">取消后晚到 final 残留 CommitBuffer 错上下文注入、stop spawn 无 abort/代际校验、350ms 固定延迟改事件驱动、token/device_id parse unwrap panic、重连不重建会话丢音频、UNAUTHORIZED 无处理+unbounded channel 堆积、emit 全局广播 6 窗口、reqwest Client 每次新建、platform=macos 不符约定、check_update 忽略 force</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="18A">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">18A</span>
|
||
<span class="sub-title">dictation 会话代际+取消守卫:取消后晚到 final 不残留、不注入错上下文</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="18B">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">18B</span>
|
||
<span class="sub-title">stop spawn 任务加代际校验,快速连说不串文本/不误隐藏新会话浮层</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="18C">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">18C</span>
|
||
<span class="sub-title">收尾注入改事件驱动(收到 stop 后 final/usage 即注入),350ms 仅作超时兜底</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="18D">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">18D</span>
|
||
<span class="sub-title">ws.rs token/device_id 用 HeaderValue::from_str 优雅处理非法值,不 unwrap panic</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="18E">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">18E</span>
|
||
<span class="sub-title">ws.rs 重连后若会话进行中重发 start 或通知客户端会话失败,避免静默丢音频</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="18F">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">18F</span>
|
||
<span class="sub-title">ws.rs 处理 UNAUTHORIZED(emit+清 token 引导登录)+音频 channel 改 bounded</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="18G">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">18G</span>
|
||
<span class="sub-title">asr/hotkey 事件改 emit_to(overlay) 定向,不广播 6 窗口</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="18H">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">18H</span>
|
||
<span class="sub-title">reqwest::Client 改 OnceLock 共享实例;metrics platform 改 mac/win;check_update 处理 force</span>
|
||
<div class="sub-badges"><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="mac">mac</span> <span class="tag t-tag" data-tag="Windows">Windows</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-12</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">feedback:multipart 接收 + 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">telemetry:metrics/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 E2E:wav 推流断言 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">反馈页 + metrics(App 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>
|
||
|
||
<li class="todo-card s-done"
|
||
data-id="19"
|
||
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">5/5 子任务</span>
|
||
<button class="reject-btn" data-id="19" data-title="桌面前端正确性修复">拒绝验收</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item-desc">登录 QR 不处理 expired+隐藏窗口永久轮询、设置整结构回写覆盖 token 致登出、overlay 错误帧 BAD_REQUEST/INTERNAL 无文案 setError 空、tray/login 窗口主题未初始化、轮询样板收敛 usePoll</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="19A">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">19A</span>
|
||
<span class="sub-title">登录 QR 轮询处理 expired 自动换码;窗口隐藏(非卸载)时停止轮询</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="19B">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">19B</span>
|
||
<span class="sub-title">设置窗口改增量写(set_settings 仅传改动项),不整结构覆盖 token</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="19C">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">19C</span>
|
||
<span class="sub-title">overlay 错误帧兜底文案(BAD_REQUEST/INTERNAL/未知码),不 setError 空串</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="19D">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">19D</span>
|
||
<span class="sub-title">tray/login 入口补主题初始化(get_settings→setThemePref)</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="19E">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">19E</span>
|
||
<span class="sub-title">收敛轮询样板为 shared/usePoll 钩子(存活标志+清理+在途去重)</span>
|
||
<div class="sub-badges"><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-12</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card s-done"
|
||
data-id="20"
|
||
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">5/5 子任务</span>
|
||
<button class="reject-btn" data-id="20" data-title="Android 客户端正确性修复">拒绝验收</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item-desc">onRelease 在 onOpen 前 sendStop 时序错乱致空文本、/v1/me 未发 X-Device-ID 致 touchDevice no-op、错误文案改 server-first、AccountRepository 冗余派生状态简化、KeyboardScreen partial 全屏重组收窄</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="20A">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">20A</span>
|
||
<span class="sub-title">onRelease 等 onOpen 后再 sendStop(或缓冲 stop 待 start 后补发),修握手时序</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="20B">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">20B</span>
|
||
<span class="sub-title">/v1/me 请求带 X-Device-ID 头,使 touchDevice 生效</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="20C">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">20C</span>
|
||
<span class="sub-title">错误文案改 server message 优先、本地表仅兜底未知码</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="20D">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">20D</span>
|
||
<span class="sub-title">AccountRepository 只存 token/balance/trialUsed/limit,state/trialRemaining 推导</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="20E">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">20E</span>
|
||
<span class="sub-title">KeyboardScreen 拆分状态流,partial 只重组 PartialBar</span>
|
||
<div class="sub-badges"><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="Android">Android</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-12</span>
|
||
|
||
</div>
|
||
</div>
|
||
</li>
|
||
|
||
<li class="todo-card s-done"
|
||
data-id="21"
|
||
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">7/7 子任务</span>
|
||
<button class="reject-btn" data-id="21" data-title="iOS 客户端正确性修复">拒绝验收</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item-desc">finishing 阶段周期 usage 帧误判 stop 结算致丢字、AsrAudioCapture stop 与 tap 回调数据竞争崩溃、usage omitempty 0 值处理、CommitController 死代码删除、180s 本地计时器双轨移除、MetricsQueue 每事件全目录扫描、错误文案 server-first、deep link 剪贴板无条件覆盖</div>
|
||
|
||
<div class="subtask-block">
|
||
<div class="subtask-header">
|
||
<span class="subtask-label">子任务</span>
|
||
<span class="subtask-progress-text">7 / 7 完成</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="21A">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">21A</span>
|
||
<span class="sub-title">finishing 阶段只用收尾标志/final 结束会话,不把周期 usage 帧当 stop 结算致丢字</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="21B">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">21B</span>
|
||
<span class="sub-title">AsrAudioCapture stop 与 tap 回调同步(串行队列/锁),消除数据竞争崩溃</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="21C">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">21C</span>
|
||
<span class="sub-title">applyUsage 处理 usage 0 值(协议去 omitempty 后按 0 覆盖余额/试用)</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="21D">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">21D</span>
|
||
<span class="sub-title">删除 CommitController 死代码(移出键盘 target)</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="21E">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">21E</span>
|
||
<span class="sub-title">移除 iOS 180s 本地强制定稿计时器,统一以服务端 SESSION_LIMIT 为准</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="21F">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">21F</span>
|
||
<span class="sub-title">MetricsQueue 改近似计数/flush 时 trim,不每事件全目录扫描</span>
|
||
<div class="sub-badges"><span class="tag status-badge s-done">待验收</span></div>
|
||
</li>
|
||
<li class="subtask-item s-done" data-sid="21G">
|
||
<span class="sub-icon s-done">✓</span>
|
||
<span class="sub-sid">21G</span>
|
||
<span class="sub-title">错误文案 server message 优先;deep link 剪贴板覆盖降级为兜底</span>
|
||
<div class="sub-badges"><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="iOS">iOS</span></div>
|
||
<div class="item-meta">
|
||
<span class="meta-date">🕐 2026-06-12</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();
|
||
|
||
// 通过本地服务(http)打开时,按钮直接写库;用 file:// 直接打开则回退为「复制命令」
|
||
const SERVED = location.protocol === 'http:' || location.protocol === 'https:';
|
||
function postAction(url, payload) {
|
||
return fetch(url, {
|
||
method: 'POST',
|
||
headers: payload ? { 'Content-Type': 'application/json' } : undefined,
|
||
body: payload ? JSON.stringify(payload) : undefined,
|
||
}).then(r => r.json());
|
||
}
|
||
|
||
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;
|
||
}
|
||
if (SERVED) {
|
||
postAction('/api/reject/' + rejectId, { reason })
|
||
.then(d => { if (d.ok) { location.reload(); } else { alert('拒绝失败:' + (d.error || '')); } })
|
||
.catch(() => alert('请求失败,确认本地服务是否在运行'));
|
||
return;
|
||
}
|
||
const cmd = '/todo reject ' + rejectId + ' ' + JSON.stringify(reason);
|
||
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 = '已复制 ✓';
|
||
});
|
||
});
|
||
|
||
// ── 确认闸:服务模式直接写库;file:// 模式回退为展开命令 ──
|
||
document.querySelectorAll('.approve-btn').forEach(btn => {
|
||
btn.addEventListener('click', e => {
|
||
e.stopPropagation();
|
||
const id = btn.dataset.id;
|
||
if (SERVED) {
|
||
btn.disabled = true; btn.textContent = '确认中…';
|
||
postAction('/api/approve/' + id)
|
||
.then(d => {
|
||
if (d.ok) { location.reload(); }
|
||
else { btn.disabled = false; btn.textContent = '确认执行 ✓'; alert('确认失败:' + (d.error || '')); }
|
||
})
|
||
.catch(() => { btn.disabled = false; btn.textContent = '确认执行 ✓'; alert('请求失败,确认本地服务是否在运行'); });
|
||
} else {
|
||
const box = document.getElementById('approve-cmd-' + 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> |