等待后端更新接口

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
+124 -37
View File
@@ -15,6 +15,7 @@
var documentRef = root.document;
var recordsById = Object.create(null);
var canEditContent = false;
var writePending = false;
function getApi() {
@@ -253,19 +254,26 @@
return recordId ? url + '&recordId=' + encodeURIComponent(recordId) : url;
}
function canEditRecords(genealogy) {
return Boolean(genealogy && (genealogy.canEditContent === true || genealogy.canManage === true));
}
function renderGrowthRow(record) {
var summary = [];
var actions = '<button class="pill" type="button" data-growth-detail-id="' +
escapeHtml(record.recordId) + '">查看详情</button>';
if (record.lineagePersonName) summary.push(record.lineagePersonName);
if (record.recordType) summary.push(record.recordType);
if (record.recordDate) summary.push(record.recordDate);
if (!summary.length) summary.push('未填写日期和关联人物');
if (canEditContent) {
actions += '<a class="pill" href="' + escapeHtml(buildEditUrl(record.genealogyId, record.recordId)) +
'">编辑</a><button class="pill is-danger" type="button" data-growth-delete-id="' +
escapeHtml(record.recordId) + '">删除</button>';
}
return '<article class="module-row growth-row"><div><h3>' + escapeHtml(record.recordTitle) + '</h3><p>' +
escapeHtml(summary.join(' · ')) + '</p></div><div class="row-actions">' +
'<button class="pill" type="button" data-growth-detail-id="' + escapeHtml(record.recordId) + '">查看详情</button>' +
'<a class="pill" href="' + escapeHtml(buildEditUrl(record.genealogyId, record.recordId)) + '">编辑</a>' +
'<button class="pill is-danger" type="button" data-growth-delete-id="' + escapeHtml(record.recordId) + '">删除</button>' +
'</div></article>';
escapeHtml(summary.join(' · ')) + '</p></div><div class="row-actions">' + actions + '</div></article>';
}
function detailValue(label, value) {
@@ -274,9 +282,16 @@
function renderGrowthDetail(record) {
var count;
var actions = '';
if (!record) return '<div class="api-empty">请选择一条成长记录查看详情</div>';
if (!record) return stateHtml('empty', '请选择一条成长记录查看详情');
count = attachmentCount(record.mediaOssIds);
if (canEditContent) {
actions = '<div class="bottom-actions"><a class="btn ghost" href="' +
escapeHtml(buildEditUrl(record.genealogyId, record.recordId)) + '">编辑记录</a>' +
'<button class="btn ghost" type="button" data-growth-delete-id="' +
escapeHtml(record.recordId) + '">删除记录</button></div>';
}
return '<div class="form-like growth-detail">' +
detailValue('标题', record.recordTitle) +
detailValue('关联人物', record.lineagePersonName || record.lineagePersonNo) +
@@ -288,9 +303,7 @@
detailValue('记录人', record.appUserNickName) +
detailValue('状态', record.status === '0' ? '正常' : '停用') +
detailValue('备注', record.remark) +
'</div><div class="bottom-actions"><a class="btn ghost" href="' +
escapeHtml(buildEditUrl(record.genealogyId, record.recordId)) + '">编辑记录</a>' +
'<button class="btn ghost" type="button" data-growth-delete-id="' + escapeHtml(record.recordId) + '">删除记录</button></div>';
'</div>' + actions;
}
function showMessage(message) {
@@ -311,6 +324,10 @@
return Number(error && (error.status || error.code)) === 403;
}
function getApiStateType(error) {
return isForbidden(error) ? 'forbidden' : 'error';
}
function redirectUnauthorized(api, error) {
if (!shouldRedirectToLogin(api, error)) return false;
if (api && api.clearToken) api.clearToken();
@@ -327,13 +344,38 @@
if (root.ProfileUI && root.ProfileUI.syncGenealogyContextLinks) root.ProfileUI.syncGenealogyContextLinks();
}
function setFormStatus(message) {
var status = query('[data-growth-form-status]');
if (status) status.textContent = message || '';
function stateHtml(type, message) {
if (root.ProfileUI && root.ProfileUI.renderApiState) return root.ProfileUI.renderApiState(type, message);
return '<div class="api-state api-state--' + type + '" role="' +
(type === 'error' || type === 'forbidden' ? 'alert' : 'status') +
'" aria-live="polite">' + escapeHtml(message) + '</div>';
}
function setEditorEnabled(enabled, message) {
function setState(container, type, message) {
if (!container) return;
if (root.ProfileUI && root.ProfileUI.setApiState) {
root.ProfileUI.setApiState(container, type, message);
return;
}
container.innerHTML = stateHtml(type, message);
}
function setFormStatus(message, type) {
var status = query('[data-growth-form-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 setEditorEnabled(enabled, message, type) {
var placeholder = query('[data-growth-editor-placeholder]');
queryAll('[data-growth-editor], [data-growth-editor-action]').forEach(function (element) {
@@ -341,19 +383,37 @@
});
if (placeholder) {
placeholder.hidden = Boolean(enabled);
if (message) placeholder.textContent = message;
if (!enabled && message) {
if (type) setState(placeholder, type, message);
else placeholder.textContent = message;
}
}
}
function setEditAccess(enabled) {
canEditContent = Boolean(enabled);
queryAll('[data-growth-create-link]').forEach(function (element) {
element.hidden = !canEditContent;
});
}
async function loadCapability(api, genealogyId) {
var genealogy = await api.genealogyDetail(genealogyId);
setEditAccess(canEditRecords(genealogy));
return genealogy;
}
function renderNoContext() {
var list = query('[data-growth-list]');
var detail = query('[data-growth-detail]');
var message = '请先选择家谱,再查看或维护成长记录。';
if (list) list.innerHTML = '<div class="api-empty">' + message + '</div>';
if (detail) detail.innerHTML = '<div class="api-empty">当前没有家谱上下文。</div>';
setEditorEnabled(false, message);
setFormStatus(message);
setState(list, 'empty', message);
setState(detail, 'empty', '当前没有家谱上下文。');
setEditAccess(false);
setEditorEnabled(false, message, 'empty');
setFormStatus(message, 'empty');
}
function requireGenealogyId() {
@@ -363,11 +423,18 @@
return genealogyId;
}
function setWritePending(pending) {
function setWritePending(pending, label) {
var submit = query('[data-growth-form] [type="submit"]');
writePending = Boolean(pending);
queryAll('[data-growth-form] input, [data-growth-form] textarea, [data-growth-form] select, [data-growth-form] button, [data-growth-delete-id]').forEach(function (control) {
control.disabled = writePending;
});
if (submit) {
if (!submit.dataset.defaultLabel) submit.dataset.defaultLabel = submit.textContent;
submit.textContent = writePending && label ? label : submit.dataset.defaultLabel;
submit.setAttribute('aria-busy', writePending ? 'true' : 'false');
}
}
function renderGrowthRecords(data) {
@@ -382,11 +449,11 @@
});
if (!container) return records;
if (!Array.isArray(data) || invalidCount) {
container.innerHTML = '<div class="api-empty">成长记录响应缺少稳定 GrowthRecordVo 字段,请联系后端核对。</div>';
setState(container, 'error', '成长记录响应缺少稳定 GrowthRecordVo 字段,请联系后端核对。');
return [];
}
if (!records.length) {
container.innerHTML = '<div class="api-empty">暂无成长记录</div>';
setState(container, 'empty', '暂无成长记录');
return [];
}
container.innerHTML = records.map(renderGrowthRow).join('');
@@ -405,6 +472,7 @@
var record;
if (!genealogyId || !normalizeId(recordId) || redirectUnauthorized(api)) return null;
setState(query('[data-growth-detail]'), 'loading', '正在加载成长记录详情…');
try {
record = normalizeGrowthRecord(await api.growthRecordDetail(genealogyId, recordId));
if (!record) throw new Error('成长记录详情响应缺少稳定 GrowthRecordVo 字段');
@@ -413,7 +481,11 @@
return record;
} catch (error) {
if (redirectUnauthorized(api, error)) return null;
renderDetail(null);
setState(
query('[data-growth-detail]'),
getApiStateType(error),
isForbidden(error) ? '当前账号无权查看该成长记录。' : '成长记录详情加载失败,请稍后重试。'
);
showMessage(isForbidden(error) ? '当前账号无权查看该成长记录。' : (error.message || '成长记录详情加载失败'));
return null;
}
@@ -429,7 +501,9 @@
genealogyId = requireGenealogyId();
if (!genealogyId) return;
syncGenealogyLinks();
setState(query('[data-growth-list]'), 'loading', '正在加载成长记录…');
try {
await loadCapability(api, genealogyId);
records = renderGrowthRecords(await api.growthRecords(genealogyId));
requestedRecordId = getCurrentRecordId();
if (requestedRecordId && recordsById[requestedRecordId]) {
@@ -441,11 +515,12 @@
}
} catch (error) {
if (redirectUnauthorized(api, error)) return;
if (query('[data-growth-list]')) {
query('[data-growth-list]').innerHTML = '<div class="api-empty">' +
(isForbidden(error) ? '当前账号无权查看该家谱的成长记录。' : '成长记录加载失败,请稍后重试。') +
'</div>';
}
setEditAccess(false);
setState(
query('[data-growth-list]'),
getApiStateType(error),
isForbidden(error) ? '当前账号无权查看该家谱的成长记录。' : '成长记录加载失败,请稍后重试。'
);
showMessage(isForbidden(error) ? '当前账号无权查看该家谱的成长记录。' : (error.message || '成长记录加载失败'));
}
}
@@ -510,8 +585,11 @@
if (!genealogyId) return;
recordId = getCurrentRecordId();
syncGenealogyLinks();
setEditorEnabled(false, '正在加载成长记录编辑信息…');
setEditorEnabled(false, '正在加载成长记录编辑信息…', 'loading');
setFormStatus('正在读取家谱权限…', 'loading');
try {
await loadCapability(api, genealogyId);
if (!canEditContent) throw { status: 403, message: '当前账号无权维护该家谱的成长记录。' };
result = await Promise.all([
api.lineagePersonOptions(genealogyId),
recordId ? api.growthRecordDetail(genealogyId, recordId) : Promise.resolve(null)
@@ -524,12 +602,17 @@
if (query('[data-growth-editor-title]')) query('[data-growth-editor-title]').textContent = '编辑成长记录';
}
setEditorEnabled(true);
setFormStatus('');
} catch (error) {
if (redirectUnauthorized(api, error)) return;
setEditAccess(false);
setEditorEnabled(false, isForbidden(error)
? '当前账号无权维护该家谱的成长记录。'
: (error.message || '成长记录编辑信息加载失败'));
setFormStatus(error.message || '成长记录编辑信息加载失败');
: (error.message || '成长记录编辑信息加载失败'), getApiStateType(error));
setFormStatus(
isForbidden(error) ? '当前账号无权维护该家谱的成长记录。' : (error.message || '成长记录编辑信息加载失败'),
getApiStateType(error)
);
}
}
@@ -544,16 +627,16 @@
var savedId;
var verifiedDetail;
if (writePending || !genealogyId || redirectUnauthorized(api)) return;
if (writePending || !canEditContent || !genealogyId || redirectUnauthorized(api)) return;
body = buildGrowthRecordBody(getFormValues(form));
validation = validateGrowthRecordBody(body);
if (validation) {
setFormStatus(validation);
setFormStatus(validation, 'error');
return;
}
delete body.invalidSortOrder;
setWritePending(true);
setFormStatus('正在保存成长记录…');
setWritePending(true, '正在保存…');
setFormStatus('正在保存成长记录…', 'loading');
try {
result = recordId
? await api.updateGrowthRecord(genealogyId, recordId, body)
@@ -566,7 +649,10 @@
if (root.location) root.location.href = buildListUrl(genealogyId, savedId);
} catch (error) {
if (redirectUnauthorized(api, error)) return;
setFormStatus(isForbidden(error) ? '当前账号无权保存该成长记录。' : (error.message || '成长记录保存失败'));
setFormStatus(
isForbidden(error) ? '当前账号无权保存该成长记录。' : (error.message || '成长记录保存失败'),
getApiStateType(error)
);
} finally {
setWritePending(false);
}
@@ -577,7 +663,7 @@
var genealogyId = requireGenealogyId();
var record = recordsById[recordId];
if (writePending || !genealogyId || !normalizeId(recordId) || redirectUnauthorized(api)) return;
if (writePending || !canEditContent || !genealogyId || !normalizeId(recordId) || redirectUnauthorized(api)) return;
if (root.confirm && !root.confirm('确认删除“' + (record ? record.recordTitle : '该成长记录') + '”吗?删除后不可恢复,并会释放附件引用。')) return;
setWritePending(true);
try {
@@ -647,6 +733,7 @@
validateGrowthRecordBody: validateGrowthRecordBody,
normalizeGrowthRecord: normalizeGrowthRecord,
matchesSavedRecord: matchesSavedRecord,
canEditRecords: canEditRecords,
renderLineageOptions: renderLineageOptions,
renderGrowthDetail: renderGrowthDetail,
shouldRedirectToLogin: shouldRedirectToLogin,