fix: 应用 xhigh 代码评审的跨端修复
来自 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>
This commit is contained in:
+522
-11
@@ -254,10 +254,10 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
<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>22</strong>全部</div>
|
||||
<div class="stat-pill"><strong>4</strong>待开始</div>
|
||||
<div class="stat-pill"><strong>0</strong>开发中</div>
|
||||
<div class="stat-pill"><strong>12</strong>待验收</div>
|
||||
<div class="stat-pill"><strong>18</strong>待验收</div>
|
||||
<div class="stat-pill"><strong>0</strong>已验收</div>
|
||||
|
||||
</div>
|
||||
@@ -292,7 +292,7 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
<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="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>
|
||||
|
||||
@@ -301,7 +301,7 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
|
||||
<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-count">4</span>
|
||||
<span class="s-arrow">▴ 收起</span>
|
||||
</div>
|
||||
<div class="section-list-wrap " id="list-wrap-open">
|
||||
@@ -462,6 +462,35 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
<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>
|
||||
@@ -481,7 +510,7 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
</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-count">18</span>
|
||||
<span class="s-arrow">▴ 收起</span>
|
||||
</div>
|
||||
<div class="section-list-wrap " id="list-wrap-done">
|
||||
@@ -930,6 +959,255 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
</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"
|
||||
@@ -1197,6 +1475,213 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
<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>
|
||||
@@ -1244,6 +1729,16 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
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;
|
||||
@@ -1364,8 +1859,13 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
reasonInput.focus();
|
||||
return;
|
||||
}
|
||||
const escaped = reason.replace(/\/g, '\\').replace(/"/g, '\"');
|
||||
const cmd = '/todo reject ' + rejectId + ' ' + escaped;
|
||||
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';
|
||||
@@ -1384,12 +1884,23 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
|
||||
});
|
||||
});
|
||||
|
||||
// ── 确认闸:展开命令 + 复制 ──
|
||||
// ── 确认闸:服务模式直接写库;file:// 模式回退为展开命令 ──
|
||||
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';
|
||||
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 => {
|
||||
|
||||
Reference in New Issue
Block a user