diff --git a/templates/kin/tree.php b/templates/kin/tree.php
index 899976a..0912269 100644
--- a/templates/kin/tree.php
+++ b/templates/kin/tree.php
@@ -45,6 +45,24 @@ $rankKey = static function (int $id) use ($people): string {
};
// ---- ④ 打成前端要的数据包(代数 → 户 → 人)----
+
+// 「我」的血亲集合:只走 parent/child 边(不含配偶)能从「我」到达的人。
+// 用途:给每张卡标 blood —— 前端据此判定一户的「主父户」
+// (我的户同时被父母户与岳父母户认作子女,树递归只能走本家那条,
+// 否则树变图、布局重复铺人;判定标准就是「父户的主位是不是我方血亲」)。
+$blood = [$meId => true];
+$bq = [$meId];
+while ($bq) {
+ $bid = (int)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;
+ }
+ }
+}
+
$payloadUnits = [];
foreach ($units as $i => $u) {
$sorted = array_map('intval', $u['ids']);
@@ -66,6 +84,8 @@ foreach ($units as $i => $u) {
'me' => $id === (int)$meId,
'ph' => (int)($p['is_placeholder'] ?? 0) === 1,
'gender' => $g === 'm' ? 'M' : ($g === 'f' ? 'F' : 'U'),
+ // ⚠️ 本家血亲标记:前端用它判定一户的「主父户」(见上方 $blood 的说明)
+ 'blood' => isset($blood[$id]),
// ⚠️ 长幼排序键:前端要靠它分「哥哥/弟弟」「姐姐/妹妹」。
// 不用生日硬排(很多人没填生日),用 Kinship 里已有的 rankValueFor ——
// 它先看 birth_rank,再退回生日,最后用 id 兜底,保证顺序稳定。
@@ -82,21 +102,8 @@ foreach ($units as $i => $u) {
// 我排在她右边"(实测线上就是这个症状:红围脖@639 在我的左边)。
//
// 正解:按「**与"我"的血缘距离**」判定 —— 这一户里离「我」更近的那一位才是主位。
- // 我用一次不带配偶边的 BFS 算出血亲集合(Kinship::bloodRelatives 语义),
+ // 血亲集合 $blood 已在循环外算好(只走 parent/child 边的 BFS),
// 两边都在血亲集合里时,退到「与我的步数」比大小。
- $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) {
@@ -180,17 +187,17 @@ $payloadJson = json_encode(