Files
FamilyBook/templates/trips/_revise_form.php
T
laoyang 252812ed93 v50:旅程题图裁剪修好(AJAX 片段漏绑)/ 修正表单换最新控件+取消 / 打标签误报修复 / 名册按钮编辑蓝删除红
用户 2026-10-14 四条。

① 旅程详情点点「编辑」,里面的图片改不了、拖入/选中都不弹裁剪框
   用户原话:「应该弹出来一个让我裁剪的那个框。但是现在却没有那个裁剪的框。」
   **真根因**(assets/js/app.js):裁剪那段 IIFE 是**首屏一次性**的 ——
     `var inputs = querySelectorAll('[data-crop-ratio]'); if (!inputs.length) return;`
     在脚本加载那一刻扫一遍,扫不到就整段放弃。而「编辑旅程」是 **AJAX 取片段、
     innerHTML 塞进弹框**的(templates/trips/show.php 的 loadInto)⇒ 详情页首屏
     **没有**题图框 ⇒ 当场 return ⇒ 片段里的框**从来没有 change 监听**
     ⇒ 拖入/选中什么都不发生。
   修法:拆成 `bindOne(input)`(幂等,打 `data-crop-bound` 标记)+ `scan(scope)`;
     首屏调一次 + **MutationObserver 补挂**;库的按需加载改成"首次真要用时才拉"。
   ⚠️ 与「拖动上传」那段(bindInput/scan/MutationObserver)**同一手法** ——
      它早就解决了"动态插进来的文件框也要接得住",裁剪这段当年漏了这层。

② 旅程「修正」表单(templates/trips/_revise_form.php)
   用户三条:「开始和结束时间…应该改成我们最新的控件样式」「上面记录实际执行情况
   那一段话说明也不要了」「记录这次修正的按钮应该放在右边,另外应该加一个取消」。
   · 起止换 `$dtPlugin = 'antd'`(与 node_form.php 同款;当年 v41 刻意没换,现按用户要求统一)
   · 删 show.php 里 `.rev-tip` 整段
   · 按钮行 `rev-foot` 靠右 + 新增 `[data-rev-cancel]`;取消由 show.php 的**事件委托**
     处理(`details.rev-open` 收起)—— 不用内联脚本(片段会被 AJAX 换进来)

③ 名册打标签误报「这个人不在你的名册里」
   用户原话:「我搜索出来一个人…给他打标签,它会显示说这个人不在我的名册里,
   其实他是在我的名册里的。」
   **真根因**(index.php 的 people/tags):`isset(PersonRoster::visibleIds(...)[$pid])`,
   而 `visibleIds()` 返回的是 **id 值列表** `[2,3,4,5]`(键是 0,1,2,3)——
   把值列表当 id→值 映射用。只有 `$pid` 恰好等于数组下标时才为真:名册里人少时
   (下标<pid)**谁都判"不在名册"**;一般情况只有"第 pid+1 个"碰巧过。
   修法:改用 `in_array(..., true)`(与同文件 `inMyRoster` 写法一致)。
   ⚠️ **没改 `visibleIds()` 的返回形状** —— 另一处调用已是正确的 in_array,改形状会
      静默弄坏它。陷阱:`PersonGroup::visibleIds()` 是集合、`PersonRoster::visibleIds()`
      是值列表,**同名不同形状**,已在两处注释里写明。
   (附带确认:不在名册的人本来就不出现在列表里,用户"不在名册就该搜不出来"本就成立。)

④ 名册列表按钮:编辑蓝底、删除红底
   用**作用域类** `.person-edit`(var(--blue)) / `.person-del`(var(--red)) 三处形态都写,
   不动全局 .btn-edit/.btn-danger 的语义(v41 踩过"裸类改色波及影院管理页")。
   hover 在这里补 `filter: brightness(.92)`(文末"全站悬停统一"段是白名单写的)。

