v24 第 8 条:凡「选人」都走同一套弹窗 + 拼音首字母(补上唯一漏做的一条)
用户原话:「名册详情页面,添加关系那里,选择一个人,应该也是和观影人一样, 点击弹窗,用拼音首字母选择,否则人多的时候,这个选择起来太麻烦了。」 - 成员详情页:①「添加关系 → 对方」 ②「分享他的名片给…」→ 全局选人组件(单选) - 任务:③ 列表页「共享给(多选)」 ④ 列表页「负责人」 ⑤ 详情页「负责人」 (共享候选人先把自己过滤掉 —— 共享给自己是空操作) - 纪念日:「与谁相关」→ 单选,且保留原下拉第一项「不指定」(ppAllowEmpty) - 「对方」是必填,但组件里是原生 radio(HTML 没有"必选一个 radio"的可靠约束) → 页面补一道 submit 拦截,否则用户点了按钮会静默无反应 顺带修一个用户没提、我自己抓到的真 bug: _person_picker.php 原用**文件顶层**的 `static $ppSeq` 做 id 计数 —— PHP 里被 include 的文件,顶层 static 初值**每次 include 都重新绑定**(与函数体内的 static 不同)→ 同一页 include 两次都拿 pp1 → DOM id 撞车(getElementById / <label for> 全抓到第一个)。实测 include 三次得到 pp1,pp1,pp1。改用 $GLOBALS['ppSeq']。这个坑只有同一页出现两个组件时才暴露,且资源页第二个组件 只有真有资源时才渲染 —— 所以写成**单元级**探针(同一请求 include 两次)。 另修一个构建层隐患(本轮部署时踩到,白查了一轮): 本机 core.autocrlf=true,一次 git stash 往返就把 6 个文件全改成 CRLF;而部署 打包取的是工作树 → 包里带 CRLF 上去 → 部署脚本里 grep -qxF '<整行 CSS 选择器>' 的校验在 Linux 上一条都匹配不到(报错却指向"CSS 少了某条规则",极易误诊)。 → .gitattributes 加 `* text=auto eol=lf`(必须排在 -text 那几条之前), 并在打包前加一道行尾体检 _fb_eol_check.py(失败时点名文件)。 验证:反向验证对着 git stash 出来的真·改动前状态跑 → 11 通过 / 17 失败; 新增 _fb_picker_unify.py 28/0;e2e 785/0;几何 428/0;移动端 688/0;交互 97/0; 升级 126/0;家谱 34/0;专项 91/0;导入 21/0;豆瓣 22/0;行尾体检 + 两道新静态 门禁均实测可失败。线上 6 文件 md5 一致、CR=0。
This commit is contained in:
+49
-14
@@ -372,15 +372,27 @@ $shortKind = \App\Birthday::KINDS;
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<?php /* 用户 2026-10-03 第 8 条:「添加关系那里,选择一个人,应该也是和观影人一样,
|
||||
点击弹窗,用拼音首字母选择,否则人多的时候,这个选择起来太麻烦了。」
|
||||
—— 原来是个 <select>,名册一长就得在几百个选项里瞪眼找。
|
||||
换成全局选人组件(与观影人同一套:弹窗 + 头像 + 首字母联想)。
|
||||
|
||||
⚠️ 这里**不能**写 `required`:组件在无 JS 时退化成一组原生 radio,
|
||||
「必选一个 radio」HTML 没有这个约束(radio 组的 required 也不可靠)。
|
||||
改成提交时用 JS 拦一下,把"没选人"挡在客户端;
|
||||
万一真漏过去,服务端 kin/relate 也会判「选的人不对」并给人话提示。 */ ?>
|
||||
<label>对方</label>
|
||||
<select class="select" name="to_id" required>
|
||||
<option value="">— 选择一个人 —</option>
|
||||
<?php foreach ($options as $o): ?>
|
||||
<option value="<?= (int)$o['id'] ?>">
|
||||
<?= e((string)$o['name']) ?><?= !empty($o['my_nickname']) ? '(' . e((string)$o['my_nickname']) . ')' : '' ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php
|
||||
$ppName = 'to_id';
|
||||
$ppPeople = $options;
|
||||
$ppSelected = []; // 每次进页面都不预选:这是"新记一条关系",不是改旧的
|
||||
$ppMode = 'single';
|
||||
$ppOpenBtn = '选择对方';
|
||||
$ppTitle = '对方是谁';
|
||||
$ppEmptyText = '还没有选人';
|
||||
$ppAllowEmpty = false;
|
||||
require __DIR__ . '/../_person_picker.php';
|
||||
?>
|
||||
</div>
|
||||
<div class="field" style="justify-content:flex-end">
|
||||
<button class="btn btn-sm" type="submit">记下这条关系</button>
|
||||
@@ -481,12 +493,20 @@ $shortKind = \App\Birthday::KINDS;
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="person_id" value="<?= $pid ?>">
|
||||
<input type="hidden" name="back" value="<?= $pid ?>">
|
||||
<label class="sr-only" for="shareTo">分享给谁</label>
|
||||
<select class="select" id="shareTo" name="to_id">
|
||||
<?php foreach ($options as $o): $oid = (int)$o['id']; ?>
|
||||
<option value="<?= $oid ?>"><?= e((string)$o['name']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php /* 与「添加关系」同一套:既然这一页已经在用弹窗选人了,
|
||||
就别让分享还留一个上百项的下拉(同页两种手感更别扭)。 */ ?>
|
||||
<div class="share-to">
|
||||
<?php
|
||||
$ppName = 'to_id';
|
||||
$ppPeople = $options;
|
||||
$ppSelected = [];
|
||||
$ppMode = 'single';
|
||||
$ppOpenBtn = '选择分享给谁';
|
||||
$ppTitle = '把他的名片分享给谁';
|
||||
$ppEmptyText = '还没有选人';
|
||||
require __DIR__ . '/../_person_picker.php';
|
||||
?>
|
||||
</div>
|
||||
<button class="btn btn-sm" type="submit">分享</button>
|
||||
</form>
|
||||
</details>
|
||||
@@ -608,4 +628,19 @@ $shortKind = \App\Birthday::KINDS;
|
||||
kind.addEventListener('change', sync);
|
||||
sync();
|
||||
})();
|
||||
|
||||
// 「添加关系」的「对方」换成了弹窗选人组件(第 8 条),它没有原生 required ——
|
||||
// 这里补一道客户端拦截,别让用户点了「记下这条关系」却什么都没发生(服务端会拒,
|
||||
// 但来回一趟还看不到错在哪)。选人组件里勾中的那个 radio 才是真正的值。
|
||||
(function () {
|
||||
var form = document.querySelector('.rel-form');
|
||||
if (!form) return;
|
||||
form.addEventListener('submit', function (ev) {
|
||||
var picked = form.querySelector('.pp-list input[name="to_id"]:checked');
|
||||
if (!picked || picked.value === '0') {
|
||||
ev.preventDefault();
|
||||
alert('还没选「对方」——点上面的按钮,在弹出的列表里选一个人。');
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user