|
|
|
|
import random
|
|
|
|
|
from django.shortcuts import render
|
|
|
|
|
from rest_framework.decorators import api_view
|
|
|
|
|
from rest_framework.response import Response
|
|
|
|
|
from rest_framework.views import APIView
|
|
|
|
|
from rest_framework import status
|
|
|
|
|
import openpyxl
|
|
|
|
|
from .models import Students
|
|
|
|
|
from .models import Pledge
|
|
|
|
|
from channels.layers import get_channel_layer
|
|
|
|
|
from asgiref.sync import async_to_sync
|
|
|
|
|
from django.http import JsonResponse
|
|
|
|
|
from decimal import Decimal
|
|
|
|
|
from django.http import HttpResponse
|
|
|
|
|
from django.db.models import Min, Max
|
|
|
|
|
from django.db import transaction
|
|
|
|
|
|
|
|
|
|
# class TestView(APIView):
|
|
|
|
|
# def get(self, request):
|
|
|
|
|
# data = {
|
|
|
|
|
# "message": "Hello from Django!",
|
|
|
|
|
# "status": "success"
|
|
|
|
|
# }
|
|
|
|
|
# return Response(data, status=status.HTTP_200_OK)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# @api_view(['POST'])
|
|
|
|
|
# def upload_students(request):
|
|
|
|
|
# # 获取上传的文件
|
|
|
|
|
# file = request.FILES.get('file')
|
|
|
|
|
#
|
|
|
|
|
# if not file:
|
|
|
|
|
# return Response({'error': '没有上传文件'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
#
|
|
|
|
|
# try:
|
|
|
|
|
# # 读取 Excel 文件
|
|
|
|
|
# wb = openpyxl.load_workbook(file)
|
|
|
|
|
# sheet = wb.active
|
|
|
|
|
#
|
|
|
|
|
# # 遍历 Excel 表格的每一行,并保存到数据库
|
|
|
|
|
# for row in sheet.iter_rows(min_row=2, values_only=True):
|
|
|
|
|
# sid, name = row[0], row[1]
|
|
|
|
|
#
|
|
|
|
|
# # 使用 update_or_create 保存到数据库
|
|
|
|
|
# Students.objects.update_or_create(
|
|
|
|
|
# sid=sid,
|
|
|
|
|
# defaults={'name': name, 'score': 0}
|
|
|
|
|
# )
|
|
|
|
|
#
|
|
|
|
|
# return Response({'message': '导入成功!'}, status=status.HTTP_200_OK)
|
|
|
|
|
#
|
|
|
|
|
# except Exception as e:
|
|
|
|
|
# return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_view(['POST'])
|
|
|
|
|
def upload_students(request):
|
|
|
|
|
file = request.FILES.get('file')
|
|
|
|
|
|
|
|
|
|
if not file:
|
|
|
|
|
return Response({'error': '没有上传文件'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
wb = openpyxl.load_workbook(file)
|
|
|
|
|
sheet = wb.active
|
|
|
|
|
|
|
|
|
|
# 使用列表收集学生数据
|
|
|
|
|
students_data = []
|
|
|
|
|
for row in sheet.iter_rows(min_row=2, values_only=True):
|
|
|
|
|
sid, name = row[0], row[1]
|
|
|
|
|
students_data.append(Students(sid=sid, name=name, score=0))
|
|
|
|
|
|
|
|
|
|
# 开始一个事务
|
|
|
|
|
with transaction.atomic():
|
|
|
|
|
# 清空表
|
|
|
|
|
Students.objects.all().delete()
|
|
|
|
|
# 批量插入学生数据
|
|
|
|
|
Students.objects.bulk_create(students_data)
|
|
|
|
|
|
|
|
|
|
return Response({'message': '导入成功!'}, status=status.HTTP_200_OK)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_view(['GET'])
|
|
|
|
|
def get_student_info(request, student_id):
|
|
|
|
|
try:
|
|
|
|
|
student = Students.objects.get(sid=student_id)
|
|
|
|
|
return JsonResponse({'name': student.name, 'score': student.score})
|
|
|
|
|
except Students.DoesNotExist:
|
|
|
|
|
return JsonResponse({'error': 'Student not found'}, status=404)
|
|
|
|
|
|
|
|
|
|
@api_view(['POST'])
|
|
|
|
|
def update_student_score(request):
|
|
|
|
|
student_id = request.data.get('student_id')
|
|
|
|
|
score = request.data.get('score')
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
student = Students.objects.get(sid=student_id)
|
|
|
|
|
student.score = Decimal(score) # 将分数转换为 Decimal 类型
|
|
|
|
|
student.save()
|
|
|
|
|
return JsonResponse({'success': True})
|
|
|
|
|
except Students.DoesNotExist:
|
|
|
|
|
return JsonResponse({'error': 'Student not found'}, status=404)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return JsonResponse({'error': str(e)}, status=500)
|
|
|
|
|
|
|
|
|
|
@api_view(['GET'])
|
|
|
|
|
def get_student_info_by_name(request, student_name):
|
|
|
|
|
try:
|
|
|
|
|
student = Students.objects.get(name=student_name) # 根据姓名查询学生
|
|
|
|
|
return JsonResponse({'name': student.name, 'score': student.score})
|
|
|
|
|
except Students.DoesNotExist:
|
|
|
|
|
return JsonResponse({'error': 'Student not found'}, status=404)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_view(['POST'])
|
|
|
|
|
def send_exemption_card(request):
|
|
|
|
|
student_id = request.data.get('studentId')
|
|
|
|
|
student_name = request.data.get('studentName')
|
|
|
|
|
new_score = request.data.get('newScore')
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
student = Students.objects.get(sid=student_id)
|
|
|
|
|
student.score = new_score # 更新积分
|
|
|
|
|
student.save()
|
|
|
|
|
|
|
|
|
|
return JsonResponse({'message': '豁免卡信息处理成功'}, status=200)
|
|
|
|
|
except Students.DoesNotExist:
|
|
|
|
|
return JsonResponse({'error': '学生未找到'}, status=404)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_view(['GET'])
|
|
|
|
|
def leaderboard(request):
|
|
|
|
|
# 获取积分排名前5的学生
|
|
|
|
|
top_students = Students.objects.order_by('-score')[:5]
|
|
|
|
|
leaderboard_data = [{'name': student.name, 'score': student.score} for student in top_students]
|
|
|
|
|
|
|
|
|
|
return JsonResponse(leaderboard_data, safe=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_view(['POST'])
|
|
|
|
|
def create_pledge(request):
|
|
|
|
|
student_id = request.data.get('studentId')
|
|
|
|
|
student_name = request.data.get('studentName')
|
|
|
|
|
pledge_score = request.data.get('pledgeScore')
|
|
|
|
|
|
|
|
|
|
if not student_id or not student_name or not pledge_score:
|
|
|
|
|
return Response({'error': '所有字段都是必需的'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
|
|
|
|
pledge = Pledge.objects.create(
|
|
|
|
|
student_id=student_id,
|
|
|
|
|
student_name=student_name,
|
|
|
|
|
pledge_score=pledge_score,
|
|
|
|
|
status=0 # 设置状态为 0,表示未完成
|
|
|
|
|
)
|
|
|
|
|
return Response({'message': '典当信息已保存', 'pledge_id': pledge.id}, status=status.HTTP_201_CREATED)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@api_view(['POST'])
|
|
|
|
|
def update_question_score(request):
|
|
|
|
|
student_id = request.data.get('studentId')
|
|
|
|
|
question_score = request.data.get('questionScore')
|
|
|
|
|
print(request.data)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
student = Students.objects.get(sid=student_id)
|
|
|
|
|
# student = Students.objects.prefetch_related('pledges').get(sid=student_id)
|
|
|
|
|
student.score += Decimal(question_score) # 直接增加教师给的积分
|
|
|
|
|
student.save() # 保存更新后的积分
|
|
|
|
|
pledge = Pledge.objects.filter(student_id=student_id).order_by('-created_at').first()
|
|
|
|
|
# pledge = student.pledges.order_by('-created_at').first()
|
|
|
|
|
|
|
|
|
|
if pledge:
|
|
|
|
|
if pledge.status == 0: # 典当状态为0
|
|
|
|
|
pledge_score_decimal = Decimal(pledge.pledge_score) # 获取典当的积分
|
|
|
|
|
if question_score >= 2:
|
|
|
|
|
student.score += pledge_score_decimal * Decimal(2) # 加倍典当积分
|
|
|
|
|
else:
|
|
|
|
|
student.score -= pledge_score_decimal # 减去典当积分
|
|
|
|
|
pledge.status = 1 # 更新典当状态为1
|
|
|
|
|
pledge.save() # 保存更新后的典当状态
|
|
|
|
|
student.save() # 保存最终的学生积分
|
|
|
|
|
|
|
|
|
|
# 返回积分和典当信息
|
|
|
|
|
return Response({
|
|
|
|
|
'message': '积分更新成功',
|
|
|
|
|
'current_score': str(student.score),
|
|
|
|
|
'pledge_score': str(pledge.pledge_score),
|
|
|
|
|
'pledge_status': pledge.status,
|
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
|
else:
|
|
|
|
|
# 返回更新后的积分和初始积分
|
|
|
|
|
return Response({
|
|
|
|
|
'message': '积分更新成功,但没有新的典当信息',
|
|
|
|
|
'updated_score': str(student.score),
|
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
|
else:
|
|
|
|
|
return Response({
|
|
|
|
|
'updated_score': str(student.score),
|
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
|
|
|
|
|
|
except Students.DoesNotExist:
|
|
|
|
|
return Response({'error': '学生不存在'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 定义导出学生数据的 API 视图,接受 POST 请求
|
|
|
|
|
@api_view(['POST'])
|
|
|
|
|
def export_students_scores(request):
|
|
|
|
|
try:
|
|
|
|
|
# 获取所有学生信息
|
|
|
|
|
students = Students.objects.all()
|
|
|
|
|
|
|
|
|
|
# 找到最低和最高积分用于计算百分比
|
|
|
|
|
min_score = students.aggregate(min_score=Min('score'))['min_score']
|
|
|
|
|
max_score = students.aggregate(max_score=Max('score'))['max_score']
|
|
|
|
|
|
|
|
|
|
# 处理为百分比
|
|
|
|
|
def calculate_percentage(score, min_score, max_score):
|
|
|
|
|
if max_score == min_score: # 避免分母为0
|
|
|
|
|
return 50 # 所有学生得分相同时,统一设为50%
|
|
|
|
|
return (score - min_score) / (max_score - min_score) * 100
|
|
|
|
|
|
|
|
|
|
# 创建 Excel 工作簿
|
|
|
|
|
wb = openpyxl.Workbook()
|
|
|
|
|
ws = wb.active
|
|
|
|
|
ws.title = "学生积分百分比"
|
|
|
|
|
|
|
|
|
|
# 写入表头
|
|
|
|
|
ws.append(["学号", "姓名", "积分", "百分比"])
|
|
|
|
|
|
|
|
|
|
# 写入每个学生的信息
|
|
|
|
|
for student in students:
|
|
|
|
|
percentage = calculate_percentage(student.score, min_score, max_score)
|
|
|
|
|
ws.append([student.sid, student.name, float(student.score), f"{percentage:.2f}%"])
|
|
|
|
|
|
|
|
|
|
# 保存 Excel 文件
|
|
|
|
|
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
|
|
|
|
|
response['Content-Disposition'] = 'attachment; filename=students_scores.xlsx'
|
|
|
|
|
wb.save(response)
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|