验证(新增 2 套件 + 更新 1 处旧断言):
 · _fb_v50_ui.py(22 条真机断言:题图绑定/选中与拖入都弹裁剪框 16:9、修正 antd+无说明+
   靠右+取消能收起、名册内 3 人打标签均成功且不误报、编辑蓝删除红)
 · _b50_falsify.py(**10 注入 / 21 断言全抓**)
 · _fb_e2e.py 的 ★第28-6条断言随 v50-4 升级(原查 var(--brand-soft),现查蓝+红作用域类)
 · familybook_deploy.sh 加 v50 静态断言段(含两条"旧写法必须已不在"的反向断言)
 · e2e 1511/0、几何、各批反向验证全绿;**v50 四条 22/0**、**v50 反向验证 21/0**;
   全流水线 **PUSH_RC=0**,部署脚本 0 FAIL(含"第50批形态");线上 6 文件 md5 逐字节一致;
   线上门禁诊断 16 项全 YES,临时页已删并复验 404

⚠️ 收尾时发现并修掉一个**自设陷阱**:我在 show.php 的删除说明里**整句引用了**用户点名要删的
   那句原话 ⇒ 朴素 strpos 判"已删"时会命中我自己的注释(线上诊断 C8=NO)。
   部署断言用 `_code_has`(剥注释)所以是对的,但这类字串留在注释里迟早坑到别的检查
   ⇒ 已改成不整句照抄。**改注释也改了文件哈希 ⇒ 又重跑一次全量部署**。
⚠️ 流水线末段唯一"失败"同 v49:沙箱安全删除门禁(按轮次累计删满 50 就终止进程);
   单独重跑 _fb_v46_carddav.py = 29/0 ⇒ 环境护栏,与本次改动无关。
2026-10-15 02:57:19 +08:00

