v24 第 18 批:选人弹框改「暂存 + 确定」两段式(用户第 18 条)
用户原话:「在弹出框里输入一个人的首字母…筛选出这个人,点击这个人的头像或者是名字,
把这个人的信息**暂存到这个选择框的上半部分**。这时候他可以继续在输入框里面输入另外
一个人的拼音首字母,等所有人都选完之后,**点击确定按钮**完成多选然后再返回原来的界面儿,
把他选中的多个人都放入到之前的页面儿里。」
改动:
- templates/_person_picker.php:多选弹框加**暂存区**(搜索框之下的"上半部分")
与底部「取消 / 确定」;这两块**只在 `$ppMode='multi'` 时渲染**。
- assets/js/person_picker.js:
· 点候选人(**click**,不是 change —— 用户点的是"头像或名字")→ 进暂存区、
弹窗**不关**、输入框清空并重新聚焦("继续输入另一个人的首字母");
· 再点同一个人 = 从暂存区撤掉;暂存区里每个 chip 也带 ×;
· 「确定」= 关弹窗(勾选本来就在 input 上,等于已生效)+ 重画外面 chips;
· 「取消」= 按打开时的快照还原;
· **没点确定就关**(× / Esc / 点遮罩)→ 问一句"要保留吗",**绝不静默丢**;
· 单选保持旧行为(点一个即选中并关闭)。
- assets/css/app.css:.pp-stage / .pp-actions 等(含 `[hidden]` 规则 —— 本项目老坑)。
🔴 两个设计取舍(都写在代码注释里):
① **暂存状态就用 `input.checked` 表达,不另存一份数组**。字段的提交语义只由
`input.checked` 决定(表单直接提交它们),另存一份就必然要"确定时写回 input"——
漏做就是"我选了、保存后没人"(第 11 批栽过同类)。所以确定 = 关弹窗。
② **单选完全不动**:它的字段名(person_id / owner_id)在后端是**一个值**,
多选会直接改坏数据。模板里包在 `if ($ppIsMulti)` 里,e2e 断言钉住"单选不许有"。
🔴 真机探针(新套件 _fb_b18_picker.py)抓到两个 jsdom 测不出的真 bug:
① **单选点"已选中的那个人"→ 浏览器不触发 change**(值没变)→ 弹窗一直开着
→ 用户以为"点了没反应"。补一刀 `if (!stagedMode && box.checked) closeModal(true)`,
并在 jsdom 里加了同口径回归断言(runSingle())。
② 人数显示按 id 当 class 查(`pp-stage-n`)→ 取到 null → 永远显示 0(chip 却正常)。
验证:
- e2e 937/0(+17 条本批断言,含单选回归)· 升级 149/0 · 城市解析 32/32 ·
桌面几何 428/0 · 移动端 688/0 · 交互 92/0 · 窄屏溢出 24/0 ·
**选人弹框真机 10/10**(新套件,含"暂存区几何上在搜索框之下、清单之上")·
题图真机 4/4。
- 反向验证 3/3:退回"点一个关一次" / 去掉关闭时的询问 / 给单选也渲染暂存区
—— 三种坏法全部被断言抓住。
This commit is contained in:
@@ -22,6 +22,24 @@
|
||||
*
|
||||
* ⚠️ 同一页出现多个选择器时 $ppId 必须不同 —— 片段自己按出现顺序编号,
|
||||
* 调用方不用管(但同一页重复 include 同一份变量也不会撞)。
|
||||
*
|
||||
* ────────────────────────────────────────────────────────────────
|
||||
* v24 第 18 批(用户第 18 条):**多选改成"暂存 + 确定"两段式**。
|
||||
*
|
||||
* 用户原话:「在弹出框里输入一个人的首字母…筛选出这个人,点击这个人的头像或者是名字,
|
||||
* 把这个人的信息**暂存到这个选择框的上半部分**。这时候他可以继续在输入框里面输入
|
||||
* 另外一个人的拼音首字母,等所有人都选完之后,**点击确定按钮**完成多选然后再返回
|
||||
* 原来的界面儿,把他选中的多个人都放入到之前的页面儿里。」
|
||||
*
|
||||
* 与旧行为的差别(这是本批的核心):
|
||||
* · 旧:勾一个 = 立刻出 chip **并关掉弹窗** → 选 5 个人要开合 5 次;
|
||||
* · 新:勾一个 = 进弹窗**上半部分的暂存区**、弹窗**不关**、输入框清空继续搜下一个;
|
||||
* 全部选完点「确定」才关闭并把结果写回原页面。
|
||||
* · 关掉弹窗(× / Esc / 点遮罩)**不会**丢掉改动 —— 见下面"取消即还原"的说明。
|
||||
*
|
||||
* ⚠️ 单选($ppMode = 'single')**不改**:单选语义就是"只能有一个",
|
||||
* 再加一个确定按钮等于让用户白点一次。它的字段名(person_id / owner_id…)
|
||||
* 在后端是一个值,多选会直接改坏数据。所以暂存区与确定按钮**只在 multi 下渲染**。
|
||||
*/
|
||||
|
||||
$ppMode = $ppMode ?? 'multi';
|
||||
@@ -81,6 +99,17 @@ $ppHasSel = count(array_filter($ppSelected)) > 0;
|
||||
<input class="input pp-search" id="<?= e($ppId) ?>-search" type="text"
|
||||
placeholder="输入名字或拼音首字母,如 yyq 找「杨永全」" autocomplete="off">
|
||||
</div>
|
||||
<?php /* ---- 暂存区(**只有多选**才有;v24 第 18 批)----
|
||||
用户原话:「把选出来的人暂存到**选择框的上半部分**…等所有人都选完之后,
|
||||
点击确定按钮完成多选」。所以这里就是"已经点了头像/名字、还没点确定"
|
||||
的那批人。它由 JS 渲染(点一个 append 一个),服务端不预置内容 ——
|
||||
服务端渲染的 chips(弹窗外面那个)才是"已经确定过"的人。 */ ?>
|
||||
<?php if ($ppIsMulti): ?>
|
||||
<div class="pp-stage" id="<?= e($ppId) ?>-stage" hidden>
|
||||
<span class="pp-stage-label">已选 <b id="<?= e($ppId) ?>-stage-n">0</b> 人</span>
|
||||
<div class="pp-stage-chips" id="<?= e($ppId) ?>-stage-chips"></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
/* ⚠️ v24 第 11 批 #7 续:候选人清单**首屏不建 DOM**。
|
||||
线上真实数据下,每页 1~3 个选人组件 × 1184 人 = 几千个 <label>+<input>,
|
||||
@@ -134,6 +163,16 @@ $ppHasSel = count(array_filter($ppSelected)) > 0;
|
||||
<?php unset($ppRow); ?>
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
<?php /* ---- 底部按钮(v24 第 18 批)----
|
||||
⚠️ multi 才有「确定」;single 保持旧行为(点一个即选、立即关闭),
|
||||
因为单选语义就是"只能有一个",多一步确定是白让人点。 */ ?>
|
||||
<?php if ($ppIsMulti): ?>
|
||||
<div class="pp-actions">
|
||||
<button type="button" class="btn btn-ghost pp-cancel" id="<?= e($ppId) ?>-cancel">取消</button>
|
||||
<button type="button" class="btn pp-confirm" id="<?= e($ppId) ?>-confirm">确定</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<noscript><style>.pp-open { display: none; } .pp-modal { position: static; display: block; background: none; padding: 0; } .pp-modal-box { box-shadow: none; border: 1px solid var(--line); max-height: none; }</style></noscript>
|
||||
|
||||
Reference in New Issue
Block a user