From 693eb64d653cda6c952451cc5ae0c029adb75c1e Mon Sep 17 00:00:00 2001 From: laoyang Date: Fri, 2 Oct 2026 13:38:34 +0800 Subject: [PATCH] =?UTF-8?q?v18b:=20=E4=BF=AE=E3=80=8C=E9=85=8D=E5=81=B6?= =?UTF-8?q?=E7=AB=99=E5=88=B0=E4=BA=86=E6=88=91=E5=B7=A6=E8=BE=B9=E3=80=8D?= =?UTF-8?q?=E2=80=94=E2=80=94=20=E6=88=B7=E7=9A=84=E4=B8=BB=E4=BD=8D?= =?UTF-8?q?=E6=94=B9=E7=94=A8=E3=80=8C=E4=B8=8E=E6=88=91=E7=9A=84=E8=A1=80?= =?UTF-8?q?=E7=BC=98=E8=B7=9D=E7=A6=BB=E3=80=8D=E5=88=A4=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户上线后如果细看会发现的问题:线上真实数据里 户 = [红围脖(妻子), 杨永全(我)] —— 妻子被当成了"本家血亲"排在我左边。 根因:服务端判"哪张卡是这一户的血亲位"用的是「**他有父母在本图上**」—— 而一对夫妻**两边父母都可能在图上**(我的父母 + 妻子的父母),两边都成立, 于是取到第一个(妻子)。用真实数据量出来的证据: 户4 = [(3 红围脖), (1 杨永全)],两边都有 parents。 修法:改成按「**与「我」的血缘距离**」判定 —— 先用一次**不带配偶边**的 BFS 算出本家血亲集合(与 Kinship::bloodRelatives 同义),两边都在集合里时, 取"离我更近"的那一位当主位。修完线上实测: 户5 = [杨永全, 红围脖] ← 我在左、妻子在右,符合参考实现「配偶排右手边」。 顺带把移动端几何里的卡片比例断言从 v17 的 118:92 更新到 v18 的 88:106 (卡片形状换了,旧常量会让它误报)。移动端几何 520 项全过。 验证:真实数据(11 人)渲染 —— 0 重叠、11 条连线、无 JS 报错; 位置核对:我在 751、妻子在我右 863、年长的姐姐在我左 458、 父母在我上方居中(665/777)、儿子在我右下(975)、外甥在姐姐下方。其余功能未动。 --- templates/kin/tree.php | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/templates/kin/tree.php b/templates/kin/tree.php index 2c99b63..37c5d06 100644 --- a/templates/kin/tree.php +++ b/templates/kin/tree.php @@ -75,21 +75,39 @@ foreach ($units as $i => $u) { if (!$cards) { continue; } - // ⚠️ 户内部:**血亲在前、配偶在后**(配偶排右手边)。 - // 只按长幼排会让"妻子排到丈夫左边",夫妻横线看着别扭。 - $head = null; - foreach ($cards as $c) { - // 血亲 = 这个户里"有父母在本图上"的那一位;都没有就取第一位 - if ($head === null) { - $head = $c; - } - foreach ($graph['parents'][(int)$c['id']] ?? [] as $par) { - if (isset($unitOf[(int)$par]) && (int)$unitOf[(int)$par] !== $i) { - $head = $c; - break 2; + // ⚠️⚠️ 户内部:**本家血亲在前、配偶在后**(配偶排右手边,参考实现就是这样)。 + // + // "血亲"不能只按"他有父母在本图上"判定 —— 一对夫妻**两边父母都可能在图上** + // (我的父母 + 妻子的父母),那样两边都算血亲,取到第一个就成了"妻子当主位、 + // 我排在她右边"(实测线上就是这个症状:红围脖@639 在我的左边)。 + // + // 正解:按「**与"我"的血缘距离**」判定 —— 这一户里离「我」更近的那一位才是主位。 + // 我用一次不带配偶边的 BFS 算出血亲集合(Kinship::bloodRelatives 语义), + // 两边都在血亲集合里时,退到「与我的步数」比大小。 + $blood = []; + $bq = [$meId]; + $blood[$meId] = true; + while ($bq) { + $bid = array_shift($bq); + foreach (array_merge($graph['parents'][$bid] ?? [], $graph['children'][$bid] ?? []) as $nb) { + $nb = (int)$nb; + if (!isset($blood[$nb])) { + $blood[$nb] = true; + $bq[] = $nb; } } } + $head = null; + $headScore = null; + foreach ($cards as $c) { + $cid = (int)$c['id']; + // 分数越小越"本家":0 = 血亲本身,1 = 配偶,2 = 其它 + $sc = isset($blood[$cid]) ? 0 : 1; + if ($head === null || $sc < $headScore) { + $head = $c; + $headScore = $sc; + } + } if ($head !== null) { $rest = []; foreach ($cards as $c) {