Files
ns2.0/templates/my_comments.html

572 lines
15 KiB
HTML
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}我的评论{% endblock %}
{% block content %}
<div class="comments-container">
<div class="header">
<a href="{{ url_for('more') }}" class="back-link" title="返回">
<i class="fas fa-arrow-left"></i>
</a>
<h1>我的评论</h1>
</div>
<div class="comments-filter">
<div class="filter-tabs">
<button class="filter-tab active" data-status="all">全部</button>
<button class="filter-tab" data-status="pending">待审核</button>
<button class="filter-tab" data-status="approved">已通过</button>
<button class="filter-tab" data-status="rejected">已拒绝</button>
</div>
</div>
<div class="comments-list-wrapper">
<div id="comments-list" class="comments-list">
<!-- Comments will be dynamically loaded here -->
</div>
<div id="comments-empty-state" class="empty-state" style="display: none;">
<div class="empty-state-icon">
<i class="fas fa-comment-slash"></i>
</div>
<h2>暂无评论</h2>
<p>您还没有发表任何评论。在 资讯 页面开始您的探索吧!</p>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const commentsList = document.getElementById('comments-list');
const emptyState = document.getElementById('comments-empty-state');
const filterTabs = document.querySelectorAll('.filter-tab');
let allComments = [];
function fetchMyComments() {
commentsList.innerHTML = `
<div class="loading-spinner">
<i class="fas fa-spinner fa-spin"></i>
<p>正在加载评论...</p>
</div>
`;
fetch('/my_comments', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => {
// 检查响应状态
if (response.status === 401) {
// 未登录,重定向到登录页
window.location.href = '/login';
throw new Error('未登录');
}
if (!response.ok) {
throw new Error(`HTTP错误状态码${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
allComments = Array.isArray(data.comments) ? data.comments : [];
renderComments('all');
} else {
showErrorState(data.error || '获取评论失败');
}
})
.catch(error => {
if (error.message === '未登录') {
// 已在上面处理重定向
return;
}
console.error('获取评论时发生错误:', error);
showErrorState(error.message || '网络错误,请稍后重试');
});
}
function renderComments(status) {
// Update filter tab styles
filterTabs.forEach(tab => {
tab.classList.toggle('active', tab.dataset.status === status);
});
const filteredComments = status === 'all'
? allComments
: allComments.filter(comment => comment.status === status);
if (filteredComments.length === 0) {
commentsList.style.display = 'none';
emptyState.style.display = 'flex';
return;
}
commentsList.style.display = 'block';
emptyState.style.display = 'none';
const commentsHtml = filteredComments.map(comment => {
const statusClasses = {
'pending': {
icon: 'fa-clock',
text: '待审核',
color: 'warning'
},
'approved': {
icon: 'fa-check-circle',
text: '已通过',
color: 'success'
},
'rejected': {
icon: 'fa-times-circle',
text: '已拒绝',
color: 'danger'
}
}[comment.status] || {
icon: 'fa-question-circle',
text: '未知状态',
color: 'info'
};
const formatDate = (dateString) => {
try {
const date = new Date(dateString);
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
} catch (error) {
console.error('日期格式化错误:', error);
return dateString;
}
};
return `
<div class="comment-card" data-comment-id="${comment.id}">
<div class="comment-header">
<div class="comment-header-left">
<div class="comment-status ${statusClasses.color}">
<i class="fas ${statusClasses.icon}"></i>
${statusClasses.text}
</div>
<div class="comment-date">
${formatDate(comment.created_at)}
</div>
</div>
<div class="comment-header-right">
<button class="btn btn-view btn-small" onclick="window.location.href='/wiki/${comment.wiki_entry_id}'">
<i class="fas fa-eye"></i>
</button>
${status === 'all' || ['pending', 'draft'].includes(comment.status) ? `
<button class="btn btn-delete btn-small" data-comment-id="${comment.id}">
<i class="fas fa-trash"></i>
</button>
` : ''}
</div>
</div>
<div class="comment-body">
<p class="comment-text">${comment.content}</p>
<a href="/wiki/${comment.wiki_entry_id}" class="comment-wiki-link">
${comment.wiki_title || '未知条目'}
</a>
</div>
</div>
`;
}).join('');
commentsList.innerHTML = commentsHtml;
// Add delete event listeners
document.querySelectorAll('.btn-delete').forEach(button => {
button.addEventListener('click', function() {
const commentId = this.getAttribute('data-comment-id');
deleteComment(commentId);
});
});
}
function deleteComment(commentId) {
if (!confirm('确定要删除这条评论吗?')) return;
fetch(`/wiki/comment/${commentId}/delete`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => {
if (!response.ok) {
throw new Error('删除失败');
}
return response.json();
})
.then(data => {
if (data.success) {
allComments = allComments.filter(comment => comment.id !== parseInt(commentId));
const activeTab = document.querySelector('.filter-tab.active');
renderComments(activeTab.dataset.status);
} else {
alert(data.error || '删除评论失败');
}
})
.catch(error => {
alert(error.message || '删除评论时发生网络错误');
});
}
function showErrorState(message) {
commentsList.innerHTML = `
<div class="error-state">
<i class="fas fa-exclamation-triangle"></i>
<h2>出错了</h2>
<p>${message}</p>
</div>
`;
emptyState.style.display = 'none';
}
// Add filter tab event listeners
filterTabs.forEach(tab => {
tab.addEventListener('click', function() {
renderComments(this.dataset.status);
});
});
// Initial load
fetchMyComments();
// Back link navigation
document.querySelector('.back-link').addEventListener('click', function(e) {
e.preventDefault();
window.history.back();
});
});
</script>
{% block styles %}
<style>
:root {
--bg-primary: #ffffff;
--bg-secondary: #f5f5f7;
--text-primary: #1a1a1a;
--text-secondary: #666666;
--text-light: #8a8a8a;
--border-color: #e0e0e4;
--accent-color: #007aff;
--success-color: #34c759;
--warning-color: #ff9500;
--danger-color: #ff3b30;
}
[data-theme="dark"] {
--bg-primary: #121212;
--bg-secondary: #1e1e1e;
--text-primary: #e0e0e0;
--text-secondary: #a0a0a0;
--text-light: #6a6a6a;
--border-color: #333;
--accent-color: #5e9eff;
--success-color: #30d158;
--warning-color: #ff9f0a;
--danger-color: #ff453a;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
transition: all 0.3s ease;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
background-color: var(--bg-secondary);
color: var(--text-primary);
line-height: 1.6;
}
.comments-container {
max-width: 1200px;
margin: 0 auto;
padding: 60px 15px 20px 15px;
}
.header {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 30px;
background: white;
padding: 10px 15px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.back-link {
color: #666;
text-decoration: none;
padding: 8px;
border-radius: 50%;
background: #f5f5f7;
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
}
.back-link:hover {
background: #e5e5e7;
color: #333;
}
.header h1 {
margin: 0;
font-size: 20px;
color: #333;
font-weight: 500;
font-family: "SimHei", "黑体", sans-serif;
}
.comments-filter {
margin-bottom: 20px;
display: flex;
justify-content: center;
}
.filter-tabs {
display: flex;
background-color: var(--bg-secondary);
border-radius: 20px;
overflow: hidden;
border: 1px solid var(--border-color);
justify-content: center;
}
.filter-tab {
padding: 8px 16px;
background-color: transparent;
border: none;
cursor: pointer;
color: var(--text-secondary);
font-weight: 500;
font-size: 0.9em;
transition: all 0.3s;
}
.filter-tab.active {
color: var(--accent-color);
background-color: rgba(0,122,255,0.1);
}
.comments-list-wrapper {
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
padding: 20px;
}
.comment-card {
background-color: var(--bg-secondary);
border-radius: 12px;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.comment-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.comment-header-left {
display: flex;
align-items: center;
gap: 10px;
}
.comment-header-right {
display: flex;
align-items: center;
gap: 5px;
}
.btn-small {
width: 32px;
height: 32px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.btn-small i {
margin: 0;
}
.comment-status {
font-size: 0.7em;
padding: 3px 8px;
border-radius: 12px;
font-weight: 600;
text-transform: uppercase;
display: inline-flex;
align-items: center;
gap: 5px;
}
.comment-status.warning {
background-color: rgba(255,149,0,0.1);
color: var(--warning-color);
}
.comment-status.success {
background-color: rgba(52,199,89,0.1);
color: var(--success-color);
}
.comment-status.danger {
background-color: rgba(255,59,48,0.1);
color: var(--danger-color);
}
.comment-date {
color: var(--text-light);
font-size: 0.8em;
}
.comment-body {
margin-bottom: 15px;
}
.comment-text {
color: var(--text-primary);
font-size: 0.95em;
margin-bottom: 10px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.comment-wiki-link {
color: var(--accent-color);
text-decoration: none;
font-size: 0.85em;
font-weight: 500;
}
.comment-actions {
display: none; /* Remove old actions container */
}
.btn {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 6px 12px;
border: none;
border-radius: 20px;
font-size: 0.8em;
cursor: pointer;
transition: all 0.3s;
}
.btn-view {
background-color: rgba(0,122,255,0.1);
color: var(--accent-color);
}
.btn-delete {
background-color: rgba(255,59,48,0.1);
color: var(--danger-color);
}
.btn:hover {
opacity: 0.8;
}
.empty-state, .error-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 50px 20px;
color: var(--text-secondary);
}
.empty-state-icon, .error-state i {
font-size: 3rem;
opacity: 0.3;
margin-bottom: 15px;
}
.loading-spinner {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 50px;
color: var(--text-secondary);
}
@media (max-width: 600px) {
.comments-container {
border-radius: 0;
}
.filter-tabs {
flex-direction: row;
width: 100%;
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
justify-content: center;
}
.filter-tabs::-webkit-scrollbar {
display: none;
}
.filter-tab {
flex-shrink: 0;
}
}
/* Dark mode styles */
[data-theme="dark"] .header {
background: #242424;
}
[data-theme="dark"] .header h1 {
color: #fff;
}
[data-theme="dark"] .back-link {
color: #ccc;
background: #333;
}
[data-theme="dark"] .back-link:hover {
background: #444;
color: #fff;
}
[data-theme="dark"] .comments-list-wrapper {
background: #242424;
}
</style>
{% endblock %}
{% endblock %}