227 lines
10 KiB
HTML
227 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{% block title %}评委系统{% endblock %}</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
body {
|
|
font-family: 'Inter', sans-serif;
|
|
background-color: #f3f4f6;
|
|
}
|
|
.glass-effect {
|
|
background: rgba(255, 255, 255, 0.95);
|
|
backdrop-filter: blur(10px);
|
|
}
|
|
.animate-fade-in {
|
|
animation: fadeIn 0.5s ease-out;
|
|
}
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(10px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
/* Custom Scrollbar */
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
::-webkit-scrollbar-track {
|
|
background: #f1f1f1;
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background: #cbd5e1;
|
|
border-radius: 4px;
|
|
}
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: #94a3b8;
|
|
}
|
|
|
|
/* Modal Transitions */
|
|
.modal {
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
transition: all 0.3s ease-in-out;
|
|
}
|
|
.modal.active {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
}
|
|
.modal-content {
|
|
transform: scale(0.95);
|
|
transition: transform 0.3s ease-in-out;
|
|
}
|
|
.modal.active .modal-content {
|
|
transform: scale(1);
|
|
}
|
|
|
|
/* Status Badges */
|
|
.status-submitted, .status-succeeded {
|
|
background-color: #dcfce7;
|
|
color: #166534;
|
|
}
|
|
.status-pending {
|
|
background-color: #fef9c3;
|
|
color: #854d0e;
|
|
}
|
|
.status-processing {
|
|
background-color: #dbeafe;
|
|
color: #1e40af;
|
|
}
|
|
.status-failed {
|
|
background-color: #fee2e2;
|
|
color: #991b1b;
|
|
}
|
|
</style>
|
|
{% block extra_css %}{% endblock %}
|
|
</head>
|
|
<body class="text-gray-800 antialiased min-h-screen flex flex-col">
|
|
{% if request.session.judge_id %}
|
|
<header class="bg-white shadow-sm sticky top-0 z-50 transition-all duration-300">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex justify-between h-16">
|
|
<div class="flex items-center">
|
|
<a href="{% url 'judge_dashboard' %}" class="flex-shrink-0 flex items-center gap-2 text-blue-600 hover:text-blue-700 transition-colors">
|
|
<i class="fas fa-gavel text-xl"></i>
|
|
<h1 class="font-bold text-xl tracking-tight">评委评分系统</h1>
|
|
</a>
|
|
<nav class="hidden md:ml-8 md:flex md:space-x-8">
|
|
<a href="{% url 'judge_dashboard' %}"
|
|
class="inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium transition-colors duration-200
|
|
{% if request.resolver_match.url_name == 'judge_dashboard' %}border-blue-500 text-gray-900{% else %}border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700{% endif %}">
|
|
<i class="fas fa-th-list mr-2"></i>项目列表
|
|
</a>
|
|
{% if request.session.judge_role == 'judge' or request.session.judge_role == 'guest' %}
|
|
<a href="{% url 'judge_ai_manage' %}"
|
|
class="inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium transition-colors duration-200
|
|
{% if request.resolver_match.url_name == 'judge_ai_manage' %}border-blue-500 text-gray-900{% else %}border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700{% endif %}">
|
|
<i class="fas fa-robot mr-2"></i>AI服务管理
|
|
</a>
|
|
{% endif %}
|
|
</nav>
|
|
</div>
|
|
<div class="flex items-center">
|
|
<div class="hidden md:flex items-center mr-6 text-sm">
|
|
<span class="font-medium text-gray-700 mr-2">{{ request.session.judge_name }}</span>
|
|
<span class="px-2 py-0.5 rounded-full text-xs font-medium bg-blue-50 text-blue-700 border border-blue-100">
|
|
{% if request.session.judge_role == 'judge' %}评委
|
|
{% elif request.session.judge_role == 'guest' %}嘉宾
|
|
{% elif request.session.judge_role == 'contestant' %}选手
|
|
{% else %}{{ request.session.judge_role }}{% endif %}
|
|
</span>
|
|
</div>
|
|
<button onclick="logout()" class="ml-4 px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-red-500 hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-all shadow-sm hover:shadow">
|
|
<i class="fas fa-sign-out-alt mr-1"></i>退出
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile Navigation -->
|
|
<div class="md:hidden border-t border-gray-200 bg-gray-50">
|
|
<div class="p-4 border-b border-gray-200 flex items-center justify-between">
|
|
<span class="font-medium text-gray-900">{{ request.session.judge_name }}</span>
|
|
<span class="px-2 py-0.5 rounded-full text-xs font-medium bg-blue-50 text-blue-700 border border-blue-100">
|
|
{% if request.session.judge_role == 'judge' %}评委
|
|
{% elif request.session.judge_role == 'guest' %}嘉宾
|
|
{% elif request.session.judge_role == 'contestant' %}选手
|
|
{% else %}{{ request.session.judge_role }}{% endif %}
|
|
</span>
|
|
</div>
|
|
<div class="grid grid-cols-2 divide-x divide-gray-200">
|
|
<a href="{% url 'judge_dashboard' %}" class="block py-3 text-center text-sm font-medium text-gray-700 hover:bg-gray-100 hover:text-blue-600">
|
|
<i class="fas fa-th-list mb-1 block text-lg"></i>项目列表
|
|
</a>
|
|
{% if request.session.judge_role == 'judge' or request.session.judge_role == 'guest' %}
|
|
<a href="{% url 'judge_ai_manage' %}" class="block py-3 text-center text-sm font-medium text-gray-700 hover:bg-gray-100 hover:text-blue-600">
|
|
<i class="fas fa-robot mb-1 block text-lg"></i>AI管理
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</header>
|
|
{% endif %}
|
|
|
|
<main class="flex-grow w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 animate-fade-in">
|
|
{% if messages %}
|
|
<div class="mb-6 space-y-2">
|
|
{% for message in messages %}
|
|
<div class="rounded-md p-4 shadow-sm border-l-4 flex items-center
|
|
{% if message.tags == 'error' %}bg-red-50 border-red-500 text-red-700
|
|
{% elif message.tags == 'success' %}bg-green-50 border-green-500 text-green-700
|
|
{% else %}bg-blue-50 border-blue-500 text-blue-700{% endif %}">
|
|
<i class="fas {% if message.tags == 'error' %}fa-exclamation-circle{% elif message.tags == 'success' %}fa-check-circle{% else %}fa-info-circle{% endif %} mr-3 text-lg"></i>
|
|
<p class="text-sm font-medium">{{ message }}</p>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
|
|
<footer class="bg-white border-t border-gray-200 mt-auto">
|
|
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
|
<p class="text-center text-sm text-gray-500">
|
|
© {% now "Y" %} 评委评分系统. All rights reserved.
|
|
</p>
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
function logout() {
|
|
if(confirm('确定要退出登录吗?')) {
|
|
window.location.href = "{% url 'judge_logout' %}";
|
|
}
|
|
}
|
|
|
|
// 通用 Fetch 封装,处理 CSRF
|
|
function getCookie(name) {
|
|
let cookieValue = null;
|
|
if (document.cookie && document.cookie !== '') {
|
|
const cookies = document.cookie.split(';');
|
|
for (let i = 0; i < cookies.length; i++) {
|
|
const cookie = cookies[i].trim();
|
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return cookieValue;
|
|
}
|
|
const csrftoken = getCookie('csrftoken');
|
|
|
|
async function apiCall(url, method='POST', data=null) {
|
|
const options = {
|
|
method: method,
|
|
headers: {
|
|
'X-CSRFToken': csrftoken
|
|
}
|
|
};
|
|
if (data && !(data instanceof FormData)) {
|
|
options.headers['Content-Type'] = 'application/json';
|
|
options.body = JSON.stringify(data);
|
|
} else if (data instanceof FormData) {
|
|
options.body = data;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(url, options);
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
return await response.json();
|
|
} catch (e) {
|
|
console.error('API Error:', e);
|
|
alert('操作失败: ' + e.message);
|
|
throw e;
|
|
}
|
|
}
|
|
</script>
|
|
{% block extra_js %}{% endblock %}
|
|
</body>
|
|
</html>
|