diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user
index c07c428..0ff53f6 100644
--- a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user
+++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user
@@ -3,7 +3,7 @@
<_PublishTargetUrl>C:\inetpub\wwwroot\dockwebapi2
- True|2026-09-10T01:14:56.2914193Z||;True|2026-09-09T16:40:16.6461154+08:00||;True|2026-09-08T13:55:23.1502435+08:00||;True|2026-09-08T08:04:53.4279263+08:00||;True|2026-09-07T08:48:17.4682304+08:00||;True|2026-09-04T14:39:08.7878670+08:00||;True|2026-09-04T14:35:48.2937877+08:00||;True|2026-09-04T11:45:16.1372876+08:00||;True|2026-09-04T11:42:59.9356436+08:00||;True|2026-09-03T16:05:52.5270232+08:00||;True|2026-09-03T14:52:56.8559144+08:00||;True|2026-09-02T11:08:23.8720038+08:00||;True|2026-09-02T10:58:16.8081797+08:00||;True|2026-08-26T13:34:12.3805892+08:00||;True|2026-08-25T08:31:30.7787234+08:00||;True|2026-08-20T13:10:46.4725468+08:00||;True|2026-08-20T13:10:28.3142576+08:00||;True|2026-08-19T16:10:27.3362887+08:00||;True|2026-08-19T16:01:12.6234971+08:00||;True|2026-08-19T15:42:46.6576265+08:00||;True|2026-08-19T13:39:59.9363522+08:00||;True|2026-08-19T13:36:53.0379313+08:00||;True|2026-08-19T13:31:36.0841398+08:00||;True|2026-08-19T11:44:37.5319626+08:00||;True|2026-08-19T09:36:45.6000047+08:00||;True|2026-08-19T09:34:36.8468631+08:00||;True|2026-08-19T08:35:41.2202300+08:00||;True|2026-08-18T16:20:59.0170916+08:00||;
+ True|2026-09-13T11:02:59.5654245Z||;True|2026-09-10T09:14:56.2914193+08:00||;True|2026-09-09T16:40:16.6461154+08:00||;True|2026-09-08T13:55:23.1502435+08:00||;True|2026-09-08T08:04:53.4279263+08:00||;True|2026-09-07T08:48:17.4682304+08:00||;True|2026-09-04T14:39:08.7878670+08:00||;True|2026-09-04T14:35:48.2937877+08:00||;True|2026-09-04T11:45:16.1372876+08:00||;True|2026-09-04T11:42:59.9356436+08:00||;True|2026-09-03T16:05:52.5270232+08:00||;True|2026-09-03T14:52:56.8559144+08:00||;True|2026-09-02T11:08:23.8720038+08:00||;True|2026-09-02T10:58:16.8081797+08:00||;True|2026-08-26T13:34:12.3805892+08:00||;True|2026-08-25T08:31:30.7787234+08:00||;True|2026-08-20T13:10:46.4725468+08:00||;True|2026-08-20T13:10:28.3142576+08:00||;True|2026-08-19T16:10:27.3362887+08:00||;True|2026-08-19T16:01:12.6234971+08:00||;True|2026-08-19T15:42:46.6576265+08:00||;True|2026-08-19T13:39:59.9363522+08:00||;True|2026-08-19T13:36:53.0379313+08:00||;True|2026-08-19T13:31:36.0841398+08:00||;True|2026-08-19T11:44:37.5319626+08:00||;True|2026-08-19T09:36:45.6000047+08:00||;True|2026-08-19T09:34:36.8468631+08:00||;True|2026-08-19T08:35:41.2202300+08:00||;True|2026-08-18T16:20:59.0170916+08:00||;
\ No newline at end of file
diff --git a/WebVue/src/components/master/AncestryTreeChartModal.vue b/WebVue/src/components/master/AncestryTreeChartModal.vue
index 9d31565..5357386 100644
--- a/WebVue/src/components/master/AncestryTreeChartModal.vue
+++ b/WebVue/src/components/master/AncestryTreeChartModal.vue
@@ -69,10 +69,12 @@ const data = ref(null);
const hasPerson = computed(() => !!data.value?.CurrentPerson?.FamilyPerson?.PersonId);
const rootPersonId = computed(() => data.value?.CurrentPerson?.FamilyPerson?.PersonId ?? "");
-/** 全族索引:人员信息 / 夫妻关系(双向)/ 亲子关系 */
+/** 全族索引:人员信息 / 夫妻关系(双向)/ 亲子关系 / 亲子反向索引 */
let personMap = new Map();
let spousesOf = new Map();
let childrenOf = new Map();
+/** 孩子 -> 父母记录列表(一个孩子可能同时挂在生父、过继父等多个父节点下) */
+let parentsOf = new Map();
/** 已展开(显示孩子)的节点 personId 集合 */
const expandedIds = ref>(new Set());
@@ -155,6 +157,7 @@ const buildIndex = (resp: FamilyTreeData) => {
personMap = new Map();
spousesOf = new Map();
childrenOf = new Map();
+ parentsOf = new Map();
// 1) 所有人员信息(含性别),优先作为人员卡片数据源
const persons = resp?.CurrentPerson?.FamilyTreePersons ?? [];
@@ -238,10 +241,29 @@ const buildIndex = (resp: FamilyTreeData) => {
orderby: c.Orderby,
});
childrenOf.set(c.PersonId, list);
+ // 反向记录:同一孩子可能有多条父记录(生父 / 过继父),保留以判断由谁承担后代
+ const parentList = parentsOf.get(c.ChildrenId) ?? [];
+ parentList.push({ parentId: c.PersonId, relation: c.RelationType });
+ parentsOf.set(c.ChildrenId, parentList);
}
});
};
+/** 承祧 / 入嗣 / 收养类关系:孩子被过继到该父名下,由其承担其后代世系 */
+const ADOPTIVE_RELATIONS = new Set(["C", "E", "F", "G", "H", "I", "J", "K", "L"]);
+
+/**
+ * 同一孩子挂在多个父节点下时,选定“承担后代”的父节点:
+ * 优先取承祧 / 过继关系的一方(如“继子”“承嗣”),否则取记录顺序中的第一个。
+ * 其余父节点仅显示该孩子的引用卡片,不再展开其后代,避免后代被重复展示。
+ */
+const primaryParentOf = (personId: string): string => {
+ const parents = parentsOf.get(personId) ?? [];
+ if (parents.length === 0) return "";
+ const adopted = parents.find((p) => ADOPTIVE_RELATIONS.has(p.relation ?? ""));
+ return (adopted ?? parents[0]).parentId;
+};
+
/** 构建图数据:递归一次性展示所有人员,祖先为根,配偶同行右侧,孩子列在配偶正下方 */
const buildGraphData = () => {
const nodes: any[] = [];
@@ -320,8 +342,36 @@ const buildGraphData = () => {
// 孩子列与本人第一行的配偶列对齐(x + 260),即孩子位于配偶正下方,竖直跟第一行对齐
const childBaseX = x + 260;
children.forEach((c: any) => {
- walk(c.id, depth + 1, childBaseX);
- edges.push({ source: "n-" + personId, target: "n-" + c.id, data: { kind: "parent" } });
+ // 一个孩子可能同时是多方之子(生父 / 过继父):每个父节点下各显示一张卡片。
+ // 由“承祧 / 过继”的一方承担其后代,其余父节点只显示一张引用卡片(不展开其后代)。
+ const isPrimary = primaryParentOf(c.id) === personId;
+ if (isPrimary) {
+ if (!visited.has(c.id)) {
+ walk(c.id, depth + 1, childBaseX);
+ }
+ edges.push({ source: "n-" + personId, target: "n-" + c.id, data: { kind: "parent" } });
+ } else {
+ const childInfo = personMap.get(c.id) ?? {};
+ const refId = "r-" + personId + "-" + c.id;
+ nodes.push({
+ id: refId,
+ style: { x: childBaseX, y: cursor },
+ data: {
+ kind: "member",
+ personId: c.id,
+ tag: "族员",
+ name: (childInfo.Surname ?? c.ChildrenSurname ?? "") + (childInfo.GenealogyName ?? c.ChildrenGenealogyName ?? ""),
+ commonName: childInfo.CommonName ?? c.ChildrenCommonName,
+ gender: childInfo.Gender ?? c.gender,
+ avatarUrl: childInfo.AvatarUrl ?? "",
+ hasChildren: false,
+ expanded: false,
+ loaded: true,
+ },
+ });
+ cursor += Y_STEP;
+ edges.push({ source: "n-" + personId, target: refId, data: { kind: "parent" } });
+ }
});
}
};