98 lines
5.6 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
/**
* 「修正」表单(v24 第 13 批):记录一段计划旅程的**实际**执行情况。
*
* 用户原话:「另外一个按钮,用来记录实际的情况,按钮名字就叫修正,但是记住,
* 这个实际的行程和计划行程,是一条记录,不是两条,点击这个按钮,
* 则让用户选择实际的执行时间,包括开始和结束时间,实际的参与人等信息,
* 就相当于是修改了一下这个行程,只不过,之前的计划行程数据要保留,
* 为了以后做对比。修正,是无限次数的。」
*
* ⚠️ 与「编辑」的区别:
* · 编辑 = 改**计划**本身(排错了计划就改它);
* · 修正 = 记**实际**发生了什么(计划不动,实际值进历史,供对比)。
* 两者都作用在同一条 trip_nodes 记录上(用户明确"是一条记录,不是两条")。
*
* 🔴 v50(用户 2026-10-14)三条:
* ① 「修正一个计划行程的时候的开始和结束时间,仍然是之前的那种**控件样式**,
* 应该改成我们**最新的控件**样式。」
* ⇒ 换 `$dtPlugin = 'antd'`(与「添加/编辑行程」的 node_form.php 同款)。
* 当年(v41)这里刻意**没换**,理由是"修正表单内联在 `<details>` 里、
* 一段行程一份、可能十几份并存,antd 每份都要挂 React 组件,不划算"。
* 用户现在明确要统一,且实测详情页通常只有一两段计划行程需要修正 ——
* 按用户要求换,代价可接受。
* ② 「上面记录实际执行情况那一段话说明也不要了。」
* ⇒ 删掉 `.rev-tip` 那段(那段文字在 show.php 的 `.rev-panel` 里,见那边的改动)。
* ③ 「记录这次修正的按钮应该放在**右边**,另外应该加一个**关闭/取消**的按钮,
* 就是如果不再修正的话,应该有一个取消,不要让这个框显示了。」
* ⇒ 按钮行右对齐;补一颗「取消」——`.rev-open` 是 `<details>`,
* 取消 = 把 `open` 去掉(见下面内联脚本 + show.php 的委托)。
*
* 变量(require 前设好):
* $rvNode 被修正的这段旅程
* $rvTripId 活动 id
* $rvPeople 人名册(选实际参与人)
* $rvMembers 当前参与人 id
*/
$rvPrefix = 'rv' . (int)$rvNode['id'];
$rvN = (int)($rvNode['revision_n'] ?? 0);
?>
<form class="rev-form" method="post" action="<?= e(url('trips/node_revise')) ?>">
<?= csrf_field() ?>
<input type="hidden" name="trip_id" value="<?= (int)$rvTripId ?>">
<input type="hidden" name="id" value="<?= (int)$rvNode['id'] ?>">
<div class="nf-grid">
<?php /* 实际的起止时间:默认填计划值,方便"只改时间"这种最常见的情况。
🔴 v50:换成与「添加/编辑行程」**同一套最新控件**(AntD RangePicker)。
⚠️ 隐藏字段仍是 `rev_starts_at_date/_hour/_minute`,提交契约不变
(trips/node_revise 收的还是 read_dt_input 那一套)。 */ ?>
<div class="field dt-range full">
<label>实际的开始 / 结束</label>
<?php $dtName = 'rev_starts_at'; $dtValue = $rvNode['starts_at'] ?? '';
$dtId = $rvPrefix . '-s'; $dtRange = 'start'; $dtPlugin = 'antd';
require __DIR__ . '/../_datetime.php'; ?>
<?php $dtName = 'rev_ends_at'; $dtValue = $rvNode['ends_at'] ?? '';
$dtId = $rvPrefix . '-e'; $dtRange = 'end'; $dtPlugin = 'antd';
require __DIR__ . '/../_datetime.php'; ?>
<span class="tip">默认是计划的时间,改成实际发生的即可。</span>
</div>
<?php /* 用户第 17 批 第 3 条:「参与人那里,和记录电影人一样,**弹框选择**,
不要全列出来,太多了。」——修正表单也是"选参与人",同样走统一组件。
⚠️ 本批同时**去掉了「实际地点」输入框**:用户第 1 条把"地点"这件事
收敛成了**出发地 / 到达地**(城市由它们聚合),单留一个 free-text
「实际地点」会让人分不清它和出发地是什么关系。
修正要记的就是用户第 13 批原话里那三样:实际时间 / 实际参与人 / 说明。 */ ?>
<div class="field full">
<label for="<?= e($rvPrefix) ?>-detail">这次修正的说明</label>
<input class="input" id="<?= e($rvPrefix) ?>-detail" name="detail"
placeholder="如:航班延误,改到下午才到">
</div>
<?php if (!empty($rvPeople)): ?>
<div class="field full">
<label>实际参与的人</label>
<?php
$ppName = 'members[]';
$ppPeople = $rvPeople;
$ppSelected = $rvMembers;
$ppMode = 'multi';
$ppOpenBtn = '+ 选择实际参与的人';
$ppTitle = '这次实际去的都有谁';
require __DIR__ . '/../_person_picker.php';
?>
</div>
<?php endif; ?>
</div>
<?php /* 🔴 v50 用户第 3 条:按钮**靠右**(`margin-left:auto` 把主按钮推过去),
并补一颗「取消」把 details 收起来(不再修正时用)。 */ ?>
<div class="btn-row rev-foot">
<?php if ($rvN > 0): ?>
<span class="tip rev-foot-note">之前已记过 <?= $rvN ?> 次;原计划数据都留着。</span>
<?php endif; ?>
<button class="btn btn-ghost btn-sm" type="button" data-rev-cancel>取消</button>
<button class="btn btn-sm" type="submit">
<?= $rvN > 0 ? '再记一次修正' : '记录这次修正' ?>
</button>
</div>
</form>
<?php unset($rvPrefix, $rvN); ?>