下拉 —— 名册一多就变成"在一长串里瞪眼找",而且三种地方三种手感。 * * 用法(在模板里先准备好变量再 include): * $ppName 表单字段名。多选传 'attendees[]';单选传 'owner_id' 等 * $ppPeople 候选的人(Person::roster() 的行,至少要有 id / name) * $ppSelected 已选的 id 数组(单选传 0 或 1 个) * $ppMode 'multi'(默认)| 'single' * $ppOpenBtn 打开按钮文案(默认 multi=「+ 添加人」/ single=「选择」) * $ppTitle 弹窗标题(默认「选择人」) * $ppAllowEmpty 单选模式下是否给一个「不选」选项(筛选表单用;值为 0) * $ppEmptyText 单选且未选时的占位(默认「未选择」) * $ppTip 可选,渲染在按钮下面的一句话 * * ⚠️ 无 JS 时也能用:选项就是弹窗列表里的原生 checkbox / radio, * noscript 样式把弹窗摊平成一个普通列表,提交语义与有 JS 时完全一致。 * * ⚠️ 同一页出现多个选择器时 $ppId 必须不同 —— 片段自己按出现顺序编号, * 调用方不用管(但同一页重复 include 同一份变量也不会撞)。 * * ──────────────────────────────────────────────────────────────── * v24 第 18 批(用户第 18 条):**多选改成"暂存 + 确定"两段式**。 * * 用户原话:「在弹出框里输入一个人的首字母…筛选出这个人,点击这个人的头像或者是名字, * 把这个人的信息**暂存到这个选择框的上半部分**。这时候他可以继续在输入框里面输入 * 另外一个人的拼音首字母,等所有人都选完之后,**点击确定按钮**完成多选然后再返回 * 原来的界面儿,把他选中的多个人都放入到之前的页面儿里。」 * * 与旧行为的差别(这是本批的核心): * · 旧:勾一个 = 立刻出 chip **并关掉弹窗** → 选 5 个人要开合 5 次; * · 新:勾一个 = 进弹窗**上半部分的暂存区**、弹窗**不关**、输入框清空继续搜下一个; * 全部选完点「确定」才关闭并把结果写回原页面。 * · 关掉弹窗(× / Esc / 点遮罩)**不会**丢掉改动 —— 见下面"取消即还原"的说明。 * * ⚠️ 单选($ppMode = 'single')**不改**:单选语义就是"只能有一个", * 再加一个确定按钮等于让用户白点一次。它的字段名(person_id / owner_id…) * 在后端是一个值,多选会直接改坏数据。所以暂存区与确定按钮**只在 multi 下渲染**。 */ $ppMode = $ppMode ?? 'multi'; $ppPeople = $ppPeople ?? []; $ppSelected = array_map('intval', (array)($ppSelected ?? [])); $ppOpenBtn = $ppOpenBtn ?? ($ppMode === 'single' ? '选择' : '+ 添加人'); $ppTitle = $ppTitle ?? '选择'; $ppEmptyText = $ppEmptyText ?? '未选择'; $ppAllowEmpty = !empty($ppAllowEmpty); // 同一页多个实例要各有一套 id,否则 document.getElementById 全抓到第一个。 // // ⚠️⚠️ 别用文件顶层的 `static $ppSeq` 做这个计数 —— PHP 里**被 include 的文件**顶层的 // `static` 初值会**每次 include 都重新绑定**(与函数体内的 static 不同,那个才跨调用)。 // 实测:同一页 include 三次,拿到的都是 pp1。资源页今天就有两处(归属人 + 共享给谁), // DOM 里两套 pp1 撞在一起,getElementById / `