|
|
from channels.generic.websocket import AsyncWebsocketConsumer
|
|
|
import json
|
|
|
import random
|
|
|
from asgiref.sync import sync_to_async
|
|
|
from .models import Students
|
|
|
|
|
|
|
|
|
class ClassroomConsumer(AsyncWebsocketConsumer):
|
|
|
async def connect(self):
|
|
|
self.teacher_group = 'teacher_group'
|
|
|
self.student_group = 'student_group'
|
|
|
|
|
|
await self.channel_layer.group_add(self.teacher_group, self.channel_name)
|
|
|
await self.channel_layer.group_add(self.student_group, self.channel_name)
|
|
|
|
|
|
await self.accept()
|
|
|
|
|
|
async def disconnect(self, close_code):
|
|
|
await self.channel_layer.group_discard(self.teacher_group, self.channel_name)
|
|
|
await self.channel_layer.group_discard(self.student_group, self.channel_name)
|
|
|
|
|
|
async def receive(self, text_data):
|
|
|
data = json.loads(text_data)
|
|
|
|
|
|
if data['action'] == 'pick_student':
|
|
|
selected_student = await self.pick_student()
|
|
|
await self.send_student_message(selected_student)
|
|
|
|
|
|
elif data['action'] == 'use_exemption_card':
|
|
|
# 处理学生使用豁免卡的信息
|
|
|
student_id = data['studentId']
|
|
|
new_score = data['newScore']
|
|
|
|
|
|
# 更新学生积分等逻辑,假设在数据库中保存
|
|
|
await self.update_student_score(student_id, new_score)
|
|
|
|
|
|
# 将豁免卡信息发送给教师组
|
|
|
await self.channel_layer.group_send(
|
|
|
self.teacher_group,
|
|
|
{
|
|
|
'type': 'exemption_card_used',
|
|
|
'student_id': student_id,
|
|
|
'student_name': data['studentName'],
|
|
|
'new_score': new_score,
|
|
|
}
|
|
|
)
|
|
|
|
|
|
# 处理教师端收到豁免卡使用信息
|
|
|
async def exemption_card_used(self, event):
|
|
|
student_id = event['student_id']
|
|
|
student_name = event['student_name']
|
|
|
new_score = event['new_score']
|
|
|
|
|
|
# 在教师端显示学生使用豁免卡的信息
|
|
|
await self.send(text_data=json.dumps({
|
|
|
'action': 'exemption_card_used',
|
|
|
'student_id': student_id,
|
|
|
'student_name': student_name,
|
|
|
'new_score': new_score,
|
|
|
}))
|
|
|
|
|
|
async def send_student_message(self, student):
|
|
|
if student is None:
|
|
|
return # 如果没有选中学生,直接返回
|
|
|
|
|
|
message = {
|
|
|
'name': student.name,
|
|
|
'student_id': student.sid,
|
|
|
}
|
|
|
|
|
|
# 将点名结果发送到学生组
|
|
|
await self.channel_layer.group_send(
|
|
|
self.student_group,
|
|
|
{
|
|
|
'type': 'student_message',
|
|
|
'message': message,
|
|
|
}
|
|
|
)
|
|
|
|
|
|
# 接收到点名结果后发送给学生端
|
|
|
async def student_message(self, event):
|
|
|
message = event['message']
|
|
|
await self.send(text_data=json.dumps({
|
|
|
'action': 'student_picked',
|
|
|
'name': message['name'],
|
|
|
'student_id': message['student_id'],
|
|
|
}))
|
|
|
|
|
|
async def pick_student(self):
|
|
|
# 使用 sync_to_async 获取学生列表
|
|
|
students = await sync_to_async(list)(Students.objects.all())
|
|
|
|
|
|
if not students:
|
|
|
return None
|
|
|
|
|
|
# 计算权重
|
|
|
weights = []
|
|
|
for student in students:
|
|
|
score = float(student.score)
|
|
|
if score < 0:
|
|
|
weights.append(-score) # 负分数,绝对值越大权重越大
|
|
|
elif score == 0:
|
|
|
weights.append(0.2) # 分数为0,设置为一个中等权重
|
|
|
else:
|
|
|
weights.append(1 / (score + 10)) # 正分数,分数越大权重越小
|
|
|
|
|
|
# 防止所有权重为0的情况
|
|
|
if sum(weights) == 0:
|
|
|
return random.choice(students) # 如果所有权重为0,随机选一个学生
|
|
|
|
|
|
# 根据权重选择学生
|
|
|
chosen_student = random.choices(students, weights=weights, k=1)[0]
|
|
|
return chosen_student
|
|
|
|
|
|
async def update_student_score(self, student_id, new_score):
|
|
|
# 使用 Django ORM 更新学生积分
|
|
|
student = await sync_to_async(Students.objects.get)(sid=student_id)
|
|
|
student.score = new_score
|
|
|
await sync_to_async(student.save)()
|