115 lines
5.1 KiB
HTML
115 lines
5.1 KiB
HTML
{% extends "admin_base.html" %}
|
|
|
|
{% block title %}杯赛管理 - 智联青云管理后台{% endblock %}
|
|
|
|
{% block admin_content %}
|
|
<div class="space-y-6">
|
|
<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="futuristic-card-dark overflow-hidden">
|
|
<div class="table-responsive">
|
|
<table class="table-futuristic" style="min-width: 900px;">
|
|
<thead>
|
|
<tr>
|
|
<th style="min-width: 60px;">ID</th>
|
|
<th style="min-width: 200px;">名称</th>
|
|
<th style="min-width: 150px;">主办方</th>
|
|
<th style="min-width: 120px;">状态</th>
|
|
<th style="min-width: 150px;">开始日期</th>
|
|
<th style="min-width: 180px;">操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="contests-tbody">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div id="empty-msg" class="text-center py-12 text-slate-500 hidden">暂无杯赛</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
const isAdmin = {{ 'true' if user and user.role == 'admin' else 'false' }};
|
|
const statusMap = {
|
|
'upcoming': ['即将开始', 'bg-blue-500/20 text-blue-400 border-blue-500/30'],
|
|
'registering': ['正在报名', 'bg-green-500/20 text-green-400 border-green-500/30'],
|
|
'ongoing': ['进行中', 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30'],
|
|
'ended': ['已结束', 'bg-slate-500/20 text-slate-400 border-slate-500/30'],
|
|
'abolished': ['已废止', 'bg-red-500/20 text-red-400 border-red-500/30']
|
|
};
|
|
|
|
async function loadContests() {
|
|
try {
|
|
const res = await fetch('/api/admin/contests');
|
|
const data = await res.json();
|
|
const tbody = document.getElementById('contests-tbody');
|
|
const empty = document.getElementById('empty-msg');
|
|
if (!data.success || !data.contests.length) {
|
|
empty.classList.remove('hidden');
|
|
return;
|
|
}
|
|
let html = '';
|
|
data.contests.forEach(c => {
|
|
const [statusText, statusClass] = statusMap[c.status] || ['未知', 'bg-slate-500/20 text-slate-400 border-slate-500/30'];
|
|
const abolishBtn = c.status !== 'abolished'
|
|
? `<button onclick="abolishContest(${c.id}, '${c.name.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>`
|
|
: '';
|
|
const deleteBtn = isAdmin && c.status === 'abolished'
|
|
? `<button onclick="deleteContest(${c.id}, '${c.name.replace(/'/g, "\\'")}')" class="btn-outline-futuristic px-3 py-1 text-xs border-orange-500/30 text-orange-400 hover:bg-orange-500/20 hover:border-orange-500/50">删除</button>`
|
|
: '';
|
|
html += `<tr>
|
|
<td>${c.id}</td>
|
|
<td class="font-medium text-slate-200" style="max-width: 200px; white-space: normal; word-wrap: break-word;">${c.name}</td>
|
|
<td class="text-slate-400" style="max-width: 150px; white-space: normal; word-wrap: break-word;">${c.organizer || '-'}</td>
|
|
<td><span class="badge-futuristic ${statusClass}">${statusText}</span></td>
|
|
<td class="text-slate-400">${c.start_date || '-'}</td>
|
|
<td class="space-x-2">
|
|
<a href="/contests/${c.id}" class="text-xs text-cyan-400 hover:text-cyan-300 hover:underline">查看</a>
|
|
${abolishBtn}
|
|
${deleteBtn}
|
|
</td>
|
|
</tr>`;
|
|
});
|
|
tbody.innerHTML = html;
|
|
} catch(e) {
|
|
console.error(e);
|
|
}
|
|
}
|
|
|
|
async function abolishContest(id, name) {
|
|
if (!confirm(`确定要废止杯赛「${name}」吗?\n\n废止后:\n- 该杯赛下所有考试将被关闭\n- 无法再报名或参加考试\n- 数据将保留,可再执行删除彻底移除`)) return;
|
|
try {
|
|
const res = await fetch(`/api/admin/contests/${id}/abolish`, {method: 'POST'});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
alert('杯赛已废止');
|
|
loadContests();
|
|
} else {
|
|
alert(data.message || '操作失败');
|
|
}
|
|
} catch(e) {
|
|
alert('网络错误');
|
|
}
|
|
}
|
|
|
|
async function deleteContest(id, name) {
|
|
if (!confirm(`确定要彻底删除杯赛「${name}」吗?\n\n删除后:\n- 杯赛将从系统中完全移除\n- 不再显示在首页杯赛数量中\n- 用户无法再看到该杯赛\n- 此操作不可恢复!`)) return;
|
|
try {
|
|
const res = await fetch(`/api/admin/contests/${id}/delete`, {method: 'POST'});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
alert('杯赛已彻底删除');
|
|
loadContests();
|
|
} else {
|
|
alert(data.message || '操作失败');
|
|
}
|
|
} catch(e) {
|
|
alert('网络错误');
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', loadContests);
|
|
</script>
|
|
{% endblock %}
|