1067 lines
44 KiB
JavaScript
1067 lines
44 KiB
JavaScript
(function (root, factory) {
|
|
if (typeof module === 'object' && module.exports) {
|
|
module.exports = factory(root);
|
|
return;
|
|
}
|
|
|
|
root.CeremonyAdminPages = factory(root);
|
|
if (root.document) {
|
|
root.document.addEventListener('DOMContentLoaded', function () {
|
|
root.CeremonyAdminPages.init();
|
|
});
|
|
}
|
|
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
|
|
'use strict';
|
|
|
|
function confirmAction(message) {
|
|
if (root.ProfileUI && typeof root.ProfileUI.confirmAction === 'function') {
|
|
return root.ProfileUI.confirmAction(message);
|
|
}
|
|
return Promise.resolve(!root['confirm'] || root['confirm'](message));
|
|
}
|
|
|
|
var MediaDisplay = root.MediaDisplay || (typeof require === 'function' ? require('./media-display.js') : null);
|
|
|
|
var documentRef = root.document;
|
|
var ceremoniesById = Object.create(null);
|
|
var giftsById = Object.create(null);
|
|
var inviteeOptionsByUserId = Object.create(null);
|
|
var currentCeremony = null;
|
|
var canEditContent = false;
|
|
var writePending = false;
|
|
var invitationStatuses = ['PENDING', 'ACCEPTED', 'DECLINED', 'CANCELED'];
|
|
var invitationStatusLabels = {
|
|
PENDING: '待响应',
|
|
ACCEPTED: '已接受',
|
|
DECLINED: '已拒绝',
|
|
CANCELED: '已取消'
|
|
};
|
|
|
|
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 stringValue(value) {
|
|
return value === undefined || value === null ? '' : String(value);
|
|
}
|
|
|
|
function trimOrUndefined(value) {
|
|
var text = stringValue(value).trim();
|
|
|
|
return text || undefined;
|
|
}
|
|
|
|
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 normalizeNullableId(value) {
|
|
if (value === undefined || value === null || value === '') return '';
|
|
return normalizeId(value);
|
|
}
|
|
|
|
function queryParam(search, name) {
|
|
return new URLSearchParams(stringValue(search).replace(/^\?/, '')).get(name) || '';
|
|
}
|
|
|
|
function getCurrentGenealogyId(search) {
|
|
var source = search === undefined && root.location ? root.location.search : search;
|
|
var contextId;
|
|
|
|
if (search === undefined && root.ProfileUI && root.ProfileUI.getGenealogyId) {
|
|
contextId = root.ProfileUI.getGenealogyId();
|
|
if (contextId) return normalizeId(contextId);
|
|
}
|
|
return normalizeId(queryParam(source, 'genealogyId'));
|
|
}
|
|
|
|
function getCurrentCeremonyId(search) {
|
|
var source = search === undefined && root.location ? root.location.search : search;
|
|
|
|
return normalizeId(queryParam(source, 'ceremonyId'));
|
|
}
|
|
|
|
function optionalSafeInteger(value) {
|
|
var number;
|
|
|
|
if (value === undefined || value === null || value === '') return undefined;
|
|
number = Number(value);
|
|
return Number.isSafeInteger(number) ? number : undefined;
|
|
}
|
|
|
|
function optionalFiniteNumber(value) {
|
|
var number;
|
|
|
|
if (value === undefined || value === null || value === '') return undefined;
|
|
number = Number(value);
|
|
return Number.isFinite(number) ? number : undefined;
|
|
}
|
|
|
|
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 = stringValue(value);
|
|
|
|
if (!/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/.test(text)) return '';
|
|
return text.slice(0, 16).replace(' ', 'T');
|
|
}
|
|
|
|
function isValidBackendDateTime(value) {
|
|
var match = stringValue(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 buildCeremonyBody(values) {
|
|
var source = values || {};
|
|
var body = {
|
|
ceremonyType: stringValue(source.ceremonyType).trim(),
|
|
ceremonyTitle: stringValue(source.ceremonyTitle).trim(),
|
|
status: '0'
|
|
};
|
|
var optionalNames = ['ceremonyDesc', 'location', 'locationAddress'];
|
|
var ceremonyTime = toBackendDateTime(source.ceremonyTime);
|
|
var longitude = optionalFiniteNumber(source.longitude);
|
|
var latitude = optionalFiniteNumber(source.latitude);
|
|
var coverOssId = normalizeNullableId(source.coverOssId);
|
|
var sortOrder = optionalSafeInteger(source.sortOrder);
|
|
|
|
optionalNames.forEach(function (name) {
|
|
var value = trimOrUndefined(source[name]);
|
|
if (value !== undefined) body[name] = value;
|
|
});
|
|
if (ceremonyTime !== undefined) body.ceremonyTime = ceremonyTime;
|
|
if (source.longitude !== undefined && source.longitude !== null && source.longitude !== '') {
|
|
if (longitude !== undefined) body.longitude = longitude;
|
|
else body.invalidLongitude = true;
|
|
}
|
|
if (source.latitude !== undefined && source.latitude !== null && source.latitude !== '') {
|
|
if (latitude !== undefined) body.latitude = latitude;
|
|
else body.invalidLatitude = true;
|
|
}
|
|
if (source.coverOssId !== undefined && source.coverOssId !== null && source.coverOssId !== '') {
|
|
if (coverOssId) body.coverOssId = coverOssId;
|
|
else body.invalidCoverOssId = true;
|
|
}
|
|
if (source.sortOrder !== undefined && source.sortOrder !== null && source.sortOrder !== '') {
|
|
if (sortOrder !== undefined) body.sortOrder = sortOrder;
|
|
else body.invalidSortOrder = true;
|
|
}
|
|
return body;
|
|
}
|
|
|
|
function validateCeremonyBody(body) {
|
|
if (!body || !body.ceremonyType) return '请填写活动类型';
|
|
if (!body.ceremonyTitle) return '请填写活动标题';
|
|
if (body.ceremonyTime !== undefined && !isValidBackendDateTime(body.ceremonyTime)) return '活动时间格式无效';
|
|
if ((body.longitude === undefined) !== (body.latitude === undefined)) return '经度和纬度必须同时提供';
|
|
if (body.invalidLongitude) return '经度必须是有效数字';
|
|
if (body.invalidLatitude) return '纬度必须是有效数字';
|
|
if (body.longitude !== undefined && (body.longitude < -180 || body.longitude > 180)) return '经度范围必须是 -180 到 180';
|
|
if (body.latitude !== undefined && (body.latitude < -90 || body.latitude > 90)) return '纬度范围必须是 -90 到 90';
|
|
if (stringValue(body.locationAddress).length > 300) return '详细地址不能超过 300 个字符';
|
|
if (body.invalidCoverOssId) return '封面文件编号无效,请重新选择文件';
|
|
if (body.invalidSortOrder) return '排序值必须是安全整数';
|
|
if (body.status === '1') return '当前 PC 无法重新读取停用活动,暂不开放停用';
|
|
if (body.status !== '0') return '活动状态只能是 0';
|
|
return '';
|
|
}
|
|
|
|
function buildCeremonyGiftBody(values) {
|
|
var source = values || {};
|
|
var body = {};
|
|
var giverName = trimOrUndefined(source.giverName);
|
|
var giftMessage = trimOrUndefined(source.giftMessage);
|
|
var giftAmount = optionalFiniteNumber(source.giftAmount);
|
|
|
|
if (giverName !== undefined) body.giverName = giverName;
|
|
if (source.giftAmount !== undefined && source.giftAmount !== null && source.giftAmount !== '') {
|
|
if (giftAmount !== undefined) body.giftAmount = giftAmount;
|
|
else body.invalidGiftAmount = true;
|
|
}
|
|
if (giftMessage !== undefined) body.giftMessage = giftMessage;
|
|
return body;
|
|
}
|
|
|
|
function validateCeremonyGiftBody(body) {
|
|
if (!body || (body.giftAmount === undefined && !body.invalidGiftAmount)) return '请填写礼金金额';
|
|
if (body.invalidGiftAmount) return '礼金金额必须是有效数字';
|
|
if (body.giftAmount < 0) return '礼金金额不能小于 0';
|
|
return '';
|
|
}
|
|
|
|
function normalizeCeremony(item) {
|
|
var ceremonyId = normalizeId(item && item.ceremonyId);
|
|
var genealogyId = normalizeId(item && item.genealogyId);
|
|
var sponsorUserId = normalizeNullableId(item && item.sponsorUserId);
|
|
var coverFile = MediaDisplay && MediaDisplay.normalizeFileAccess(item && item.coverFile);
|
|
var ceremonyType = stringValue(item && item.ceremonyType).trim();
|
|
var ceremonyTitle = stringValue(item && item.ceremonyTitle).trim();
|
|
var longitude = optionalFiniteNumber(item && item.longitude);
|
|
var latitude = optionalFiniteNumber(item && item.latitude);
|
|
var giftCount = optionalSafeInteger(item && item.giftCount);
|
|
var giftAmount = optionalFiniteNumber(item && item.giftAmount);
|
|
var sortOrder = optionalSafeInteger(item && item.sortOrder);
|
|
var status = stringValue(item && item.status);
|
|
var ceremony;
|
|
|
|
if (!ceremonyId || !genealogyId || !ceremonyType || !ceremonyTitle) return null;
|
|
if (item.sponsorUserId !== undefined && item.sponsorUserId !== null && item.sponsorUserId !== '' && !sponsorUserId) return null;
|
|
if (item.coverFile !== undefined && item.coverFile !== null && !coverFile) return null;
|
|
if ((item.longitude !== undefined && item.longitude !== null && item.longitude !== '' && longitude === undefined) ||
|
|
(item.latitude !== undefined && item.latitude !== null && item.latitude !== '' && latitude === undefined)) return null;
|
|
if ((longitude === undefined) !== (latitude === undefined)) return null;
|
|
if (item.giftCount !== undefined && item.giftCount !== null && item.giftCount !== '' && giftCount === undefined) return null;
|
|
if (item.giftAmount !== undefined && item.giftAmount !== null && item.giftAmount !== '' && giftAmount === undefined) return null;
|
|
if (item.sortOrder !== undefined && item.sortOrder !== null && item.sortOrder !== '' && sortOrder === undefined) return null;
|
|
if (status !== '0' && status !== '1') return null;
|
|
ceremony = {
|
|
ceremonyId: ceremonyId,
|
|
genealogyId: genealogyId,
|
|
genealogyNo: stringValue(item.genealogyNo),
|
|
genealogyName: stringValue(item.genealogyName),
|
|
surname: stringValue(item.surname),
|
|
sponsorNickName: stringValue(item.sponsorNickName),
|
|
sponsorPhone: stringValue(item.sponsorPhone),
|
|
ceremonyType: ceremonyType,
|
|
ceremonyTitle: ceremonyTitle,
|
|
ceremonyDesc: stringValue(item.ceremonyDesc),
|
|
ceremonyTime: stringValue(item.ceremonyTime),
|
|
location: stringValue(item.location),
|
|
locationAddress: stringValue(item.locationAddress),
|
|
status: status,
|
|
remark: stringValue(item.remark)
|
|
};
|
|
if (sponsorUserId) ceremony.sponsorUserId = sponsorUserId;
|
|
if (coverFile) ceremony.coverFile = coverFile;
|
|
if (longitude !== undefined) ceremony.longitude = longitude;
|
|
if (latitude !== undefined) ceremony.latitude = latitude;
|
|
if (giftCount !== undefined) ceremony.giftCount = giftCount;
|
|
if (giftAmount !== undefined) ceremony.giftAmount = giftAmount;
|
|
if (sortOrder !== undefined) ceremony.sortOrder = sortOrder;
|
|
return ceremony;
|
|
}
|
|
|
|
function normalizeCeremonyGift(item) {
|
|
var giftId = normalizeId(item && item.giftId);
|
|
var genealogyId = normalizeId(item && item.genealogyId);
|
|
var ceremonyId = normalizeId(item && item.ceremonyId);
|
|
var giverUserId = normalizeNullableId(item && item.giverUserId);
|
|
var giftAmount = optionalFiniteNumber(item && item.giftAmount);
|
|
var status = stringValue(item && item.status);
|
|
var gift;
|
|
|
|
if (!giftId || !genealogyId || !ceremonyId || giftAmount === undefined || giftAmount < 0) return null;
|
|
if (item.giverUserId !== undefined && item.giverUserId !== null && item.giverUserId !== '' && !giverUserId) return null;
|
|
if (status !== '0' && status !== '1') return null;
|
|
gift = {
|
|
giftId: giftId,
|
|
genealogyId: genealogyId,
|
|
genealogyNo: stringValue(item.genealogyNo),
|
|
genealogyName: stringValue(item.genealogyName),
|
|
surname: stringValue(item.surname),
|
|
ceremonyId: ceremonyId,
|
|
ceremonyTitle: stringValue(item.ceremonyTitle),
|
|
giverNickName: stringValue(item.giverNickName),
|
|
giverPhone: stringValue(item.giverPhone),
|
|
giverName: stringValue(item.giverName),
|
|
giftAmount: giftAmount,
|
|
giftMessage: stringValue(item.giftMessage),
|
|
giftTime: stringValue(item.giftTime),
|
|
status: status,
|
|
remark: stringValue(item.remark)
|
|
};
|
|
if (giverUserId) gift.giverUserId = giverUserId;
|
|
return gift;
|
|
}
|
|
|
|
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 inviteVersion = optionalSafeInteger(item && item.inviteVersion);
|
|
var invitation;
|
|
|
|
if (!invitationId || !genealogyId || !ceremonyId || !inviteeUserId || invitationStatuses.indexOf(inviteStatus) < 0) return null;
|
|
if (item.inviteVersion !== undefined && item.inviteVersion !== null && item.inviteVersion !== '' && inviteVersion === undefined) return null;
|
|
invitation = {
|
|
invitationId: invitationId,
|
|
genealogyId: genealogyId,
|
|
ceremonyId: ceremonyId,
|
|
inviteeUserId: inviteeUserId,
|
|
inviteStatus: inviteStatus,
|
|
deliveredTime: stringValue(item.deliveredTime),
|
|
readTime: stringValue(item.readTime),
|
|
responseTime: stringValue(item.responseTime)
|
|
};
|
|
if (inviteVersion !== undefined) invitation.inviteVersion = inviteVersion;
|
|
return invitation;
|
|
}
|
|
|
|
function normalizeInviteeOption(item) {
|
|
var memberId = normalizeId(item && item.memberId);
|
|
var genealogyId = normalizeId(item && item.genealogyId);
|
|
var appUserId = normalizeNullableId(item && item.appUserId);
|
|
var status = stringValue(item && item.status);
|
|
|
|
if (!memberId || !genealogyId || !appUserId || status !== '0') return null;
|
|
return {
|
|
memberId: memberId,
|
|
genealogyId: genealogyId,
|
|
appUserId: appUserId,
|
|
appUserNickName: stringValue(item.appUserNickName),
|
|
memberName: stringValue(item.memberName),
|
|
roleType: stringValue(item.roleType),
|
|
status: status
|
|
};
|
|
}
|
|
|
|
function normalizeList(data, normalizer) {
|
|
var normalized;
|
|
|
|
if (!Array.isArray(data)) return [];
|
|
normalized = data.map(normalizer);
|
|
return normalized.some(function (item) { return !item; }) ? [] : normalized;
|
|
}
|
|
|
|
function buildInviteesBody(values) {
|
|
var seen = Object.create(null);
|
|
var ids = [];
|
|
|
|
(Array.isArray(values) ? values : []).forEach(function (value) {
|
|
var id = normalizeId(value);
|
|
if (id && !seen[id]) {
|
|
seen[id] = true;
|
|
ids.push(id);
|
|
}
|
|
});
|
|
return { inviteeUserIds: ids };
|
|
}
|
|
|
|
function escapeHtml(value) {
|
|
return stringValue(value)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
function detailValue(label, value) {
|
|
return '<p><span>' + escapeHtml(label) + '</span><b>' + escapeHtml(value === '' || value === undefined ? '未提供' : value) + '</b></p>';
|
|
}
|
|
|
|
function buildListUrl(genealogyId) {
|
|
return 'profile-ceremony.html?genealogyId=' + encodeURIComponent(genealogyId);
|
|
}
|
|
|
|
function buildEditUrl(genealogyId, ceremonyId) {
|
|
var url = 'profile-gift-edit.html?genealogyId=' + encodeURIComponent(genealogyId);
|
|
|
|
return ceremonyId ? url + '&ceremonyId=' + encodeURIComponent(ceremonyId) : url;
|
|
}
|
|
|
|
function buildDetailUrl(genealogyId, ceremonyId) {
|
|
return 'profile-ceremony-detail.html?genealogyId=' + encodeURIComponent(genealogyId) +
|
|
'&ceremonyId=' + encodeURIComponent(ceremonyId);
|
|
}
|
|
|
|
function renderCeremonyDetail(ceremony) {
|
|
var mapLink = '';
|
|
var actions = '';
|
|
|
|
if (!ceremony) return '';
|
|
if (ceremony.longitude !== undefined && ceremony.latitude !== undefined) {
|
|
mapLink = ' <a class="pill" target="_blank" rel="noopener noreferrer" href="https://uri.amap.com/marker?position=' +
|
|
encodeURIComponent(ceremony.longitude + ',' + ceremony.latitude) + '&name=' +
|
|
encodeURIComponent(ceremony.location || ceremony.locationAddress || ceremony.ceremonyTitle) + '">打开地图</a>';
|
|
}
|
|
if (canEditContent) {
|
|
actions = '<div class="bottom-actions"><a class="btn ghost" href="' +
|
|
escapeHtml(buildEditUrl(ceremony.genealogyId, ceremony.ceremonyId)) + '">编辑活动</a>' +
|
|
'<button class="btn danger" type="button" data-ceremony-delete-id="' +
|
|
escapeHtml(ceremony.ceremonyId) + '">删除活动</button></div>';
|
|
}
|
|
return (MediaDisplay ? MediaDisplay.renderImage(ceremony.coverFile, {
|
|
alt: ceremony.ceremonyTitle + '封面', className: 'ceremony-cover-media'
|
|
}) : '') + '<div class="form-like ceremony-detail">' +
|
|
detailValue('活动标题', ceremony.ceremonyTitle) +
|
|
detailValue('活动类型', ceremony.ceremonyType) +
|
|
detailValue('活动说明', ceremony.ceremonyDesc) +
|
|
detailValue('活动时间', ceremony.ceremonyTime) +
|
|
detailValue('地点', ceremony.location) +
|
|
'<p><span>详细地址</span><b>' + escapeHtml(ceremony.locationAddress || '未提供') + mapLink + '</b></p>' +
|
|
detailValue('发起人', ceremony.sponsorNickName) +
|
|
detailValue('祭品数量', ceremony.giftCount === undefined ? '' : ceremony.giftCount) +
|
|
detailValue('礼金合计', ceremony.giftAmount === undefined ? '' : ceremony.giftAmount) +
|
|
detailValue('备注', ceremony.remark) +
|
|
'</div>' + actions;
|
|
}
|
|
|
|
function renderCeremonyRow(ceremony) {
|
|
var actions = '<a class="pill" href="' + escapeHtml(buildDetailUrl(ceremony.genealogyId, ceremony.ceremonyId)) + '">查看详情</a>';
|
|
|
|
if (canEditContent) {
|
|
actions += '<a class="pill" href="' + escapeHtml(buildEditUrl(ceremony.genealogyId, ceremony.ceremonyId)) +
|
|
'">编辑</a><button class="pill is-danger" type="button" data-ceremony-delete-id="' +
|
|
escapeHtml(ceremony.ceremonyId) + '">删除</button>';
|
|
}
|
|
return '<article class="module-row ceremony-row"><div><h3>' + escapeHtml(ceremony.ceremonyTitle) +
|
|
'</h3><p>' + escapeHtml([ceremony.ceremonyType, ceremony.ceremonyTime, ceremony.location].filter(Boolean).join(' · ')) +
|
|
'</p></div><div class="row-actions">' + actions + '</div></article>';
|
|
}
|
|
|
|
function renderGiftList(data) {
|
|
var gifts = Array.isArray(data) ? data.map(normalizeCeremonyGift) : [];
|
|
|
|
if (gifts.some(function (gift) { return !gift; })) return '';
|
|
if (!gifts.length) return '';
|
|
return gifts.map(function (gift) {
|
|
var action = canEditContent
|
|
? '<button class="pill is-danger" type="button" data-ceremony-gift-delete-id="' +
|
|
escapeHtml(gift.giftId) + '">删除</button>'
|
|
: '';
|
|
return '<article class="module-row ceremony-gift-row"><div><h3>' +
|
|
escapeHtml(gift.giverName || gift.giverNickName || '匿名宗亲') + ' · ' +
|
|
escapeHtml(gift.giftAmount) + '</h3><p>' +
|
|
escapeHtml([gift.giftMessage, gift.giftTime].filter(Boolean).join(' · ') || '未提供留言') +
|
|
'</p></div><div class="row-actions">' + action + '</div></article>';
|
|
}).join('');
|
|
}
|
|
|
|
function renderInvitationList(data) {
|
|
var invitations = normalizeList(data, normalizeInvitation);
|
|
|
|
if (!Array.isArray(data) || (data.length && !invitations.length)) return '';
|
|
if (!invitations.length) return '';
|
|
return invitations.map(function (invitation) {
|
|
var option = inviteeOptionsByUserId[invitation.inviteeUserId];
|
|
var label = option && (option.memberName || option.appUserNickName) || '已邀请成员';
|
|
return '<article class="module-row ceremony-invitee-row"><div><h3>' + escapeHtml(label) +
|
|
'</h3><p>' + escapeHtml(invitationStatusLabels[invitation.inviteStatus]) +
|
|
(invitation.deliveredTime ? ' · ' + escapeHtml(invitation.deliveredTime) : '') +
|
|
'</p></div></article>';
|
|
}).join('');
|
|
}
|
|
|
|
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');
|
|
else root.location.href = 'login.html';
|
|
return true;
|
|
}
|
|
|
|
function showMessage(message) {
|
|
if (root.layui && root.layui.layer) root.layui.layer.msg(message);
|
|
else if (root.alert) root.alert(message);
|
|
}
|
|
|
|
function getApiStateType(error) {
|
|
return isForbidden(error) ? 'forbidden' : 'error';
|
|
}
|
|
|
|
function setStatus(selector, message, type) {
|
|
var target = query(selector);
|
|
|
|
if (!target) return;
|
|
if (!message) {
|
|
target.innerHTML = '';
|
|
return;
|
|
}
|
|
if (type && root.ProfileUI && root.ProfileUI.setApiState) {
|
|
root.ProfileUI.setApiState(target, type, message);
|
|
return;
|
|
}
|
|
target.textContent = message;
|
|
}
|
|
|
|
function syncLinks() {
|
|
if (root.ProfileUI && root.ProfileUI.syncGenealogyContextLinks) root.ProfileUI.syncGenealogyContextLinks();
|
|
}
|
|
|
|
function setWritePending(value) {
|
|
writePending = Boolean(value);
|
|
queryAll('[data-ceremony-form] input, [data-ceremony-form] textarea, [data-ceremony-form] button, [data-ceremony-gift-form] input, [data-ceremony-gift-form] textarea, [data-ceremony-gift-form] button, [data-ceremony-invitee-form] input, [data-ceremony-invitee-form] button, [data-ceremony-delete-id], [data-ceremony-gift-delete-id]').forEach(function (control) {
|
|
control.disabled = writePending;
|
|
});
|
|
}
|
|
|
|
function setEditorEnabled(enabled, message) {
|
|
var placeholder = query('[data-ceremony-editor-placeholder]');
|
|
|
|
queryAll('[data-ceremony-editor], [data-ceremony-editor-action], [data-ceremony-admin-editor]').forEach(function (element) {
|
|
element.hidden = !enabled;
|
|
});
|
|
if (placeholder) {
|
|
placeholder.hidden = Boolean(enabled);
|
|
if (message) placeholder.textContent = message;
|
|
}
|
|
}
|
|
|
|
function renderNoContext() {
|
|
var message = '请先选择家谱,再查看或维护祭祀活动。';
|
|
|
|
setStatus('[data-ceremony-list]', message, 'empty');
|
|
setStatus('[data-ceremony-detail]', '当前没有家谱上下文。', 'empty');
|
|
setStatus('[data-ceremony-gift-list]', '当前没有家谱上下文。', 'empty');
|
|
setStatus('[data-ceremony-invitation-list]', '当前没有家谱上下文。', 'empty');
|
|
setStatus('[data-ceremony-invitee-options]', '当前没有家谱上下文。', 'empty');
|
|
setEditorEnabled(false, message);
|
|
setStatus('[data-ceremony-form-status]', message, 'forbidden');
|
|
}
|
|
|
|
function requireGenealogyId() {
|
|
var genealogyId = getCurrentGenealogyId();
|
|
|
|
if (!genealogyId) renderNoContext();
|
|
return genealogyId;
|
|
}
|
|
|
|
function canEditCeremonies(genealogy) {
|
|
return Boolean(genealogy && (genealogy.canEditContent === true || genealogy.canManage === true));
|
|
}
|
|
|
|
async function loadCapability(api, genealogyId) {
|
|
var detail = await api.genealogyDetail(genealogyId);
|
|
|
|
canEditContent = canEditCeremonies(detail);
|
|
queryAll('[data-ceremony-create-link], [data-ceremony-editor-action], [data-ceremony-admin-editor]').forEach(function (element) {
|
|
element.hidden = !canEditContent;
|
|
});
|
|
return detail;
|
|
}
|
|
|
|
function renderCeremonies(data) {
|
|
var container = query('[data-ceremony-list]');
|
|
var ceremonies = normalizeList(data, normalizeCeremony);
|
|
|
|
ceremoniesById = Object.create(null);
|
|
ceremonies.forEach(function (ceremony) { ceremoniesById[ceremony.ceremonyId] = ceremony; });
|
|
if (!container) return ceremonies;
|
|
if (!Array.isArray(data) || (data.length && !ceremonies.length)) {
|
|
setStatus('[data-ceremony-list]', '活动响应缺少稳定 CeremonyVo 字段,请联系后端核对。', 'error');
|
|
return [];
|
|
}
|
|
if (!ceremonies.length) {
|
|
setStatus('[data-ceremony-list]', '暂无祭祀活动', 'empty');
|
|
return [];
|
|
}
|
|
container.innerHTML = ceremonies.map(renderCeremonyRow).join('');
|
|
return ceremonies;
|
|
}
|
|
|
|
async function loadCeremonies() {
|
|
var api = getApi();
|
|
var genealogyId;
|
|
|
|
if (redirectUnauthorized(api)) return;
|
|
genealogyId = requireGenealogyId();
|
|
if (!genealogyId) return;
|
|
syncLinks();
|
|
setStatus('[data-ceremony-list]', '正在加载祭祀活动…', 'loading');
|
|
try {
|
|
await loadCapability(api, genealogyId);
|
|
renderCeremonies(await api.ceremonies(genealogyId));
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
setStatus(
|
|
'[data-ceremony-list]',
|
|
isForbidden(error) ? '当前账号无权查看该家谱的祭祀活动。' : '活动加载失败,请稍后重试。',
|
|
getApiStateType(error)
|
|
);
|
|
showMessage(isForbidden(error) ? '当前账号无权查看该家谱的祭祀活动。' : (error.message || '活动加载失败'));
|
|
}
|
|
}
|
|
|
|
function getFormValues(form) {
|
|
var values = {};
|
|
|
|
queryAll('[name]', form).forEach(function (field) { values[field.name] = field.value; });
|
|
return values;
|
|
}
|
|
|
|
function setFieldValue(formSelector, name, value) {
|
|
var field = query(formSelector + ' [name="' + name + '"]');
|
|
|
|
if (field) field.value = value === undefined || value === null ? '' : String(value);
|
|
}
|
|
|
|
function fillCeremonyForm(ceremony) {
|
|
var contentField;
|
|
var contentEditor;
|
|
|
|
if (!ceremony || ceremony.status !== '0') throw new Error('停用活动无法通过当前 PC 接口重新读取或编辑');
|
|
['ceremonyType', 'ceremonyTitle', 'ceremonyDesc', 'location', 'locationAddress', 'longitude', 'latitude', 'coverOssId', 'sortOrder'].forEach(function (name) {
|
|
setFieldValue('[data-ceremony-form]', name, ceremony[name]);
|
|
});
|
|
setFieldValue('[data-ceremony-form]', 'ceremonyTime', toDateTimeInputValue(ceremony.ceremonyTime));
|
|
setFieldValue('[data-ceremony-form]', 'status', '0');
|
|
contentField = query('[data-ceremony-form] [name="ceremonyDesc"]');
|
|
if (contentField && root.AppRichEditor && root.AppRichEditor.init) {
|
|
contentEditor = root.AppRichEditor.init(contentField);
|
|
if (contentEditor && contentEditor.editor && contentEditor.editor.setHtml) {
|
|
contentEditor.editor.setHtml(ceremony.ceremonyDesc || '');
|
|
contentEditor.sync();
|
|
}
|
|
}
|
|
}
|
|
|
|
async function loadCeremonyEditor() {
|
|
var api = getApi();
|
|
var genealogyId;
|
|
var ceremonyId;
|
|
var ceremony;
|
|
|
|
if (redirectUnauthorized(api)) return;
|
|
genealogyId = requireGenealogyId();
|
|
if (!genealogyId) return;
|
|
ceremonyId = getCurrentCeremonyId();
|
|
syncLinks();
|
|
setEditorEnabled(false, '正在加载活动编辑信息…');
|
|
setStatus('[data-ceremony-form-status]', '正在读取家谱权限…', 'loading');
|
|
try {
|
|
await loadCapability(api, genealogyId);
|
|
if (!canEditContent) throw { status: 403, message: '当前账号无权维护该家谱的祭祀活动。' };
|
|
if (ceremonyId) {
|
|
ceremony = normalizeCeremony(await api.ceremonyDetail(genealogyId, ceremonyId));
|
|
if (!ceremony || ceremony.ceremonyId !== ceremonyId) throw new Error('活动详情响应缺少稳定 ceremonyId');
|
|
fillCeremonyForm(ceremony);
|
|
if (query('[data-ceremony-editor-title]')) query('[data-ceremony-editor-title]').textContent = '编辑祭祀活动';
|
|
}
|
|
setEditorEnabled(true);
|
|
setStatus('[data-ceremony-form-status]', '');
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
setEditorEnabled(false, isForbidden(error) ? '当前账号无权维护该家谱的祭祀活动。' : (error.message || '活动编辑信息加载失败'));
|
|
setStatus(
|
|
'[data-ceremony-form-status]',
|
|
isForbidden(error) ? '当前账号无权维护该家谱的祭祀活动。' : (error.message || '活动编辑信息加载失败'),
|
|
getApiStateType(error)
|
|
);
|
|
}
|
|
}
|
|
|
|
async function loadGifts(api, genealogyId, ceremonyId) {
|
|
var data;
|
|
var gifts;
|
|
var container = query('[data-ceremony-gift-list]');
|
|
|
|
setStatus('[data-ceremony-gift-list]', '正在加载祭品…', 'loading');
|
|
data = await api.ceremonyGifts(genealogyId, ceremonyId);
|
|
gifts = normalizeList(data, normalizeCeremonyGift);
|
|
giftsById = Object.create(null);
|
|
gifts.forEach(function (gift) { giftsById[gift.giftId] = gift; });
|
|
if (!container) return gifts;
|
|
if (!Array.isArray(data) || (data.length && !gifts.length)) {
|
|
setStatus('[data-ceremony-gift-list]', '祭品响应缺少稳定 CeremonyGiftVo 字段,请联系后端核对。', 'error');
|
|
return [];
|
|
}
|
|
if (!gifts.length) {
|
|
setStatus('[data-ceremony-gift-list]', '暂无祭品记录', 'empty');
|
|
return [];
|
|
}
|
|
container.innerHTML = renderGiftList(gifts);
|
|
return gifts;
|
|
}
|
|
|
|
function renderInviteeOptions(options, invitations) {
|
|
var container = query('[data-ceremony-invitee-options]');
|
|
var selected = Object.create(null);
|
|
|
|
invitations.forEach(function (invitation) {
|
|
if (invitation.inviteStatus !== 'CANCELED') selected[invitation.inviteeUserId] = true;
|
|
});
|
|
if (!container) return;
|
|
if (!options.length) {
|
|
setStatus('[data-ceremony-invitee-options]', '暂无已绑定账号的正常成员', 'empty');
|
|
return;
|
|
}
|
|
container.innerHTML = options.map(function (option) {
|
|
var label = option.memberName || option.appUserNickName || '家谱成员';
|
|
return '<label class="editor-choice"><input type="checkbox" data-invitee-user-id="' +
|
|
escapeHtml(option.appUserId) + '"' + (selected[option.appUserId] ? ' checked' : '') +
|
|
' /> <span>' + escapeHtml(label) + '</span></label>';
|
|
}).join('');
|
|
}
|
|
|
|
async function loadInvitees(api, genealogyId, ceremonyId) {
|
|
var results;
|
|
var options;
|
|
var invitations;
|
|
var list = query('[data-ceremony-invitation-list]');
|
|
|
|
setStatus('[data-ceremony-invitation-list]', '正在加载邀请记录…', 'loading');
|
|
setStatus('[data-ceremony-invitee-options]', '正在加载成员选项…', 'loading');
|
|
results = await Promise.all([
|
|
api.genealogyMemberOptions(genealogyId),
|
|
api.ceremonyInvitations(genealogyId, ceremonyId)
|
|
]);
|
|
options = normalizeList(results[0], normalizeInviteeOption);
|
|
invitations = normalizeList(results[1], normalizeInvitation);
|
|
|
|
inviteeOptionsByUserId = Object.create(null);
|
|
options.forEach(function (option) { inviteeOptionsByUserId[option.appUserId] = option; });
|
|
if (!Array.isArray(results[0]) || (results[0].length && !options.length)) {
|
|
setStatus('[data-ceremony-invitee-options]', '成员选项响应字段不完整', 'error');
|
|
} else {
|
|
renderInviteeOptions(options, invitations);
|
|
}
|
|
if (!list) return { options: options, invitations: invitations };
|
|
if (!Array.isArray(results[1]) || (results[1].length && !invitations.length)) {
|
|
setStatus('[data-ceremony-invitation-list]', '邀请响应字段不完整', 'error');
|
|
} else if (!invitations.length) {
|
|
setStatus('[data-ceremony-invitation-list]', '暂无邀请记录', 'empty');
|
|
} else {
|
|
list.innerHTML = renderInvitationList(results[1]);
|
|
}
|
|
return { options: options, invitations: invitations };
|
|
}
|
|
|
|
async function loadCeremonyDetailPage() {
|
|
var api = getApi();
|
|
var genealogyId;
|
|
var ceremonyId;
|
|
|
|
if (redirectUnauthorized(api)) return;
|
|
genealogyId = requireGenealogyId();
|
|
ceremonyId = getCurrentCeremonyId();
|
|
if (!genealogyId || !ceremonyId) {
|
|
if (genealogyId) {
|
|
setStatus('[data-ceremony-detail]', '缺少有效活动编号。', 'error');
|
|
setStatus('[data-ceremony-gift-list]', '缺少有效活动编号。', 'empty');
|
|
setStatus('[data-ceremony-invitation-list]', '缺少有效活动编号。', 'empty');
|
|
setStatus('[data-ceremony-invitee-options]', '缺少有效活动编号。', 'empty');
|
|
}
|
|
return;
|
|
}
|
|
syncLinks();
|
|
setStatus('[data-ceremony-detail]', '正在加载活动详情…', 'loading');
|
|
setStatus('[data-ceremony-gift-list]', '正在加载祭品…', 'loading');
|
|
try {
|
|
await loadCapability(api, genealogyId);
|
|
currentCeremony = normalizeCeremony(await api.ceremonyDetail(genealogyId, ceremonyId));
|
|
if (!currentCeremony || currentCeremony.ceremonyId !== ceremonyId) throw new Error('活动详情响应缺少稳定 ceremonyId');
|
|
if (query('[data-ceremony-detail]')) query('[data-ceremony-detail]').innerHTML = renderCeremonyDetail(currentCeremony);
|
|
if (query('[data-ceremony-detail-title]')) query('[data-ceremony-detail-title]').textContent = currentCeremony.ceremonyTitle;
|
|
if (query('[data-ceremony-editor-action]')) query('[data-ceremony-editor-action]').href = buildEditUrl(genealogyId, ceremonyId);
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
setStatus(
|
|
'[data-ceremony-detail]',
|
|
isForbidden(error) ? '当前账号无权查看该活动。' : (error.message || '活动详情加载失败'),
|
|
getApiStateType(error)
|
|
);
|
|
setStatus(
|
|
'[data-ceremony-gift-list]',
|
|
isForbidden(error) ? '当前账号无权查看该活动。' : '祭品加载失败,请稍后重试。',
|
|
getApiStateType(error)
|
|
);
|
|
setStatus(
|
|
'[data-ceremony-invitation-list]',
|
|
isForbidden(error) ? '当前账号无权查看该活动。' : '邀请记录加载失败,请稍后重试。',
|
|
getApiStateType(error)
|
|
);
|
|
setStatus(
|
|
'[data-ceremony-invitee-options]',
|
|
isForbidden(error) ? '当前账号无权查看该活动。' : '成员选项加载失败,请稍后重试。',
|
|
getApiStateType(error)
|
|
);
|
|
showMessage(isForbidden(error) ? '当前账号无权查看该活动。' : (error.message || '活动详情加载失败'));
|
|
return;
|
|
}
|
|
try {
|
|
await loadGifts(api, genealogyId, ceremonyId);
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
setStatus(
|
|
'[data-ceremony-gift-list]',
|
|
isForbidden(error) ? '当前账号无权查看该活动祭品。' : (error.message || '祭品加载失败'),
|
|
getApiStateType(error)
|
|
);
|
|
showMessage(isForbidden(error) ? '当前账号无权查看该活动祭品。' : (error.message || '祭品加载失败'));
|
|
}
|
|
if (!canEditContent) {
|
|
setStatus('[data-ceremony-invitation-list]', '当前账号无权查看或维护受邀名单。', 'forbidden');
|
|
setStatus('[data-ceremony-invitee-options]', '当前账号无权查看或维护受邀名单。', 'forbidden');
|
|
return;
|
|
}
|
|
try {
|
|
await loadInvitees(api, genealogyId, ceremonyId);
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
setStatus(
|
|
'[data-ceremony-invitation-list]',
|
|
isForbidden(error) ? '当前账号无权查看或维护受邀名单。' : (error.message || '邀请记录加载失败'),
|
|
getApiStateType(error)
|
|
);
|
|
setStatus(
|
|
'[data-ceremony-invitee-options]',
|
|
isForbidden(error) ? '当前账号无权查看或维护受邀名单。' : '成员选项加载失败,请稍后重试。',
|
|
getApiStateType(error)
|
|
);
|
|
showMessage(isForbidden(error) ? '当前账号无权查看或维护受邀名单。' : (error.message || '邀请记录加载失败'));
|
|
}
|
|
}
|
|
|
|
async function submitCeremony(form) {
|
|
var api = getApi();
|
|
var genealogyId = requireGenealogyId();
|
|
var ceremonyId = getCurrentCeremonyId();
|
|
var body;
|
|
var validation;
|
|
var saved;
|
|
var savedId;
|
|
var verified;
|
|
|
|
if (writePending || !canEditContent || !genealogyId || redirectUnauthorized(api)) return;
|
|
if (root.AppRichEditor && root.AppRichEditor.syncAll) root.AppRichEditor.syncAll();
|
|
body = buildCeremonyBody(getFormValues(form));
|
|
validation = validateCeremonyBody(body);
|
|
if (validation) {
|
|
setStatus('[data-ceremony-form-status]', validation, 'error');
|
|
return;
|
|
}
|
|
delete body.invalidLongitude;
|
|
delete body.invalidLatitude;
|
|
delete body.invalidCoverOssId;
|
|
delete body.invalidSortOrder;
|
|
setWritePending(true);
|
|
setStatus('[data-ceremony-form-status]', '正在保存活动…', 'loading');
|
|
try {
|
|
saved = normalizeCeremony(ceremonyId
|
|
? await api.updateCeremony(genealogyId, ceremonyId, body)
|
|
: await api.createCeremony(genealogyId, body));
|
|
savedId = ceremonyId || (saved && saved.ceremonyId);
|
|
if (!savedId) throw new Error('保存响应缺少 ceremonyId');
|
|
verified = normalizeCeremony(await api.ceremonyDetail(genealogyId, savedId));
|
|
if (!verified || verified.ceremonyId !== savedId) throw new Error('保存后未能重读同一活动');
|
|
if (root.location) root.location.href = buildDetailUrl(genealogyId, savedId);
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
setStatus(
|
|
'[data-ceremony-form-status]',
|
|
isForbidden(error) ? '当前账号无权保存该活动。' : (error.message || '活动保存失败'),
|
|
getApiStateType(error)
|
|
);
|
|
} finally {
|
|
setWritePending(false);
|
|
}
|
|
}
|
|
|
|
async function submitGift(form) {
|
|
var api = getApi();
|
|
var genealogyId = requireGenealogyId();
|
|
var ceremonyId = getCurrentCeremonyId();
|
|
var body;
|
|
var validation;
|
|
var saved;
|
|
|
|
if (writePending || !canEditContent || !genealogyId || !ceremonyId || redirectUnauthorized(api)) return;
|
|
body = buildCeremonyGiftBody(getFormValues(form));
|
|
validation = validateCeremonyGiftBody(body);
|
|
if (validation) {
|
|
setStatus('[data-ceremony-gift-status]', validation, 'error');
|
|
return;
|
|
}
|
|
delete body.invalidGiftAmount;
|
|
setWritePending(true);
|
|
setStatus('[data-ceremony-gift-status]', '正在添加祭品…', 'loading');
|
|
try {
|
|
saved = normalizeCeremonyGift(await api.createCeremonyGift(genealogyId, ceremonyId, body));
|
|
if (!saved || saved.ceremonyId !== ceremonyId) throw new Error('添加祭品响应缺少稳定 giftId');
|
|
if (!(await loadGifts(api, genealogyId, ceremonyId)).some(function (gift) { return gift.giftId === saved.giftId; })) {
|
|
throw new Error('添加后祭品列表未返回同一记录');
|
|
}
|
|
form.reset();
|
|
setStatus('[data-ceremony-gift-status]', '祭品已添加');
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
setStatus(
|
|
'[data-ceremony-gift-status]',
|
|
isForbidden(error) ? '当前账号无权添加祭品。' : (error.message || '祭品添加失败'),
|
|
getApiStateType(error)
|
|
);
|
|
} finally {
|
|
setWritePending(false);
|
|
}
|
|
}
|
|
|
|
async function submitInvitees() {
|
|
var api = getApi();
|
|
var genealogyId = requireGenealogyId();
|
|
var ceremonyId = getCurrentCeremonyId();
|
|
var availableInviteeInputs;
|
|
var body;
|
|
|
|
if (writePending || !canEditContent || !genealogyId || !ceremonyId || redirectUnauthorized(api)) return;
|
|
availableInviteeInputs = queryAll('[data-invitee-user-id]');
|
|
if (!availableInviteeInputs.length) {
|
|
setStatus('[data-ceremony-invitee-status]', '当前没有可邀请的家谱成员', 'empty');
|
|
return;
|
|
}
|
|
body = buildInviteesBody(availableInviteeInputs.filter(function (input) {
|
|
return input.checked;
|
|
}).map(function (input) {
|
|
return input.getAttribute('data-invitee-user-id');
|
|
}));
|
|
setWritePending(true);
|
|
setStatus('[data-ceremony-invitee-status]', '正在更新受邀人…', 'loading');
|
|
try {
|
|
await api.replaceCeremonyInvitees(genealogyId, ceremonyId, body.inviteeUserIds);
|
|
await loadInvitees(api, genealogyId, ceremonyId);
|
|
setStatus('[data-ceremony-invitee-status]', '受邀名单已更新');
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
setStatus(
|
|
'[data-ceremony-invitee-status]',
|
|
isForbidden(error) ? '当前账号无权维护受邀名单。' : (error.message || '受邀名单更新失败'),
|
|
getApiStateType(error)
|
|
);
|
|
} finally {
|
|
setWritePending(false);
|
|
}
|
|
}
|
|
|
|
async function deleteCeremony(ceremonyId) {
|
|
var api = getApi();
|
|
var genealogyId = requireGenealogyId();
|
|
var ceremony = ceremoniesById[ceremonyId] || currentCeremony;
|
|
|
|
if (writePending || !canEditContent || !genealogyId || !normalizeId(ceremonyId) || redirectUnauthorized(api)) return;
|
|
if (!await confirmAction('确认删除“' + (ceremony ? ceremony.ceremonyTitle : '该活动') + '”吗?删除后不可恢复。')) return;
|
|
setWritePending(true);
|
|
try {
|
|
await api.deleteCeremony(genealogyId, ceremonyId);
|
|
if (query('[data-ceremony-list-page]')) await loadCeremonies();
|
|
else if (root.location) root.location.href = buildListUrl(genealogyId);
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
showMessage(isForbidden(error) ? '当前账号无权删除该活动。' : (error.message || '活动删除失败'));
|
|
} finally {
|
|
setWritePending(false);
|
|
}
|
|
}
|
|
|
|
async function deleteGift(giftId) {
|
|
var api = getApi();
|
|
var genealogyId = requireGenealogyId();
|
|
var ceremonyId = getCurrentCeremonyId();
|
|
var gift = giftsById[giftId];
|
|
|
|
if (writePending || !canEditContent || !genealogyId || !ceremonyId || !normalizeId(giftId) || redirectUnauthorized(api)) return;
|
|
if (!await confirmAction('确认删除“' + (gift && (gift.giverName || gift.giverNickName) || '该祭品') + '”的记录吗?')) return;
|
|
setWritePending(true);
|
|
try {
|
|
await api.deleteCeremonyGift(genealogyId, ceremonyId, giftId);
|
|
await loadGifts(api, genealogyId, ceremonyId);
|
|
showMessage('祭品记录已删除');
|
|
} catch (error) {
|
|
if (redirectUnauthorized(api, error)) return;
|
|
showMessage(isForbidden(error) ? '当前账号无权删除该祭品。' : (error.message || '祭品删除失败'));
|
|
} finally {
|
|
setWritePending(false);
|
|
}
|
|
}
|
|
|
|
function bindActions() {
|
|
if (!documentRef) return;
|
|
documentRef.addEventListener('click', function (event) {
|
|
var ceremonyDelete = event.target.closest('[data-ceremony-delete-id]');
|
|
var giftDelete = event.target.closest('[data-ceremony-gift-delete-id]');
|
|
|
|
if (ceremonyDelete) {
|
|
event.preventDefault();
|
|
deleteCeremony(ceremonyDelete.getAttribute('data-ceremony-delete-id'));
|
|
} else if (giftDelete) {
|
|
event.preventDefault();
|
|
deleteGift(giftDelete.getAttribute('data-ceremony-gift-delete-id'));
|
|
}
|
|
});
|
|
documentRef.addEventListener('submit', function (event) {
|
|
var ceremonyForm = event.target.closest('[data-ceremony-form]');
|
|
var giftForm = event.target.closest('[data-ceremony-gift-form]');
|
|
var inviteeForm = event.target.closest('[data-ceremony-invitee-form]');
|
|
|
|
if (ceremonyForm) {
|
|
event.preventDefault();
|
|
submitCeremony(ceremonyForm);
|
|
} else if (giftForm) {
|
|
event.preventDefault();
|
|
submitGift(giftForm);
|
|
} else if (inviteeForm) {
|
|
event.preventDefault();
|
|
submitInvitees();
|
|
}
|
|
});
|
|
}
|
|
|
|
function init() {
|
|
if (!documentRef) return;
|
|
bindActions();
|
|
if (query('[data-ceremony-list-page]')) loadCeremonies();
|
|
if (query('[data-ceremony-edit-page]')) loadCeremonyEditor();
|
|
if (query('[data-ceremony-detail-page]')) loadCeremonyDetailPage();
|
|
}
|
|
|
|
return {
|
|
getCurrentGenealogyId: getCurrentGenealogyId,
|
|
getCurrentCeremonyId: getCurrentCeremonyId,
|
|
buildCeremonyBody: buildCeremonyBody,
|
|
validateCeremonyBody: validateCeremonyBody,
|
|
buildCeremonyGiftBody: buildCeremonyGiftBody,
|
|
validateCeremonyGiftBody: validateCeremonyGiftBody,
|
|
normalizeCeremony: normalizeCeremony,
|
|
normalizeCeremonyGift: normalizeCeremonyGift,
|
|
normalizeInvitation: normalizeInvitation,
|
|
normalizeInviteeOption: normalizeInviteeOption,
|
|
buildInviteesBody: buildInviteesBody,
|
|
canEditCeremonies: canEditCeremonies,
|
|
renderCeremonyDetail: renderCeremonyDetail,
|
|
renderGiftList: renderGiftList,
|
|
shouldRedirectToLogin: shouldRedirectToLogin,
|
|
isForbidden: isForbidden,
|
|
init: init
|
|
};
|
|
});
|