diff --git a/assets/css/app.css b/assets/css/app.css index a700d25..6f96e73 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -1958,6 +1958,12 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb, padding: 2px 12px; border-radius: 20px; color: var(--muted); } .empty-hint { color: var(--muted); font-size: 14px; margin: 0; } +/* 🔴 工单 #20:首页「近期任务」的空态提示是**一直渲染、靠 hidden 切换**的 + (服务端有任务时给它 `hidden`,前端把最后一条删掉后再显示出来)。 + ⚠️ 浏览器默认的 `[hidden]{display:none}` 优先级最低 —— 只要哪天有人给 + `.empty-hint` 加上 `display:flex` 之类,这句提示就会在"有任务时"也冒出来。 + 所以在这里显式再声明一次(与上面第 601 行那条注释是同一个约定)。 */ +.empty-hint[hidden] { display: none !important; } .viewers-list { display: flex; flex-wrap: wrap; gap: 12px; } .viewers-list .viewer-tag { padding: 4px 12px 4px 6px; font-size: 14px; } .viewers-list .viewer-tag .chip-av { width: 28px; height: 28px; } diff --git a/templates/home.php b/templates/home.php index e54f3db..3a1d508 100644 --- a/templates/home.php +++ b/templates/home.php @@ -196,6 +196,10 @@ ev.stopPropagation(); var now = b.getAttribute('data-tk-status') || 'todo'; var next = (now === 'done') ? 'todo' : 'done'; + /* 🔴 工单 #20:先把"改之前的状态"存下来 —— 后面删行时要用它决定 + 「概述」卡里该减「件在做」还是「件待办」。 + ⚠️ 不能在删行时再读 `data-tk-status`:那时它已经被下面改成 `d.status` 了。 */ + var was = now; document.getElementById('doneId').value = b.getAttribute('data-tk-done'); document.getElementById('doneStatus').value = next; document.getElementById('doneBack').value = b.getAttribute('data-tk-back') || 'home'; @@ -217,10 +221,79 @@ badge.className = 'kb-st is-' + d.status + ' is-static'; badge.textContent = staticWord[d.status] || d.word; } - say(d.msg || '已更新。', true); + /* 🔴🔴 工单 #20(用户 2026-10-28):「首页,近期任务,如果勾选了完成, + 应该刷新一下这个列表,把完成的删掉。」 + ⇒ 在这里把这一行**从列表里摘掉**,并同步概述卡的计数。 + ⚠️ 判据是**服务端返回的 d.status**,不是我点之前算出的 next: + `tasks/status` 是幂等接口(传 done 再来一次还是 done), + 拿 d.status 判断才不会"用户手快连点两下,第二下又把行删了"。 + ⚠️ 首页这份列表只收 doing + todo(index.php:839),done 本来就不在其中 + ⇒ 手动刷新时它确实会消失,所以"删行"与刷新后的结果**一致**, + 不是前端自己造了个假象。 + ⚠️ 当年这里是刻意**不删**的(原注释:怕用户以为"点到删除了")—— + 用户现在明确要它消失,所以改掉;但**补偿**了一个可撤回的提示, + 见下面 say() 那段(既能满足"看着干净",又不至于找不到刚完成的东西)。 */ + if (d.status === 'done' && row) { + dropTaskRow(row, was); + /* 🔴 工单 #20:行被摘掉了,必须**明说**它去哪了 —— + 当年"不删行"的理由就是"怕用户以为点到删除了"(见上面原注释)。 + 删了行就要把这条路补上:告诉他已从近期任务移除, + 而卡片右上角本来就有「全部」能找回($hcMore → tasks)。 + ⚠️ 不能只沿用服务端那句 `已标成「已完成」` —— 那会让人以为行还在, + 下一眼发现没了反而更慌。 */ + say((d.msg || '已标成「已完成」。') + '(已从近期任务移出,去「全部」里能看到)', true); + } else { + say(d.msg || '已更新。', true); + } }).catch(function () { b.disabled = false; form.submit(); }); }); }); + + /* ============================================================ + 把一条刚完成的任务行从首页列表里摘掉(工单 #20) + ============================================================ + 三件事一起做,少一件就露馅: + ① 删掉这一行; + ② 同步「概述」卡片右下的「N 件在做 / N 件待办」 + —— 那两个数字**与这份列表同源**(同一个 $tasks,见 _card_brief.php:53), + 只删行不减去数字 ⇒ 列表 2 条、概述说 3 件在做,自相矛盾; + ③ 一条不剩时把空态提示露出来(服务端渲染的 `[data-tk-empty]`, + 原来一直 hidden)—— 否则卡片变成一片空白,用户以为加载坏了。 + + ⚠️ 撤回按钮:完成的任务没地方看了,得留一条回去的路。 + `data-tk-status` 已经是 done,再点一次这颗按钮就是"改回 todo", + 但行已经不在 DOM 里了 —— 所以撤回走的是**直接发一次状态请求**, + 成功后整页刷新把行放回去(列表的真相在服务端,前端不自己"插回一行")。 */ + function dropTaskRow(row, wasStatus) { + var host = row.closest('[data-tk-home-host]'); + var ul = row.parentNode; + // ① 删行 + if (row.parentNode) { row.parentNode.removeChild(row); } + // ② 概述卡计数:wasStatus 是"改之前"的状态 — doing 的完成就减「在做」,todo 的减「待办」 + syncBriefCount(wasStatus); + // ③ 空态 + if (ul && ul.querySelectorAll('[data-task-row]').length === 0) { + if (ul.parentNode) { ul.parentNode.removeChild(ul); } + var empty = host ? host.querySelector('[data-tk-empty]') : null; + if (empty) { empty.hidden = false; } + } + } + + /* 概述卡的「N 件在做 / N 件待办」减 1(工单 #20) + ⚠️ 用 `[data-hbs]` 定位(模板里刚加的钩子),**不靠中文文案** —— + "件在做"改一个字就失效,而这是 JS 要读的东西。 + ⚠️ 减到 0 时把那个 藏起来:服务端是 `if ($nTodo > 0)` 才渲染待办那一条, + 前端不藏的话会出现「0 件待办」——服务端永远不会画出来的状态。 */ + function syncBriefCount(wasStatus) { + if (wasStatus !== 'doing' && wasStatus !== 'todo') { return; } + var a = document.querySelector('.hb-stats a.hbs[data-hbs="' + wasStatus + '"]'); + if (!a) { return; } + var b = a.querySelector('b'); + if (!b) { return; } + var n = Math.max(0, (parseInt(b.textContent, 10) || 0) - 1); + b.textContent = String(n); + if (n === 0) { a.hidden = true; } + } })(); diff --git a/templates/home/_card_brief.php b/templates/home/_card_brief.php index f9959a5..2509d78 100644 --- a/templates/home/_card_brief.php +++ b/templates/home/_card_brief.php @@ -51,12 +51,16 @@ foreach (($tasks ?? []) as $__t) { = count($todayEvents ?? []) ?> 条日程(今天) - + 「在做」与「待办」按状态拆开数 —— 见 v53 第 2 条那条注释。 + 🔴 工单 #20:`data-hbs` 是给首页脚本定位用的 —— 勾完成一条任务后, + 这两个数字要跟着减 1(否则与列表自相矛盾)。 + ⚠️ 不能让脚本去匹配中文「件在做」:文案改一个字就失效, + 而且这里是 JS 会读的钩子,写成文案匹配等于把展示文案变成接口。 */ ?> + = $nDoing ?> 件在做 0): ?> - + = $nTodo ?> 件待办 diff --git a/templates/home/_card_tasks.php b/templates/home/_card_tasks.php index 89b9b8e..6deff6f 100644 --- a/templates/home/_card_tasks.php +++ b/templates/home/_card_tasks.php @@ -20,10 +20,15 @@ * 面板取不到(404 / 网络)时,浮层会退回 `rows` 那份只读信息 —— 不会白屏。 */ ?> -
没有进行中的任务,也没有待办。
- +>没有进行中的任务,也没有待办。
+