2026-10-07 11:35:31 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 任务「完成」复选框(v24 第 25 批 用户第 6 条)—— 全站唯一画法。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 用户原话:「任务相关的模块,所有的任务,前面都带一个复选框,在任何地方,
|
|
|
|
|
|
* 点这个复选框,这个任务就完成了。」
|
|
|
|
|
|
*
|
|
|
|
|
|
* 所以它出现在**每一个**列出任务的地方:任务看板、首页「手头在做」、任务详情、
|
|
|
|
|
|
* 子任务列表。抄四份必然走样(改一处忘三处),所以抽成这一个片段。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 用法(在模板里先准备好变量再 include):
|
|
|
|
|
|
* $tkId 任务的 id(必填)
|
|
|
|
|
|
* $tkStatus 当前状态('todo' / 'doing' / 'done')
|
|
|
|
|
|
* $tkBack 改完之后回哪儿:'tasks'(默认)或 'show'(详情页里点的时候)
|
|
|
|
|
|
* $tkLabel 可选,无障碍用的说明(默认「标记完成」)
|
|
|
|
|
|
* $tkStatic 可选,true = 只读账号 → 渲染成**不可点**的静态方块(不是按钮)
|
|
|
|
|
|
*
|
|
|
|
|
|
* ⚠️ 三件必须做对的事:
|
|
|
|
|
|
* ① **它是 button 不是 input[type=checkbox]** ——
|
|
|
|
|
|
* 它要发一个带 CSRF 的表单(或者被 JS 接管),
|
|
|
|
|
|
* `input` 的 `checked` 是浏览器自己管的,会被"点了没提交成功但看着已勾上"骗到。
|
|
|
|
|
|
* 用 button + `aria-pressed` 表达状态,页面上的"勾没勾"始终由**服务端状态**说了算。
|
|
|
|
|
|
* ② 表单**全页只渲染一份**(`#taskDoneForm`,见下面的说明):几十张卡就是几十份 form,
|
|
|
|
|
|
* 那是名册页被密码管理器拖垮的同一个坑(2369 个 form 的实测记录在 people/index.php)。
|
|
|
|
|
|
* 所以卡片上只放 `data-tk-done="<id>"`,真正的表单在页面末尾。
|
|
|
|
|
|
* ③ **不写 `checked` 属性、不写 `onsubmit`**:状态由服务端渲染的 class 决定,
|
|
|
|
|
|
* 点击由 app.js 统一接管(有 JS → AJAX 就地改;无 JS → 表单提交回 302)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
$tkId = (int)($tkId ?? 0);
|
|
|
|
|
|
$tkStatus = (string)($tkStatus ?? 'todo');
|
|
|
|
|
|
$tkBack = (string)($tkBack ?? 'tasks');
|
|
|
|
|
|
$tkLabel = (string)($tkLabel ?? '标记完成');
|
|
|
|
|
|
$tkStatic = !empty($tkStatic);
|
|
|
|
|
|
$tkIsDone = $tkStatus === 'done';
|
|
|
|
|
|
if ($tkId <= 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
<?php if ($tkStatic): ?>
|
|
|
|
|
|
<span class="tk-check is-static<?= $tkIsDone ? ' is-done' : '' ?>"
|
2026-10-07 15:31:26 +08:00
|
|
|
|
aria-hidden="true"></span>
|
2026-10-07 11:35:31 +08:00
|
|
|
|
<?php else: ?>
|
2026-10-07 15:31:26 +08:00
|
|
|
|
<?php /* 🔴 v24 第 26 批 用户第 3 条:**不要任何浮层文字提示**。
|
|
|
|
|
|
用户原话:「所有任务的前面复选框,都不要文字提示,现在问题提示把复选框都盖住了」——
|
|
|
|
|
|
`title="…"` 会弹一个系统 tooltip,正好压在 18px 的方块上(鼠标一停就盖住半个)。
|
|
|
|
|
|
去掉 title;无障碍说明仍在(`.visually-hidden` 里的文案是**屏读**用的,
|
|
|
|
|
|
不产生任何可见浮层,也不占位)。 */ ?>
|
2026-10-07 11:35:31 +08:00
|
|
|
|
<button type="button" class="tk-check<?= $tkIsDone ? ' is-done' : '' ?>"
|
|
|
|
|
|
data-tk-done="<?= $tkId ?>"
|
|
|
|
|
|
data-tk-status="<?= e($tkStatus) ?>"
|
|
|
|
|
|
data-tk-back="<?= e($tkBack) ?>"
|
2026-10-07 15:31:26 +08:00
|
|
|
|
aria-pressed="<?= $tkIsDone ? 'true' : 'false' ?>">
|
2026-10-07 11:35:31 +08:00
|
|
|
|
<span class="visually-hidden"><?= e($tkLabel) ?>:<?= e(\App\Task::statusWord($tkStatus)) ?></span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<?php endif; ?>
|