Files
FamilyBook/templates/tasks/_edit_form.php
T
laoyang 8c651b43eb v43 第 43 批:六条反馈(界面 5 + 条目详情浮层)
用户 2026-10-11 反馈六条,逐条定位真根因后修复:

① 纪念日「日期」多出一个控件 —— 只保留最新的那个
   两层根因:(a)原生 `input[type=date]` 当初没包在 `.dt-native` 里,
   v42 那条"AntD 挂上后收起原生框"的选择器根本不命中;(b)更要命的是
   `.dt-native` 基类写着 `display: contents` —— 该元素**没有盒子**,
   给它 position/width 完全无效 ⇒ 必须把 display 显式改回 block 才收得起来。

② 编辑纪念日把底层列表页弄没 —— 「修改」原来是整页跳 `days/edit`
   (套 layout = 一张只有弹框的空白页)。改为 `?embed=1` 只吐弹框那一块,
   列表页 JS 取回来替换 `#anNewCard` 并打开 —— 与「新建」同一观感。
   内嵌形态标 `$anModalOnly` 以免打 standalone 标记(关闭时不再跳页)。

③ 拖图裁剪的层被弹框盖住 —— `.crop-overlay` 是 z-index:100 而 `.cal-modal`
   是 200 ⇒ 裁剪层被整块盖住。提到 260(与 v41 的 .cn-modal 同一处理)。

④ 行程弹框里"参与的人"弹不出选人框 —— person_picker.js 只绑定一次,
   而弹框表单是 AJAX 片段 ⇒ 里面的 `.pp` 从未被 init。三件事一起:
   暴露 `window.fbInitPickers()`(幂等)+ layout 暴露 `window.fbLoadPicker()`
   (脚本是按需加载的)+ 塞完片段后补调初始化。

⑤ 日程新建排版/控件/文案 —— 改走观影式 `.mv-grid`(标签对齐 + 冒号);
   起止补上 `$dtPlugin='antd'`(试点正式推广到日程);标签「时间范围」→「开始 / 结束」;
   删三句提示(结束留空 / 多选提醒 / 全天)。

⑥ 条目详情浮层(首页日程 / 首页近期任务 / 日程页条目)——
   点条目不再直接跳页,弹浮层显示详情;「详细信息」跳该来源详情页;
   「编辑」就地换成该来源的编辑表单(四处 `?embed=1` 片段)。
   新增 `templates/_entry_popup.php` + `assets/js/entry_popup.js` +
   `fb_entry_json()`(三个入口共用一个编码函数)。

验证:php -l 157 文件全过;div 深度 33 组合全配平;片段体检 20 片段无越界;
本地 e2e 1510/0;v43 真机 33/0;v43 反向验证 8/0;v38 36/0;v42 33/0;
b31/b32 反向验证 8/0 与 5/0;部署断言本地空跑 RC=0;完整流水线 PUSH_RC=0。
2026-10-12 00:24:20 +08:00

130 lines
6.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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 = 不输出自己的「保存」,由浮层底栏给)
*/
$tkT = is_array($t ?? null) ? $t : [];
$tkPeople = (array)($people ?? []);
$tkParents = (array)($parents ?? []);
$tkCats = (array)($categories ?? []);
$tkBoards = (array)($boards ?? []);
$tkEmbed = !empty($tkEditEmbed);
?>
<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) ?>">
<div class="nf-grid">
<div class="field full">
<label for="tk-title">标题</label>
<input class="input" id="tk-title" name="title" required value="<?= e((string)($tkT['title'] ?? '')) ?>">
</div>
<div class="field">
<label>截止时间(留空=不上日历)</label>
<?php $dtName = 'due_at'; $dtValue = $tkT['due_at'] ?? null;
$dtRequired = false;
require __DIR__ . '/../_datetime.php'; ?>
</div>
<div class="field">
<label>负责人</label>
<?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="field">
<label>循环</label>
<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="field">
<label>挂到哪个父任务下</label>
<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="field">
<label>分类</label>
<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="field">
<label>看板</label>
<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="field full">
<label for="tk-note">备注</label>
<textarea class="input" id="tk-note" name="note" rows="3"><?= e((string)($tkT['note'] ?? '')) ?></textarea>
</div>
</div>
<?php /* ⚠️ 「状态」不在这里改(由 tasks/status 路由管,它还要处理循环任务)。
浮层形态下由它的底栏给「保存」;整页详情页里带自己的按钮。 */ ?>
<?php if (!$tkEmbed): ?>
<div class="btn-row"><button class="btn btn-sm" type="submit">保存</button></div>
<?php endif; ?>
</form>
<?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,
$dtName, $dtValue, $dtRequired,
$ppName, $ppPeople, $ppSelected, $ppMode, $ppOpenBtn, $ppTitle,
$ppEmptyText, $ppAllowEmpty); ?>