需求(用户 2026-10-25):必填项原来在标题后面加一个红色星号,排版经常不齐。
改成「标题本身红色 + 加粗」——用户习惯后,看到红色加粗的标题就知道是必填。
CSS(assets/css/app.css):
- :root 新增 --req:#B03A2E、--req-w:700。
· 不用 --red(#C0533F):那是动作红(删除按钮底色),当文字色放在暖纸底
#F7F3EA 上对比度只有 ≈3.4:1,13-14px 标签偏浅;#B03A2E 约 4.6:1。
· --req-w 必须 700 不能 650/600:本站标签基线字重本来就是 600
(.form-grid > .field > label / .card .field > label / .mv-row > .mv-lb /
.dt-range-label 四处都是 600),650 会被取整回 600 = 完全没加粗。
- 文件末尾新增「必填项统一标记」段,覆盖四种标签形态:
label.is-req / .mv-lb.is-req / .dt-inline-lab.is-req / .dt-range-label.is-req,
用 !important 打穿各宿主选择器的特异性(颜色与字重是语义标记,不该被面板样式盖掉)。
- 冒号跟着变红:.mv-lb::after / .dt-inline-lab::after 原本是灰色 400,
只改标签本体会剩「红字 + 灰冒号」的半截效果。
- 包裹层兜底(.field.is-req > label 等),只作用直接子级 ——
不写 .field.is-req label,那会把「提醒」那排 checkbox 的小标签一起染红。
- 深色主题给备用色 #F08A78。
- 保留 .mv-row > .mv-lb > i(万一有没清干净的星号不至于露灰星花,且静态断言会报出来)。
模板(16 个文件 / 30 处):
- _event_fields.php / _datetime.php 的标签闭包第三参数 $star → $req,
$dtLabelStar → $dtLabelReq,删掉死引用 $evLabelStar。
- 其余 14 个模板把 `<i>*</i>` 换成给标签加 is-req 类。
- 用显式 .is-req 而不靠 required 属性反推:CSS 无父选择器,:has() 旧 WebView
不可用,且影院名称/板块名本来就靠 JS 校验没有 required。
验证:
- 静态 _fb_v94_static.py 22/0,反向 9/9(含「--req-w 必须严格大于从 CSS 解析出的
标签基线字重」,不写死 700)。
- 真浏览器 _fb_v94_req.py 63/0,反向 5/5(加粗/必须红/!important 必要性/
星号必须消失/每形态单独覆盖,五类注入各自精确命中预期断言)。
- 全量流水线(含 60+ 套件)通过并部署。
- 线上真实页面 _fb_v94_live.py 31/0:观影「片名」、旅程「旅程名」、
成员「姓名」、导航「网址/所属板块」实测 color=rgb(176,58,46) weight=700,
同页非必填 color=rgb(44,35,29) weight=600,冒号同色,无星号。
173 lines
9.0 KiB
PHP
173 lines
9.0 KiB
PHP
<?php
|
||
/**
|
||
* 🔴 v43(用户 2026-10-11 第 6 条)—— 任务的「编辑」表单,**独立一份**。
|
||
*
|
||
* 为什么要独立出来:
|
||
* 原来它内联在 `tasks/show.php` 的 `<details>` 里。而条目详情浮层点「编辑」时,
|
||
* 需要**单独取这份表单**(`tasks/edit?embed=1`)—— 不可能去详情页里抠。
|
||
* 抽成一份后,详情页与浮层用的是**同一张表单**,不会出现"两处字段不一致"。
|
||
*
|
||
* ⚠️ 字段名 / 服务端契约与原来**一字未改**(tasks/update 收的就是这些)。
|
||
* ⚠️ 「状态」不在这里改:状态由专门的 `tasks/status` 路由管(它还要处理循环任务),
|
||
* 文案里也说明了这一点(与 v24 第 14 批的口径一致)。
|
||
*
|
||
* 🔴🔴 **本片段一律用带前缀的局部变量(`$tk*`),绝不碰入参的名字。**
|
||
* 第一版写的是 `$t = is_array($t ?? null) ? $t : [];` —— 看似无害,其实是在
|
||
* **覆盖宿主模板的 `$t`**(那是"这条任务"本身)。只读一次没问题,
|
||
* 但下一个人只要把某个 `$tk*` 改回 `$t`(很自然)就会让详情页后半段的
|
||
* `$t['children']` / 评论区全是 null —— **而且是静默的**。
|
||
* 项目的"片段体检"(`_fb_frag_guard`)当场抓到了这处裸赋值,是对的。
|
||
* ⇒ 入参先**收进 `$tkT`**,后面全用它。
|
||
*
|
||
* 用法(include 前设好):
|
||
* $t 任务(Task::find 的形状)
|
||
* $people 名册
|
||
* $parents 可选父任务候选
|
||
* $categories / $boards 分类与看板
|
||
* $tkEditEmbed 是否"浮层形态"(true = 不输出自己的「保存」,由浮层底栏给)
|
||
* $tkEditModal 🔴 v55:是否**套 `.cal-modal` 弹框壳**(用户 2026-10-17 第 3 条
|
||
* 「编辑任务,弹框处理」)。详情页传 true;条目浮层 / AJAX 片段不传
|
||
* (它自己已经在浮层里,再套一层弹框就是"框中框")。
|
||
* $tkEditOpen 弹框初始是否打开(默认 **关闭** —— 详情页要点「编辑」才开)。
|
||
* $tkEditTitle 弹框标题(默认「编辑任务」)
|
||
*/
|
||
$tkT = is_array($t ?? null) ? $t : [];
|
||
$tkPeople = (array)($people ?? []);
|
||
$tkParents = (array)($parents ?? []);
|
||
$tkCats = (array)($categories ?? []);
|
||
$tkBoards = (array)($boards ?? []);
|
||
$tkModal = !empty($tkEditModal);
|
||
$tkOpen = !empty($tkEditOpen);
|
||
$tkMdlTitle = (string)($tkEditTitle ?? '编辑任务');
|
||
$tkEmbed = !empty($tkEditEmbed);
|
||
?>
|
||
<?php
|
||
/* 🔴 v55(用户 2026-10-17 第 3 条):「编辑任务,弹框处理。」
|
||
弹框壳(`.cal-modal`,与「新建任务 / 新建日程 / 编辑观影记录」同一套类名)。
|
||
⚠️ **表单本体一个字未改** —— 只是外面多包一层;字段名 / action / 契约全不动。
|
||
⚠️ `$tkEditEmbed` 为 true 时(详情页与条目浮层都是)保存键由**底栏**给,
|
||
所以下面 `$tkEmbed` 那段的「保存」不输出,改在底栏放。 */
|
||
?>
|
||
<?php if ($tkModal): ?>
|
||
<div class="cal-modal" id="tkEditCard" role="dialog" aria-modal="true"
|
||
aria-label="<?= e($tkMdlTitle) ?>"<?= $tkOpen ? '' : ' hidden' ?>>
|
||
<div class="cal-modal-panel">
|
||
<div class="cal-modal-head">
|
||
<b><?= e($tkMdlTitle) ?></b>
|
||
<button type="button" class="cal-modal-x" id="tkEditX" aria-label="关闭">✕</button>
|
||
</div>
|
||
<div class="cal-modal-body">
|
||
<?php endif; ?>
|
||
<form method="post" action="<?= e(url('tasks/update')) ?>" class="node-form" id="tkEditForm">
|
||
<?= csrf_field() ?>
|
||
<input type="hidden" name="id" value="<?= (int)($tkT['id'] ?? 0) ?>">
|
||
<?php /* 🔴 v55:编辑完回详情页(服务端 `tasks/update` 本来就 `redirect('tasks/show')`)——
|
||
这里**不传** back,与原来一致。 */ ?>
|
||
<?php /* 🔴 v44(用户 2026-10-12 第 5 条):编辑表单也统一成观影式排版 +
|
||
最新时间控件 + 文案精简(与「新建任务」弹框一致)——
|
||
同一件事在两个入口长得不一样,用户会以为"进了别的页面"。 */ ?>
|
||
<div class="mv-grid">
|
||
<div class="mv-row">
|
||
<span class="mv-lb is-req">任务名称</span>
|
||
<input class="input" id="tk-title" name="title" required value="<?= e((string)($tkT['title'] ?? '')) ?>">
|
||
</div>
|
||
<div class="mv-row">
|
||
<span class="mv-lb">截止时间</span>
|
||
<?php /* 🔴 v44:截止时间用 AntD 单点控件(与新建同一套);括号去掉。 */ ?>
|
||
<?php $dtName = 'due_at'; $dtValue = $tkT['due_at'] ?? null;
|
||
$dtRequired = false; $dtPlugin = 'antd-single';
|
||
require __DIR__ . '/../_datetime.php'; ?>
|
||
</div>
|
||
<div class="mv-row">
|
||
<span class="mv-lb">负责人</span>
|
||
<?php /* 第 8 条同一诉求:负责人也是「选人」,人多时用弹窗 + 首字母更快。
|
||
保留原下拉的「不指定」(pp-item-none + value=0)。 */ ?>
|
||
<?php
|
||
$ppName = 'assignee_id';
|
||
$ppPeople = $tkPeople;
|
||
$ppSelected = [(int)($tkT['assignee_id'] ?? 0)];
|
||
$ppMode = 'single';
|
||
$ppOpenBtn = '更换负责人';
|
||
$ppTitle = '谁负责这件事';
|
||
$ppEmptyText = '不指定';
|
||
$ppAllowEmpty = true;
|
||
require __DIR__ . '/../_person_picker.php';
|
||
?>
|
||
</div>
|
||
<div class="mv-row">
|
||
<span class="mv-lb">循环</span>
|
||
<select class="select" name="repeat_rule">
|
||
<?php foreach (\App\Task::REPEAT as $rk => $rv): ?>
|
||
<option value="<?= e($rk) ?>"<?= (string)($tkT['repeat_rule'] ?? '') === (string)$rk ? ' selected' : '' ?>>
|
||
<?= e($rv) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div class="mv-row">
|
||
<span class="mv-lb">父任务</span>
|
||
<select class="select" name="parent_id">
|
||
<option value="0">(这是一项独立的任务)</option>
|
||
<?php foreach ($tkParents as $p): ?>
|
||
<option value="<?= (int)$p['id'] ?>"<?= (int)($tkT['parent_id'] ?? 0) === (int)$p['id'] ? ' selected' : '' ?>>
|
||
<?= e((string)$p['title']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<?php /* v24 第 9、10 条:分类与看板(看板把任务放到哪一块,分类是标签) */ ?>
|
||
<div class="mv-row">
|
||
<span class="mv-lb">分类</span>
|
||
<select class="select" name="category_id">
|
||
<option value="0">未分类</option>
|
||
<?php foreach ($tkCats as $c): ?>
|
||
<option value="<?= (int)$c['id'] ?>"<?= (int)($tkT['category_id'] ?? 0) === (int)$c['id'] ? ' selected' : '' ?>>
|
||
<?= e((string)$c['name']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div class="mv-row">
|
||
<span class="mv-lb">看板</span>
|
||
<select class="select" name="board_id">
|
||
<?php foreach ($tkBoards as $b): ?>
|
||
<option value="<?= (int)$b['id'] ?>"<?= (int)($tkT['board_id'] ?? 0) === (int)$b['id'] ? ' selected' : '' ?>>
|
||
<?= e((string)$b['name']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div class="mv-row">
|
||
<span class="mv-lb">备注</span>
|
||
<textarea class="input" id="tk-note" name="note" rows="3"><?= e((string)($tkT['note'] ?? '')) ?></textarea>
|
||
</div>
|
||
</div>
|
||
<?php /* ⚠️ 「状态」不在这里改(由 tasks/status 路由管,它还要处理循环任务)。 */ ?>
|
||
<?php if ($tkModal): ?>
|
||
<?php /* 🔴 v55:**弹框形态下不在这里放「保存」** —— 它归底栏(与新建任务一致:
|
||
主要动作在右下角)。`.btn-row` 那份是给"页面上的普通卡片形态"用的。 */ ?>
|
||
<?php elseif (!$tkEmbed): ?>
|
||
<div class="btn-row"><button class="btn btn-sm" type="submit">保存</button></div>
|
||
<?php endif; ?>
|
||
</form>
|
||
<?php if ($tkModal): ?>
|
||
</div><?php /* /.cal-modal-body */ ?>
|
||
<div class="cal-modal-foot">
|
||
<button class="btn btn-sm" type="submit" form="tkEditForm" id="tkEditSubmit">保存</button>
|
||
<button class="btn btn-ghost btn-sm" type="button" id="tkEditCancel">取消</button>
|
||
</div>
|
||
</div><?php /* /.cal-modal-panel */ ?>
|
||
</div><?php /* /.cal-modal */ ?>
|
||
<?php endif; ?>
|
||
<?php /* 🔴🔴 —— **千万不要 unset 入参变量**!
|
||
这几种是宿主模板的"大局变量"(`$t` = 这条任务、`$people` = 名册…),
|
||
include 之后宿主还要继续用它们(`$t['children']`、评论、子任务…)。
|
||
我第一版照抄了 `_datetime.php` 那种"用完即清"的写法,把 `$t` 一并 unset ——
|
||
结果 `tasks/show.php` 后半段全部拿不到 `$t`,**子任务列表与评论区静默消失**
|
||
(e2e 当场抓到 2 条:子任务没了、@高亮没了)。
|
||
⇒ 这里只清**本片段自己造的**临时变量(`$tk*` 与 `$dt*` / `$pp*` 那几组)。 */
|
||
unset($tkT, $tkPeople, $tkParents, $tkCats, $tkBoards, $tkEmbed,
|
||
$tkModal, $tkOpen, $tkMdlTitle, // 🔴 v55:弹框壳那三个
|
||
$dtName, $dtValue, $dtRequired,
|
||
$ppName, $ppPeople, $ppSelected, $ppMode, $ppOpenBtn, $ppTitle,
|
||
$ppEmptyText, $ppAllowEmpty); ?>
|