等待后端更新接口

This commit is contained in:
2026-08-03 16:49:26 +08:00
parent ac5823547a
commit 5b79893650
131 changed files with 5324 additions and 1392 deletions
+126 -41
View File
@@ -63,6 +63,33 @@
if (root.alert) root.alert(message);
}
function setGenerationState(selector, type, message) {
var target = query(selector);
if (!target) return;
if (root.ProfileUI && root.ProfileUI.setApiState) {
root.ProfileUI.setApiState(target, type, message);
return;
}
target.innerHTML = '<div class="api-state api-state--' + escapeHtml(type) + '" data-api-state="' + escapeHtml(type) + '">' +
escapeHtml(message) + '</div>';
}
function setGenerationFormStatus(message, type) {
var target = query('[data-generation-form-status]');
if (!target) return;
if (!message) {
target.innerHTML = '';
return;
}
if (root.ProfileUI && root.ProfileUI.setApiState) {
root.ProfileUI.setApiState(target, type || 'error', message);
return;
}
target.textContent = message;
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
@@ -196,8 +223,12 @@
return poem;
}
function canEditGenerations(genealogy) {
return Boolean(genealogy && (genealogy.canEditContent === true || genealogy.canManage === true));
}
function normalizeGenerationAccess(genealogy) {
var canEditContent = Boolean(genealogy && genealogy.canEditContent === true);
var canEditContent = canEditGenerations(genealogy);
return {
canEditContent: canEditContent,
@@ -251,11 +282,11 @@
});
if (!container) return;
if (invalidCount) {
container.innerHTML = '<div class="api-empty">字辈响应缺少 poemId、generationNo、generationText 或 status,请联系后端补充 DTO。</div>';
setGenerationState('[data-generation-list]', 'error', '字辈响应缺少 poemId、generationNo、generationText 或 status,请联系后端补充 DTO。');
return;
}
if (!poems.length) {
container.innerHTML = '<div class="api-empty">暂无字辈记录</div>';
setGenerationState('[data-generation-list]', 'empty', '暂无字辈记录');
return;
}
container.innerHTML = poems.map(renderGenerationPoem).join('');
@@ -335,7 +366,7 @@
if (!container) return false;
if (!preview) {
container.innerHTML = '<div class="api-empty">批量预览响应缺少 items,请联系后端补充 DTO。</div>';
setGenerationState('[data-generation-batch-preview]', 'error', '批量预览响应缺少 items,请联系后端补充 DTO。');
return false;
}
summary = '新增 ' + (preview.createCount === undefined ? '-' : preview.createCount) +
@@ -386,18 +417,35 @@
if (target) target.textContent = message || '';
}
function setGenerationEditorVisible(visible) {
var editor = query('[data-generation-editor]');
if (editor) editor.hidden = !visible;
}
function setGenerationSubmitPending(pending) {
queryAll('[data-generation-editor-submit]').forEach(function (button) {
if (!button.dataset.defaultLabel) button.dataset.defaultLabel = button.textContent;
button.disabled = Boolean(pending) || !managementAccess;
button.textContent = pending ? '正在保存…' : button.dataset.defaultLabel;
button.setAttribute('aria-busy', pending ? 'true' : 'false');
});
}
function refreshManagementControls() {
var disabled = !managementAccess || writePending;
queryAll('[data-generation-management]').forEach(function (element) {
element.hidden = !managementAccess;
});
if (!managementAccess) setGenerationEditorVisible(false);
queryAll('[data-generation-add], [data-generation-batch-action], [data-generation-edit], [data-generation-status]').forEach(function (control) {
control.disabled = disabled;
});
queryAll('[data-generation-management] textarea, [data-generation-management] input').forEach(function (control) {
queryAll('[data-generation-management] textarea, [data-generation-management] input, [data-generation-editor] textarea, [data-generation-editor] input, [data-generation-editor] select, [data-generation-editor] button').forEach(function (control) {
control.disabled = disabled;
});
setGenerationSubmitPending(writePending);
}
function setManagementEnabled(enabled) {
@@ -411,12 +459,11 @@
}
function renderForbiddenState() {
var container = query('[data-generation-list]');
if (container) container.innerHTML = '<div class="api-empty">当前账号没有字辈维护权限</div>';
setGenerationState('[data-generation-list]', 'forbidden', '当前账号没有字辈维护权限');
lastPreviewSignature = '';
setManagementEnabled(false);
setBatchStatus('当前账号没有字辈维护权限');
setGenerationFormStatus('当前账号没有字辈维护权限', 'forbidden');
}
function syncGenealogyLinks(genealogyId) {
@@ -440,34 +487,47 @@
if (!genealogyId) {
container = query('[data-generation-list]');
if (container) container.innerHTML = '<div class="api-empty">请从具体家谱进入字辈管理</div>';
if (container) setGenerationState('[data-generation-list]', 'error', '请从具体家谱进入字辈管理');
setGenerationEditorVisible(false);
setGenerationFormStatus('请从具体家谱进入字辈管理', 'error');
showMessage('请从具体家谱进入字辈管理');
}
return genealogyId;
}
function promptForPoem(existing) {
var generationNo;
var generationText;
var description;
var sortOrder;
function openPoemEditor(poemId) {
var form = query('[data-generation-form]');
var existing = poemId ? poemsById[poemId] : null;
var title = query('[data-generation-editor-title]');
if (!root.prompt) return null;
generationNo = root.prompt('世代序号(从 1 开始)', existing ? String(existing.generationNo) : '');
if (generationNo === null) return null;
generationText = root.prompt('字辈文字(最多 50 个字符)', existing ? existing.generationText : '');
if (generationText === null) return null;
description = root.prompt('说明(最多 500 个字符,可留空)', existing && existing.description ? existing.description : '');
if (description === null) return null;
sortOrder = root.prompt('排序值(可留空,越小越靠前)', existing && existing.sortOrder !== undefined ? String(existing.sortOrder) : '');
if (sortOrder === null) return null;
return buildGenerationPoemBody({
generationNo: generationNo,
generationText: generationText,
description: description,
sortOrder: sortOrder,
status: existing && existing.status
if (!managementAccess || writePending || !form || (poemId && !existing)) return;
form.reset();
queryAll('[name]', form).forEach(function (field) {
var value;
if (field.name === 'poemId') value = poemId || '';
if (field.name === 'generationNo') value = existing ? existing.generationNo : '';
if (field.name === 'generationText') value = existing ? existing.generationText : '';
if (field.name === 'description') value = existing && existing.description ? existing.description : '';
if (field.name === 'sortOrder') value = existing && existing.sortOrder !== undefined ? existing.sortOrder : '';
if (field.name === 'status') value = existing ? existing.status : '';
if (value !== undefined) field.value = value;
});
if (title) title.textContent = existing ? '编辑字辈' : '新增字辈';
setGenerationFormStatus('');
setGenerationEditorVisible(true);
if (root.location && root.location.hash !== '#generation-editor') root.location.hash = 'generation-editor';
if (query('[name="generationNo"]', form) && query('[name="generationNo"]', form).focus) {
query('[name="generationNo"]', form).focus();
}
}
function closePoemEditor() {
var form = query('[data-generation-form]');
if (form) form.reset();
setGenerationFormStatus('');
setGenerationEditorVisible(false);
}
async function loadGenerationPoems() {
@@ -479,6 +539,7 @@
genealogyId = requireGenealogyId();
if (!genealogyId) return;
syncGenealogyLinks(genealogyId);
setGenerationState('[data-generation-list]', 'loading', '正在加载字辈记录…');
try {
access = normalizeGenerationAccess(await api.genealogyDetail(genealogyId));
setManagementEnabled(access.canEditContent);
@@ -489,27 +550,37 @@
renderForbiddenState();
return;
}
setGenerationState('[data-generation-list]', 'error', '字辈列表加载失败,请稍后重试。');
showMessage(error.message || '字辈列表加载失败');
}
}
async function savePoem(poemId) {
async function submitPoem(form) {
var api = getApi();
var genealogyId;
var existing = poemId ? poemsById[poemId] : null;
var poemId;
var body;
var validation;
if (writePending || !managementAccess || redirectUnauthorized(api)) return;
if (writePending || !managementAccess || redirectUnauthorized(api) || !form) return;
genealogyId = requireGenealogyId();
if (!genealogyId || (poemId && !existing)) return;
body = promptForPoem(existing);
if (!body) return;
validation = validateGenerationPoemBody(body);
if (validation) {
showMessage(validation);
if (!genealogyId) return;
poemId = normalizeId(getFormValues(form).poemId);
if (getFormValues(form).poemId && !poemId) {
setGenerationFormStatus('字辈编号无效,请返回列表重新编辑。', 'error');
return;
}
if (poemId && !poemsById[poemId]) {
setGenerationFormStatus('当前字辈不存在或已更新,请返回列表刷新后重试。', 'error');
return;
}
body = buildGenerationPoemBody(getFormValues(form));
validation = validateGenerationPoemBody(body);
if (validation) {
setGenerationFormStatus(validation, 'error');
return;
}
setGenerationFormStatus('正在保存字辈…', 'loading');
setWritePending(true);
try {
if (poemId) {
@@ -518,6 +589,7 @@
await api.createGenerationPoem(genealogyId, body);
}
showMessage('字辈已保存');
closePoemEditor();
await loadGenerationPoems();
} catch (error) {
if (redirectUnauthorized(api, error)) return;
@@ -525,7 +597,7 @@
renderForbiddenState();
return;
}
showMessage(error.message || '字辈保存失败');
setGenerationFormStatus(error.message || '字辈保存失败', 'error');
} finally {
setWritePending(false);
}
@@ -645,6 +717,13 @@
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('submit', function (event) {
var form = event.target.closest('[data-generation-form]');
if (!form) return;
event.preventDefault();
submitPoem(form);
});
documentRef.addEventListener('click', function (event) {
var target = event.target;
var action = target.closest('[data-generation-batch-action]');
@@ -658,12 +737,17 @@
}
if (target.closest('[data-generation-add]')) {
event.preventDefault();
savePoem('');
openPoemEditor('');
return;
}
if (target.closest('[data-generation-editor-cancel]')) {
event.preventDefault();
closePoemEditor();
return;
}
if (!poemButton) return;
event.preventDefault();
if (poemButton.hasAttribute('data-generation-edit')) savePoem(poemButton.getAttribute('data-generation-edit'));
if (poemButton.hasAttribute('data-generation-edit')) openPoemEditor(poemButton.getAttribute('data-generation-edit'));
if (poemButton.hasAttribute('data-generation-status')) togglePoemStatus(poemButton.getAttribute('data-generation-status'));
});
}
@@ -680,6 +764,7 @@
buildBatchBody: buildBatchBody,
validateGenerationPoemBody: validateGenerationPoemBody,
validateBatchBody: validateBatchBody,
canEditGenerations: canEditGenerations,
splitPoemText: splitPoemText,
normalizeGenerationPoem: normalizeGenerationPoem,
normalizeGenerationAccess: normalizeGenerationAccess,