feat(tsk_PbcHccuPmwxV): 任务取消/删除 UI 入口(带确认)

## 后端
- Store.deleteTask():BFS 收集子孙 id,清理 events,删根节点(子孙/runs/approvals 由 FK CASCADE 自动清除),广播 task.updated{kind:'delete'}
- API POST /api/tasks/:id/cancel:transition → cancelled(复用状态机守卫)
- API DELETE /api/tasks/:id:级联删除任务及子孙

## 前端
- 任务行(task-row):鼠标悬停后右侧出现「✕取消」「🗑删除」浮动按钮,点击弹 confirm() 二次确认(含子孙数提示),stopPropagation 防止触发行展开
- 任务详情(detail):底部行内确认区——「取消任务」显示确认条(确认取消 / 算了),「删除」显示含级联提示的高亮确认条,折叠/切换项目时自动清除确认状态
- 归档详情对话框:底部增加「🗑 删除归档」按钮,confirm() 确认后删除并关闭弹窗
- CSS:.task-row-cancel/.task-row-delete(悬停淡入)、.detail-actions / .detail-action-confirm / .detail-confirm-msg、.archive-modal-actions

## 测试
- 新增 4 个 store 测试:deleteTask 叶子、deleteTask 级联、deleteTask 不存在、transition→cancelled
- 全部 78 条 pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 03:37:01 +08:00
parent 740d2c2637
commit b60225779c
5 changed files with 279 additions and 3 deletions
+36 -1
View File
@@ -608,7 +608,8 @@ li.ev-updated { --ev: var(--muted); }
max-height: none; overflow-y: visible; /* 解除闸卡片 pre.doc 的 280px 限高,由 .preview-body 统一滚动 */
}
.preview-body .gate-doc-label { margin-top: 14px; }
.preview-foot {
.preview-foot,
.archive-modal-actions {
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
padding: 12px 16px; border-top: 1px solid var(--line);
background: var(--panel-2);
@@ -770,3 +771,37 @@ li.ev-updated { --ev: var(--muted); }
/* 配置面板内的同步行 */
.cfg-sync-row { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--line-soft); align-items: center; gap: 10px; }
/* ── 任务行:取消 / 删除快捷按钮(默认隐藏,鼠标悬停行时显示) ── */
.task-row-cancel,
.task-row-delete {
flex: none; opacity: 0; transition: opacity .15s;
pointer-events: none;
}
.task-row:hover .task-row-cancel,
.task-row:hover .task-row-delete {
opacity: 1; pointer-events: auto;
}
.task-row-cancel { color: var(--red); }
.task-row-delete { color: var(--faint); }
.task-row-delete:hover { color: var(--red) !important; }
/* ── 任务详情:取消 / 删除操作区 ── */
.detail-actions {
display: flex; align-items: flex-start; gap: 10px;
flex-wrap: wrap;
padding-top: 6px;
border-top: 1px dashed var(--line-soft);
}
.detail-action-confirm {
display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
padding: 6px 10px;
background: rgba(255,93,93,.06);
border: 1px solid var(--red-dim);
}
.detail-action-confirm-del {
background: rgba(255,93,93,.09);
}
.detail-confirm-msg {
font-size: 12px; color: var(--ink);
}