feat:考试记录导出功能

This commit is contained in:
zty 2024-06-04 16:25:22 +08:00
parent cf38fbd5e3
commit 8b747cb05f
4 changed files with 59 additions and 60 deletions

View File

@ -1,29 +0,0 @@
from openpyxl.workbook import Workbook
from django.conf import settings
from datetime import datetime
from openpyxl.styles import Font, Fill
import json
BASE_DIR = settings.BASE_DIR
def export_question(questions):
'''
params: serializer questions
return: xlsx path
'''
wb = Workbook()
ws1 = wb.active
ws1.title = '题目表'
ws1.append(['分类','题型', '题干', '选项', '正确答案', '解析'])
row = ws1.row_dimensions[1]
row.font = Font(bold=True)
for i in questions:
# options=''
# for key in i.options:
# pass
ws1.append([i.questioncat.name, i.type, i.name, json.dumps(i.options, ensure_ascii=False), ''.join(sorted(i.right)), i.resolution])
filename = 'questions' + datetime.now().strftime("%Y%m%d%H%M%S") +'.xlsx'
path = '/media/export/' + filename
wb.save((BASE_DIR + path).replace('\\', '/'))
return path

View File

@ -5,7 +5,7 @@ from openpyxl.styles import Font, Fill
import json
import os
def export_question(questions):
def export_question(questions:object):
'''
params: serializer questions
return: xlsx path
@ -24,4 +24,33 @@ def export_question(questions):
if not os.path.exists(full_path):
os.makedirs(full_path)
wb.save(full_path+filename)
return path + filename
return path + filename
def export_record(records:object):
'''
params: serializer records
return: xlsx path
'''
wb = Workbook()
ws1 = wb.active
ws1.title = '答题记录表'
ws1.append(['类型', '用户', '是否通过', '得分', '总分', '耗时(时分秒)', '答题时间', '部门'])
row = ws1.row_dimensions[1]
row.font = Font(bold=True)
for i in records:
tookformat = get_took_format(i.took)
ws1.append([i.type, i.create_by.name, i.is_pass, i.score, i.total_score, str(tookformat), str(i.start_time), i.belong_dept.name])
filename = 'records' + datetime.now().strftime("%Y%m%d%H%M%S") +'.xlsx'
path = '/media/temp/'
full_path = settings.BASE_DIR + '/media/temp/'
if not os.path.exists(full_path):
os.makedirs(full_path)
wb.save(full_path+filename)
return path + filename
def get_took_format(took:int):
m, s = divmod(took, 60)
h, m = divmod(m, 60)
return "%02d:%02d:%02d" % (h, m, s)

View File

@ -1,7 +1,7 @@
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.mixins import ListModelMixin, DestroyModelMixin, RetrieveModelMixin
from apps.exam.exports import export_question
from apps.exam.exports import export_question, export_record
from apps.exam.models import Question, Questioncat, PaperQuestion
from apps.exam.serializers import (QuestionSerializer, QuestioncatSerializer, PaperSerializer, ExamDetailSerializer, ExamRecordDetailSerializer, ExamListSerializer,
ExamCreateUpdateSerializer, ExamListSerializer, ExamRecordSubmitSerializer, PaperDetailSerializer, PaperCreateUpdateSerializer, AnswerDetailOutSerializer, ExamRecordListSerializer)
@ -23,7 +23,6 @@ from apps.edu.serializers import CertificateSerializer
from utils.queryset import get_child_queryset2
from apps.system.permission import has_permission
from apps.exam.parse_word import interpret_text
from .export import export_question
import os
import shutil
from django.db.models import Q
@ -65,22 +64,10 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
perms_map = {'get': '*', 'post':'question', 'put':'question', 'delete':'question'}
queryset = Question.objects.all()
serializer_class = QuestionSerializer
filterset_fields = ['level', 'type', 'year']
filterset_fields = ['level', 'type', 'year', 'questioncat']
search_fields = ['name', 'options', 'resolution']
@action(methods=['get'], detail=False,
url_path='export', url_name='export_question', perms_map=[{'get': '*'}], serializer_class=Serializer)
def export_question(self, request):
"""
导出题目
导出题目
"""
queryset = self.filter_queryset(self.get_queryset())
path = export_question(queryset)
return Response({'path': path})
@action(methods=['post'], detail=False, url_name='enable_question', perms_map={'post': 'question'}, serializer_class=Serializer)
def enable(self, request):
"""
@ -93,7 +80,7 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
Question.objects.filter(pk__in=ids).update(enabled=True)
return Response(status=200)
@action(methods=['post'], detail=False, perms_map=[{'*':'question_delete'}])
@action(methods=['post'], detail=False, perms_map={'*':'question_delete'})
def deletes(self, request):
"""
批量删除
@ -104,8 +91,7 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
return Response()
return Response({'error':'权限不足'})
@action(methods=['get'], detail=False,
url_path='export', url_name='export_question', perms_map=[{'*':'export_question'}])
@action(methods=['get'], detail=False, perms_map={'get':'export_question'})
def export(self, request):
"""
导出题目
@ -294,8 +280,7 @@ class PaperViewSet(ModelViewSet):
return Response()
@action(methods=['put'], detail=True, url_path='clone', url_name='clone_paper',
perms_map=[{'put':'clone_paper'}])
@action(methods=['put'], detail=True, url_path='clone', url_name='clone_paper', perms_map={'put':'clone_paper'})
def clone(self, request, pk=None):
'''
克隆试卷
@ -492,7 +477,7 @@ class ExamViewSet(CreateUpdateCustomMixin, ModelViewSet):
instance.delete(soft=False)
return Response(status=204)
@action(methods=['post'], detail=True, perms_map=[{'post': '*'}], serializer_class=Serializer, permission_classes = [IsAuthenticated])
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=Serializer, permission_classes = [IsAuthenticated])
@transaction.atomic
def start(self, request, *args, **kwargs):
"""
@ -564,7 +549,8 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
if has_permission('ctc_manager', self.request.user):
return qs
# 如果是部门管理员,只能看到自己部门下的考试记录
# return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
elif has_permission('exam_manager', self.request.user):
return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
# 如果是普通员工,只能看到自己考试记录
else:
return qs.filter(create_by=self.request.user)
@ -577,11 +563,9 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
def perform_destroy(self, instance): # 考试记录物理删除
instance.delete(soft=False)
@action(methods=['post'], detail=False, perms_map=[{'post': '*'}], serializer_class=Serializer, permission_classes = [IsAuthenticated])
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=Serializer, permission_classes = [IsAuthenticated])
def clear(self, request, pk=None):
"""
清除七日前未提交的考试记录
清除七日前未提交的考试记录
"""
now = timezone.now
@ -589,8 +573,19 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
ExamRecord.objects.filter(create_time__lte=days7_ago, is_submited=False).delete(soft=False)
return Response(status=False)
@action(methods=['get'], detail=False,
url_path='export', url_name='export_record', perms_map={'*': 'export_ansrecord'}, serializer_class=Serializer)
def export(self, request):
"""
导出答题记录
"""
queryset = self.filter_queryset(self.get_queryset())
path = export_record(queryset)
return Response({'path': path})
@action(methods=['post'], detail=True, perms_map=[{'post': '*'}], serializer_class=ExamRecordSubmitSerializer, permission_classes = [IsAuthenticated])
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=ExamRecordSubmitSerializer, permission_classes = [IsAuthenticated])
@transaction.atomic
def submit(self, request, pk=None):
'''

View File

@ -348,8 +348,11 @@ class UserExamViewset(ImpMixin, ModelViewSet):
for row in sheet.iter_rows(min_row=start, values_only=True): # 假设第一行是表头,从第二行开始读取数据
if row[0] is not None:
dept = Organization.objects.get(name=row[3])
if not dept:
return Response({'msg': '部门不存在'})
user_depts = get_child_queryset2(request.user.dept).order_by('sort')
serializer = OrganizationSerializer(user_depts, many=True)
depts = any(i.id==dept.id for i in serializer.data)
if depts is False:
return Response({'msg': f'本公司下不存在此部门{row[3]}'})
serializer_data = {
'name': row[1],
'username':row[2],
@ -510,6 +513,7 @@ class UserViewSet(PageOrNot, ModelViewSet):
while sheet['b'+str(i)].value:
name = sheet['b'+str(i)].value
email = sheet['e'+str(i)].value
dept = Organization.objects.get(name=sheet['j'+str(i)].value)
if not User.objects.filter(username=email).exists():
user = User.objects.create(name=name,
username=email,
@ -517,7 +521,7 @@ class UserViewSet(PageOrNot, ModelViewSet):
dept=dept)
else:
user = User.objects.get(username=email)
dept = Organization.objects.get(name=sheet['j'+str(i)].value)
if sheet['f'+str(i)].value:
user.roles.add(role1)
if sheet['g'+str(i)].value: