修改完成

This commit is contained in:
2026-09-13 19:41:13 +08:00
parent 15b301b358
commit d040507cb8
27 changed files with 2238 additions and 551 deletions
+972 -3
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -1263,3 +1263,34 @@
flex-basis: 100%;
}
}
.attachment-edit-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 220px));
gap: 12px;
margin-top: 12px;
}
.attachment-edit-list:empty { display: none; }
.attachment-edit-item {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
min-width: 0;
padding: 10px;
border: 1px solid var(--border, #e6ddcf);
border-radius: 8px;
}
.attachment-edit-item :is(img, video) {
width: 100%;
height: 140px;
object-fit: contain;
background: var(--paper, #faf7f0);
}
.attachment-edit-name { overflow-wrap: anywhere; font-size: 13px; }
.attachment-edit-remove { margin-top: auto; }
.attachment-edit-remove:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.attachment-edit-remove:disabled { opacity: .5; cursor: not-allowed; }
+3 -3
View File
@@ -1425,9 +1425,9 @@ textarea {
@media (prefers-reduced-motion: reduce) {
*,
*:before,
*:after {
*:not(:where(.page-home-portal, .page-home-portal *)),
*:not(:where(.page-home-portal, .page-home-portal *))::before,
*:not(:where(.page-home-portal, .page-home-portal *))::after {
animation-duration: .01ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
+2 -1
View File
@@ -510,7 +510,6 @@
if (!album || album.status !== '0') throw new Error('停用相册无法通过当前 PC 接口重新读取或编辑');
setFieldValue('[data-album-form]', 'albumName', album.albumName);
setFieldValue('[data-album-form]', 'albumDesc', album.albumDesc);
setFieldValue('[data-album-form]', 'coverOssId', album.coverOssId);
setFieldValue('[data-album-form]', 'sortOrder', album.sortOrder);
setFieldValue('[data-album-form]', 'status', '0');
}
@@ -537,6 +536,8 @@
album = findAlbumById(albums, albumId);
if (!album) throw new Error('相册列表未返回当前相册');
fillAlbumForm(album);
var albumResponse = albums.find(function (entry) { return String(entry.albumId) === albumId; });
root.AttachmentEditor.setFiles('#albumCoverOssId', albumResponse.coverFile ? [albumResponse.coverFile] : []);
if (query('[data-album-editor-title]')) query('[data-album-editor-title]').textContent = '编辑相册';
}
setEditorEnabled(true);
+5 -3
View File
@@ -102,6 +102,7 @@
var sortOrder = optionalSafeInteger(source.sortOrder);
if (articleSummary !== undefined) body.articleSummary = articleSummary;
if (source.coverOssId === null) body.coverOssId = null;
if (source.coverOssId !== undefined && source.coverOssId !== null && source.coverOssId !== '') {
if (coverOssId) body.coverOssId = coverOssId;
else body.invalidCoverOssId = true;
@@ -446,7 +447,7 @@
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
values[field.name] = root.AttachmentEditor ? root.AttachmentEditor.readField(field) : field.value;
});
return values;
}
@@ -464,7 +465,6 @@
if (!article || article.status !== '0') throw new Error('停用谱文无法通过当前 PC 接口重新读取或编辑');
setFieldValue('articleTitle', article.articleTitle);
setFieldValue('articleSummary', article.articleSummary);
setFieldValue('coverOssId', article.coverOssId);
setFieldValue('articleContent', article.articleContent);
setFieldValue('authorName', article.authorName);
setFieldValue('sortOrder', article.sortOrder);
@@ -496,9 +496,11 @@
await loadCapability(api, genealogyId);
if (!canEditContent) throw { status: 403, message: '当前账号无权维护该家谱的谱文。' };
if (articleId) {
article = normalizeArticle(await api.articleDetail(genealogyId, articleId));
var articleResponse = await api.articleDetail(genealogyId, articleId);
article = normalizeArticle(articleResponse);
if (!article || article.articleId !== articleId) throw new Error('谱文详情响应缺少稳定 ArticleVo 字段');
fillArticleForm(article);
root.AttachmentEditor.setFiles('#articleCoverOssId', articleResponse.coverFile ? [articleResponse.coverFile] : []);
if (query('[data-article-editor-title]')) query('[data-article-editor-title]').textContent = '编辑谱文';
}
setEditorEnabled(true);
+182
View File
@@ -0,0 +1,182 @@
(function (root, factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.AttachmentEditor = factory(root);
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var editors = new Map();
function normalizeFiles(files) {
var seen = new Set();
return (files || []).map(function (file) {
var ossId = file && file.ossId;
if ((typeof ossId === 'number' && !Number.isSafeInteger(ossId)) || !/^[1-9][0-9]*$/.test(String(ossId))) {
throw new Error('原附件缺少有效的上传标识,暂不能保存,请刷新后重试');
}
return {
ossId: String(ossId),
fileName: String(file.fileName || '附件'),
mediaType: String(file.mediaType || '').toLowerCase(),
accessUrl: root.MediaDisplay ? (root.MediaDisplay.normalizeFileAccess(file) || {}).accessUrl || '' : ''
};
}).filter(function (file) {
if (seen.has(file.ossId)) return false;
seen.add(file.ossId);
return true;
});
}
function release(files) {
files.forEach(function (file) {
if (file.objectUrl) root.URL.revokeObjectURL(file.objectUrl);
});
}
function getEditor(target) {
if (typeof target === 'string') target = root.document.querySelector(target);
return editors.get(target);
}
function sync(editor) {
editor.target.value = editor.files.map(function (file) { return file.ossId; }).join(',');
editor.preview.replaceChildren();
editor.files.forEach(function (file) {
var card = root.document.createElement('div');
var url = file.objectUrl || file.accessUrl;
var name = root.document.createElement('span');
var remove = root.document.createElement('button');
var media;
card.className = 'attachment-edit-item';
if (url && /^(image|video)(\/|$)/.test(file.mediaType)) {
media = root.document.createElement(/^image/.test(file.mediaType) ? 'img' : 'video');
media.src = url;
if (media.tagName === 'IMG') media.alt = file.fileName;
else { media.controls = true; media.preload = 'metadata'; }
media.addEventListener('error', function () {
media.hidden = true;
name.textContent = file.fileName + '(预览不可用,附件仍保留)';
});
card.appendChild(media);
}
name.className = 'attachment-edit-name';
name.textContent = file.fileName;
card.appendChild(name);
remove.type = 'button';
remove.className = 'pill attachment-edit-remove';
remove.textContent = '移除';
remove.setAttribute('aria-label', '移除 ' + file.fileName);
remove.disabled = editor.busy || editor.input.disabled;
// 相册接口尚不支持可靠清空封面,仅允许替换。
if (editor.input.hasAttribute('data-attachment-replace-only')) {
remove.hidden = true;
}
remove.addEventListener('click', function () {
if (editor.busy || editor.input.disabled) return;
editor.files = editor.files.filter(function (existing) { return existing !== file; });
release([file]);
editor.cleared = true;
sync(editor);
});
card.appendChild(remove);
editor.preview.appendChild(card);
});
if (editor.status && !editor.busy) {
editor.status.textContent = editor.files.length
? '已选择 ' + editor.files.length + ' 个文件;移除或替换将在保存后生效'
: (editor.cleared ? '附件已移除,保存后生效' : '未选择文件');
}
}
function init() {
root.document.querySelectorAll('[data-attachment-editor]').forEach(function (input) {
var target = root.document.querySelector(input.getAttribute('data-upload-target'));
var preview;
var editor;
if (!target || editors.has(target)) return;
preview = root.document.createElement('div');
preview.className = 'attachment-edit-list';
preview.setAttribute('aria-label', '已选择的附件');
input.insertAdjacentElement('afterend', preview);
editor = {
target: target, input: input, preview: preview,
status: root.document.querySelector(input.getAttribute('data-upload-status')),
multiple: input.getAttribute('data-upload-multiple') === 'true',
files: [], cleared: false, busy: false
};
editors.set(target, editor);
new root.MutationObserver(function () {
preview.querySelectorAll('button').forEach(function (button) { button.disabled = input.disabled || editor.busy; });
}).observe(input, { attributes: true, attributeFilter: ['disabled'] });
});
}
function setFiles(target, files) {
init();
var editor = getEditor(target);
if (!editor) throw new Error('附件编辑控件未初始化');
editor.invalid = true;
var normalized = normalizeFiles(files);
release(editor.files);
editor.files = normalized;
editor.cleared = false;
editor.invalid = false;
sync(editor);
}
function addUploaded(target, upload, file) {
var editor = getEditor(target);
if (!editor) return false;
var attachment = normalizeFiles([{ ossId: upload.ossId, fileName: file.name, mediaType: file.type }])[0];
if (editor.files.some(function (existing) { return existing.ossId === attachment.ossId; })) return true;
attachment.objectUrl = root.URL.createObjectURL(file);
if (!editor.multiple) { release(editor.files); editor.files = []; }
editor.files.push(attachment);
editor.cleared = false;
sync(editor);
return true;
}
function clear(target) {
var editor = getEditor(target);
if (!editor || editor.busy || editor.input.disabled) return;
release(editor.files);
editor.files = [];
editor.cleared = true;
sync(editor);
}
function readField(field) {
var editor = getEditor(field);
// nullable 单封面 PATCH:空值仅在用户主动移除时提交 null。
if (editor && !editor.multiple && editor.cleared && !editor.files.length) return null;
return field.value;
}
function setBusy(target, busy) {
var editor = getEditor(target);
if (!editor) return;
editor.busy = busy;
editor.preview.querySelectorAll('button').forEach(function (button) { button.disabled = busy || editor.input.disabled; });
}
if (root.document) {
root.document.addEventListener('DOMContentLoaded', init);
root.document.addEventListener('submit', function (event) {
var pending = Array.from(editors.values()).some(function (editor) { return editor.input.form === event.target && editor.busy; });
var invalid = Array.from(editors.values()).some(function (editor) { return editor.input.form === event.target && editor.invalid; });
if (!pending && !invalid) return;
event.preventDefault();
event.stopImmediatePropagation();
var status = event.target.querySelector('.upload-status');
if (status) status.textContent = invalid ? '原附件读取不完整,请刷新后重试,暂不能保存' : '文件正在上传,请等待上传完成后再保存';
}, true);
root.addEventListener('pagehide', function (event) {
if (!event.persisted) editors.forEach(function (editor) { release(editor.files); });
});
}
return { init: init, normalizeFiles: normalizeFiles, setFiles: setFiles, addUploaded: addUploaded, clear: clear, readField: readField, setBusy: setBusy };
});
+6 -3
View File
@@ -166,6 +166,7 @@
if (latitude !== undefined) body.latitude = latitude;
else body.invalidLatitude = true;
}
if (source.coverOssId === null) body.coverOssId = null;
if (source.coverOssId !== undefined && source.coverOssId !== null && source.coverOssId !== '') {
if (coverOssId) body.coverOssId = coverOssId;
else body.invalidCoverOssId = true;
@@ -615,7 +616,7 @@
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) { values[field.name] = field.value; });
queryAll('[name]', form).forEach(function (field) { values[field.name] = root.AttachmentEditor ? root.AttachmentEditor.readField(field) : field.value; });
return values;
}
@@ -630,7 +631,7 @@
var contentEditor;
if (!ceremony || ceremony.status !== '0') throw new Error('停用活动无法通过当前 PC 接口重新读取或编辑');
['ceremonyType', 'ceremonyTitle', 'ceremonyDesc', 'location', 'locationAddress', 'longitude', 'latitude', 'coverOssId', 'sortOrder'].forEach(function (name) {
['ceremonyType', 'ceremonyTitle', 'ceremonyDesc', 'location', 'locationAddress', 'longitude', 'latitude', 'sortOrder'].forEach(function (name) {
setFieldValue('[data-ceremony-form]', name, ceremony[name]);
});
setFieldValue('[data-ceremony-form]', 'ceremonyTime', toDateTimeInputValue(ceremony.ceremonyTime));
@@ -662,9 +663,11 @@
await loadCapability(api, genealogyId);
if (!canEditContent) throw { status: 403, message: '当前账号无权维护该家谱的祭祀活动。' };
if (ceremonyId) {
ceremony = normalizeCeremony(await api.ceremonyDetail(genealogyId, ceremonyId));
var ceremonyResponse = await api.ceremonyDetail(genealogyId, ceremonyId);
ceremony = normalizeCeremony(ceremonyResponse);
if (!ceremony || ceremony.ceremonyId !== ceremonyId) throw new Error('活动详情响应缺少稳定 ceremonyId');
fillCeremonyForm(ceremony);
root.AttachmentEditor.setFiles('#giftCoverOssId', ceremonyResponse.coverFile ? [ceremonyResponse.coverFile] : []);
if (query('[data-ceremony-editor-title]')) query('[data-ceremony-editor-title]').textContent = '编辑祭祀活动';
}
setEditorEnabled(true);
+13 -1
View File
@@ -302,7 +302,7 @@
if (trimOrUndefined(source.sortOrder) !== undefined && sortOrder === undefined) {
throw new Error('排序值必须是非负整数');
}
if (mediaOssIds !== undefined) body.mediaOssIds = mediaOssIds;
if (source.mediaOssIds !== undefined) body.mediaOssIds = mediaOssIds || '';
if (status !== undefined) body.status = status;
if (sortOrder !== undefined) body.sortOrder = sortOrder;
return body;
@@ -618,11 +618,22 @@
function fillFeedForm(data) {
var feed = normalizeFeed(data);
var contentField;
var contentEditor;
if (!feed) throw new Error('动态响应缺少 feedId 或 feedContent,请联系后端补充 DTO。');
queryAll('[data-feed-form] [name]').forEach(function (field) {
if (feed[field.name] !== undefined && feed[field.name] !== null) field.value = feed[field.name];
});
contentField = query('[data-feed-form] [name="feedContent"]');
if (contentField && root.AppRichEditor && root.AppRichEditor.init) {
contentEditor = root.AppRichEditor.init(contentField);
if (contentEditor && contentEditor.editor && contentEditor.editor.setHtml) {
contentEditor.editor.setHtml(feed.feedContent);
contentEditor.sync();
}
}
root.AttachmentEditor.setFiles('#feedMedia', data.mediaFiles || []);
}
function canEditFeeds(genealogy) {
@@ -788,6 +799,7 @@
setFeedFormStatus('');
} catch (error) {
if (redirectUnauthorized(api, error)) return;
setFeedFormEnabled(false);
setFeedFormStatus(
getApiStateType(error) === 'forbidden' ? '当前账号无权维护该家谱的动态。' : (error.message || '动态详情加载失败'),
getApiStateType(error)
+4 -15
View File
@@ -124,7 +124,7 @@
if (recordContent !== undefined) body.recordContent = recordContent;
if (recordDate !== undefined) body.recordDate = recordDate;
if (remindTime !== undefined) body.remindTime = remindTime;
if (mediaOssIds !== undefined) body.mediaOssIds = mediaOssIds;
if (source.mediaOssIds !== undefined) body.mediaOssIds = mediaOssIds || '';
if (sortOrderText !== undefined) {
body.sortOrder = toSafeInteger(sortOrderText);
if (body.sortOrder === undefined) body.invalidSortOrder = true;
@@ -136,7 +136,7 @@
function validateGrowthRecordBody(body) {
if (!body || !body.recordTitle) return '请填写记录标题';
if (body.lineagePersonId !== undefined && !normalizeId(body.lineagePersonId)) return '请选择有效的世系人物';
if (body.mediaOssIds !== undefined && !/^[1-9][0-9]*(,[1-9][0-9]*)*$/.test(body.mediaOssIds)) {
if (body.mediaOssIds !== undefined && body.mediaOssIds !== '' && !/^[1-9][0-9]*(,[1-9][0-9]*)*$/.test(body.mediaOssIds)) {
return '附件上传结果无效';
}
if (body.invalidSortOrder || (Object.prototype.hasOwnProperty.call(body, 'sortOrder') && !Number.isSafeInteger(body.sortOrder))) {
@@ -554,7 +554,6 @@
setFieldValue('recordContent', record.recordContent);
setFieldValue('recordDate', toDateInputValue(record.recordDate));
setFieldValue('remindTime', toDateTimeInputValue(record.remindTime));
setFieldValue('mediaOssIds', record.mediaOssIds);
setFieldValue('sortOrder', record.sortOrder);
setFieldValue('status', '0');
contentField = query('[data-growth-form] [name="recordContent"]');
@@ -564,11 +563,6 @@
editorInstance.editor.setHtml(record.recordContent || '');
}
}
if (query('[data-growth-media-status]')) {
query('[data-growth-media-status]').textContent = record.mediaOssIds
? '已保留 ' + attachmentCount(record.mediaOssIds) + ' 个附件,可继续选择追加'
: '未选择文件';
}
}
function applyLineageOptions(data, selectedId, fallbackName) {
@@ -603,6 +597,7 @@
applyLineageOptions(result[0], record && record.lineagePersonId, record && record.lineagePersonName);
if (record) {
fillGrowthForm(record);
root.AttachmentEditor.setFiles('#growthMediaOssIds', result[1].mediaFiles || []);
if (query('[data-growth-editor-title]')) query('[data-growth-editor-title]').textContent = '编辑成长记录';
}
setEditorEnabled(true);
@@ -683,13 +678,7 @@
}
function clearMediaSelection() {
var target = query('[data-growth-form] [name="mediaOssIds"]');
var status = query('[data-growth-media-status]');
var fileInput = query('[data-growth-media-input]');
if (target) target.value = '';
if (fileInput) fileInput.value = '';
if (status) status.textContent = '未选择文件';
root.AttachmentEditor.clear('#growthMediaOssIds');
}
function bindActions() {
+6 -16
View File
@@ -110,7 +110,7 @@
if (memoContent !== undefined) body.memoContent = memoContent;
if (remindTime !== undefined) body.remindTime = remindTime;
if (completed !== undefined) body.completed = completed;
if (mediaOssIds !== undefined) body.mediaOssIds = mediaOssIds;
if (source.mediaOssIds !== undefined) body.mediaOssIds = mediaOssIds || '';
if (sortOrderText !== undefined) {
body.sortOrder = toSafeInteger(sortOrderText);
if (body.sortOrder === undefined) body.invalidSortOrder = true;
@@ -141,7 +141,7 @@
if (body.completed !== undefined && body.completed !== '0' && body.completed !== '1') {
return '完成状态只能是未完成或已完成';
}
if (body.mediaOssIds !== undefined && !/^[1-9][0-9]*(,[1-9][0-9]*)*$/.test(body.mediaOssIds)) {
if (body.mediaOssIds !== undefined && body.mediaOssIds !== '' && !/^[1-9][0-9]*(,[1-9][0-9]*)*$/.test(body.mediaOssIds)) {
return '附件上传结果无效';
}
if (body.invalidSortOrder || (Object.prototype.hasOwnProperty.call(body, 'sortOrder') && !Number.isSafeInteger(body.sortOrder))) {
@@ -518,14 +518,8 @@
setFieldValue('memoContent', memo.memoContent);
setFieldValue('remindTime', toDateTimeInputValue(memo.remindTime));
setFieldValue('completed', memo.completed);
setFieldValue('mediaOssIds', memo.mediaOssIds);
setFieldValue('sortOrder', memo.sortOrder);
setFieldValue('status', '0');
if (query('[data-memo-media-status]')) {
query('[data-memo-media-status]').textContent = memo.mediaOssIds
? '已保留 ' + attachmentCount(memo.mediaOssIds) + ' 个附件,可继续选择追加'
: '未选择文件';
}
}
async function loadMemoEditor() {
@@ -545,9 +539,11 @@
await loadCapability(api, genealogyId);
if (!canEditContent) throw { status: 403, message: '当前账号无权维护该家谱的备忘录。' };
if (memoId) {
memo = normalizeMemo(await api.memoDetail(genealogyId, memoId));
var memoResponse = await api.memoDetail(genealogyId, memoId);
memo = normalizeMemo(memoResponse);
if (!memo) throw new Error('备忘录详情响应缺少稳定 MemoVo 字段');
fillMemoForm(memo);
root.AttachmentEditor.setFiles('#memoMediaOssIds', memoResponse.mediaFiles || []);
if (query('[data-memo-editor-title]')) query('[data-memo-editor-title]').textContent = '编辑备忘录';
}
setEditorEnabled(true);
@@ -628,13 +624,7 @@
}
function clearMediaSelection() {
var target = query('[data-memo-form] [name="mediaOssIds"]');
var status = query('[data-memo-media-status]');
var fileInput = query('[data-memo-media-input]');
if (target) target.value = '';
if (fileInput) fileInput.value = '';
if (status) status.textContent = '未选择文件';
root.AttachmentEditor.clear('#memoMediaOssIds');
}
function bindActions() {
+4 -3
View File
@@ -252,7 +252,7 @@
menu.setAttribute("aria-hidden", "true");
inner.className = "container site-mobile-menu-inner";
[...navLinks.querySelectorAll("a"), ...(navActions ? navActions.querySelectorAll("a") : [])].forEach((link) => {
[...navLinks.querySelectorAll("a, button"), ...(navActions ? navActions.querySelectorAll("a") : [])].forEach((link) => {
inner.appendChild(link.cloneNode(true));
});
menu.appendChild(inner);
@@ -288,9 +288,10 @@
initSiteMenu();
refreshPublicUser();
// 只在精确指针设备上启用动效,触屏和减少动效偏好下保持静态
// 鼠标反馈仅用于精确指针;首页独立启用动效,其他页面遵循系统偏好
const finePointer = window.matchMedia("(hover: hover) and (pointer: fine)").matches;
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
const reduceMotion = !document.body.classList.contains("page-home-portal") &&
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!finePointer || reduceMotion) return;
+6 -16
View File
@@ -150,7 +150,7 @@
else if (!isExactJsonNumber(amountText, body.giftAmount)) body.invalidGiftPrecision = true;
}
if (recordContent !== undefined) body.recordContent = recordContent;
if (mediaOssIds !== undefined) body.mediaOssIds = mediaOssIds;
if (source.mediaOssIds !== undefined) body.mediaOssIds = mediaOssIds || '';
if (sortOrderText !== undefined) {
body.sortOrder = toSafeInteger(sortOrderText);
if (body.sortOrder === undefined) body.invalidSortOrder = true;
@@ -168,7 +168,7 @@
if (body.eventTime !== undefined && !isValidBackendDateTime(body.eventTime)) {
return '事件时间格式无效';
}
if (body.mediaOssIds !== undefined && !/^[1-9][0-9]*(,[1-9][0-9]*)*$/.test(body.mediaOssIds)) {
if (body.mediaOssIds !== undefined && body.mediaOssIds !== '' && !/^[1-9][0-9]*(,[1-9][0-9]*)*$/.test(body.mediaOssIds)) {
return '附件上传结果无效';
}
if (body.invalidSortOrder || (Object.prototype.hasOwnProperty.call(body, 'sortOrder') && !Number.isSafeInteger(body.sortOrder))) {
@@ -576,14 +576,8 @@
setFieldValue('eventTime', toDateTimeInputValue(record.eventTime));
setFieldValue('giftAmount', record.giftAmount);
setFieldValue('recordContent', record.recordContent);
setFieldValue('mediaOssIds', record.mediaOssIds);
setFieldValue('sortOrder', record.sortOrder);
setFieldValue('status', '0');
if (query('[data-relative-media-status]')) {
query('[data-relative-media-status]').textContent = record.mediaOssIds
? '已保留 ' + attachmentCount(record.mediaOssIds) + ' 个附件,可继续选择追加'
: '未选择文件';
}
}
async function loadRelativeEditor() {
@@ -603,9 +597,11 @@
await loadCapability(api, genealogyId);
if (!canEditContent) throw { status: 403, message: '当前账号无权维护该家谱的亲友记录。' };
if (relativeId) {
record = normalizeRelativeRecord(await api.relativeRecordDetail(genealogyId, relativeId));
var relativeResponse = await api.relativeRecordDetail(genealogyId, relativeId);
record = normalizeRelativeRecord(relativeResponse);
if (!record) throw new Error('亲友记录详情响应缺少稳定 RelativeRecordVo 字段');
fillRelativeForm(record);
root.AttachmentEditor.setFiles('#relativeMediaOssIds', relativeResponse.mediaFiles || []);
if (query('[data-relative-editor-title]')) query('[data-relative-editor-title]').textContent = '编辑亲友记录';
}
setEditorEnabled(true);
@@ -688,13 +684,7 @@
}
function clearMediaSelection() {
var target = query('[data-relative-form] [name="mediaOssIds"]');
var status = query('[data-relative-media-status]');
var fileInput = query('[data-relative-media-input]');
if (target) target.value = '';
if (fileInput) fileInput.value = '';
if (status) status.textContent = '未选择文件';
root.AttachmentEditor.clear('#relativeMediaOssIds');
}
function bindActions() {
+5 -1
View File
@@ -225,6 +225,7 @@
if (!files.length || !target || redirectUnauthorized(api)) return;
input.disabled = true;
if (root.AttachmentEditor) root.AttachmentEditor.setBusy(target, true);
try {
for (index = 0; index < files.length; index += 1) {
@@ -235,7 +236,9 @@
}
}));
if (!result.ossId) throw new Error('上传响应缺少 ossId');
target.value = mergeUploadTargetValue(target.value, result.ossId, multiple);
if (!root.AttachmentEditor || !root.AttachmentEditor.addUploaded(target, result, files[index])) {
target.value = mergeUploadTargetValue(target.value, result.ossId, multiple);
}
setUploadStatus(status, '', buildUploadStatus(result.fileName || files[index].name, result.ossId));
}
} catch (error) {
@@ -244,6 +247,7 @@
showMessage(isForbidden(error) ? '当前账号无权上传文件。' : (error.message || '上传失败'));
} finally {
input.disabled = false;
if (root.AttachmentEditor) root.AttachmentEditor.setBusy(target, false);
input.value = '';
}
}
+5 -6
View File
@@ -97,6 +97,7 @@
if (videoDesc !== undefined) body.videoDesc = videoDesc;
if (coverOssId !== undefined) body.coverOssId = coverOssId;
if (source.coverOssId === null) body.coverOssId = null;
if (videoOssId !== undefined) body.videoOssId = videoOssId;
if (durationText !== undefined) {
body.durationSeconds = toSafeInteger(durationText);
@@ -114,7 +115,7 @@
if (!body || !body.videoTitle) return '请填写视频标题';
if (!body.videoOssId) return '请先选择并上传视频文件';
if (!normalizeId(body.videoOssId)) return '视频文件上传结果无效';
if (body.coverOssId !== undefined && !normalizeId(body.coverOssId)) return '封面上传结果无效';
if (body.coverOssId !== undefined && body.coverOssId !== null && !normalizeId(body.coverOssId)) return '封面上传结果无效';
if (body.invalidDuration || (body.durationSeconds !== undefined && !Number.isSafeInteger(body.durationSeconds))) {
return '视频时长必须是安全整数';
}
@@ -488,7 +489,7 @@
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
values[field.name] = root.AttachmentEditor ? root.AttachmentEditor.readField(field) : field.value;
});
return values;
}
@@ -502,13 +503,9 @@
function fillVideoForm(video) {
setFieldValue('videoTitle', video.videoTitle);
setFieldValue('videoDesc', video.videoDesc);
setFieldValue('coverOssId', video.coverOssId);
setFieldValue('videoOssId', video.videoOssId);
setFieldValue('durationSeconds', video.durationSeconds);
setFieldValue('sortOrder', video.sortOrder);
setFieldValue('status', '0');
if (query('[data-video-file-status]')) query('[data-video-file-status]').textContent = '已保留原视频文件,可重新选择替换';
if (query('[data-video-cover-status]')) query('[data-video-cover-status]').textContent = video.coverOssId ? '已保留原封面,可重新选择替换' : '未选择封面';
}
async function loadVideoEditor() {
@@ -540,6 +537,8 @@
video = normalizeVideo(result[1]);
if (!video) throw new Error('视频详情响应缺少稳定 VideoVo 字段');
fillVideoForm(video);
root.AttachmentEditor.setFiles('#video-oss-id', result[1].videoFile ? [result[1].videoFile] : []);
root.AttachmentEditor.setFiles('#video-cover-oss-id', result[1].coverFile ? [result[1].coverFile] : []);
if (query('[data-video-editor-title]')) query('[data-video-editor-title]').textContent = '编辑视频';
}
setFormStatus('');