' + escapeHtml(record.meritTitle) + '
' + escapeHtml(record.donorName + ' · ' + summary.join(' · ')) + '
(function (root, factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.MeritPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.MeritPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
var recordsById = Object.create(null);
var writePending = false;
var meritTypes = {
donation: '捐赠',
repair: '修缮',
public: '公益',
other: '其他'
};
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, node) {
return documentRef ? (node || documentRef).querySelector(selector) : null;
}
function queryAll(selector, node) {
return documentRef ? Array.prototype.slice.call((node || documentRef).querySelectorAll(selector)) : [];
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function queryParam(search, name) {
return new URLSearchParams(String(search || '').replace(/^\?/, '')).get(name) || '';
}
function normalizeId(value) {
if (value === undefined || value === null || value === '') return '';
if (typeof value === 'number' && !Number.isSafeInteger(value)) return '';
return /^[1-9][0-9]*$/.test(String(value)) ? String(value) : '';
}
function getCurrentGenealogyId(search) {
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 normalizeId(profileGenealogyId);
}
return normalizeId(queryParam(source, 'genealogyId'));
}
function getCurrentMeritId(search) {
var source = search === undefined && root.location ? root.location.search : search;
return normalizeId(queryParam(source, 'meritId'));
}
function toBackendDateTime(value) {
var text = trimOrUndefined(value);
if (!text) return undefined;
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(text)) return text.replace('T', ' ') + ':00';
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(text)) return text.replace('T', ' ');
return text;
}
function toDateTimeInputValue(value) {
var text = String(value || '');
if (!/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/.test(text)) return '';
return text.slice(0, 16).replace(' ', 'T');
}
function toFiniteNumber(value) {
var text = trimOrUndefined(value);
var number;
if (!text) return undefined;
number = Number(text);
return Number.isFinite(number) ? number : undefined;
}
function toSafeInteger(value) {
var number = toFiniteNumber(value);
return Number.isSafeInteger(number) ? number : undefined;
}
function decimalKey(value) {
var text = String(value).trim().replace(/^([+-]?)\./, '$10.');
var match = text.match(/^([+-]?)(\d+)(?:\.(\d*))?(?:[eE]([+-]?\d+))?$/);
var coefficient;
var scale;
if (!match) return '';
coefficient = BigInt((match[2] + (match[3] || '')).replace(/^0+(?=\d)/, ''));
scale = (match[3] || '').length - Number(match[4] || 0);
if (coefficient === 0n) return '0:0';
if (scale < 0) {
coefficient *= 10n ** BigInt(-scale);
scale = 0;
}
while (scale > 0 && coefficient % 10n === 0n) {
coefficient /= 10n;
scale -= 1;
}
if (match[1] === '-') coefficient = -coefficient;
return String(coefficient) + ':' + String(scale);
}
function isExactJsonNumber(sourceText, number) {
return Number.isFinite(number) && decimalKey(sourceText) === decimalKey(JSON.stringify(number));
}
function buildMeritRecordBody(values) {
var source = values || {};
var body = {
donorName: String(source.donorName || '').trim(),
meritTitle: String(source.meritTitle || '').trim()
};
var meritType = trimOrUndefined(source.meritType);
var meritContent = trimOrUndefined(source.meritContent);
var amountText = trimOrUndefined(source.amount);
var meritTime = toBackendDateTime(source.meritTime);
var sortOrderText = trimOrUndefined(source.sortOrder);
var status = trimOrUndefined(source.status);
if (meritType !== undefined) body.meritType = meritType;
if (meritContent !== undefined) body.meritContent = meritContent;
if (amountText !== undefined) {
body.amount = toFiniteNumber(amountText);
if (body.amount === undefined) body.invalidAmount = true;
else if (!isExactJsonNumber(amountText, body.amount)) body.invalidAmountPrecision = true;
}
if (meritTime !== undefined) body.meritTime = meritTime;
if (sortOrderText !== undefined) {
body.sortOrder = toSafeInteger(sortOrderText);
if (body.sortOrder === undefined) body.invalidSortOrder = true;
}
if (status !== undefined) body.status = status;
return body;
}
function isValidBackendDateTime(value) {
var match = String(value || '').match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
var year;
var month;
var day;
var days;
if (!match) return false;
year = Number(match[1]);
month = Number(match[2]);
day = Number(match[3]);
if (month < 1 || month > 12 || Number(match[4]) > 23 || Number(match[5]) > 59 || Number(match[6]) > 59) return false;
days = [31, year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
return day >= 1 && day <= days[month - 1];
}
function validateMeritRecordBody(body) {
if (!body || !body.donorName) return '请填写功德人姓名';
if (!body.meritTitle) return '请填写功德标题';
if (body.meritType !== undefined && !Object.prototype.hasOwnProperty.call(meritTypes, body.meritType)) {
return '功德类型无效';
}
if (body.invalidAmount || (Object.prototype.hasOwnProperty.call(body, 'amount') && !Number.isFinite(body.amount))) {
return '功德金额必须是有限数字';
}
if (body.invalidAmountPrecision) return '功德金额超出浏览器可安全提交的精度';
if (body.meritTime !== undefined && !isValidBackendDateTime(body.meritTime)) return '功德时间格式无效';
if (body.invalidSortOrder || (Object.prototype.hasOwnProperty.call(body, 'sortOrder') && !Number.isSafeInteger(body.sortOrder))) {
return '排序值必须是安全整数';
}
if (body.status === '1') return '当前 PC 无法重新读取停用功德记录,暂不开放停用';
if (body.status !== undefined && body.status !== '0') return '功德记录状态只能是 0';
return '';
}
function stringValue(value) {
return value === undefined || value === null ? '' : String(value);
}
function normalizeAmount(value) {
var text;
if (value === undefined || value === null || value === '') return '';
if (typeof value === 'number') return Number.isFinite(value) ? String(value) : '';
text = String(value).trim();
return /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(text) ? text : '';
}
function optionalSafeInteger(value) {
var number;
if (value === undefined || value === null || value === '') return undefined;
number = Number(value);
return Number.isSafeInteger(number) ? number : undefined;
}
function normalizeMeritRecord(item) {
var meritId = normalizeId(item && item.meritId);
var genealogyId = normalizeId(item && item.genealogyId);
var appUserId = normalizeId(item && item.appUserId);
var donorName = String(item && item.donorName || '').trim();
var meritType = stringValue(item && item.meritType);
var meritTitle = String(item && item.meritTitle || '').trim();
var amount = normalizeAmount(item && item.amount);
var meritTime = stringValue(item && item.meritTime);
var sortOrder = optionalSafeInteger(item && item.sortOrder);
var status = stringValue(item && item.status);
var record;
if (!meritId || !genealogyId || !donorName || !meritTitle || !Object.prototype.hasOwnProperty.call(meritTypes, meritType)) {
return null;
}
if (item.appUserId !== undefined && item.appUserId !== null && item.appUserId !== '' && !appUserId) return null;
if (item.amount !== undefined && item.amount !== null && item.amount !== '' && amount === '') return null;
if (meritTime && !isValidBackendDateTime(meritTime)) return null;
if (item.sortOrder !== undefined && item.sortOrder !== null && item.sortOrder !== '' && sortOrder === undefined) return null;
if (status !== '0' && status !== '1') return null;
record = {
meritId: meritId,
genealogyId: genealogyId,
genealogyNo: stringValue(item.genealogyNo),
genealogyName: stringValue(item.genealogyName),
surname: stringValue(item.surname),
appUserNickName: stringValue(item.appUserNickName),
appUserPhone: stringValue(item.appUserPhone),
donorName: donorName,
meritType: meritType,
meritTitle: meritTitle,
meritContent: stringValue(item.meritContent),
amount: amount,
meritTime: meritTime,
status: status,
remark: stringValue(item.remark)
};
if (appUserId) record.appUserId = appUserId;
if (sortOrder !== undefined) record.sortOrder = sortOrder;
return record;
}
function matchesSavedMerit(item, expectedMeritId) {
var record = normalizeMeritRecord(item);
return Boolean(record && record.meritId === normalizeId(expectedMeritId));
}
function isEditableMerit(record) {
return Boolean(record && record.status === '0');
}
function escapeHtml(value) {
return stringValue(value)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function buildListUrl(genealogyId, meritId) {
var url = 'profile-merit.html?genealogyId=' + encodeURIComponent(genealogyId);
return meritId ? url + '&meritId=' + encodeURIComponent(meritId) : url;
}
function buildEditUrl(genealogyId, meritId) {
var url = 'profile-merit-edit.html?genealogyId=' + encodeURIComponent(genealogyId);
return meritId ? url + '&meritId=' + encodeURIComponent(meritId) : url;
}
function renderMeritRow(record) {
var summary = [meritTypes[record.meritType]];
if (record.meritTime) summary.push(record.meritTime);
if (record.amount) summary.push('金额:' + record.amount);
return ' ' +
escapeHtml(record.donorName + ' · ' + summary.join(' · ')) + '' + escapeHtml(record.meritTitle) + '
' + escapeHtml(label) + '' + escapeHtml(value || '未提供') + '
'; } function renderMeritDetail(record) { if (!record) return '