mobile app database models admin_contests admin_dashboard admin_exams admin_posts admin_teacher_applications admin_users apply_contest apply_teacher base chat contest_detail contest_list exam_result forum notifications profile themes

This commit is contained in:
2026-03-03 16:02:23 +08:00
parent 0764566742
commit 9a08140623
30 changed files with 1531 additions and 834 deletions

View File

@@ -4,53 +4,55 @@
{% block admin_content %}
<div class="space-y-6">
<h1 class="text-2xl font-bold text-slate-900">帖子管理</h1>
<h1 class="text-3xl font-extrabold bg-gradient-to-r from-blue-400 via-purple-400 to-pink-400 bg-clip-text text-transparent">帖子管理</h1>
<div class="flex gap-4">
<input id="search-input" type="text" placeholder="搜索标题/内容..." class="flex-1 px-4 py-2 border border-slate-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
<select id="tag-filter" class="px-4 py-2 border border-slate-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
<input id="search-input" type="text" placeholder="搜索标题/内容..." class="input-futuristic flex-1">
<select id="tag-filter" class="input-futuristic">
<option value="">全部标签</option>
<option value="讨论">讨论</option>
<option value="求助">求助</option>
<option value="分享">分享</option>
<option value="公告">公告</option>
</select>
<button onclick="loadPosts()" class="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm hover:bg-blue-700">搜索</button>
<button onclick="loadPosts()" class="btn-futuristic px-6">搜索</button>
</div>
<div class="bg-white shadow-sm rounded-lg border border-slate-200 overflow-hidden">
<table class="min-w-full divide-y divide-slate-200">
<thead class="bg-slate-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">标题</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">作者</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">标签</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">置顶</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">发布时间</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">操作</th>
</tr>
</thead>
<tbody id="posts-tbody" class="bg-white divide-y divide-slate-200"></tbody>
</table>
<div id="loading-spinner" class="text-center py-8 text-slate-400 hidden">
<svg class="animate-spin h-6 w-6 mx-auto" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<div class="futuristic-card-dark overflow-hidden">
<div class="overflow-x-auto">
<table class="table-futuristic">
<thead>
<tr>
<th>ID</th>
<th>标题</th>
<th>作者</th>
<th>标签</th>
<th>置顶</th>
<th>发布时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="posts-tbody"></tbody>
</table>
</div>
<div id="loading-spinner" class="text-center py-8 text-slate-500 hidden">
<svg class="animate-spin h-6 w-6 mx-auto text-cyan-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<span class="text-sm">加载中...</span>
</div>
<div id="empty-msg" class="text-center py-12 text-slate-400 hidden">暂无帖子</div>
<div id="empty-msg" class="text-center py-12 text-slate-500 hidden">暂无帖子</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
const tagClassMap = {
'讨论': 'bg-blue-100 text-blue-800',
'求助': 'bg-yellow-100 text-yellow-800',
'分享': 'bg-green-100 text-green-800',
'公告': 'bg-red-100 text-red-800'
'讨论': 'bg-blue-500/20 text-blue-400 border-blue-500/30',
'求助': 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30',
'分享': 'bg-green-500/20 text-green-400 border-green-500/30',
'公告': 'bg-red-500/20 text-red-400 border-red-500/30'
};
async function loadPosts() {
@@ -79,19 +81,19 @@ async function loadPosts() {
let html = '';
data.posts.forEach(p => {
const tagClass = tagClassMap[p.tag] || 'bg-slate-100 text-slate-800';
const tagClass = tagClassMap[p.tag] || 'bg-slate-500/20 text-slate-400 border-slate-500/30';
html += `<tr>
<td class="px-6 py-4 text-sm text-slate-900">${p.id}</td>
<td class="px-6 py-4 text-sm text-slate-900 max-w-xs truncate">${p.title}</td>
<td class="px-6 py-4 text-sm text-slate-500">${p.author}</td>
<td class="px-6 py-4"><span class="px-2 py-1 text-xs rounded-full ${tagClass}">${p.tag || '-'}</span></td>
<td class="px-6 py-4">
<span class="px-2 py-1 text-xs rounded-full ${p.pinned ? 'bg-orange-100 text-orange-800' : 'bg-slate-100 text-slate-500'}">${p.pinned ? '已置顶' : '未置顶'}</span>
<td>${p.id}</td>
<td class="font-medium text-slate-200 max-w-xs truncate">${p.title}</td>
<td class="text-slate-400">${p.author}</td>
<td><span class="badge-futuristic ${tagClass}">${p.tag || '-'}</span></td>
<td>
<span class="badge-futuristic ${p.pinned ? 'bg-orange-500/20 text-orange-400 border-orange-500/30' : 'bg-slate-500/20 text-slate-400 border-slate-500/30'}">${p.pinned ? '已置顶' : '未置顶'}</span>
</td>
<td class="px-6 py-4 text-sm text-slate-500">${p.created_at}</td>
<td class="px-6 py-4 space-x-2">
<button onclick="togglePin(${p.id}, ${p.pinned})" class="px-2 py-1 text-xs ${p.pinned ? 'bg-slate-100 text-slate-700 border-slate-300' : 'bg-orange-100 text-orange-700 border-orange-300'} border rounded hover:opacity-80">${p.pinned ? '取消置顶' : '置顶'}</button>
<button onclick="deletePost(${p.id}, '${p.title.replace(/'/g, "\\'")}')" class="px-2 py-1 text-xs bg-red-100 text-red-700 border border-red-300 rounded hover:bg-red-200">删除</button>
<td class="text-slate-400">${p.created_at}</td>
<td class="space-x-2">
<button onclick="togglePin(${p.id}, ${p.pinned})" class="${p.pinned ? 'btn-outline-futuristic' : 'btn-futuristic'} px-3 py-1 text-xs">${p.pinned ? '取消置顶' : '置顶'}</button>
<button onclick="deletePost(${p.id}, '${p.title.replace(/'/g, "\\'")}')" class="btn-outline-futuristic px-3 py-1 text-xs border-red-500/30 text-red-400 hover:bg-red-500/20 hover:border-red-500/50">删除</button>
</td>
</tr>`;
});