(function (root, factory) {
// 世系人物模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.LineagePages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.LineagePages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
var selectedPersonId = '';
var editingPersonId = '';
var relationMode = '';
var peopleById = Object.create(null);
var currentPageNum = 1;
var currentPageSize = 20;
var currentPageTotal = null;
var managementAccess = true;
var writePending = false;
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function shouldRedirectToLogin(api, error) {
var status = error && (error.status || error.code);
return !api || !api.getToken || !api.getToken() || Number(status) === 401;
}
function isForbidden(error) {
return Number(error && (error.status || error.code)) === 403;
}
function redirectUnauthorized(api, error) {
if (!shouldRedirectToLogin(api, error)) return false;
if (api && api.clearToken) api.clearToken();
if (!root.location) return true;
if (typeof root.location.replace === 'function') {
root.location.replace('login.html');
return true;
}
root.location.href = 'login.html';
return true;
}
function query(selector, rootNode) {
return documentRef ? (rootNode || documentRef).querySelector(selector) : null;
}
function queryAll(selector, rootNode) {
return documentRef ? Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector)) : [];
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
if (root.alert) root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId(search) {
var page = query('[data-lineage-page]');
var source = search === undefined && root.location ? root.location.search : search;
var profileGenealogyId;
if (search === undefined && root.ProfileUI && root.ProfileUI.getGenealogyId) {
profileGenealogyId = root.ProfileUI.getGenealogyId();
if (profileGenealogyId) return profileGenealogyId;
}
return getQueryParam(source, 'genealogyId') || (page && page.getAttribute('data-genealogy-id')) || '';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function toIntegerOrUndefined(value) {
var text = trimOrUndefined(value);
var number;
if (!text) return undefined;
number = Number(text);
return Number.isInteger(number) && Number.isSafeInteger(number) ? number : undefined;
}
function getPersonId(item) {
var value = item && item.personId;
var text;
if (value === undefined || value === null || value === '') return '';
if (typeof value === 'number' && !Number.isSafeInteger(value)) return '';
text = String(value);
return /^\d+$/.test(text) ? text : '';
}
function buildLineagePersonBody(values) {
var source = values || {};
var body = { name: trimOrUndefined(source.name) };
var optionalFields = [
'personNo', 'aliasName', 'sex', 'generationName', 'birthDate', 'birthLunar', 'birthPlace',
'deathDate', 'deathLunar', 'deathPlace', 'burialPlace', 'personStatus', 'biography',
'remark', 'relationName'
];
var generation = trimOrUndefined(source.generation);
var sortOrder = trimOrUndefined(source.sortOrder);
optionalFields.forEach(function (field) {
var value = trimOrUndefined(source[field]);
if (value !== undefined) body[field] = value;
});
if (generation !== undefined) body.generation = Number(generation);
if (sortOrder !== undefined) body.sortOrder = Number(sortOrder);
return body;
}
function validateLineagePersonBody(body) {
if (!body || !body.name) return '请填写成员姓名';
if (body.generation !== undefined && (!Number.isInteger(body.generation) || !Number.isSafeInteger(body.generation))) {
return '世代序号必须是整数';
}
if (body.sortOrder !== undefined && (!Number.isInteger(body.sortOrder) || !Number.isSafeInteger(body.sortOrder))) {
return '排序值必须是整数';
}
return '';
}
function normalizeLineagePerson(item) {
var personId = getPersonId(item);
var name = trimOrUndefined(item && item.name);
var person;
if (!personId || !name) return null;
person = { personId: personId, name: name };
[
'genealogyName', 'genealogyNo', 'appUserNickName', 'personNo', 'aliasName', 'sex', 'generationName',
'fatherName', 'motherName', 'spouseNames', 'birthDate', 'birthLunar', 'birthPlace', 'deathDate',
'deathLunar', 'deathPlace', 'burialPlace', 'personStatus', 'biography', 'status', 'remark',
'relationType', 'relationName'
].forEach(function (field) {
if (item && item[field] !== undefined && item[field] !== null) person[field] = String(item[field]);
});
['appUserId', 'genealogyId', 'fatherId', 'motherId', 'avatarOssId'].forEach(function (field) {
if (item && item[field] !== undefined && item[field] !== null) {
if (typeof item[field] === 'number' && !Number.isSafeInteger(item[field])) return;
person[field] = String(item[field]);
}
});
if (toIntegerOrUndefined(item && item.generation) !== undefined) person.generation = toIntegerOrUndefined(item.generation);
if (toIntegerOrUndefined(item && item.sortOrder) !== undefined) person.sortOrder = toIntegerOrUndefined(item.sortOrder);
return person;
}
function normalizeList(data) {
if (Array.isArray(data)) return data;
if (data && Array.isArray(data.rows)) return data.rows;
return [];
}
function escapeHtml(value) {
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function getPersonSummary(person) {
var values = [];
if (person.generation !== undefined) values.push('第 ' + person.generation + ' 世');
if (person.generationName) values.push('字辈:' + person.generationName);
if (person.aliasName) values.push('别名:' + person.aliasName);
if (person.relationName) values.push('关系称谓:' + person.relationName);
if (person.personStatus) values.push('人物状态:' + person.personStatus);
return values.join(' · ') || '未填写世代信息';
}
function renderLineageList(data) {
var container = query('[data-lineage-list]');
var normalized = normalizeList(data).map(normalizeLineagePerson);
var invalidCount = normalized.filter(function (item) { return !item; }).length;
var people = normalized.filter(Boolean);
peopleById = Object.create(null);
people.forEach(function (person) {
peopleById[person.personId] = person;
});
if (!container) return;
if (invalidCount) {
container.innerHTML = '
人物响应缺少可安全使用的 personId 或 name,请联系后端补充 DTO。
';
return;
}
if (!people.length) {
container.innerHTML = '
暂无世系人物
';
return;
}
container.innerHTML = people.map(function (person) {
var selected = person.personId === selectedPersonId ? ' is-selected' : '';
return '';
}).join('');
}
function renderTreeNode(item, ancestry) {
var person = normalizeLineagePerson(item);
var nextAncestry;
var spouses;
var children;
var branches = '';
if (!person) return '';
if (ancestry[person.personId]) {
return '