Accept Merge Request #113 增加了比赛列表页 : (hohoTT-dev -> dev)

Merge Request: 增加了比赛列表页
Created By: @hohoTT
Accepted By: @virusdefender
URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/113
This commit is contained in:
virusdefender 2015-08-22 20:44:58 +08:00
commit edd0f9d84c
6 changed files with 179 additions and 14 deletions

View File

@ -1,15 +1,19 @@
# coding=utf-8 # coding=utf-8
import json import json
import datetime
from django.utils.timezone import localtime
from django.shortcuts import render from django.shortcuts import render
from django.db import IntegrityError from django.db import IntegrityError
from django.utils import dateparse from django.utils import dateparse
from django.db.models import Q from django.db.models import Q
from django.core.paginator import Paginator
from rest_framework.views import APIView from rest_framework.views import APIView
from utils.shortcuts import (serializer_invalid_response, error_response, from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, paginate, rand_str, error_page) success_response, paginate, rand_str, error_page)
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN
from group.models import Group from group.models import Group
from announcement.models import Announcement
from .models import Contest, ContestProblem from .models import Contest, ContestProblem
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer, from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
@ -17,7 +21,11 @@ from .serializers import (CreateContestSerializer, ContestSerializer, EditContes
def contest_page(request, contest_id): def contest_page(request, contest_id):
pass try:
contest = Contest.objects.get(id=contest_id, visible=True)
except Contest.DoesNotExist:
return error_page(request, u"比赛不存在")
return render(request, "oj/contest/problems.html", {"contest": contest})
class ContestAdminAPIView(APIView): class ContestAdminAPIView(APIView):
@ -221,3 +229,46 @@ class ContestProblemAdminAPIView(APIView):
Q(description__contains=keyword)) Q(description__contains=keyword))
return paginate(request, contest_problem, ContestProblemSerializer) return paginate(request, contest_problem, ContestProblemSerializer)
def contest_list_page(request, page=1):
# 正常情况
contests = Contest.objects.filter(visible=True)
# 搜索的情况
keyword = request.GET.get("keyword", None)
if keyword:
contests = contests.filter(title__contains=keyword)
# 筛选我能参加的比赛
join = request.GET.get("join", None)
if join:
contests = Contest.objects.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all()))
paginator = Paginator(contests, 20)
try:
current_page = paginator.page(int(page))
except Exception:
return error_page(request, u"不存在的页码")
previous_page = next_page = None
try:
previous_page = current_page.previous_page_number()
except Exception:
pass
try:
next_page = current_page.next_page_number()
except Exception:
pass
# 右侧的公告列表
announcements = Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time")
# 系统当前时间
now = datetime.datetime.now()
return render(request, "oj/contest/contest_list.html",
{"contests": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page,
"keyword": keyword, "announcements": announcements,
"join": join, "now": now})

View File

@ -40,12 +40,15 @@ urlpatterns = [
url(r'^api/admin/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"), url(r'^api/admin/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"),
url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"), url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"), url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^contest/(?P<contest_id>\d+)/$', "contest.views.contest_page", name="contest_page"),
url(r'^announcement/(?P<announcement_id>\d+)/$', "announcement.views.announcement_page", url(r'^announcement/(?P<announcement_id>\d+)/$', "announcement.views.announcement_page",
name="announcement_page"), name="announcement_page"),
url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"), url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"),
name="add_contest_page"), name="add_contest_page"),
url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"), url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"), url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^contests/$', "contest.views.contest_list_page", name="contest_list_page"),
url(r'^contests/(?P<page>\d+)/$', "contest.views.contest_list_page", name="contest_list_page"),
url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html$', AdminTemplateView.as_view(), url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html$', AdminTemplateView.as_view(),
name="admin_template"), name="admin_template"),
url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"), url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"),

View File

@ -0,0 +1,12 @@
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
公告
</h3></div>
<div class="panel-body">
{% for item in announcements %}
<p>{{ forloop.counter }}.&nbsp;&nbsp;<a href="/announcement/{{ item.id }}/" target="_blank">{{ item.title }}</a></p>
{% endfor %}
</div>
</div>

View File

@ -0,0 +1,81 @@
{% extends "oj_base.html" %}
{% block body %}
{% load contest %}
<div class="container main">
<div class="row">
<div class="col-lg-9">
<div class="row">
<div class="right">
<form class="form-inline" method="get">
<div class="form-group-sm">
<input name="keyword" class="form-control" placeholder="请输入关键词">
<input type="submit" value="搜索" class="btn btn-primary">
</div>
</form>
</div>
</div>
<div>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>比赛名称</th>
<th>开始时间</th>
<th>比赛类型</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for item in contests %}
<tr>
<th scope="row"><a href="/contest/{{ item.id }}/">{{ item.id }}</a></th>
<td><a href="/contest/{{ item.id }}/">{{ item.title }}</a></td>
<td>{{ item.start_time }}</td>
{% ifequal item.contest_type 0 %}
<td>小组赛</td>
{% endifequal %}
{% ifequal item.contest_type 1 %}
<td>公开赛</td>
{% endifequal %}
{% ifequal item.contest_type 2 %}
<td>公开赛(密码保护)</td>
{% endifequal %}
<td class="{{ item|contest_status_color }}">{{ item|contest_status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-group">
<label>仅显示当前可参加的比赛
<input id="join" type="checkbox" {% if join %}checked{% endif %} onchange="if(this.checked){location.href='/contests/?join=True'}else{location.href='/contests/'}">
</label>
</div>
<nav>
<ul class="pager">
{% if previous_page %}
<li class="previous">
<a href="/contests/{{ previous_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if join %}?join={{ join }}{% endif %}">
<span aria-hidden="true">&larr;</span> 上一页</a></li>
{% endif %}
{% if next_page %}
<li class="next">
<a href="/contests/{{ next_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if join %}?join={{ join }}{% endif %}">下一页 <span
aria-hidden="true">&rarr;</span></a></li>
{% endif %}
</ul>
</nav>
</div>
</div>
<div class="col-lg-3">
{% include "oj/announcement/_announcement_panel.html" %}
</div>
</div>
</div>
{% endblock %}
{% block js_block %}
{% endblock %}

View File

@ -55,18 +55,7 @@
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<div class="panel panel-info"> {% include "oj/announcement/_announcement_panel.html" %}
<div class="panel-heading">
<h3 class="panel-title">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
公告
</h3></div>
<div class="panel-body">
{% for item in announcements %}
{{ forloop.counter }}.&nbsp;&nbsp;<a href="/announcement/{{ item.id }}/" target="_blank">{{ item.title }}</a>
{% endfor %}
</div>
</div>
<div class="panel panel-info"> <div class="panel panel-info">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title"> <h3 class="panel-title">

View File

@ -0,0 +1,29 @@
# coding=utf-8
import datetime
from django.utils.timezone import localtime
def get_contest_status(contest):
now = datetime.datetime.now()
if localtime(contest.start_time).replace(tzinfo=None) > now:
return "没有开始"
if localtime(contest.end_time).replace(tzinfo=None) < now:
return "已经结束"
return "正在进行"
def get_contest_status_color(contest):
now = datetime.datetime.now()
if localtime(contest.start_time).replace(tzinfo=None) > now:
return "info"
if localtime(contest.end_time).replace(tzinfo=None) < now:
return "warning"
return "success"
from django import template
register = template.Library()
register.filter("contest_status", get_contest_status)
register.filter("contest_status_color", get_contest_status_color)