Merge branch 'table' into 'master'

Table

See merge request mathwave/sprint!15
This commit is contained in:
Egor Matveev 2022-04-05 22:37:09 +00:00
commit 88e9074015
8 changed files with 97 additions and 7 deletions

View File

@ -8,7 +8,7 @@ from django.db.models import JSONField
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from Main.models import Set from Main.models import Set, SetTask
from Main.models.solution_file import SolutionFile from Main.models.solution_file import SolutionFile
from Main.models.task import Task from Main.models.task import Task
from Sprint.settings import CONSTS from Sprint.settings import CONSTS
@ -32,6 +32,10 @@ class Solution(models.Model):
models.Index(fields=['set', '-time_sent']), models.Index(fields=['set', '-time_sent']),
] ]
@cached_property
def settask(self):
return SetTask.objects.filter(set=self.set, task=self.task).first()
@property @property
def percentage_done(self): def percentage_done(self):
if self.test is None: if self.test is None:

View File

@ -29,6 +29,9 @@ class UserInfo(models.Model):
verified = models.BooleanField(default=False) verified = models.BooleanField(default=False)
teacher = models.BooleanField(default=False) teacher = models.BooleanField(default=False)
def __str__(self):
return self.surname + ' ' + self.name
@property @property
def tasks_solved(self): def tasks_solved(self):
fltr = Task.objects.filter(solution__result=CONSTS["ok_status"], solution__user=self.user).distinct() fltr = Task.objects.filter(solution__result=CONSTS["ok_status"], solution__user=self.user).distinct()

View File

@ -22,4 +22,14 @@ def settask(set, task):
@register.filter('startswith') @register.filter('startswith')
def startswith(s, prefix): def startswith(s, prefix):
return s.startswith(prefix) return s is not None and s.startswith(prefix)
@register.filter('make_pair')
def make_pair(user, task):
return user, task
@register.filter('get_info')
def get_info(data, pair):
return data.get(pair)

View File

@ -13,10 +13,18 @@ class SolutionsTableView(BaseView):
set: Optional[Set] = None set: Optional[Set] = None
task: Optional[Task] = None task: Optional[Task] = None
setTask: Optional[SetTask] = None setTask: Optional[SetTask] = None
look: int
@property
def view_file(self):
if self.look == 0:
return "solutions_table.html"
return "solutions_table_1.html"
def pre_handle(self): def pre_handle(self):
if 'page' not in self.request.GET: if 'page' not in self.request.GET:
raise AccessError() raise AccessError()
self.look = int(self.request.GET.get('look') or 0)
self.page = int(self.request.GET['page']) self.page = int(self.request.GET['page'])
if self.setTask is not None: if self.setTask is not None:
self.set = self.setTask.set self.set = self.setTask.set
@ -37,6 +45,16 @@ class SolutionsTableView(BaseView):
raise AccessError() raise AccessError()
else: else:
queryset = queryset.filter(user=self.request.user, task=self.task, set=self.set) queryset = queryset.filter(user=self.request.user, task=self.task, set=self.set)
if self.look == 1:
data = dict()
users = set()
for solution in queryset.order_by('id'): # type: Solution
if (solution.user_id, solution.settask.id) not in data or data[(solution.user_id, solution.settask.id)] != 'OK':
data[(solution.user_id, solution.settask.id)] = solution.result
users.add(solution.user)
self.context['data'] = data
self.context['users'] = sorted(users, key=lambda u: str(u.userinfo))
return
offset = self.page_size * (self.page - 1) offset = self.page_size * (self.page - 1)
limit = self.page_size limit = self.page_size
self.context["solutions"] = queryset.order_by("-id")[offset:offset + limit] self.context["solutions"] = queryset.order_by("-id")[offset:offset + limit]

View File

