(function (root, factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.GenealogyEntryPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.GenealogyEntryPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
function normalizeTargetPage(value) {
var target = String(value || '');
var hashIndex = target.indexOf('#');
var hash = hashIndex < 0 ? '' : target.slice(hashIndex);
var parts;
var params;
if (hashIndex >= 0) target = target.slice(0, hashIndex);
parts = target.split('?');
if (!/^profile-[a-z-]+\.html$/.test(parts[0])) return 'profile-family-home.html';
params = new URLSearchParams(parts[1] || '');
params.delete('genealogyId');
return parts[0] + (params.toString() ? '?' + params.toString() : '') + hash;
}
function getTargetPage(search) {
var params = new URLSearchParams(String(search === undefined && root.location ? root.location.search : search || '').replace(/^\?/, ''));
return normalizeTargetPage(params.get('next'));
}
function buildStatus(quota) {
var source = quota || {};
var details = [];
if (Number(source.createRemaining) === -1) details.push('创建不限');
else if (Number(source.createRemaining) >= 0) details.push('还可创建 ' + source.createRemaining + ' 部');
if (Number(source.joinRemaining) === -1) details.push('加入不限');
else if (Number(source.joinRemaining) >= 0) details.push('还可加入 ' + source.joinRemaining + ' 部');
return details.length ? '家谱额度:' + details.join(',') + '。' : '';
}
function escapeHtml(value) {
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function trimOrUndefined(value) {
var text;
if (value === undefined || value === null) return undefined;
text = String(value).trim();
return text || undefined;
}
function normalizeId(value) {
var text;
if (typeof value === 'number' && !Number.isSafeInteger(value)) return '';
if (value === undefined || value === null) return '';
text = String(value).trim();
return /^[1-9][0-9]*$/.test(text) ? text : '';
}
function buildGenealogyCreateBody(values) {
var source = values || {};
var body = {
genealogyName: String(source.genealogyName || '').trim(),
surname: String(source.surname || '').trim(),
regionCode: String(source.regionCode || '').trim()
};
var optionalNames = ['ancestralHall', 'originPlace', 'addressDetail', 'intro'];
var coverOssId = normalizeId(source.coverOssId);
var visibility = trimOrUndefined(source.visibility);
var joinMode = trimOrUndefined(source.joinMode);
optionalNames.forEach(function (name) {
var value = trimOrUndefined(source[name]);
if (value !== undefined) body[name] = value;
});
if (source.coverOssId !== undefined && source.coverOssId !== null && source.coverOssId !== '') {
if (coverOssId) body.coverOssId = coverOssId;
else body.invalidCoverOssId = true;
}
if (visibility !== undefined) body.visibility = visibility;
if (joinMode !== undefined) body.joinMode = joinMode;
return body;
}
function validateGenealogyCreateBody(body) {
if (!body || !body.genealogyName) return '请填写谱名';
if (!body.surname) return '请填写姓氏';
if (!body.regionCode) return '请选择家谱所在地区';
if (body.visibility !== undefined && ['0', '1', '2'].indexOf(body.visibility) < 0) return '可见范围选项无效';
if (body.joinMode !== undefined && ['0', '1', '2'].indexOf(body.joinMode) < 0) return '加入方式选项无效';
if (body.invalidCoverOssId) return '封面文件无效,请重新选择';
return '';
}
function canCreateGenealogy(quota) {
var remaining = Number(quota && quota.createRemaining);
if (quota && typeof quota.canCreate === 'boolean') return quota.canCreate;
return Number.isInteger(remaining) && (remaining === -1 || remaining > 0);
}
function normalizeCreatedGenealogy(item) {
var genealogyId = normalizeId(item && item.genealogyId);
var genealogyName = String(item && item.genealogyName || '').trim();
var surname = String(item && item.surname || '').trim();
if (!genealogyId || !genealogyName || !surname) return null;
return {
genealogyId: genealogyId,
genealogyName: genealogyName,
surname: surname,
regionFullName: String(item && item.regionFullName || '')
};
}
function buildCreatedGenealogyUrl(item) {
var genealogy = normalizeCreatedGenealogy(item);
return genealogy ? buildEntryUrl(genealogy.genealogyId, 'profile-family-home.html') : '';
}
function shouldRedirectToLogin(api, error) {
var status = error && (error.status || error.code);
return !api || !api.getToken || !api.getToken() || Number(status) === 401;
}
function redirectToLogin(api) {
if (api && api.clearToken) api.clearToken();
if (!root.location) return;
if (typeof root.location.replace === 'function') root.location.replace('login.html');
else root.location.href = 'login.html';
}
function getFormValues(form) {
var values = {};
Array.prototype.forEach.call(form.querySelectorAll('[name]'), function (field) {
values[field.name] = field.value;
});
return values;
}
function getApiStateType(error) {
return Number(error && (error.status || error.code)) === 403 ? 'forbidden' : 'error';
}
function setCreateStatus(message, type) {
var status = root.document && root.document.querySelector('[data-genealogy-create-status]');
if (!status) return;
if (!message) {
status.innerHTML = '';
return;
}
if (root.ProfileUI && root.ProfileUI.setApiState) {
root.ProfileUI.setApiState(status, type || 'error', message);
return;
}
status.textContent = message;
}
function setEntryStatus(message, type) {
var status = root.document && root.document.querySelector('[data-genealogy-entry-status]');
if (!status) return;
if (!message) {
status.innerHTML = '';
return;
}
if (type && root.ProfileUI && root.ProfileUI.setApiState) {
root.ProfileUI.setApiState(status, type, message);
return;
}
status.textContent = message;
}
function setGenealogyListState(container, type, message) {
if (!container) return;
if (root.ProfileUI && root.ProfileUI.setApiState) {
root.ProfileUI.setApiState(container, type, message);
return;
}
container.textContent = message;
}
function setCreatePending(pending) {
var button = root.document && root.document.querySelector('[data-genealogy-create-submit]');
if (!button) return;
if (!button.dataset.defaultLabel) button.dataset.defaultLabel = button.textContent;
button.disabled = Boolean(pending);
button.textContent = pending ? '正在创建…' : button.dataset.defaultLabel;
button.setAttribute('aria-busy', pending ? 'true' : 'false');
}
async function initGenealogyCreatePage() {
var form = root.document && root.document.querySelector('[data-genealogy-create-form]');
var quotaElement = root.document && root.document.querySelector('[data-genealogy-create-quota]');
var api = root.GenealogyApi && root.GenealogyApi.defaultClient;
var quota;
var writePending = false;
if (!form) return;
if (shouldRedirectToLogin(api)) {
redirectToLogin(api);
return;
}
setCreateStatus('正在读取创建额度…', 'loading');
try {
quota = await api.genealogyQuota();
if (quotaElement) quotaElement.textContent = buildStatus(quota) || '当前额度信息不可用';
if (!canCreateGenealogy(quota)) {
setCreateStatus('当前没有可用的家谱创建额度', 'empty');
form.querySelector('[data-genealogy-create-submit]').disabled = true;
return;
}
setCreateStatus('');
} catch (error) {
if (shouldRedirectToLogin(api, error)) {
redirectToLogin(api);
return;
}
if (quotaElement) quotaElement.textContent = '家谱额度读取失败';
setCreateStatus(error.message || '无法读取家谱创建额度', getApiStateType(error));
form.querySelector('[data-genealogy-create-submit]').disabled = true;
return;
}
if (form.__genealogyCreateBound) return;
form.__genealogyCreateBound = true;
form.addEventListener('submit', async function (event) {
var body;
var validation;
var created;
var verified;
event.preventDefault();
if (writePending) return;
body = buildGenealogyCreateBody(getFormValues(form));
validation = validateGenealogyCreateBody(body);
if (validation) {
setCreateStatus(validation, 'error');
return;
}
delete body.invalidCoverOssId;
writePending = true;
setCreatePending(true);
setCreateStatus('正在创建家谱…', 'loading');
try {
created = normalizeCreatedGenealogy(await api.createGenealogy(body));
if (!created) throw new Error('创建响应缺少有效家谱信息');
verified = normalizeCreatedGenealogy(await api.genealogyDetail(created.genealogyId));
if (!verified || verified.genealogyId !== created.genealogyId) throw new Error('创建后无法读取同一家谱');
if (root.ProfileUI && root.ProfileUI.setCurrentGenealogyContext) {
root.ProfileUI.setCurrentGenealogyContext(verified.genealogyId, verified.genealogyName);
}
if (root.location) root.location.href = buildCreatedGenealogyUrl(verified);
} catch (error) {
if (shouldRedirectToLogin(api, error)) {
redirectToLogin(api);
return;
}
setCreateStatus(error.message || '创建家谱失败,请稍后重试', getApiStateType(error));
} finally {
writePending = false;
setCreatePending(false);
}
});
}
function normalizeGenealogy(item) {
var source = item || {};
var id = source.genealogyId === undefined || source.genealogyId === null
? ''
: String(source.genealogyId);
if (!/^[1-9][0-9]*$/.test(id) || !source.genealogyName) return null;
return {
genealogyId: id,
genealogyName: String(source.genealogyName),
surname: source.surname === undefined || source.surname === null ? '' : String(source.surname),
regionFullName: source.regionFullName === undefined || source.regionFullName === null ? '' : String(source.regionFullName),
memberCount: source.memberCount,
personCount: source.personCount,
roleType: source.roleType === undefined || source.roleType === null ? '' : String(source.roleType),
canManage: source.canManage === true
};
}
function buildEntryUrl(genealogyId, target) {
var normalizedTarget = normalizeTargetPage(target);
var parts = normalizedTarget.split('#');
var pathAndQuery = parts[0];
var hash = parts.length > 1 ? '#' + parts.slice(1).join('#') : '';
var pathParts = pathAndQuery.split('?');
var params = new URLSearchParams(pathParts[1] || '');
params.set('genealogyId', String(genealogyId));
return pathParts[0] + '?' + params.toString() + hash;
}
function renderGenealogies(container, data, target) {
var items = Array.isArray(data) ? data.map(normalizeGenealogy).filter(Boolean) : [];
if (!container) return items;
if (!Array.isArray(data) || (data.length && !items.length)) {
setGenealogyListState(container, 'error', '家谱响应字段不完整,请联系后端核对。');
return [];
}
if (!items.length) {
setGenealogyListState(container, 'empty', '当前账号还没有可进入的家谱');
return [];
}
container.innerHTML = items.map(function (item) {
var meta = [
item.surname ? item.surname + '氏' : '',
item.regionFullName,
item.memberCount === undefined || item.memberCount === null ? '' : item.memberCount + ' 位成员',
item.personCount === undefined || item.personCount === null ? '' : item.personCount + ' 位世系人物'
].filter(Boolean).join(' · ');
return '' +
'' + escapeHtml(item.genealogyName) + '
' + escapeHtml(meta) +
'
' + (item.canManage ? '管理并进入' : '进入家谱') + '';
}).join('');
return items;
}
async function init() {
if (root.document && root.document.querySelector('[data-genealogy-create-page]')) {
await initGenealogyCreatePage();
return;
}
var status = root.document && root.document.querySelector('[data-genealogy-entry-status]');
var api = root.GenealogyApi && root.GenealogyApi.defaultClient;
var target = getTargetPage();
var container = root.document && root.document.querySelector('[data-genealogy-list="mine"]');
var sortSelect = root.document && root.document.querySelector('[data-genealogy-sort-select]');
var sortUp = root.document && root.document.querySelector('[data-genealogy-sort-up]');
var sortDown = root.document && root.document.querySelector('[data-genealogy-sort-down]');
var sortSave = root.document && root.document.querySelector('[data-genealogy-sort-save]');
var result;
var sortPending = false;
if (!status) return;
if (shouldRedirectToLogin(api)) {
redirectToLogin(api);
return;
}
if (!api || !api.genealogyQuota || !api.genealogiesMine || !api.saveGenealogyOrder) {
setEntryStatus('家谱入口接口初始化失败,请刷新后重试。', 'error');
setGenealogyListState(container, 'error', '家谱列表接口初始化失败,请刷新后重试。');
return;
}
setGenealogyListState(container, 'loading', '正在读取我的家谱…');
setEntryStatus('正在读取家谱额度…', 'loading');
try {
result = await api.genealogiesMine();
renderGenealogies(container, result, target);
if (sortSelect) {
var sortItems = Array.isArray(result) ? result.map(normalizeGenealogy).filter(Boolean) : [];
sortSelect.innerHTML = sortItems.map(function (item) {
return '';
}).join('');
[sortSelect, sortUp, sortDown, sortSave].forEach(function (control) {
if (control) control.disabled = sortItems.length < 2;
});
}
} catch (error) {
if (shouldRedirectToLogin(api, error)) {
redirectToLogin(api);
return;
}
setGenealogyListState(
container,
getApiStateType(error),
getApiStateType(error) === 'forbidden' ? '当前账号无权查看我的家谱。' : '无法读取我的家谱,请稍后重试。'
);
}
function moveSelected(offset) {
var index;
var targetIndex;
var option;
if (!sortSelect || sortPending) return;
index = sortSelect.selectedIndex;
targetIndex = index + offset;
if (index < 0 || targetIndex < 0 || targetIndex >= sortSelect.options.length) return;
option = sortSelect.options[index];
if (offset < 0) sortSelect.insertBefore(option, sortSelect.options[targetIndex]);
else sortSelect.insertBefore(sortSelect.options[targetIndex], option);
sortSelect.selectedIndex = targetIndex;
}
if (sortUp) sortUp.addEventListener('click', function () { moveSelected(-1); });
if (sortDown) sortDown.addEventListener('click', function () { moveSelected(1); });
if (sortSave) sortSave.addEventListener('click', async function () {
if (sortPending || !sortSelect) return;
sortPending = true;
[sortSelect, sortUp, sortDown, sortSave].forEach(function (control) { if (control) control.disabled = true; });
setEntryStatus('正在保存家谱顺序…', 'loading');
try {
await api.saveGenealogyOrder(Array.prototype.map.call(sortSelect.options, function (option) { return option.value; }));
setEntryStatus('家谱顺序已保存');
} catch (error) {
setEntryStatus(error.message || '家谱顺序保存失败,请稍后重试。', getApiStateType(error));
} finally {
sortPending = false;
[sortSelect, sortUp, sortDown, sortSave].forEach(function (control) {
if (control) control.disabled = sortSelect.options.length < 2;
});
}
});
try {
result = await api.genealogyQuota();
setEntryStatus(buildStatus(result));
} catch (error) {
if (shouldRedirectToLogin(api, error)) {
redirectToLogin(api);
return;
}
setEntryStatus(
getApiStateType(error) === 'forbidden' ? '当前账号无权读取家谱额度。' : '家谱额度读取失败,请稍后重试。',
getApiStateType(error)
);
}
}
return {
normalizeTargetPage: normalizeTargetPage,
getTargetPage: getTargetPage,
buildStatus: buildStatus,
buildGenealogyCreateBody: buildGenealogyCreateBody,
validateGenealogyCreateBody: validateGenealogyCreateBody,
canCreateGenealogy: canCreateGenealogy,
normalizeCreatedGenealogy: normalizeCreatedGenealogy,
buildCreatedGenealogyUrl: buildCreatedGenealogyUrl,
shouldRedirectToLogin: shouldRedirectToLogin,
initGenealogyCreatePage: initGenealogyCreatePage,
normalizeGenealogy: normalizeGenealogy,
buildEntryUrl: buildEntryUrl,
renderGenealogies: renderGenealogies,
init: init
};
});