用户 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 ⇒ 环境护栏,与本次改动无关。
98 lines
5.6 KiB
PHP
98 lines
5.6 KiB
PHP
<?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); ?>
|