@ -50,7 +50,7 @@
Результат Результат
</td> </td>
<td> <td>
<span class="badge badge-{% if solution.result == in_queue_status %}secondary{% else %}{% if solution.result == ok_status %}success{% else %}{% if solution.result == testing_status %}info{% else %}danger{% endif %}{% endif %}{% endif %}">{% if solution.result == testing_status %}<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="circle-notch" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="width: 20px;" class="svg-inline--fa fa-circle-notch fa-w-16 fa-spin fa-lg"><path fill="currentColor" d="M288 39.056v16.659c0 10.804 7.281 20.159 17.686 23.066C383.204 100.434 440 171.518 440 256c0 101.689-82.295 184-184 184-101.689 0-184-82.295-184-184 0-84.47 56.786-155.564 134.312-177.219C216.719 75.874 224 66.517 224 55.712V39.064c0-15.709-14.834-27.153-30.046-23.234C86.603 43.482 7.394 141.206 8.003 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.788 504 256c0-115.633-79.14-212.779-186.211-240.236C302.678 11.889 288 23.456 288 39.056z" class=""></path></svg> {% endif %}{{ solution.result }}</span> <span class="badge badge-{% if solution.result == in_queue_status %}secondary{% else %}{% if solution.result == ok_status %}success{% else %}{% if solution.result|startswith:testing_status %}info{% else %}danger{% endif %}{% endif %}{% endif %}">{% if solution.result == testing_status %}<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="circle-notch" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="width: 20px;" class="svg-inline--fa fa-circle-notch fa-w-16 fa-spin fa-lg"><path fill="currentColor" d="M288 39.056v16.659c0 10.804 7.281 20.159 17.686 23.066C383.204 100.434 440 171.518 440 256c0 101.689-82.295 184-184 184-101.689 0-184-82.295-184-184 0-84.47 56.786-155.564 134.312-177.219C216.719 75.874 224 66.517 224 55.712V39.064c0-15.709-14.834-27.153-30.046-23.234C86.603 43.482 7.394 141.206 8.003 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.788 504 256c0-115.633-79.14-212.779-186.211-240.236C302.678 11.889 288 23.456 288 39.056z" class=""></path></svg> {% endif %}{{ solution.result }}</span>
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -1,12 +1,25 @@
{% extends 'base_main.html' %} {% extends 'base_main.html' %}
{% block scripts %} {% block scripts %}
var look = 0;
var page = 1; var page = 1;
function setLook(number) {
look = number;
var n = number.toString();
var butid = 'button' + n;
document.getElementById(butid).classList.add('btn-dark');
document.getElementById(butid).classList.remove('btn-light');
document.getElementById(butid).focused = false;
butid = 'button' + (1 - number).toString();
document.getElementById(butid).classList.remove('btn-dark');
document.getElementById(butid).classList.add('btn-light');
document.getElementById(butid).focused = false;
}
function setPage(number) { function setPage(number) {
page = number; page = number;
} }
function doPoll() { function doPoll() {
jQuery.get('/polling/solutions_table?{{ query }}&teacher=true&page=' + page.toString(), function(data) { jQuery.get('/polling/solutions_table?{{ query }}&teacher=true&page=' + page.toString() + '&look=' + look.toString(), function(data) {
var e = document.getElementById('solutions'); var e = document.getElementById('solutions');
if (e.innerHTML !== data) if (e.innerHTML !== data)
e.innerHTML = data; e.innerHTML = data;
@ -24,7 +37,13 @@
{% block main %} {% block main %}
<h2>Решения <a href="{% if in_set %}/set?set_id={{ set.id }}{% else %}/task?task_id={{ task.id }}{% endif %}">{% if in_set %}{{ set.name }}{% else %}{{ task.name }}{% endif %}</a></h2> <h2>Решения <a href="{% if in_set %}/set?set_id={{ set.id }}{% else %}/task?task_id={{ task.id }}{% endif %}">{% if in_set %}{{ set.name }}{% else %}{{ task.name }}{% endif %}</a></h2>
<h4>Фильтр</h4> <table style="margin-bottom: 10px;">
<tr>
<td><button class="btn btn-dark" id="button0" onclick="setLook(0)">Список</button></td>
<td><button class="btn btn-light" id="button1" onclick="setLook(1)">Таблица</button></td>
</tr>
</table>
<!--h4>Фильтр</h4>
<div> <div>
<select name="set_id" style="width: 33%"> <select name="set_id" style="width: 33%">
<option value="0">Все сеты</option> <option value="0">Все сеты</option>
@ -44,6 +63,6 @@
<option value="{{ user.username }}" {% if user.username == username %}selected{% endif %}>{{ user.userinfo }}</option> <option value="{{ user.username }}" {% if user.username == username %}selected{% endif %}>{{ user.userinfo }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div-->
<div id="solutions"></div> <div id="solutions"></div>
{% endblock %} {% endblock %}

View File

@ -7,7 +7,7 @@
<th scope="col">Язык</th> <th scope="col">Язык</th>
<th scope="col">Результат</th> <th scope="col">Результат</th>
</thead> </thead>
<tbody id="solutions"> <tbody>
{% for solution in solutions %} {% for solution in solutions %}
<tr> <tr>
<td> <td>

View File

@ -0,0 +1,36 @@
{% load filters %}
<table class="table-bordered" style="margin-top: 30px; table-layout: fixed; width: 100%;">
<thead>
<th scope="col"></th>
{% for task in set.settasks_ordered %}
<th style="text-align: center;" scope="col">{{ task.name }}</th>
{% endfor %}
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user.userinfo }}</td>
{% for task in set.settasks_ordered %}
<td style="text-align: center;">
{% with pair=user.id|make_pair:task.id %}
{% with result=data|get_info:pair %}
{% if result == in_queue_status %}
<span class="badge badge-secondary">{{ result }}</span>
{% else %}{% if result == ok_status %}
<span class="badge badge-success">{{ result }}</span>
{% else %}{% if result|startswith:testing_status %}
<span class="badge badge-info">{{ result }}</span>
{% else %}{% if result %}
<span class="badge badge-danger">{{ result }}</span>
{% else %}
<span class="badge badge-warning">-</span>
{% endif %}{% endif %}{% endif %}{% endif %}
{% endwith %}
{% endwith %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>