Files
Exam/competition/game_views.py
2026-01-09 18:28:10 +08:00

247 lines
9.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- 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
})