194 lines
10 KiB
JavaScript
194 lines
10 KiB
JavaScript
const members = [{"id":"4661dd7b-f3b9-42d1-bf00-b14899e2a92e","name":"唐治明","birthYear":1960,"gender":"男","generation":"父亲","fatherId":"f24a95c7-fa68-4f56-b0ed-e1f7fb2c91e1"},{"id":"d4498bfb-c0ce-4218-bc8f-3f0cc0cf6984","name":"舒邦莲","birthYear":1960,"gender":"女","generation":"父亲"},{"id":"f24a95c7-fa68-4f56-b0ed-e1f7fb2c91e1","name":"唐有奎","birthYear":1900,"gender":"男","generation":"祖父"},{"id":"1be537aa-88cb-4b82-8c09-e18e05922499","name":"唐治安","birthYear":1960,"gender":"男","generation":"父亲","fatherId":"f24a95c7-fa68-4f56-b0ed-e1f7fb2c91e1"},{"id":"e6d9c5b3-6397-4d88-878b-e22e5c9f512b","name":"万华群","birthYear":1960,"gender":"女","generation":"父亲"},{"name":"唐治芳","birthYear":1960,"gender":"女","generation":"父亲","fatherId":"f24a95c7-fa68-4f56-b0ed-e1f7fb2c91e1","id":"4b78f55d-34b0-4407-a672-3d6b3e826f0f"},{"name":"邓能春","birthYear":1960,"gender":"男","generation":"父亲","id":"a7bcc3b5-c4fc-4fca-8bd4-44cf6078d678"},{"id":"208fb133-6a0b-4540-a1ff-ad8ce154c33f","name":"唐伟","birthYear":1990,"gender":"男","generation":"自己","fatherId":"4661dd7b-f3b9-42d1-bf00-b14899e2a92e","motherId":"d4498bfb-c0ce-4218-bc8f-3f0cc0cf6984"},{"name":"唐永洪","birthYear":1990,"gender":"男","generation":"自己","fatherId":"4661dd7b-f3b9-42d1-bf00-b14899e2a92e","motherId":"d4498bfb-c0ce-4218-bc8f-3f0cc0cf6984","id":"ab86880b-502c-4249-9ce4-ff3327c3fd1b"},{"id":"de8e2fc8-2a1e-4dc1-b010-cd29b9312105","name":"唐雪","birthYear":1990,"gender":"女","generation":"自己","fatherId":"1be537aa-88cb-4b82-8c09-e18e05922499","motherId":"e6d9c5b3-6397-4d88-878b-e22e5c9f512b"},{"name":"唐波","birthYear":1990,"gender":"男","generation":"自己","fatherId":"1be537aa-88cb-4b82-8c09-e18e05922499","motherId":"e6d9c5b3-6397-4d88-878b-e22e5c9f512b","id":"08a22bcd-5af6-4589-8739-9ea796c41a01"},{"name":"邓静","birthYear":1990,"gender":"女","generation":"自己","fatherId":"a7bcc3b5-c4fc-4fca-8bd4-44cf6078d678","motherId":"4b78f55d-34b0-4407-a672-3d6b3e826f0f","id":"1ebd23c6-dadf-4cec-98fe-5bff971bc591"},{"id":"4c3f6e87-8756-48de-9141-5881778974ce","name":"邓正悦","birthYear":1990,"gender":"女","generation":"自己","fatherId":"a7bcc3b5-c4fc-4fca-8bd4-44cf6078d678","motherId":"4b78f55d-34b0-4407-a672-3d6b3e826f0f"},{"name":"张红","birthYear":1990,"gender":"女","generation":"自己","id":"a74c5ba0-5fe1-4862-a651-f81b641deb72"},{"name":"郭思琪","birthYear":1990,"gender":"女","generation":"自己","id":"95672071-9f60-4728-9209-00a24a01fb3a"},{"id":"a1fa7080-3e49-49bb-b2d7-ec94e005369f","name":"唐世宁","birthYear":2020,"gender":"女","generation":"子女","fatherId":"ab86880b-502c-4249-9ce4-ff3327c3fd1b","motherId":"95672071-9f60-4728-9209-00a24a01fb3a"},{"id":"74ab3d7a-3dad-4279-aecb-13e7ef12c0ff","name":"唐瑾瑜","birthYear":2020,"gender":"女","generation":"子女","fatherId":"08a22bcd-5af6-4589-8739-9ea796c41a01","motherId":"a74c5ba0-5fe1-4862-a651-f81b641deb72"},{"id":"6365ca6a-f31f-4b7a-b233-bc5a101f7025","name":"唐世严","birthYear":2020,"gender":"男","generation":"子女","fatherId":"08a22bcd-5af6-4589-8739-9ea796c41a01","motherId":"a74c5ba0-5fe1-4862-a651-f81b641deb72"}];
|
|
|
|
const GEN_ORDER = ['鼻祖','远祖','太祖','烈祖','天祖','高祖','曾祖','祖父','父亲','自己','子女','孙辈','曾孙','玄孙','来孙','晜孙','仍孙','云孙','耳孙'];
|
|
|
|
const map = {};
|
|
members.forEach(m => map[m.id] = m);
|
|
|
|
const childrenOf = {};
|
|
members.forEach(m => {
|
|
if (m.fatherId && map[m.fatherId]) (childrenOf[m.fatherId] = childrenOf[m.fatherId] || []).push(m.id);
|
|
if (m.motherId && map[m.motherId]) (childrenOf[m.motherId] = childrenOf[m.motherId] || []).push(m.id);
|
|
});
|
|
Object.keys(childrenOf).forEach(pid => { childrenOf[pid] = [...new Set(childrenOf[pid])]; });
|
|
|
|
const rankOf = {};
|
|
members.forEach(m => {
|
|
if (m.generation) {
|
|
const idx = GEN_ORDER.indexOf(m.generation);
|
|
rankOf[m.id] = (idx >= 0 ? idx : 9) * 1000;
|
|
}
|
|
});
|
|
|
|
const bfsQueue = Object.keys(rankOf);
|
|
const visitedBFS = new Set(bfsQueue);
|
|
let qi = 0;
|
|
while (qi < bfsQueue.length) {
|
|
const pid = bfsQueue[qi++];
|
|
(childrenOf[pid] || []).forEach(cid => {
|
|
const needed = Math.max(
|
|
map[cid].fatherId && rankOf[map[cid].fatherId] !== undefined ? rankOf[map[cid].fatherId] + 1000 : 0,
|
|
map[cid].motherId && rankOf[map[cid].motherId] !== undefined ? rankOf[map[cid].motherId] + 1000 : 0
|
|
);
|
|
if (rankOf[cid] === undefined || needed > rankOf[cid]) rankOf[cid] = needed;
|
|
if (!visitedBFS.has(cid)) { visitedBFS.add(cid); bfsQueue.push(cid); }
|
|
});
|
|
}
|
|
members.forEach(m => { if (rankOf[m.id] === undefined) rankOf[m.id] = 9 * 1000; });
|
|
|
|
const uniqueRanks = [...new Set(Object.values(rankOf))].sort((a, b) => a - b);
|
|
const rankToRow = {};
|
|
uniqueRanks.forEach((r, i) => { rankToRow[r] = i; });
|
|
const rowOf = {};
|
|
members.forEach(m => { rowOf[m.id] = rankToRow[rankOf[m.id]]; });
|
|
|
|
const families = {};
|
|
const familyKeyOfChild = {};
|
|
members.forEach(child => {
|
|
const fatherId = child.fatherId && map[child.fatherId] ? child.fatherId : '';
|
|
const motherId = child.motherId && map[child.motherId] ? child.motherId : '';
|
|
if (!fatherId && !motherId) return;
|
|
const key = `${fatherId}|${motherId}`;
|
|
familyKeyOfChild[child.id] = key;
|
|
if (!families[key]) families[key] = { fatherId: fatherId || null, motherId: motherId || null, children: [] };
|
|
families[key].children.push(child.id);
|
|
});
|
|
|
|
const familyOrderList = Object.keys(families)
|
|
.map(key => {
|
|
const fam = families[key];
|
|
const fatherYear = fam.fatherId ? map[fam.fatherId].birthYear : -Infinity;
|
|
const motherYear = fam.motherId ? map[fam.motherId].birthYear : -Infinity;
|
|
return { key, orderYear: Math.max(fatherYear, motherYear) };
|
|
})
|
|
.sort((a, b) => b.orderYear - a.orderYear || a.key.localeCompare(b.key));
|
|
|
|
const familyOrderIndex = {};
|
|
familyOrderList.forEach((item, idx) => { familyOrderIndex[item.key] = idx; });
|
|
|
|
const parentFamilyIndices = {};
|
|
Object.keys(families).forEach(key => {
|
|
const fam = families[key];
|
|
const idx = familyOrderIndex[key];
|
|
if (fam.fatherId) (parentFamilyIndices[fam.fatherId] = parentFamilyIndices[fam.fatherId] || []).push(idx);
|
|
if (fam.motherId) (parentFamilyIndices[fam.motherId] = parentFamilyIndices[fam.motherId] || []).push(idx);
|
|
});
|
|
|
|
const parentPrimaryFamilyKey = {};
|
|
Object.keys(parentFamilyIndices).forEach(pid => {
|
|
const indices = parentFamilyIndices[pid];
|
|
const minIdx = Math.min(...indices);
|
|
parentPrimaryFamilyKey[pid] = familyOrderList[minIdx] ? familyOrderList[minIdx].key : null;
|
|
});
|
|
|
|
function compareByBirthName(a, b) {
|
|
if (a.birthYear !== b.birthYear) return b.birthYear - a.birthYear;
|
|
return a.name.localeCompare(b.name, 'zh-Hans-CN');
|
|
}
|
|
|
|
function sortRowWithParentOrder(row, prevOrderIndex) {
|
|
const memberSet = new Set(row.map(m => m.id));
|
|
|
|
// 找出当前行中的配偶关系(双方都在当前行)
|
|
const spouseOf = {};
|
|
Object.keys(families).forEach(key => {
|
|
const fam = families[key];
|
|
if (!fam || !fam.fatherId || !fam.motherId) return;
|
|
if (memberSet.has(fam.fatherId) && memberSet.has(fam.motherId)) {
|
|
spouseOf[fam.fatherId] = fam.motherId;
|
|
spouseOf[fam.motherId] = fam.fatherId;
|
|
}
|
|
});
|
|
|
|
// 按父母分组
|
|
const parentGroups = {};
|
|
row.forEach(m => {
|
|
const key = familyKeyOfChild[m.id] || `solo:${m.id}`;
|
|
if (!parentGroups[key]) parentGroups[key] = [];
|
|
parentGroups[key].push(m);
|
|
});
|
|
|
|
// 计算每个父母组的排序索引
|
|
function getParentGroupIndex(key) {
|
|
if (key.startsWith('solo:')) return null;
|
|
const parts = key.split('|');
|
|
const fId = parts[0] || null;
|
|
const mId = parts[1] || null;
|
|
const indices = [];
|
|
if (fId && prevOrderIndex[fId] !== undefined) indices.push(prevOrderIndex[fId]);
|
|
if (mId && prevOrderIndex[mId] !== undefined) indices.push(prevOrderIndex[mId]);
|
|
return indices.length > 0 ? Math.min(...indices) : null;
|
|
}
|
|
|
|
// 对父母组排序
|
|
const sortedGroupKeys = Object.keys(parentGroups).sort((a, b) => {
|
|
const aIdx = getParentGroupIndex(a);
|
|
const bIdx = getParentGroupIndex(b);
|
|
if (aIdx !== null && bIdx !== null && aIdx !== bIdx) return aIdx - bIdx;
|
|
if (aIdx !== null && bIdx === null) return -1;
|
|
if (aIdx === null && bIdx !== null) return 1;
|
|
return a.localeCompare(b);
|
|
});
|
|
|
|
// 展开每个父母组,先放兄弟姐妹,再放他们的配偶
|
|
const result = [];
|
|
const processed = new Set();
|
|
sortedGroupKeys.forEach(groupKey => {
|
|
const groupMembers = parentGroups[groupKey].slice().sort(compareByBirthName);
|
|
const spousesToAdd = [];
|
|
|
|
// 先添加所有兄弟姐妹
|
|
groupMembers.forEach(m => {
|
|
if (processed.has(m.id)) return;
|
|
result.push(m);
|
|
processed.add(m.id);
|
|
|
|
// 记录需要添加的配偶(如果配偶不在当前组)
|
|
const spouseId = spouseOf[m.id];
|
|
if (spouseId && memberSet.has(spouseId) && !processed.has(spouseId)) {
|
|
const spouseKey = familyKeyOfChild[spouseId] || `solo:${spouseId}`;
|
|
if (spouseKey !== groupKey) {
|
|
spousesToAdd.push(map[spouseId]);
|
|
}
|
|
}
|
|
});
|
|
|
|
// 然后添加配偶
|
|
spousesToAdd.forEach(spouse => {
|
|
if (!processed.has(spouse.id)) {
|
|
result.push(spouse);
|
|
processed.add(spouse.id);
|
|
}
|
|
});
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
function sortTopRow(row) {
|
|
const sorted = row.slice().sort((a, b) => {
|
|
const aKey = parentPrimaryFamilyKey[a.id];
|
|
const bKey = parentPrimaryFamilyKey[b.id];
|
|
if (aKey && bKey && aKey === bKey) {
|
|
const fam = families[aKey];
|
|
if (fam && fam.fatherId === a.id && fam.motherId === b.id) return -1;
|
|
if (fam && fam.motherId === a.id && fam.fatherId === b.id) return 1;
|
|
}
|
|
return compareByBirthName(a, b);
|
|
});
|
|
return sorted;
|
|
}
|
|
|
|
const maxRow = Math.max(...Object.values(rowOf));
|
|
const gens = [];
|
|
let prevOrderIndex = {};
|
|
for (let g = 0; g <= maxRow; g++) {
|
|
const rowMembers = members.filter(m => rowOf[m.id] === g);
|
|
const ordered = g === 0 ? sortTopRow(rowMembers) : sortRowWithParentOrder(rowMembers, prevOrderIndex);
|
|
gens.push(ordered);
|
|
prevOrderIndex = {};
|
|
ordered.forEach((m, idx) => { prevOrderIndex[m.id] = idx; });
|
|
|
|
console.log(`第${g}行排序结果: ${ordered.map(m => m.name).join(', ')}`);
|
|
}
|