1
This commit is contained in:
@@ -9,216 +9,227 @@
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudProgressCircular Indeterminate="true" Color="Color.Primary" Class="d-flex justify-center my-8" />
|
||||
<MudText Class="text-center">正在加载试卷和学生数据...</MudText>
|
||||
<MudProgressCircular Indeterminate="true" Color="Color.Primary" Class="d-flex justify-center my-8" />
|
||||
<MudText Class="text-center">正在加载试卷和学生数据...</MudText>
|
||||
}
|
||||
else if (_questionsForTable.Any() && _students.Any())
|
||||
{
|
||||
<MudTable @ref="_table" T="QuestionRowData" Items="@_questionsForTable" Hover="true" Breakpoint="Breakpoint.Sm" Class="mud-elevation-2" Dense="true">
|
||||
<HeaderContent>
|
||||
<MudTh Style="width:100px;">序号</MudTh>
|
||||
<MudTh Style="width:80px; text-align:center;">分值</MudTh>
|
||||
@foreach (var student in _students)
|
||||
{
|
||||
<MudTh Style="width:120px; text-align:center;">
|
||||
@student.Name
|
||||
<MudTooltip Text="点击以切换此学生所有题目的对错">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Info" Size="Size.Small" Class="ml-1"
|
||||
@onclick="() => ToggleStudentAllAnswers(student.Id)" />
|
||||
</MudTooltip>
|
||||
</MudTh>
|
||||
}
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="序号">@context.QuestionItem.Sequence</MudTd>
|
||||
<MudTd DataLabel="分值" Style="text-align:center;">@context.QuestionItem.Score</MudTd>
|
||||
@foreach (var student in _students)
|
||||
{
|
||||
<MudTd DataLabel="@student.Name" Style="text-align:center;">
|
||||
@if (context.StudentAnswers.ContainsKey(student.Id))
|
||||
{
|
||||
<MudCheckBox @bind-Value="context.StudentAnswers[student.Id]" Size="Size.Small" Color="Color.Primary"></MudCheckBox>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Color="Color.Warning">N/A</MudText>
|
||||
}
|
||||
</MudTd>
|
||||
}
|
||||
</RowTemplate>
|
||||
<PagerContent>
|
||||
<MudTablePager />
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
<MudTable @ref="_table" T="QuestionRowData" Items="@_questionsForTable" Hover="true" Breakpoint="Breakpoint.Sm" Striped="true" Class="mud-elevation-2" Dense="true">
|
||||
<HeaderContent>
|
||||
<MudTh Style="width:100px;">序号</MudTh>
|
||||
<MudTh Style="width:80px; text-align:center;">分值</MudTh>
|
||||
@foreach (var student in _students)
|
||||
{
|
||||
<MudTh Style="width:120px; text-align:center;">
|
||||
@student.DisplayName
|
||||
<MudTooltip Text="点击以切换此学生所有题目的对错">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Info" Size="Size.Small" Class="ml-1"
|
||||
@onclick="() => ToggleStudentAllAnswers(student.Id)" />
|
||||
</MudTooltip>
|
||||
</MudTh>
|
||||
}
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="序号">@context.QuestionItem.Sequence</MudTd>
|
||||
<MudTd DataLabel="分值" Style="text-align:center;">@context.QuestionItem.Score</MudTd>
|
||||
@foreach (var student in _students)
|
||||
{
|
||||
<MudTd DataLabel="@student.DisplayName" Style="text-align:center;">
|
||||
@if (context.StudentAnswers.ContainsKey(student.Id))
|
||||
{
|
||||
<MudCheckBox @bind-Value="context.StudentAnswers[student.Id]" Size="Size.Small" Color="Color.Primary"></MudCheckBox>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Color="Color.Warning">N/A</MudText>
|
||||
}
|
||||
</MudTd>
|
||||
}
|
||||
</RowTemplate>
|
||||
<PagerContent>
|
||||
<MudTablePager />
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
|
||||
<MudPaper Class="pa-4 mt-4 mud-elevation-2 d-flex flex-column align-end">
|
||||
<MudText Typo="Typo.h6">学生总分预览:</MudText>
|
||||
@foreach (var student in _students)
|
||||
{
|
||||
<MudText Typo="Typo.subtitle1">
|
||||
@student.Name: <MudText Typo="Typo.h5" Color="Color.Primary" Class="d-inline-block ml-2">@GetStudentTotalScore(student.Id)</MudText>
|
||||
</MudText>
|
||||
}
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Success" Class="mt-4" @onclick="SubmitGrading">
|
||||
提交批改结果 (模拟)
|
||||
</MudButton>
|
||||
</MudPaper>
|
||||
<MudPaper Class="pa-4 mt-4 mud-elevation-2 d-flex flex-column align-end">
|
||||
<MudText Typo="Typo.h6">学生总分预览:</MudText>
|
||||
@foreach (var student in _students)
|
||||
{
|
||||
<MudText Typo="Typo.subtitle1">
|
||||
@student.DisplayName: <MudText Typo="Typo.h5" Color="Color.Primary" Class="d-inline-block ml-2">@GetStudentTotalScore(student.Id)</MudText>
|
||||
</MudText>
|
||||
}
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Success" Class="mt-4" @onclick="SubmitGrading">
|
||||
提交批改结果 (模拟)
|
||||
</MudButton>
|
||||
</MudPaper>
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudAlert Severity="Severity.Info" Class="mt-4">无法加载试卷或题目信息。</MudAlert>
|
||||
<MudButton Variant="Variant.Text" Color="Color.Primary" Class="mt-4" >返回试卷列表</MudButton>
|
||||
<MudAlert Severity="Severity.Info" Class="mt-4">无法加载试卷或题目信息。</MudAlert>
|
||||
<MudButton Variant="Variant.Text" Color="Color.Primary" Class="mt-4">返回试卷列表</MudButton>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string ExamId { get; set; }
|
||||
[Parameter]
|
||||
public string ExamId { get; set; }
|
||||
|
||||
[Inject]
|
||||
public IExamService ExamService { get; set; }
|
||||
[Inject]
|
||||
public IExamService ExamService { get; set; }
|
||||
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; set; }
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; set; }
|
||||
|
||||
[Inject]
|
||||
private NavigationManager Navigation { get; set; }
|
||||
[Inject]
|
||||
private NavigationManager Navigation { get; set; }
|
||||
|
||||
private MudTable<QuestionRowData> _table = new();
|
||||
private AssignmentDto Assignment { get; set; } = new AssignmentDto();
|
||||
private ExamStruct _examStruct = new ExamStruct();
|
||||
private MudTable<QuestionRowData> _table = new();
|
||||
private AssignmentDto Assignment { get; set; } = new AssignmentDto();
|
||||
private AssignmentCheckData _examStruct = new AssignmentCheckData();
|
||||
|
||||
private List<Student> _students = new List<Student>();
|
||||
private List<QuestionRowData> _questionsForTable = new List<QuestionRowData>();
|
||||
private List<StudentDto> _students = new List<StudentDto>();
|
||||
private List<QuestionRowData> _questionsForTable = new List<QuestionRowData>();
|
||||
|
||||
private bool _isLoading = true;
|
||||
private bool _isLoading = true;
|
||||
|
||||
[Inject]
|
||||
public IClassServices ClassServices { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_isLoading = true;
|
||||
await LoadExamData();
|
||||
|
||||
var result = await ClassServices.GetClassStudents();
|
||||
if (!result.Status) Snackbar.Add($"获取学生失败, {result.Message}", Severity.Error);
|
||||
_students = result.Result as List<StudentDto> ?? new List<StudentDto>();
|
||||
BuildTable();
|
||||
_isLoading = false;
|
||||
}
|
||||
|
||||
private void BuildTable()
|
||||
{
|
||||
_questionsForTable = _examStruct.Questions.Select(q =>
|
||||
{
|
||||
var rowData = new QuestionRowData
|
||||
{
|
||||
QuestionItem = q,
|
||||
StudentAnswers = new Dictionary<Guid, bool>()
|
||||
};
|
||||
foreach (var student in _students)
|
||||
{
|
||||
rowData.StudentAnswers[student.Id] = false;
|
||||
}
|
||||
return rowData;
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
private async Task LoadExamData()
|
||||
{
|
||||
if (Guid.TryParse(ExamId, out Guid parsedExamId))
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await ExamService.GetExam(parsedExamId);
|
||||
if (result.Status)
|
||||
{
|
||||
Assignment = result.Result as AssignmentDto ?? new AssignmentDto();
|
||||
_examStruct = Assignment.GetStruct();
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar?.Add($"获取试卷失败: {result.Message}", Severity.Error);
|
||||
Navigation.NavigateTo("/exam/manager");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"获取试卷时发生错误: {ex.Message}");
|
||||
Snackbar?.Add($"获取试卷失败: {ex.Message}", Severity.Error);
|
||||
Navigation.NavigateTo("/exam/manager");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine($"错误:路由参数 ExamId '{ExamId}' 不是一个有效的 GUID 格式。");
|
||||
Snackbar?.Add("无效的试卷ID,无法加载。", Severity.Error);
|
||||
Navigation.NavigateTo("/exam/manager");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_isLoading = true;
|
||||
await LoadExamData();
|
||||
GenerateTemporaryStudentsAndAnswers();
|
||||
_isLoading = false;
|
||||
}
|
||||
|
||||
private float GetStudentTotalScore(Guid studentId)
|
||||
{
|
||||
float totalScore = 0;
|
||||
foreach (var row in _questionsForTable)
|
||||
{
|
||||
if (row.StudentAnswers.TryGetValue(studentId, out bool isCorrect) && isCorrect)
|
||||
{
|
||||
totalScore += row.QuestionItem.Score;
|
||||
}
|
||||
}
|
||||
return totalScore;
|
||||
}
|
||||
|
||||
private void ToggleStudentAllAnswers(Guid studentId)
|
||||
{
|
||||
bool allCorrect = _questionsForTable.All(row => row.StudentAnswers.ContainsKey(studentId) && row.StudentAnswers[studentId]);
|
||||
|
||||
foreach (var row in _questionsForTable)
|
||||
{
|
||||
if (row.StudentAnswers.ContainsKey(studentId))
|
||||
{
|
||||
row.StudentAnswers[studentId] = !allCorrect;
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void SubmitGrading()
|
||||
{
|
||||
|
||||
List<SubmissionDto> submissionDto = new List<SubmissionDto>();
|
||||
|
||||
|
||||
private async Task LoadExamData()
|
||||
{
|
||||
if (Guid.TryParse(ExamId, out Guid parsedExamId))
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await ExamService.GetExam(parsedExamId);
|
||||
if (result.Status)
|
||||
{
|
||||
Assignment = result.Result as AssignmentDto ?? new AssignmentDto();
|
||||
_examStruct = Assignment.GetStruct();
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar?.Add($"获取试卷失败: {result.Message}", Severity.Error);
|
||||
Navigation.NavigateTo("/exam/manager");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"获取试卷时发生错误: {ex.Message}");
|
||||
Snackbar?.Add($"获取试卷失败: {ex.Message}", Severity.Error);
|
||||
Navigation.NavigateTo("/exam/manager");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine($"错误:路由参数 ExamId '{ExamId}' 不是一个有效的 GUID 格式。");
|
||||
Snackbar?.Add("无效的试卷ID,无法加载。", Severity.Error);
|
||||
Navigation.NavigateTo("/exam/manager");
|
||||
}
|
||||
}
|
||||
foreach (var student in _students)
|
||||
{
|
||||
var newSubmission = new SubmissionDto();
|
||||
newSubmission.StudentId = student.Id;
|
||||
newSubmission.AssignmentId = Assignment.Id;
|
||||
newSubmission.SubmissionTime = DateTime.Now;
|
||||
newSubmission.Status = Entities.Contracts.SubmissionStatus.Submitted;
|
||||
|
||||
// 生成临时学生和作答数据
|
||||
private void GenerateTemporaryStudentsAndAnswers()
|
||||
{
|
||||
_students = new List<Student>();
|
||||
// 生成 40 个学生
|
||||
for (int i = 1; i <= 40; i++)
|
||||
{
|
||||
_students.Add(new Student { Name = $"学生{i}" });
|
||||
}
|
||||
|
||||
_questionsForTable = _examStruct.Questions.Select(qItem =>
|
||||
{
|
||||
var rowData = new QuestionRowData
|
||||
{
|
||||
QuestionItem = qItem,
|
||||
StudentAnswers = new Dictionary<Guid, bool>()
|
||||
};
|
||||
foreach (var row in _questionsForTable)
|
||||
{
|
||||
if (row.QuestionItem.AssignmentQuestionDto.StructType == Entities.Contracts.AssignmentStructType.Struct) continue;
|
||||
if (row.StudentAnswers.TryGetValue(student.Id, out bool isCorrect))
|
||||
{
|
||||
newSubmission.SubmissionDetails.Add(new SubmissionDetailDto
|
||||
{
|
||||
IsCorrect = isCorrect,
|
||||
StudentId = student.Id,
|
||||
AssignmentQuestionId = row.QuestionItem.AssignmentQuestionDto.Id,
|
||||
PointsAwarded = isCorrect ? row.QuestionItem.AssignmentQuestionDto.Score : 0
|
||||
});
|
||||
|
||||
// 为每个学生随机生成初始的对错状态
|
||||
var random = new Random();
|
||||
foreach (var student in _students)
|
||||
{
|
||||
// 模拟随机对错,50%的概率
|
||||
rowData.StudentAnswers[student.Id] = random.Next(0, 2) == 1;
|
||||
}
|
||||
return rowData;
|
||||
}).ToList();
|
||||
}
|
||||
newSubmission.OverallGrade += isCorrect ? row.QuestionItem.AssignmentQuestionDto.Score : 0;
|
||||
}
|
||||
}
|
||||
submissionDto.Add(newSubmission);
|
||||
}
|
||||
|
||||
// 当某个学生的某个题目的作答状态改变时触发
|
||||
private void OnAnswerChanged(string questionSequence, Guid studentId, bool isCorrect)
|
||||
{
|
||||
// 可以在这里添加额外的逻辑,例如记录更改
|
||||
Console.WriteLine($"题目 {questionSequence}, 学生 {studentId} 的答案变为: {isCorrect}");
|
||||
// 由于是 @bind-Checked,数据模型已经自动更新,这里只是日志
|
||||
}
|
||||
submissionDto.ForEach(async s =>
|
||||
{
|
||||
Snackbar?.Add($"正在提交: {_students.FirstOrDefault(std => std.Id == s.StudentId)?.DisplayName} 的试卷", Severity.Info);
|
||||
await ExamService.SubmissionAssignment(s);
|
||||
});
|
||||
|
||||
// 计算某个学生的总分
|
||||
private float GetStudentTotalScore(Guid studentId)
|
||||
{
|
||||
float totalScore = 0;
|
||||
foreach (var row in _questionsForTable)
|
||||
{
|
||||
if (row.StudentAnswers.TryGetValue(studentId, out bool isCorrect) && isCorrect)
|
||||
{
|
||||
totalScore += row.QuestionItem.Score;
|
||||
}
|
||||
}
|
||||
return totalScore;
|
||||
}
|
||||
|
||||
// 切换某个学生所有题目的对错状态 (用于快速批改)
|
||||
private void ToggleStudentAllAnswers(Guid studentId)
|
||||
{
|
||||
bool allCorrect = _questionsForTable.All(row => row.StudentAnswers.ContainsKey(studentId) && row.StudentAnswers[studentId]);
|
||||
|
||||
foreach (var row in _questionsForTable)
|
||||
{
|
||||
if (row.StudentAnswers.ContainsKey(studentId))
|
||||
{
|
||||
row.StudentAnswers[studentId] = !allCorrect; // 全部取反
|
||||
}
|
||||
}
|
||||
StateHasChanged(); // 手动通知 Blazor 刷新 UI
|
||||
}
|
||||
|
||||
// 提交批改结果(模拟)
|
||||
private void SubmitGrading()
|
||||
{
|
||||
Console.WriteLine("--- 提交批改结果 ---");
|
||||
foreach (var student in _students)
|
||||
{
|
||||
Console.WriteLine($"学生: {student.Name}, 总分: {GetStudentTotalScore(student.Id)}");
|
||||
foreach (var row in _questionsForTable)
|
||||
{
|
||||
if (row.StudentAnswers.TryGetValue(student.Id, out bool isCorrect))
|
||||
{
|
||||
Console.WriteLine($" - 题目 {row.QuestionItem.Sequence}: {(isCorrect ? "正确" : "错误")}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Snackbar?.Add("批改结果已提交(模拟)", Severity.Success);
|
||||
// 实际应用中,这里会将 _questionsForTable 和 _students 的数据发送到后端API
|
||||
}
|
||||
Snackbar?.Add("批改结果已提交(模拟)", Severity.Success);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user