(function (root, factory) { if (typeof module === 'object' && module.exports) { module.exports = factory(root); return; } root.CeremonyPages = factory(root); if (root.document) { root.document.addEventListener('DOMContentLoaded', function () { root.CeremonyPages.init(); }); } })(typeof globalThis !== 'undefined' ? globalThis : window, function (root) { 'use strict'; var documentRef = root.document; var invitationsById = Object.create(null); var selectedInvitationId = ''; var writePending = false; var invitationStatuses = ['PENDING', 'ACCEPTED', 'DECLINED', 'CANCELED']; var responseStatuses = ['ACCEPTED', 'DECLINED']; var statusLabels = { PENDING: '待响应', ACCEPTED: '已接受', DECLINED: '已拒绝', CANCELED: '已取消' }; function getApi() { return root.GenealogyApi && root.GenealogyApi.defaultClient; } function query(selector, rootNode) { return documentRef ? (rootNode || documentRef).querySelector(selector) : null; } 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(); root.NavigationUtil.open('login.html'); return true; } 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 stringValue(value) { return value === undefined || value === null ? '' : String(value); } function optionalInteger(value) { var number; if (value === undefined || value === null || value === '') return undefined; number = Number(value); return Number.isSafeInteger(number) ? number : undefined; } function optionalNumber(value) { var number; if (value === undefined || value === null || value === '') return undefined; number = Number(value); return Number.isFinite(number) ? number : undefined; } function normalizeInvitation(item) { var invitationId = normalizeId(item && item.invitationId); var genealogyId = normalizeId(item && item.genealogyId); var ceremonyId = normalizeId(item && item.ceremonyId); var inviteeUserId = normalizeId(item && item.inviteeUserId); var inviteStatus = stringValue(item && item.inviteStatus); var invitation; var inviteVersion; var longitude; var latitude; if (!invitationId || !genealogyId || !ceremonyId || invitationStatuses.indexOf(inviteStatus) < 0) { return null; } invitation = { invitationId: invitationId, genealogyId: genealogyId, ceremonyId: ceremonyId, inviteStatus: inviteStatus, deliveredTime: stringValue(item.deliveredTime), readTime: stringValue(item.readTime), responseTime: stringValue(item.responseTime), ceremonyTitle: stringValue(item.ceremonyTitle), ceremonyTime: stringValue(item.ceremonyTime), location: stringValue(item.location), locationAddress: stringValue(item.locationAddress) }; if (inviteeUserId) invitation.inviteeUserId = inviteeUserId; inviteVersion = optionalInteger(item.inviteVersion); longitude = optionalNumber(item.longitude); latitude = optionalNumber(item.latitude); if (inviteVersion !== undefined) invitation.inviteVersion = inviteVersion; if (longitude !== undefined) invitation.longitude = longitude; if (latitude !== undefined) invitation.latitude = latitude; return invitation; } function normalizeList(data) { return Array.isArray(data) ? data : []; } function buildInvitationResponseBody(values) { return { inviteStatus: stringValue(values && values.inviteStatus) }; } function validateInvitationResponseBody(body) { return !body || responseStatuses.indexOf(body.inviteStatus) < 0 ? '邀请只能选择接受或拒绝' : ''; } function canRespondToInvitation(invitation) { return Boolean(invitation && invitation.inviteStatus === 'PENDING'); } function escapeHtml(value) { return stringValue(value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function invitationTitle(invitation) { return invitation.ceremonyTitle || '未命名贺礼活动'; } function renderInvitationRow(invitation) { var actions = ''; if (canRespondToInvitation(invitation)) { actions += '' + ''; } return '

' + escapeHtml(invitationTitle(invitation)) + '

' + escapeHtml(statusLabels[invitation.inviteStatus]) + (invitation.ceremonyTime ? ' · ' + escapeHtml(invitation.ceremonyTime) : '') + (invitation.location ? ' · ' + escapeHtml(invitation.location) : '') + '

' + actions + '
'; } function renderDetailValue(label, value) { return '

' + escapeHtml(label) + '' + escapeHtml(value || '未提供') + '

'; } function renderInvitationDetail(invitation) { var mapLink = ''; if (!invitation) return ''; if (invitation.longitude !== undefined && invitation.latitude !== undefined) { mapLink = ' 打开地图'; } return '
' + renderDetailValue('活动标题', invitationTitle(invitation)) + renderDetailValue('邀请状态', statusLabels[invitation.inviteStatus]) + renderDetailValue('活动时间', invitation.ceremonyTime) + renderDetailValue('地点', invitation.location) + '

详细地址' + escapeHtml(invitation.locationAddress || '未提供') + mapLink + '

' + renderDetailValue('投递时间', invitation.deliveredTime) + renderDetailValue('阅读时间', invitation.readTime) + renderDetailValue('响应时间', invitation.responseTime) + '
'; } function renderDetail(invitation) { var container = query('[data-my-invitation-detail]'); selectedInvitationId = invitation ? invitation.invitationId : ''; if (!container) return; if (!invitation) { setInvitationState('[data-my-invitation-detail]', 'empty', '请选择一条邀请查看详情'); return; } container.innerHTML = renderInvitationDetail(invitation); } function renderInvitations(data) { var container = query('[data-my-invitation-list]'); var normalized = normalizeList(data).map(normalizeInvitation); var invalidCount = normalized.filter(function (item) { return !item; }).length; var invitations = normalized.filter(Boolean); invitationsById = Object.create(null); invitations.forEach(function (invitation) { invitationsById[invitation.invitationId] = invitation; }); if (!container) return invitations; if (invalidCount) { setInvitationState('[data-my-invitation-list]', 'error', '邀请响应缺少稳定 ID 或合法状态,请联系后端核对 DTO。'); setInvitationState('[data-my-invitation-detail]', 'error', '邀请详情暂不可用,请联系后端核对 DTO。'); return []; } if (!invitations.length) { setInvitationState('[data-my-invitation-list]', 'empty', '暂无贺礼邀请'); renderDetail(null); return []; } container.innerHTML = invitations.map(renderInvitationRow).join(''); renderDetail(invitationsById[selectedInvitationId] || invitations[0]); return invitations; } function setWritePending(pending) { var buttons; writePending = pending; if (!documentRef) return; buttons = documentRef.querySelectorAll('[data-invitation-response]'); Array.prototype.forEach.call(buttons, function (button) { button.disabled = pending; }); } function setInvitationState(selector, type, message) { var container = query(selector); if (!container) return; if (!message) { container.innerHTML = ''; return; } if (type && root.ProfileUI && root.ProfileUI.setApiState) { root.ProfileUI.setApiState(container, type, message); return; } container.textContent = message; } async function loadMyInvitations() { var api = getApi(); if (redirectUnauthorized(api)) return; setInvitationState('[data-my-invitation-list]', 'loading', '正在加载我的邀请…'); setInvitationState('[data-my-invitation-detail]', 'loading', '正在加载邀请详情…'); try { renderInvitations(await api.myCeremonyInvitations()); } catch (error) { if (redirectUnauthorized(api, error)) return; setInvitationState( '[data-my-invitation-list]', isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '当前账号无权查看邀请。' : (error.message || '邀请加载失败') ); setInvitationState( '[data-my-invitation-detail]', isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '当前账号无权查看邀请。' : '邀请详情加载失败,请稍后重试。' ); } } async function respondToInvitation(invitationId, inviteStatus) { var api = getApi(); var invitation = invitationsById[normalizeId(invitationId)]; var body = buildInvitationResponseBody({ inviteStatus: inviteStatus }); var validation = validateInvitationResponseBody(body); if (writePending || redirectUnauthorized(api) || !invitation || !canRespondToInvitation(invitation)) return; if (validation) return; setWritePending(true); setInvitationState('[data-my-invitation-status]', 'loading', '正在更新邀请状态…'); try { await api.respondCeremonyInvitation(invitation.genealogyId, invitation.ceremonyId, body); selectedInvitationId = invitation.invitationId; await loadMyInvitations(); setInvitationState('[data-my-invitation-status]', '', '邀请状态已更新。'); } catch (error) { if (redirectUnauthorized(api, error)) return; setInvitationState( '[data-my-invitation-status]', isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '当前账号无权响应该邀请。' : (error.message || '邀请响应失败') ); } finally { setWritePending(false); } } function bindActions() { if (!documentRef) return; documentRef.addEventListener('click', function (event) { var detailButton = event.target.closest('[data-invitation-detail]'); var responseButton = event.target.closest('[data-invitation-response]'); if (detailButton) { event.preventDefault(); renderDetail(invitationsById[detailButton.getAttribute('data-invitation-detail')] || null); return; } if (!responseButton) return; event.preventDefault(); respondToInvitation( responseButton.getAttribute('data-invitation-id'), responseButton.getAttribute('data-invitation-response') ); }); } function init() { if (!documentRef || !query('[data-ceremony-page]')) return; bindActions(); loadMyInvitations(); } return { normalizeInvitation: normalizeInvitation, normalizeList: normalizeList, buildInvitationResponseBody: buildInvitationResponseBody, validateInvitationResponseBody: validateInvitationResponseBody, canRespondToInvitation: canRespondToInvitation, renderInvitationRow: renderInvitationRow, renderInvitationDetail: renderInvitationDetail, shouldRedirectToLogin: shouldRedirectToLogin, isForbidden: isForbidden, loadMyInvitations: loadMyInvitations, init: init }; });