first commit
This commit is contained in:
0
competition/__init__.py
Normal file
0
competition/__init__.py
Normal file
86
competition/admin.py
Normal file
86
competition/admin.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from competition.models import (BankInfo, ChoiceInfo, CompetitionKindInfo,
|
||||
CompetitionQAInfo, FillInBlankInfo)
|
||||
|
||||
|
||||
class CompetitionKindInfoAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
比赛信息后台
|
||||
"""
|
||||
|
||||
list_display = ('kind_id', 'account_id', 'app_id', 'bank_id', 'kind_name', 'total_score', 'question_num', 'total_partin_num', 'status', 'created_at', 'updated_at')
|
||||
list_filter = ('account_id', 'status')
|
||||
search_fields = ('kind_name', 'kind_id', 'app_id', 'account_id',)
|
||||
readonly_fields = ('kind_id', 'total_partin_num',)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
obj.save()
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
obj.delete()
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
return self.readonly_fields
|
||||
|
||||
|
||||
class BankInfoAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
题库后台配置
|
||||
"""
|
||||
|
||||
list_display = ('bank_id', 'bank_type', 'kind_num', 'choice_num', 'fillinblank_num', 'partin_num')
|
||||
list_filter = ('bank_type', 'bank_id',)
|
||||
search_fields = ('bank_id',)
|
||||
readonly_fields = ('bank_id', 'choice_num', 'fillinblank_num', 'kind_num', 'partin_num')
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
obj.choice_num = ChoiceInfo.objects.filter(bank_id=obj.bank_id).count()
|
||||
obj.fillinblank_num = FillInBlankInfo.objects.filter(bank_id=obj.bank_id).count()
|
||||
obj.save()
|
||||
|
||||
|
||||
class ChoiceInfoAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
选择题配置后台
|
||||
"""
|
||||
|
||||
list_display = ('bank_id', 'question', 'answer', 'item1', 'item2', 'item3', 'item4', 'source', 'status', 'created_at', 'updated_at')
|
||||
list_filter = ('bank_id', 'status')
|
||||
search_fields = ('bank_id', 'question', 'answer', 'item1', 'item2', 'item3', 'item4')
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
obj.save()
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
obj.delete()
|
||||
|
||||
|
||||
class FillInBlankInfoAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
填空题配置后台
|
||||
"""
|
||||
|
||||
list_display = ('bank_id', 'question', 'answer', 'source', 'status', 'created_at', 'updated_at')
|
||||
list_filter = ('bank_id', 'status')
|
||||
search_fields = ('bank_id', 'question', 'answer')
|
||||
|
||||
|
||||
class CompetitionQAInfoAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
答题记录信息后台
|
||||
"""
|
||||
|
||||
list_display = ('kind_id', 'status', 'uid', 'qa_id', 'score', 'created_at', 'updated_at')
|
||||
list_filter = ('kind_id', 'uid', 'qa_id', 'started', 'finished', 'status')
|
||||
search_fields = ('uid', 'kind_id', )
|
||||
readonly_fields = ('qa_id',)
|
||||
|
||||
|
||||
admin.site.register(CompetitionKindInfo, CompetitionKindInfoAdmin)
|
||||
admin.site.register(CompetitionQAInfo, CompetitionQAInfoAdmin)
|
||||
admin.site.register(ChoiceInfo, ChoiceInfoAdmin)
|
||||
admin.site.register(FillInBlankInfo, FillInBlankInfoAdmin)
|
||||
admin.site.register(BankInfo, BankInfoAdmin)
|
||||
5
competition/apps.py
Normal file
5
competition/apps.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CompetitionConfig(AppConfig):
|
||||
name = 'competition'
|
||||
287
competition/cop_render.py
Normal file
287
competition/cop_render.py
Normal file
@@ -0,0 +1,287 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import collections
|
||||
import json
|
||||
|
||||
from django.shortcuts import render
|
||||
|
||||
from account.models import Profile
|
||||
from competition.models import BankInfo, CompetitionKindInfo, CompetitionQAInfo
|
||||
from utils.decorators import check_copstatus, check_login
|
||||
from utils.errors import (BankInfoNotFound, CompetitionNotFound,
|
||||
ProfileNotFound, QuestionLogNotFound,
|
||||
QuestionNotSufficient)
|
||||
from utils.redis.rpageconfig import get_pageconfig, get_form_regex
|
||||
from utils.redis.rprofile import get_enter_userinfo
|
||||
from utils.redis.rrank import get_rank, get_rank_data
|
||||
|
||||
import datetime
|
||||
|
||||
def home(request):
|
||||
"""
|
||||
比赛首页首页视图
|
||||
:param request: 请求对象
|
||||
:return: 渲染视图: user_info: 用户信息; kind_info: 比赛信息;is_show_userinfo: 是否展示用户信息表单;user_info_has_entered: 是否已经录入表单;
|
||||
userinfo_fields: 表单字段;option_fields: 表单字段中呈现为下拉框的字段;
|
||||
"""
|
||||
uid = request.GET.get('uid', '') # 获取uid
|
||||
kind_id = request.GET.get('kind_id', '') # 获取kind_id
|
||||
created = request.GET.get('created', '0') # 获取标志位,以后会用到
|
||||
try: # 获取比赛数据
|
||||
kind_info = CompetitionKindInfo.objects.get(kind_id=kind_id)
|
||||
except CompetitionKindInfo.DoesNotExist: # 不存在渲染错误视图
|
||||
return render(request, 'err.html', CompetitionNotFound)
|
||||
try: # 获取题库数据
|
||||
bank_info = BankInfo.objects.get(bank_id=kind_info.bank_id)
|
||||
except BankInfo.DoesNotExist: # 不存在渲染错误视图
|
||||
return render(request, 'err.html', BankInfoNotFound)
|
||||
try: # 获取用户数据
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist: # 不存在渲染错误视图
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
if kind_info.question_num > bank_info.total_question_num: # 比赛出题数量是否小于题库总大小
|
||||
return render(request, 'err.html', QuestionNotSufficient)
|
||||
show_info = get_pageconfig(kind_info.app_id).get('show_info', {}) # 从redis获取页面配置信息
|
||||
is_show_userinfo = show_info.get('is_show_userinfo', False) # 页面配置信息,用来控制答题前是否展示一张表单
|
||||
form_fields = collections.OrderedDict() # 生成一个有序的用来保存表单字段的字典
|
||||
form_regexes = [] # 生成一个空的正则表达式列表
|
||||
if is_show_userinfo:
|
||||
userinfo_fields = show_info.get('userinfo_fields', '').split('#') # 从页面配置中获取userinfo_fields
|
||||
for i in userinfo_fields: # 将页面配置的每个正则表达式取出来放入正则表达式列表
|
||||
form_regexes.append(get_form_regex(i))
|
||||
userinfo_field_names = show_info.get('userinfo_field_names', '').split('#')
|
||||
for i in range(len(userinfo_fields)): # 将每个表单字段信息保存到有序的表单字段字典中
|
||||
form_fields.update({userinfo_fields[i]: userinfo_field_names[i]})
|
||||
return render(request, 'competition/index.html', { # 渲染页面
|
||||
'user_info': profile.data,
|
||||
'kind_info': kind_info.data,
|
||||
'bank_info': bank_info.data,
|
||||
'is_show_userinfo': 'true' if is_show_userinfo else 'false',
|
||||
'userinfo_has_enterd': 'true' if get_enter_userinfo(kind_id, uid) else 'false',
|
||||
'userinfo_fields': json.dumps(form_fields) if form_fields else '{}',
|
||||
'option_fields': json.dumps(show_info.get('option_fields', '')),
|
||||
'field_regexes': form_regexes,
|
||||
'created': created
|
||||
})
|
||||
|
||||
|
||||
def games(request, s):
|
||||
"""
|
||||
获取所有比赛接口
|
||||
:param request: 请求对象
|
||||
:param s: 请求关键字
|
||||
:return: 返回该请求关键字对应的所有比赛类别
|
||||
"""
|
||||
|
||||
if s == 'hot':
|
||||
# 筛选条件: 完成时间大于当前时间;根据参与人数降序排序;根据创建时间降序排序;筛选10个
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc),
|
||||
).order_by('-total_partin_num').order_by('-created_at')[:10]
|
||||
|
||||
elif s == 'tech':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.IT_ISSUE,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'edu':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.EDUCATION,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'culture':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.CULTURE,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'sport':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.SPORT,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'general':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.GENERAL,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'interview':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.INTERVIEW,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
else:
|
||||
kinds = None
|
||||
return render(request, 'competition/games.html', {
|
||||
'kinds': kinds,
|
||||
})
|
||||
|
||||
@check_login
|
||||
@check_copstatus
|
||||
def game(request):
|
||||
"""
|
||||
返回比赛题目信息的视图
|
||||
:param request: 请求对象
|
||||
:return: 渲染视图: user_info: 用户信息;kind_id: 比赛唯一标识;kind_name: 比赛名称;cop_finishat: 比赛结束时间;rule_text: 大赛规则;
|
||||
"""
|
||||
uid = request.GET.get('uid', '') # 获取uid
|
||||
kind_id = request.GET.get('kind_id', '') # 获取kind_id
|
||||
try: # 获取比赛信息
|
||||
kind_info = CompetitionKindInfo.objects.get(kind_id=kind_id)
|
||||
except CompetitionKindInfo.DoesNotExist: # 未获取到渲染错误视图
|
||||
return render(request, 'err.html', CompetitionNotFound)
|
||||
try: # 获取题库信息
|
||||
bank_info = BankInfo.objects.get(bank_id=kind_info.bank_id)
|
||||
except BankInfo.DoesNotExist: # 未获取到,渲染错误视图
|
||||
return render(request, 'err.html', BankInfoNotFound)
|
||||
try: # 获取用户信息
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist: # 未获取到,渲染错误视图
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
if kind_info.question_num > bank_info.total_question_num: # 检查题库大小
|
||||
return render(request, 'err.html', QuestionNotSufficient)
|
||||
pageconfig = get_pageconfig(kind_info.app_id) # 获取页面配置信息
|
||||
return render(request, 'competition/game.html', { # 渲染视图信息
|
||||
'user_info': profile.data,
|
||||
'kind_id': kind_info.kind_id,
|
||||
'kind_name': kind_info.kind_name,
|
||||
'cop_finishat': kind_info.cop_finishat,
|
||||
'period_time': kind_info.period_time,
|
||||
'rule_text': pageconfig.get('text_info', {}).get('rule_text', '')
|
||||
})
|
||||
|
||||
@check_login
|
||||
def result(request):
|
||||
"""
|
||||
比赛结果和排行榜的视图
|
||||
:param request: 请求对象
|
||||
:return: 渲染视图: qa_info: 答题记录数据;user_info: 用户信息数据;kind_info: 比赛信息数据;rank: 该用户当前比赛排名
|
||||
"""
|
||||
|
||||
uid = request.GET.get('uid', '')
|
||||
kind_id = request.GET.get('kind_id', '')
|
||||
qa_id = request.GET.get('qa_id', '')
|
||||
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
|
||||
try:
|
||||
kind_info = CompetitionKindInfo.objects.get(kind_id=kind_id)
|
||||
except CompetitionKindInfo.DoesNotExist:
|
||||
return render(request, 'err.html', CompetitionNotFound)
|
||||
|
||||
try:
|
||||
qa_info = CompetitionQAInfo.objects.get(qa_id=qa_id, uid=uid)
|
||||
except CompetitionQAInfo.DoesNotExist:
|
||||
return render(request, 'err.html', QuestionLogNotFound)
|
||||
|
||||
return render(request, 'competition/result.html', {
|
||||
'qa_info': qa_info.detail,
|
||||
'user_info': profile.data,
|
||||
'kind_info': kind_info.data,
|
||||
'rank': get_rank(kind_id, uid)
|
||||
})
|
||||
|
||||
|
||||
@check_login
|
||||
def rank(request):
|
||||
"""
|
||||
排行榜数据视图
|
||||
:param request: 请求对象
|
||||
:return: 渲染视图: user_info: 用户信息;kind_info: 比赛信息; rank: 所有比赛排名;
|
||||
"""
|
||||
|
||||
uid = request.GET.get('uid', '')
|
||||
kind_id = request.GET.get('kind_id', '')
|
||||
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
|
||||
try:
|
||||
kind_info = CompetitionKindInfo.objects.get(kind_id=kind_id)
|
||||
except CompetitionKindInfo.DoesNotExist:
|
||||
return render(request, 'err.html', CompetitionNotFound)
|
||||
|
||||
ranks, rank_data = get_rank_data(kind_id)
|
||||
for i in range(len(rank_data)):
|
||||
rank_data[i].update({'rank': i + 1})
|
||||
rank_data[i]['time'] = rank_data[i]['time'] / 1000.000
|
||||
|
||||
return render(request, 'competition/rank.html', {
|
||||
'user_info': profile.data,
|
||||
'kind_info': kind_info.data,
|
||||
'rank': rank_data
|
||||
})
|
||||
|
||||
|
||||
@check_login
|
||||
def search(request):
|
||||
"""
|
||||
搜索查询视图
|
||||
:param request: 请求对象
|
||||
:return: 渲染视图: user_info: 用户信息;result:查询结果比赛信息集合;key: 查询结果的关键字,是根据比赛名称查询还是根据赞助商关键字查询的结果
|
||||
"""
|
||||
|
||||
uid = request.GET.get('uid', '')
|
||||
keyword = request.GET.get('keyword', '')
|
||||
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
render(request, 'err.html', ProfileNotFound)
|
||||
|
||||
keyword = keyword.strip(' ')
|
||||
|
||||
kinds = CompetitionKindInfo.objects.filter(kind_name__contains=keyword)
|
||||
key = 'kind'
|
||||
|
||||
if not kinds:
|
||||
kinds = CompetitionKindInfo.objects.filter(sponsor_name__contains=keyword)
|
||||
key = 'sponsor'
|
||||
|
||||
return render(request, 'competition/search.html', {
|
||||
'result': kinds,
|
||||
'key': key or ''
|
||||
})
|
||||
|
||||
|
||||
@check_login
|
||||
def contact(request):
|
||||
"""
|
||||
联系我们视图
|
||||
:param request: 请求对象
|
||||
:return: 渲染视图: user_info: 用户信息
|
||||
"""
|
||||
|
||||
uid = request.GET.get('uid', '')
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
|
||||
return render(request, 'web/contact_us.html', {'user_info': profile.data})
|
||||
|
||||
|
||||
def donate(request):
|
||||
"""
|
||||
捐助视图
|
||||
:param request: 请求对象
|
||||
:return: 渲染视图: user_info: 用户信息
|
||||
"""
|
||||
|
||||
uid = request.GET.get('uid', '')
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
profile = None
|
||||
|
||||
return render(request, 'web/donate.html', {'user_info': profile.data if profile else None})
|
||||
247
competition/game_views.py
Normal file
247
competition/game_views.py
Normal file
@@ -0,0 +1,247 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import datetime
|
||||
import random
|
||||
|
||||
from django.db import transaction
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from account.models import Profile, UserInfo
|
||||
from competition.models import (BankInfo, ChoiceInfo, CompetitionKindInfo,
|
||||
CompetitionQAInfo, FillInBlankInfo)
|
||||
from TimeConvert import TimeConvert as tc
|
||||
|
||||
from utils.check_utils import check_correct_num
|
||||
from utils.decorators import check_copstatus, check_login
|
||||
from utils.errors import BankInfoNotFound, CompetitionError, ProfileError
|
||||
from utils.redis.rprofile import enter_userinfo
|
||||
from utils.redis.rrank import add_to_rank
|
||||
from utils.response import json_response
|
||||
|
||||
|
||||
@check_login
|
||||
@check_copstatus
|
||||
@transaction.atomic
|
||||
def get_questions(request):
|
||||
"""
|
||||
获取题目信息接口
|
||||
:param request: 请求对象
|
||||
:return: 返回json数据: user_info: 用户信息;kind_info: 比赛信息;qa_id: 比赛答题记录;questions: 比赛随机后的题目;
|
||||
"""
|
||||
kind_id = request.GET.get('kind_id', '') # 获取kind_id
|
||||
uid = request.GET.get('uid', '') # 获取uid
|
||||
try: # 获取比赛信息
|
||||
kind_info = CompetitionKindInfo.objects.select_for_update().get(kind_id=kind_id)
|
||||
except CompetitionKindInfo.DoesNotExist: # 未获取到,返回错误码100001
|
||||
return json_response(*CompetitionError.CompetitionNotFound)
|
||||
try: # 获取题库信息
|
||||
bank_info = BankInfo.objects.get(bank_id=kind_info.bank_id)
|
||||
except BankInfo.DoesNotExist: # 未获取到,返回错误码100004
|
||||
return json_response(*CompetitionError.BankInfoNotFound)
|
||||
try: # 获取用户信息
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist: # 未获取到,返回错误码200001
|
||||
return json_response(*ProfileError.ProfileNotFound)
|
||||
qc = ChoiceInfo.objects.filter(bank_id=kind_info.bank_id) # 选择题
|
||||
qf = FillInBlankInfo.objects.filter(bank_id=kind_info.bank_id) # 填空题
|
||||
questions = [] # 将两种题型放到同一个列表中
|
||||
for i in qc.iterator():
|
||||
questions.append(i.data)
|
||||
for i in qf.iterator():
|
||||
questions.append(i.data)
|
||||
question_num = kind_info.question_num # 出题数
|
||||
q_count = bank_info.total_question_num # 总题数
|
||||
if q_count < question_num: # 出题数大于总题数,返回错误码100005
|
||||
return json_response(CompetitionError.QuestionNotSufficient)
|
||||
qs = random.sample(questions, question_num) # 随机分配题目
|
||||
qa_info = CompetitionQAInfo.objects.select_for_update().create( # 创建答题log数据
|
||||
kind_id=kind_id,
|
||||
uid=uid,
|
||||
qsrecord=[q['question'] for q in qs],
|
||||
asrecord=[q['answer'] for q in qs],
|
||||
total_num=question_num,
|
||||
started_stamp=tc.utc_timestamp(ms=True, milli=True), # 设置开始时间戳
|
||||
started=True
|
||||
)
|
||||
for i in qs: # 剔除答案信息
|
||||
i.pop('answer')
|
||||
return json_response(200, 'OK', { # 返回JSON数据,包括题目信息,答题log信息等
|
||||
'kind_info': kind_info.data,
|
||||
'user_info': profile.data,
|
||||
'qa_id': qa_info.qa_id,
|
||||
'questions': qs
|
||||
})
|
||||
|
||||
@csrf_exempt
|
||||
@check_login
|
||||
@check_copstatus
|
||||
@transaction.atomic
|
||||
def submit_answer(request):
|
||||
"""
|
||||
提交答案接口
|
||||
:param request: 请求对象
|
||||
:return: 返回json数据: user_info: 用户信息; qa_id: 比赛答题记录标识; kind_id: 比赛唯一标识
|
||||
"""
|
||||
stop_stamp = tc.utc_timestamp(ms=True, milli=True) # 结束时间戳
|
||||
qa_id = request.POST.get('qa_id', '') # 获取qa_id
|
||||
uid = request.POST.get('uid', '') # 获取uid
|
||||
kind_id = request.POST.get('kind_id', '') # 获取kind_id
|
||||
answer = request.POST.get('answer', '') # 获取answer
|
||||
try: # 获取比赛信息
|
||||
kind_info = CompetitionKindInfo.objects.get(kind_id=kind_id)
|
||||
except CompetitionKindInfo.DoesNotExist: # 未获取到,返回错误码100001
|
||||
return json_response(*CompetitionError.CompetitionNotFound)
|
||||
try: # 获取题库信息
|
||||
bank_info = BankInfo.objects.get(bank_id=kind_info.bank_id)
|
||||
except BankInfo.DoesNotExist: # 未获取到返回错误码100004
|
||||
return json_response(*CompetitionError.BankInfoNotFound)
|
||||
try: # 获取用户信息
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist: # 未获取到,返回错误码200001
|
||||
return json_response(*ProfileError.ProfileNotFound)
|
||||
try: # 获取答题log信息
|
||||
qa_info = CompetitionQAInfo.objects.select_for_update().get(qa_id=qa_id)
|
||||
except CompetitionQAInfo.DoesNotExist: # 未获取到,返回错误码100006
|
||||
return json_response(*CompetitionError.QuestionNotFound)
|
||||
|
||||
answer = answer.rstrip('#').split('#') # 处理答案数据
|
||||
total, correct, wrong = check_correct_num(answer) # 检查答题情况
|
||||
qa_info.aslogrecord = answer
|
||||
qa_info.finished_stamp = stop_stamp
|
||||
qa_info.expend_time = stop_stamp - qa_info.started_stamp
|
||||
qa_info.finished = True
|
||||
qa_info.correct_num = correct if total == qa_info.total_num else 0
|
||||
qa_info.incorrect_num = wrong if total == qa_info.total_num else qa_info.total_num
|
||||
qa_info.save() # 保存答题log
|
||||
if qa_info.correct_num == kind_info.question_num: # 得分处理
|
||||
score = kind_info.total_score
|
||||
elif not qa_info.correct_num:
|
||||
score = 0
|
||||
else:
|
||||
score = round((kind_info.total_score / kind_info.question_num) * correct, 3)
|
||||
qa_info.score = score # 继续保存答题log
|
||||
qa_info.save()
|
||||
kind_info.total_partin_num += 1 # 保存比赛数据
|
||||
kind_info.save() # 比赛答题次数
|
||||
bank_info.partin_num += 1
|
||||
bank_info.save() # 题库答题次数
|
||||
if (kind_info.period_time > 0) and (qa_info.expend_time > kind_info.period_time * 60 * 1000): # 超时,不加入排行榜
|
||||
qa_info.status = CompetitionQAInfo.OVERTIME
|
||||
qa_info.save()
|
||||
else: # 正常完成,加入排行榜
|
||||
add_to_rank(uid, kind_id, qa_info.score, qa_info.expend_time)
|
||||
qa_info.status = CompetitionQAInfo.COMPLETED
|
||||
qa_info.save()
|
||||
return json_response(200, 'OK', { # 返回JSON数据
|
||||
'qa_id': qa_id,
|
||||
'user_info': profile.data,
|
||||
'kind_id': kind_id,
|
||||
})
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@check_login
|
||||
@check_copstatus
|
||||
@transaction.atomic
|
||||
def userinfo_entry(request):
|
||||
"""
|
||||
用户表单提交接口
|
||||
:param request: 请求对象
|
||||
:return: 返回json数据: user_info: 用户信息; kind_info: 比赛信息
|
||||
"""
|
||||
|
||||
uid = request.POST.get('uid', '')
|
||||
kind_id = request.POST.get('kind_id', '')
|
||||
result = request.POST.get('result', '')
|
||||
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
return json_response(*ProfileError.ProfileNotFound)
|
||||
|
||||
try:
|
||||
kind_info = CompetitionKindInfo.objects.get(kind_id=kind_id)
|
||||
except CompetitionKindInfo.DoesNotExist:
|
||||
return json_response(*CompetitionError.CompetitionNotFound)
|
||||
|
||||
rl = [i.split(',') for i in result.rstrip('#').split('#')]
|
||||
|
||||
ui, _ = UserInfo.objects.select_for_update().get_or_create(
|
||||
uid=uid,
|
||||
kind_id=kind_id
|
||||
)
|
||||
|
||||
for i in rl:
|
||||
if hasattr(UserInfo, i[0]):
|
||||
setattr(ui, i[0], i[1])
|
||||
ui.save()
|
||||
|
||||
enter_userinfo(kind_id, uid)
|
||||
|
||||
return json_response(200, 'OK', {
|
||||
'user_info': profile.data,
|
||||
'kind_info': kind_info.data
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def games(request, s):
|
||||
"""
|
||||
获取所有比赛接口
|
||||
:param request: 请求对象
|
||||
:param s: 请求关键字
|
||||
:return: 返回该请求关键字对应的所有比赛类别
|
||||
"""
|
||||
|
||||
if s == 'hot':
|
||||
# 筛选条件: 完成时间大于当前时间;根据参与人数降序排序;根据创建时间降序排序;筛选10个
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc),
|
||||
).order_by('-total_partin_num').order_by('-created_at')[:10]
|
||||
|
||||
elif s == 'tech':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.IT_ISSUE,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'edu':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.EDUCATION,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'culture':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.CULTURE,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'sport':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.SPORT,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'general':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.GENERAL,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
elif s == 'interview':
|
||||
kinds = CompetitionKindInfo.objects.filter(
|
||||
kind_type=CompetitionKindInfo.INTERVIEW,
|
||||
cop_finishat__gt=datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
).order_by('-total_partin_num').order_by('-created_at')
|
||||
|
||||
else:
|
||||
kinds = None
|
||||
|
||||
uid = request.session.get('uid', '')
|
||||
return json_response(200, 'OK', {
|
||||
'kinds': [i.data for i in kinds],
|
||||
'uid' : uid
|
||||
})
|
||||
138
competition/migrations/0001_initial.py
Normal file
138
competition/migrations/0001_initial.py
Normal file
@@ -0,0 +1,138 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2018-03-28 04:52
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
import shortuuidfield.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BankInfo',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('status', models.BooleanField(db_index=True, default=True, help_text='状态', verbose_name='状态')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
|
||||
('bank_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='题库唯一标识', max_length=22, null=True)),
|
||||
('choice_num', models.IntegerField(default=0, help_text='选择题数', verbose_name='选择题数')),
|
||||
('fillinblank_num', models.IntegerField(default=0, help_text='填空题数', verbose_name='填空题数')),
|
||||
('bank_type', models.IntegerField(choices=[(0, '技术类'), (1, '教育类'), (2, '文化类'), (3, '常识类'), (4, '面试题')], default=0, help_text='题库类型', verbose_name='题库类型')),
|
||||
('kind_num', models.IntegerField(default=0, help_text='比赛使用次数', verbose_name='比赛使用次数')),
|
||||
('partin_num', models.IntegerField(default=0, help_text='总答题人数', verbose_name='总答题人数')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '题库',
|
||||
'verbose_name_plural': '题库',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ChoiceInfo',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('status', models.BooleanField(db_index=True, default=True, help_text='状态', verbose_name='状态')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
|
||||
('image_url', models.CharField(blank=True, help_text='题目图片', max_length=255, null=True, verbose_name='图片链接')),
|
||||
('audio_url', models.CharField(blank=True, help_text='题目音频', max_length=255, null=True, verbose_name='音频链接')),
|
||||
('audio_time', models.IntegerField(default=0, help_text='题目音频时长', verbose_name='音频时长')),
|
||||
('bank_id', models.CharField(blank=True, db_index=True, help_text='题库唯一标识', max_length=32, null=True, verbose_name='题库id')),
|
||||
('ctype', models.IntegerField(choices=[(1, '文本'), (2, '图片'), (3, '音频')], default=1, help_text='题目类型', verbose_name='题目类型')),
|
||||
('question', models.CharField(blank=True, help_text='题目', max_length=255, null=True, verbose_name='问题')),
|
||||
('answer', models.CharField(blank=True, help_text='答案', max_length=255, null=True, verbose_name='答案')),
|
||||
('item1', models.CharField(blank=True, help_text='选项一', max_length=255, null=True, verbose_name='选项1')),
|
||||
('item2', models.CharField(blank=True, help_text='选项二', max_length=255, null=True, verbose_name='选项2')),
|
||||
('item3', models.CharField(blank=True, help_text='选项三', max_length=255, null=True, verbose_name='选项3')),
|
||||
('item4', models.CharField(blank=True, help_text='选项四', max_length=255, null=True, verbose_name='选项4')),
|
||||
('source', models.CharField(blank=True, help_text='出处', max_length=255, null=True, verbose_name='出处')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '选择题',
|
||||
'verbose_name_plural': '选择题',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CompetitionKindInfo',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('status', models.BooleanField(db_index=True, default=True, help_text='状态', verbose_name='状态')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
|
||||
('kind_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='比赛类别唯一标识', max_length=22, null=True)),
|
||||
('account_id', models.CharField(blank=True, db_index=True, help_text='商家账户唯一标识', max_length=32, null=True, verbose_name='出题账户id')),
|
||||
('app_id', models.CharField(blank=True, db_index=True, help_text='应用唯一标识', max_length=32, null=True, verbose_name='应用id')),
|
||||
('bank_id', models.CharField(blank=True, db_index=True, help_text='题库唯一标识', max_length=32, null=True, verbose_name='题库id')),
|
||||
('kind_type', models.IntegerField(choices=[(0, '技术类'), (1, '教育类'), (2, '文化类'), (3, '常识类'), (6, '地理类'), (7, '体育类'), (4, '面试题')], default=0, help_text='比赛类型', verbose_name='比赛类型')),
|
||||
('kind_name', models.CharField(blank=True, help_text='竞赛类别名称', max_length=32, null=True, verbose_name='比赛名称')),
|
||||
('sponsor_name', models.CharField(blank=True, help_text='赞助商名称', max_length=60, null=True, verbose_name='赞助商名称')),
|
||||
('total_score', models.IntegerField(default=0, help_text='总分数', verbose_name='总分数')),
|
||||
('question_num', models.IntegerField(default=0, help_text='出题数量', verbose_name='题目个数')),
|
||||
('cop_startat', models.DateTimeField(default=django.utils.timezone.now, help_text='比赛开始时间', verbose_name='比赛开始时间')),
|
||||
('period_time', models.IntegerField(default=60, help_text='答题时间(min)', verbose_name='答题时间')),
|
||||
('cop_finishat', models.DateTimeField(blank=True, help_text='比赛结束时间', null=True, verbose_name='比赛结束时间')),
|
||||
('total_partin_num', models.IntegerField(default=0, help_text='总参与人数', verbose_name='total_partin_num')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '比赛类别信息',
|
||||
'verbose_name_plural': '比赛类别信息',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CompetitionQAInfo',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('status', models.BooleanField(db_index=True, default=True, help_text='状态', verbose_name='状态')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
|
||||
('kind_id', models.CharField(blank=True, db_index=True, help_text='比赛类别唯一标识', max_length=32, null=True, verbose_name='比赛id')),
|
||||
('qa_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='QA 唯一标识', max_length=22, null=True)),
|
||||
('uid', models.CharField(blank=True, db_index=True, help_text='用户唯一标识', max_length=32, null=True, verbose_name='用户id')),
|
||||
('qsrecord', models.TextField(blank=True, help_text='问题记录', max_length=10000, null=True, verbose_name='问题记录')),
|
||||
('asrecord', models.TextField(blank=True, help_text='答案记录', max_length=10000, null=True, verbose_name='答案记录')),
|
||||
('aslogrecord', models.TextField(blank=True, help_text='答案提交记录', max_length=10000, null=True, verbose_name='答案提交记录')),
|
||||
('started_stamp', models.BigIntegerField(default=0, help_text='开始时间戳(毫秒)', verbose_name='开始时间戳')),
|
||||
('finished_stamp', models.BigIntegerField(default=0, help_text='结束时间戳(毫秒)', verbose_name='结束时间戳')),
|
||||
('expend_time', models.IntegerField(default=0, help_text='耗费时间(毫秒)', verbose_name='耗时')),
|
||||
('started', models.BooleanField(db_index=True, default=False, help_text='是否开始', verbose_name='已开始')),
|
||||
('finished', models.BooleanField(db_index=True, default=False, help_text='是否结束', verbose_name='已结束')),
|
||||
('correct_num', models.IntegerField(default=0, help_text='答对数量', verbose_name='正确数')),
|
||||
('incorrect_num', models.IntegerField(default=0, help_text='答错数量', verbose_name='错误数')),
|
||||
('total_num', models.IntegerField(default=0, help_text='总共数量', verbose_name='总数')),
|
||||
('score', models.IntegerField(default=0, help_text='分数', verbose_name='得分')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '比赛问题记录',
|
||||
'verbose_name_plural': '比赛问题记录',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FillInBlankInfo',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('status', models.BooleanField(db_index=True, default=True, help_text='状态', verbose_name='状态')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
|
||||
('image_url', models.CharField(blank=True, help_text='题目图片', max_length=255, null=True, verbose_name='图片链接')),
|
||||
('audio_url', models.CharField(blank=True, help_text='题目音频', max_length=255, null=True, verbose_name='音频链接')),
|
||||
('audio_time', models.IntegerField(default=0, help_text='题目音频时长', verbose_name='音频时长')),
|
||||
('bank_id', models.CharField(blank=True, db_index=True, help_text='题库唯一标识', max_length=32, null=True, verbose_name='题库id')),
|
||||
('ctype', models.IntegerField(choices=[(1, '文本'), (2, '图片'), (3, '音频')], default=1, help_text='题目类型', verbose_name='题目类型')),
|
||||
('question', models.CharField(blank=True, help_text='题目', max_length=255, null=True, verbose_name='问题')),
|
||||
('answer', models.CharField(blank=True, help_text='答案', max_length=255, null=True, verbose_name='答案')),
|
||||
('source', models.CharField(blank=True, help_text='出处', max_length=255, null=True, verbose_name='出处')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '填空题',
|
||||
'verbose_name_plural': '填空题',
|
||||
},
|
||||
),
|
||||
]
|
||||
30
competition/migrations/0002_auto_20180328_2246.py
Normal file
30
competition/migrations/0002_auto_20180328_2246.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2018-03-28 14:46
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('competition', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bankinfo',
|
||||
name='bank_name',
|
||||
field=models.CharField(blank=True, help_text='题库名称', max_length=40, null=True, verbose_name='题库名称'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='bankinfo',
|
||||
name='uid',
|
||||
field=models.CharField(blank=True, db_index=True, help_text='用户唯一标识', max_length=32, null=True, verbose_name='用户id'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='bankinfo',
|
||||
name='bank_type',
|
||||
field=models.IntegerField(choices=[(0, '技术类'), (1, '教育类'), (2, '文化类'), (3, '常识类'), (6, '地理类'), (7, '体育类'), (4, '面试题')], default=0, help_text='题库类型', verbose_name='题库类型'),
|
||||
),
|
||||
]
|
||||
20
competition/migrations/0003_auto_20180401_2159.py
Normal file
20
competition/migrations/0003_auto_20180401_2159.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2018-04-01 13:59
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('competition', '0002_auto_20180328_2246'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='competitionqainfo',
|
||||
name='status',
|
||||
field=models.IntegerField(choices=[(0, '未完成'), (1, '已完成'), (2, '超时')], default=0, help_text='答题状态', verbose_name='答题状态'),
|
||||
),
|
||||
]
|
||||
20
competition/migrations/0004_auto_20180404_1528.py
Normal file
20
competition/migrations/0004_auto_20180404_1528.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2018-04-04 07:28
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('competition', '0003_auto_20180401_2159'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='competitionqainfo',
|
||||
name='score',
|
||||
field=models.FloatField(default=0, help_text='分数', verbose_name='得分'),
|
||||
),
|
||||
]
|
||||
20
competition/migrations/0005_bankinfo_account_id.py
Normal file
20
competition/migrations/0005_bankinfo_account_id.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2018-04-05 15:20
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('competition', '0004_auto_20180404_1528'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bankinfo',
|
||||
name='account_id',
|
||||
field=models.CharField(blank=True, db_index=True, help_text='商家账户唯一标识', max_length=32, null=True, verbose_name='商家id'),
|
||||
),
|
||||
]
|
||||
25
competition/migrations/0006_auto_20180416_2151.py
Normal file
25
competition/migrations/0006_auto_20180416_2151.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2018-04-16 13:51
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('competition', '0005_bankinfo_account_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='competitionqainfo',
|
||||
name='correct_list',
|
||||
field=models.CharField(blank=True, help_text='正确答案列表', max_length=10000, null=True, verbose_name='正确答案列表'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='competitionqainfo',
|
||||
name='wrong_list',
|
||||
field=models.CharField(blank=True, help_text='错误答案列表', max_length=10000, null=True, verbose_name='错误答案列表'),
|
||||
),
|
||||
]
|
||||
0
competition/migrations/__init__.py
Normal file
0
competition/migrations/__init__.py
Normal file
336
competition/models.py
Normal file
336
competition/models.py
Normal file
@@ -0,0 +1,336 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from shortuuidfield import ShortUUIDField
|
||||
from utils.basemodels import CreateUpdateMixin, MediaMixin
|
||||
|
||||
|
||||
class CompetitionKindInfo(CreateUpdateMixin):
|
||||
"""比赛类别信息类"""
|
||||
|
||||
IT_ISSUE = 0
|
||||
EDUCATION = 1
|
||||
CULTURE = 2
|
||||
GENERAL = 3
|
||||
INTERVIEW = 4
|
||||
REAR = 5
|
||||
GEO = 6
|
||||
SPORT = 7
|
||||
|
||||
KIND_TYPES = (
|
||||
(IT_ISSUE, u'技术类'),
|
||||
(EDUCATION, u'教育类'),
|
||||
(CULTURE, u'文化类'),
|
||||
(GENERAL, u'常识类'),
|
||||
(GEO, u'地理类'),
|
||||
(SPORT, u'体育类'),
|
||||
(INTERVIEW, u'面试题')
|
||||
)
|
||||
|
||||
kind_id = ShortUUIDField(_(u'比赛id'), max_length=32, blank=True, null=True, help_text=u'比赛类别唯一标识', db_index=True)
|
||||
account_id = models.CharField(_(u'出题账户id'), max_length=32, blank=True, null=True, help_text=u'商家账户唯一标识', db_index=True)
|
||||
app_id = models.CharField(_(u'应用id'), max_length=32, blank=True, null=True, help_text=u'应用唯一标识', db_index=True)
|
||||
bank_id = models.CharField(_(u'题库id'), max_length=32, blank=True, null=True, help_text=u'题库唯一标识', db_index=True)
|
||||
kind_type = models.IntegerField(_(u'比赛类型'), default=IT_ISSUE, choices=KIND_TYPES, help_text=u'比赛类型')
|
||||
kind_name = models.CharField(_(u'比赛名称'), max_length=32, blank=True, null=True, help_text=u'竞赛类别名称')
|
||||
|
||||
sponsor_name = models.CharField(_(u'赞助商名称'), max_length=60, blank=True, null=True, help_text=u'赞助商名称')
|
||||
|
||||
total_score = models.IntegerField(_(u'总分数'), default=0, help_text=u'总分数')
|
||||
question_num = models.IntegerField(_(u'题目个数'), default=0, help_text=u'出题数量')
|
||||
|
||||
# 周期相关
|
||||
cop_startat = models.DateTimeField(_(u'比赛开始时间'), default=timezone.now, help_text=_(u'比赛开始时间'))
|
||||
period_time = models.IntegerField(_(u'答题时间'), default=60, help_text=u'答题时间(min)')
|
||||
cop_finishat = models.DateTimeField(_(u'比赛结束时间'), blank=True, null=True, help_text=_(u'比赛结束时间'))
|
||||
|
||||
# 参与相关
|
||||
total_partin_num = models.IntegerField(_(u'total_partin_num'), default=0, help_text=u'总参与人数')
|
||||
|
||||
class Meta:
|
||||
verbose_name = _(u'比赛类别信息')
|
||||
verbose_name_plural = _(u'比赛类别信息')
|
||||
|
||||
def __unicode__(self):
|
||||
return str(self.pk)
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return {
|
||||
'account_id': self.account_id,
|
||||
'app_id': self.app_id,
|
||||
'kind_id': self.kind_id,
|
||||
'kind_type': self.kind_type,
|
||||
'kind_name': self.kind_name,
|
||||
'total_score': self.total_score,
|
||||
'question_num': self.question_num,
|
||||
'total_partin_num': self.total_partin_num,
|
||||
'cop_startat': self.cop_startat,
|
||||
'cop_finishat': self.cop_finishat,
|
||||
'period_time': self.period_time,
|
||||
'sponsor_name': self.sponsor_name,
|
||||
}
|
||||
|
||||
|
||||
class BankInfo(CreateUpdateMixin):
|
||||
"""
|
||||
题库信息类
|
||||
"""
|
||||
|
||||
IT_ISSUE = 0
|
||||
EDUCATION = 1
|
||||
CULTURE = 2
|
||||
GENERAL = 3
|
||||
INTERVIEW = 4
|
||||
REAR = 5
|
||||
GEO = 6
|
||||
SPORT = 7
|
||||
|
||||
BANK_TYPES = (
|
||||
(IT_ISSUE, u'技术类'),
|
||||
(EDUCATION, u'教育类'),
|
||||
(CULTURE, u'文化类'),
|
||||
(GENERAL, u'常识类'),
|
||||
(GEO, u'地理类'),
|
||||
(SPORT, u'体育类'),
|
||||
(INTERVIEW, u'面试题')
|
||||
)
|
||||
|
||||
bank_id = ShortUUIDField(_(u'题库id'), max_length=32, blank=True, null=True, help_text=u'题库唯一标识', db_index=True)
|
||||
uid = models.CharField(_(u'用户id'), max_length=32, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)
|
||||
account_id = models.CharField(_(u'商家id'), max_length=32, blank=True, null=True, help_text=u'商家账户唯一标识', db_index=True)
|
||||
bank_name = models.CharField(_(u'题库名称'), max_length=40, blank=True, null=True, help_text=u'题库名称')
|
||||
|
||||
choice_num = models.IntegerField(_(u'选择题数'), default=0, help_text=u'选择题数')
|
||||
fillinblank_num = models.IntegerField(_(u'填空题数'), default=0, help_text=u'填空题数')
|
||||
bank_type = models.IntegerField(_(u'题库类型'), default=IT_ISSUE, choices=BANK_TYPES, help_text=u'题库类型')
|
||||
kind_num = models.IntegerField(_(u'比赛使用次数'), default=0, help_text=u'比赛使用次数')
|
||||
partin_num = models.IntegerField(_(u'总答题人数'), default=0, help_text=u'总答题人数')
|
||||
|
||||
class Meta:
|
||||
verbose_name = _(u'题库')
|
||||
verbose_name_plural = _(u'题库')
|
||||
|
||||
def __unicode__(self):
|
||||
return str(self.pk)
|
||||
|
||||
@property
|
||||
def total_question_num(self):
|
||||
return self.choice_num + self.fillinblank_num
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return {
|
||||
'bank_id': self.bank_id,
|
||||
'bank_name': self.bank_name,
|
||||
'choice_num': self.choice_num,
|
||||
'fillinblank_num': self.fillinblank_num,
|
||||
'bank_type': dict(self.BANK_TYPES)[self.bank_type],
|
||||
'kind_num': self.kind_num,
|
||||
'partin_num': self.partin_num,
|
||||
'total_question_num': self.total_question_num
|
||||
}
|
||||
|
||||
|
||||
class ChoiceInfo(CreateUpdateMixin, MediaMixin):
|
||||
"""
|
||||
选择题信息类
|
||||
"""
|
||||
|
||||
QUESTION_TYPE = 'choice'
|
||||
|
||||
TXT = 1
|
||||
IMG = 2
|
||||
AUDIO = 3
|
||||
|
||||
CONTENT_TYPE = (
|
||||
(TXT, u'文本'),
|
||||
(IMG, u'图片'),
|
||||
(AUDIO, u'音频'),
|
||||
)
|
||||
|
||||
bank_id = models.CharField(_(u'题库id'), max_length=32, blank=True, null=True, help_text=u'题库唯一标识', db_index=True)
|
||||
ctype = models.IntegerField(_(u'题目类型'), choices=CONTENT_TYPE, default=TXT, help_text=u'题目类型')
|
||||
question = models.CharField(_(u'问题'), max_length=255, blank=True, null=True, help_text=u'题目')
|
||||
answer = models.CharField(_(u'答案'), max_length=255, blank=True, null=True, help_text=u'答案')
|
||||
item1 = models.CharField(_(u'选项1'), max_length=255, blank=True, null=True, help_text=u'选项一')
|
||||
item2 = models.CharField(_(u'选项2'), max_length=255, blank=True, null=True, help_text=u'选项二')
|
||||
item3 = models.CharField(_(u'选项3'), max_length=255, blank=True, null=True, help_text=u'选项三')
|
||||
item4 = models.CharField(_(u'选项4'), max_length=255, blank=True, null=True, help_text=u'选项四')
|
||||
source = models.CharField(_(u'出处'), max_length=255, blank=True, null=True, help_text=u'出处')
|
||||
|
||||
class Meta:
|
||||
verbose_name = _(u'选择题')
|
||||
verbose_name_plural = _(u'选择题')
|
||||
|
||||
def __unicode__(self):
|
||||
return str(self.pk)
|
||||
|
||||
@property
|
||||
def items(self):
|
||||
tmp = []
|
||||
if self.item1:
|
||||
tmp.append(self.item1)
|
||||
if self.item2:
|
||||
tmp.append(self.item2)
|
||||
if self.item3:
|
||||
tmp.append(self.item3)
|
||||
if self.item4:
|
||||
tmp.append(self.item4)
|
||||
return tmp
|
||||
|
||||
@property
|
||||
def data_without_answer(self):
|
||||
return {
|
||||
'pk': self.pk,
|
||||
'qtype': self.QUESTION_TYPE,
|
||||
'bank_id': self.bank_id,
|
||||
'ctype': self.ctype,
|
||||
'question': self.question,
|
||||
'items': self.items,
|
||||
'source': self.source,
|
||||
'media': self.media,
|
||||
}
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return {
|
||||
'pk': self.pk,
|
||||
'qtype': self.QUESTION_TYPE,
|
||||
'bank_id': self.bank_id,
|
||||
'ctype': self.ctype,
|
||||
'question': self.question,
|
||||
'answer': self.answer,
|
||||
'items': self.items,
|
||||
'source': self.source,
|
||||
'media': self.media,
|
||||
}
|
||||
|
||||
|
||||
class FillInBlankInfo(CreateUpdateMixin, MediaMixin):
|
||||
"""
|
||||
填空题信息类
|
||||
"""
|
||||
|
||||
QUESTION_TYPE = 'fillinblank'
|
||||
|
||||
TXT = 1
|
||||
IMG = 2
|
||||
AUDIO = 3
|
||||
|
||||
CONTENT_TYPE = (
|
||||
(TXT, u'文本'),
|
||||
(IMG, u'图片'),
|
||||
(AUDIO, u'音频'),
|
||||
)
|
||||
|
||||
bank_id = models.CharField(_(u'题库id'), max_length=32, blank=True, null=True, help_text=u'题库唯一标识', db_index=True)
|
||||
ctype = models.IntegerField(_(u'题目类型'), choices=CONTENT_TYPE, default=TXT, help_text=u'题目类型')
|
||||
question = models.CharField(_(u'问题'), max_length=255, blank=True, null=True, help_text=u'题目')
|
||||
answer = models.CharField(_(u'答案'), max_length=255, blank=True, null=True, help_text=u'答案')
|
||||
source = models.CharField(_(u'出处'), max_length=255, blank=True, null=True, help_text=u'出处')
|
||||
|
||||
class Meta:
|
||||
verbose_name = _(u'填空题')
|
||||
verbose_name_plural = _(u'填空题')
|
||||
|
||||
def __unicode__(self):
|
||||
return str(self.pk)
|
||||
|
||||
@property
|
||||
def data_without_answer(self):
|
||||
return {
|
||||
'pk': self.pk,
|
||||
'bank_id': self.bank_id,
|
||||
'ctype': self.ctype,
|
||||
'question': self.question,
|
||||
'qtype': self.QUESTION_TYPE,
|
||||
'source': self.source
|
||||
}
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return {
|
||||
'pk': self.pk,
|
||||
'bank_id': self.bank_id,
|
||||
'ctype': self.ctype,
|
||||
'question': self.question,
|
||||
'qtype': self.QUESTION_TYPE,
|
||||
'answer': self.answer,
|
||||
'source': self.source
|
||||
}
|
||||
|
||||
|
||||
class CompetitionQAInfo(CreateUpdateMixin):
|
||||
"""答题记录信息类"""
|
||||
|
||||
UNCOMPLETED = 0
|
||||
COMPLETED = 1
|
||||
OVERTIME = 2
|
||||
|
||||
STATUS_CHOICES = (
|
||||
(UNCOMPLETED, u'未完成'),
|
||||
(COMPLETED, u'已完成'),
|
||||
(OVERTIME, u'超时')
|
||||
)
|
||||
|
||||
status = models.IntegerField(_(u'答题状态'), choices=STATUS_CHOICES, default=0, help_text=u'答题状态')
|
||||
kind_id = models.CharField(_(u'比赛id'), max_length=32, blank=True, null=True, help_text=u'比赛类别唯一标识', db_index=True)
|
||||
qa_id = ShortUUIDField(_(u'问题id'), max_length=32, blank=True, null=True, help_text=u'QA 唯一标识', db_index=True)
|
||||
uid = models.CharField(_(u'用户id'), max_length=32, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)
|
||||
|
||||
# 问题答案相关
|
||||
qsrecord = models.TextField(_('问题记录'), max_length=10000, blank=True, null=True, help_text=u'问题记录')
|
||||
asrecord = models.TextField(_('答案记录'), max_length=10000, blank=True, null=True, help_text=u'答案记录')
|
||||
aslogrecord = models.TextField(_('答案提交记录'), max_length=10000, blank=True, null=True, help_text=u'答案提交记录')
|
||||
|
||||
# 耗费时间相关
|
||||
started_stamp = models.BigIntegerField(_(u'开始时间戳'), default=0, help_text=u'开始时间戳(毫秒)')
|
||||
finished_stamp = models.BigIntegerField(_(u'结束时间戳'), default=0, help_text=u'结束时间戳(毫秒)')
|
||||
expend_time = models.IntegerField(_(u'耗时'), default=0, help_text=u'耗费时间(毫秒)')
|
||||
|
||||
started = models.BooleanField(_(u'已开始'), default=False, help_text=u'是否开始', db_index=True)
|
||||
finished = models.BooleanField(_(u'已结束'), default=False, help_text=u'是否结束', db_index=True)
|
||||
|
||||
# 得分相关
|
||||
correct_num = models.IntegerField(_(u'正确数'), default=0, help_text=u'答对数量')
|
||||
incorrect_num = models.IntegerField(_(u'错误数'), default=0, help_text=u'答错数量')
|
||||
correct_list = models.CharField(_(u'正确答案列表'), max_length=10000, blank=True, null=True, help_text=u'正确答案列表')
|
||||
wrong_list = models.CharField(_(u'错误答案列表'), max_length=10000, blank=True, null=True, help_text=u'错误答案列表')
|
||||
total_num = models.IntegerField(_(u'总数'), default=0, help_text=u'总共数量')
|
||||
score = models.FloatField(_(u'得分'), default=0, help_text=u'分数')
|
||||
|
||||
class Meta:
|
||||
verbose_name = _(u'比赛问题记录')
|
||||
verbose_name_plural = _(u'比赛问题记录')
|
||||
|
||||
def __unicode__(self):
|
||||
return str(self.pk)
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return {
|
||||
'qa_id': self.qa_id,
|
||||
'kind_id': self.kind_id,
|
||||
'uid': self.uid,
|
||||
}
|
||||
|
||||
@property
|
||||
def detail(self):
|
||||
return {
|
||||
'status': self.status,
|
||||
'qa_id': self.qa_id,
|
||||
'qs': self.qsrecord,
|
||||
'as': self.asrecord,
|
||||
'aslog': self.aslogrecord,
|
||||
'total_num': self.total_num,
|
||||
'correct_num': self.correct_num,
|
||||
'incorrect_num': self.incorrect_num,
|
||||
'correct_list': self.correct_list,
|
||||
'wrong_list': self.wrong_list,
|
||||
'score': self.score,
|
||||
'time': self.expend_time / 1000.000,
|
||||
}
|
||||
31
competition/rank_views.py
Normal file
31
competition/rank_views.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from account.models import Profile
|
||||
from competition.models import CompetitionKindInfo
|
||||
|
||||
from utils.response import json_response
|
||||
from utils.decorators import check_login
|
||||
from utils.redis.rrank import get_user_rank, get_rank
|
||||
from utils.errors import UserError, CompetitionError
|
||||
|
||||
|
||||
@check_login
|
||||
def get_my_rank(request):
|
||||
uid = request.GET.get('uid', '')
|
||||
kind_id = request.GET.get('kind_id', '')
|
||||
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
return json_response(*UserError.UserNotFound)
|
||||
|
||||
try:
|
||||
kind_info = CompetitionKindInfo.objects.get(kind_id=kind_id)
|
||||
except CompetitionKindInfo.DoesNotExist:
|
||||
return json_response(*CompetitionError.CompetitionNotFound)
|
||||
|
||||
return json_response(200, 'OK', {
|
||||
'time': get_user_rank(kind_id, uid).get('time', 0),
|
||||
'score': get_user_rank(kind_id, uid).get('score', 0),
|
||||
'rank': get_rank(kind_id, uid)
|
||||
})
|
||||
165
competition/set_render.py
Normal file
165
competition/set_render.py
Normal file
@@ -0,0 +1,165 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.http.response import StreamingHttpResponse
|
||||
from django.shortcuts import render
|
||||
|
||||
from account.models import Profile, UserInfo
|
||||
from competition.models import BankInfo
|
||||
from business.models import BusinessAccountInfo
|
||||
from utils.decorators import check_login
|
||||
from utils.errors import (FileNotFound, FileTypeError, ProfileNotFound,
|
||||
TemplateNotFound, BizAccountNotFound)
|
||||
from utils.small_utils import get_now_string, get_today_string
|
||||
from utils.upload_questions import upload_questions
|
||||
|
||||
|
||||
@check_login
|
||||
def index(request):
|
||||
"""
|
||||
题库和比赛导航页
|
||||
:param request: 请求对象
|
||||
:return: 渲染视图和user_info用户信息数据
|
||||
"""
|
||||
|
||||
uid = request.GET.get('uid', '')
|
||||
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
|
||||
return render(request, 'setgames/index.html', {'user_info': profile.data})
|
||||
|
||||
@check_login
|
||||
def set_bank(request):
|
||||
"""
|
||||
配置题库页面
|
||||
:param request: 请求对象
|
||||
:return: 渲染页面返回user_info用户信息数据和bank_types题库类型数据
|
||||
"""
|
||||
uid = request.GET.get('uid', '')
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid) # 检查账户信息
|
||||
except Profile.DoesNotExist:
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
bank_types = []
|
||||
for i, j in BankInfo.BANK_TYPES: # 返回所有题库类型
|
||||
bank_types.append({'id': i, 'name': j})
|
||||
return render(request, 'setgames/bank.html', { # 渲染模板
|
||||
'user_info': profile.data,
|
||||
'bank_types': bank_types
|
||||
})
|
||||
|
||||
|
||||
|
||||
@check_login
|
||||
def template_download(request):
|
||||
"""
|
||||
题库模板下载
|
||||
:param request: 请求对象
|
||||
:return: 返回excel文件的数据流
|
||||
"""
|
||||
uid = request.GET.get('uid', '') # 获取uid
|
||||
try:
|
||||
Profile.objects.get(uid=uid) # 用户信息
|
||||
except Profile.DoesNotExist:
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
def iterator(file_name, chunk_size=512): # chunk_size大小512KB
|
||||
with open(file_name, 'rb') as f: # rb,以字节读取
|
||||
while True:
|
||||
c = f.read(chunk_size)
|
||||
if c:
|
||||
yield c # 使用yield返回数据,直到所有数据返回完毕才退出
|
||||
else:
|
||||
break
|
||||
template_path = 'web/static/template/template.xlsx'
|
||||
file_path = os.path.join(settings.BASE_DIR, template_path) # 希望保留题库文件到一个单独目录
|
||||
if not os.path.exists(file_path): # 路径不存在
|
||||
return render(request, 'err.html', TemplateNotFound)
|
||||
# 将文件以流式响应返回到客户端。
|
||||
response = StreamingHttpResponse(iterator(file_path), content_type='application/vnd.ms-excel')
|
||||
response['Content-Disposition'] = 'attachment; filename=template.xlsx' # 格式为xlsx
|
||||
return response
|
||||
|
||||
|
||||
@check_login
|
||||
@transaction.atomic
|
||||
def upload_bank(request):
|
||||
"""
|
||||
上传题库
|
||||
:param request:请求对象
|
||||
:return: 返回用户信息user_info和上传成功的个数
|
||||
"""
|
||||
uid = request.POST.get('uid', '') # 获取uid
|
||||
bank_name = request.POST.get('bank_name', '') # 获取题库名称
|
||||
bank_type = request.POST.get('bank_type', BankInfo.IT_ISSUE) # 获取题库类型
|
||||
template = request.FILES.get('template', None) # 获取模板文件
|
||||
for k, v in dict(BankInfo.BANK_TYPES).items():
|
||||
if v == bank_type:
|
||||
bank_type = k
|
||||
break
|
||||
if not template: # 模板不存在
|
||||
return render(request, 'err.html', FileNotFound)
|
||||
if template.name.split('.')[-1] not in ['xls', 'xlsx']: # 模板格式为xls或者xlsx
|
||||
return render(request, 'err.html', FileTypeError)
|
||||
try: # 获取用户信息
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
|
||||
bank_info = BankInfo.objects.select_for_update().create( # 创建题库BankInfo
|
||||
uid=uid,
|
||||
bank_name=bank_name or '暂无',
|
||||
bank_type=bank_type
|
||||
)
|
||||
today_bank_repo = os.path.join(settings.BANK_REPO, get_today_string()) # 保存文件目录以当天时间为准
|
||||
if not os.path.exists(today_bank_repo):
|
||||
os.mkdir(today_bank_repo) # 不存在该目录则创建
|
||||
final_path = os.path.join(today_bank_repo, get_now_string(bank_info.bank_id)) + '.xlsx' # 生成文件名
|
||||
with open(final_path, 'wb+') as f: # 保存到目录
|
||||
f.write(template.read())
|
||||
choice_num, fillinblank_num = upload_questions(final_path, bank_info) # 使用xlrd读取excel文件到数据库
|
||||
return render(request, 'setgames/bank.html', { # 渲染视图
|
||||
'user_info': profile.data,
|
||||
'created': {
|
||||
'choice_num': choice_num,
|
||||
'fillinblank_num': fillinblank_num
|
||||
}
|
||||
})
|
||||
|
||||
@check_login
|
||||
def set_game(request):
|
||||
uid = request.GET.get('uid', '')
|
||||
|
||||
try:
|
||||
profile = Profile.objects.get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
return render(request, 'err.html', ProfileNotFound)
|
||||
|
||||
try:
|
||||
biz = BusinessAccountInfo.objects.get(email=profile.email)
|
||||
except BusinessAccountInfo.DoesNotExist:
|
||||
return render(request, 'err.html', BizAccountNotFound)
|
||||
|
||||
bank_types = []
|
||||
for i, j in BankInfo.BANK_TYPES:
|
||||
bank_types.append({'id': i, 'name': j})
|
||||
|
||||
form_fields = []
|
||||
for f in UserInfo._meta.fields:
|
||||
if f.name not in ['id', 'created_at', 'updated_at', 'kind_id', 'uid', 'status']:
|
||||
form_fields.append({'field_name': f.name, 'label': f.verbose_name})
|
||||
|
||||
banks = BankInfo.objects.values_list('bank_name', 'bank_id', 'kind_num', 'choice_num', 'fillinblank_num').order_by('-kind_num')[:10]
|
||||
banks = [{'bank_name': b[0], 'bank_id': b[1], 'kind_num': b[2], 'total_question_num': b[3] + b[4]} for b in banks]
|
||||
|
||||
return render(request, 'setgames/game.html', {
|
||||
'account_id': biz.account_id,
|
||||
'bank_types': bank_types,
|
||||
'form_fields': form_fields,
|
||||
'banks': banks,
|
||||
})
|
||||
124
competition/set_views.py
Normal file
124
competition/set_views.py
Normal file
@@ -0,0 +1,124 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.db import transaction
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from competition.models import BankInfo, CompetitionKindInfo
|
||||
from business.models import BusinessAccountInfo, AppConfigInfo, BusinessAppInfo
|
||||
from account.models import Profile
|
||||
|
||||
from utils.response import json_response
|
||||
from utils.redis.rpageconfig import set_pageconfig
|
||||
from utils.errors import SetError, BizError, ProfileError
|
||||
from utils.decorators import check_login, logerr
|
||||
|
||||
|
||||
def banks(request, s):
|
||||
if s == '999':
|
||||
banks = BankInfo.objects.values_list('bank_name', 'bank_id', 'kind_num', 'choice_num', 'fillinblank_num').order_by('-kind_num')
|
||||
return json_response(200, 'OK', {'banks': [{'bank_name': b[0], 'bank_id': b[1], 'kind_num': b[2], 'total_question_num': b[3] + b[4]} for b in banks]})
|
||||
bank_types = [t[0] for t in BankInfo.BANK_TYPES]
|
||||
|
||||
if int(s) in bank_types:
|
||||
banks = BankInfo.objects.filter(bank_type=s).values_list('bank_name', 'bank_id', 'kind_num', 'choice_num', 'fillinblank_num')
|
||||
return json_response(200, 'OK', {'banks': [{'bank_name': b[0], 'bank_id': b[1], 'kind_num': b[2], 'total_question_num': b[3] + b[4]} for b in banks]})
|
||||
|
||||
return json_response(*SetError.BankTypeError)
|
||||
|
||||
|
||||
def bank_detail(request, bank_id):
|
||||
try:
|
||||
bank = BankInfo.objects.get(bank_id=bank_id)
|
||||
except BankInfo.DoesNotExist:
|
||||
return json_response(*SetError.BankInfoNotFound)
|
||||
|
||||
return json_response(200, 'OK', {'bank_info': bank.data})
|
||||
|
||||
|
||||
@logerr
|
||||
@csrf_exempt
|
||||
@check_login
|
||||
@transaction.atomic
|
||||
def set_bank(request):
|
||||
account_id = request.POST.get('account_id', '')
|
||||
uid = request.POST.get('uid', '')
|
||||
bank_id = request.POST.get('bank_id', '')
|
||||
kind_name = request.POST.get('kind_name', '')
|
||||
sponsor_name = request.POST.get('sponsor_name', '')
|
||||
question_num = int(request.POST.get('question_num', 1))
|
||||
total_score = int(request.POST.get('total_score', 100))
|
||||
cop_startat = request.POST.get('cop_startat')
|
||||
cop_finishat = request.POST.get('cop_finishat')
|
||||
period = request.POST.get('period')
|
||||
rule_text = request.POST.get('rule_text', '')
|
||||
is_show_userinfo = request.POST.get('is_show_userinfo', 'false')
|
||||
form_data = request.POST.get('form_data', '')
|
||||
field_name_data = request.POST.get('field_name_data', '')
|
||||
option_data = request.POST.get('option_data', '')
|
||||
|
||||
try:
|
||||
BusinessAccountInfo.objects.select_for_update().get(account_id=account_id)
|
||||
except BusinessAccountInfo.DoesNotExist:
|
||||
return json_response(*BizError.BizAccountNotFound)
|
||||
|
||||
try:
|
||||
profile = Profile.objects.select_for_update().get(uid=uid)
|
||||
except Profile.DoesNotExist:
|
||||
return json_response(*ProfileError.ProfileNotFound)
|
||||
|
||||
try:
|
||||
bank_info = BankInfo.objects.select_for_update().get(bank_id=bank_id)
|
||||
except BankInfo.DoesNotExist:
|
||||
return json_response(*SetError.BankInfoNotFound)
|
||||
|
||||
app_info = BusinessAppInfo.objects.select_for_update().create(
|
||||
account_id=account_id,
|
||||
app_name=kind_name
|
||||
)
|
||||
|
||||
app_config_values = {
|
||||
'app_name': kind_name,
|
||||
'rule_text': rule_text,
|
||||
'is_show_userinfo': True if is_show_userinfo == 'true' else False,
|
||||
'userinfo_fields': form_data.rstrip('#'),
|
||||
'userinfo_field_names': field_name_data.rstrip('#'),
|
||||
'option_fields': option_data.rstrip('#'),
|
||||
}
|
||||
|
||||
app_config_info, app_config_created = AppConfigInfo.objects.select_for_update().get_or_create(
|
||||
app_id=app_info.app_id,
|
||||
defaults=app_config_values
|
||||
)
|
||||
|
||||
if not app_config_created:
|
||||
for k, v in app_config_values.items():
|
||||
setattr(app_config_info, k, v)
|
||||
app_config_info.save()
|
||||
|
||||
kind_values = {
|
||||
'kind_name': kind_name,
|
||||
'sponsor_name': sponsor_name,
|
||||
'kind_type': bank_info.bank_type,
|
||||
'total_score': total_score,
|
||||
'question_num': question_num,
|
||||
'cop_startat': cop_startat,
|
||||
'period_time': period or 0,
|
||||
'cop_finishat': cop_finishat
|
||||
}
|
||||
kind_info, kind_created = CompetitionKindInfo.objects.select_for_update().get_or_create(
|
||||
account_id=account_id,
|
||||
app_id=app_info.app_id,
|
||||
bank_id=bank_id,
|
||||
defaults=kind_values
|
||||
)
|
||||
|
||||
if not kind_created:
|
||||
for k, v in kind_values.items():
|
||||
setattr(kind_info, k, v)
|
||||
kind_info.save()
|
||||
|
||||
set_pageconfig(app_config_info.data)
|
||||
|
||||
return json_response(200, 'OK', {
|
||||
'kind_info': kind_info.data,
|
||||
})
|
||||
3
competition/tests.py
Normal file
3
competition/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
28
competition/urls.py
Normal file
28
competition/urls.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.conf.urls import include, url
|
||||
|
||||
from competition import cop_render, set_render
|
||||
|
||||
from django.urls import path,re_path
|
||||
|
||||
# 比赛url
|
||||
urlpatterns = [
|
||||
path('', cop_render.home, name='index'),
|
||||
re_path('games/s/(\w+)', cop_render.games, name='query_games'),
|
||||
path('game', cop_render.game, name='game'),
|
||||
path('result', cop_render.result, name='result'),
|
||||
path('rank', cop_render.rank, name='rank'),
|
||||
path('search', cop_render.search, name='search'),
|
||||
path('contact', cop_render.contact, name='contact'),
|
||||
path('donate', cop_render.donate, name='donate'),
|
||||
]
|
||||
|
||||
# 配置比赛url
|
||||
urlpatterns += [
|
||||
path('set', set_render.index, name='set_index'),
|
||||
path('set/bank', set_render.set_bank, name='set_bank'),
|
||||
path('set/bank/tdownload', set_render.template_download, name='template_download'),
|
||||
path('set/bank/upbank', set_render.upload_bank, name='upload_bank'),
|
||||
path('set/game', set_render.set_game, name='set_game'),
|
||||
]
|
||||
5
competition/views.py
Normal file
5
competition/views.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
def index(request):
|
||||
pass
|
||||
Reference in New Issue
Block a user