feat: 评论系统补充功能完成——图片上传、后台管理、通知跳转高亮
- 评论图片上传(LV4+,经验≥1500),JPEG/PNG 自动转 WebP,二进制搜索质量优化 - 后台评论管理页面,支持关键词搜索、分页、删除,侧边栏新增入口 - 通知跳转高亮:评论通知 RelatedID 改为 postID,消息页链接到 #comments,前端自动滚动 - 新增 adminCommentUseCase/commentStore 接口(遵循 ISP),AdminCommentRow 移至 model 层 - 前端 @mention 联想/图片上传光标插入/评论展开收起/内联回复交互完善
This commit is contained in:
@ -80,7 +80,15 @@
|
||||
{{if .IsLoggedIn}}
|
||||
<div class="comment-form">
|
||||
<textarea class="comment-input" id="commentInput" placeholder="写下你的评论..." rows="3" maxlength="5000"></textarea>
|
||||
<button class="btn btn-primary comment-submit-btn" id="commentSubmitBtn">发表评论</button>
|
||||
<div class="comment-form-actions">
|
||||
<label class="comment-upload-btn" id="commentUploadLabel">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
||||
图片
|
||||
</label>
|
||||
<input type="file" id="commentImageInput" accept="image/*" style="display:none" />
|
||||
<button class="btn btn-primary comment-submit-btn" id="commentSubmitBtn">发表评论</button>
|
||||
</div>
|
||||
<div class="comment-upload-preview" id="commentUploadPreview"></div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="comment-login-hint">
|
||||
@ -640,6 +648,71 @@
|
||||
el.textContent = '(' + (current + delta) + ')';
|
||||
}
|
||||
|
||||
// ====== 图片上传 ======
|
||||
var imageUploadInput = document.getElementById('commentImageInput');
|
||||
var uploadLabel = document.getElementById('commentUploadLabel');
|
||||
var uploadPreview = document.getElementById('commentUploadPreview');
|
||||
|
||||
if (imageUploadInput && uploadLabel) {
|
||||
uploadLabel.addEventListener('click', function() {
|
||||
imageUploadInput.click();
|
||||
});
|
||||
|
||||
imageUploadInput.addEventListener('change', function() {
|
||||
var file = imageUploadInput.files[0];
|
||||
if (!file) return;
|
||||
uploadLabel.style.pointerEvents = 'none';
|
||||
uploadLabel.style.opacity = '0.5';
|
||||
uploadLabel.textContent = '上传中...';
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
fetch('/api/comments/upload-image', {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRF-Token': csrfToken },
|
||||
body: formData
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(d) {
|
||||
uploadLabel.style.pointerEvents = 'auto';
|
||||
uploadLabel.style.opacity = '1';
|
||||
uploadLabel.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg> 图片';
|
||||
|
||||
if (d.success && d.data && d.data.url) {
|
||||
// 插入图片 URL 到文本框当前光标位置
|
||||
var imgUrl = '\n\n';
|
||||
var input = commentInput;
|
||||
var start = input.selectionStart;
|
||||
var end = input.selectionEnd;
|
||||
input.value = input.value.substring(0, start) + imgUrl + input.value.substring(end);
|
||||
input.focus();
|
||||
input.selectionStart = input.selectionEnd = start + imgUrl.length;
|
||||
} else {
|
||||
alert(d.message || '上传失败');
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
uploadLabel.style.pointerEvents = 'auto';
|
||||
uploadLabel.style.opacity = '1';
|
||||
uploadLabel.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg> 图片';
|
||||
alert('上传失败');
|
||||
});
|
||||
|
||||
imageUploadInput.value = '';
|
||||
});
|
||||
}
|
||||
|
||||
// ====== Hash 定位:从消息通知跳转时滚动到评论区 ======
|
||||
if (window.location.hash === '#comments') {
|
||||
setTimeout(function() {
|
||||
var section = document.getElementById('comments');
|
||||
if (section) {
|
||||
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}, 400);
|
||||
}
|
||||
|
||||
// ====== 初始化 ======
|
||||
loadComments(currentPage);
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user