Files
TechHelper/TechHelper.Client/Pages/Exam/ExamCheck.razor
SpecialX 017cc2169c temp
2025-07-01 19:05:07 +08:00

239 lines
7.0 KiB
Plaintext
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.

@using Entities.DTO
@using TechHelper.Client.Exam
@using TechHelper.Client.Services
@page "/exam/check/{ExamID}"
<MudText Typo="Typo.h4" Class="mb-4">试卷批改预览: @Assignment.Title</MudText>
<MudDivider Class="my-4" />
@if (_isLoading)
{
<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" 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.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>
}
@code {
[Parameter]
public string ExamId { get; set; }
[Inject]
public IExamService ExamService { get; set; }
[Inject]
private ISnackbar Snackbar { get; set; }
[Inject]
private NavigationManager Navigation { get; set; }
private MudTable<QuestionRowData> _table = new();
private AssignmentDto Assignment { get; set; } = new AssignmentDto();
private AssignmentCheckData _examStruct = new AssignmentCheckData();
private List<StudentDto> _students = new List<StudentDto>();
private List<QuestionRowData> _questionsForTable = new List<QuestionRowData>();
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");
}
}
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>();
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.Graded;
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
});
newSubmission.OverallGrade += isCorrect ? row.QuestionItem.AssignmentQuestionDto.Score : 0;
}
}
submissionDto.Add(newSubmission);
}
submissionDto.ForEach(async s =>
{
Snackbar?.Add($"正在提交: {_students.FirstOrDefault(std => std.Id == s.StudentId)?.DisplayName} 的试卷", Severity.Info);
var submidResult = await ExamService.SubmissionAssignment(s);
if (submidResult.Status)
Snackbar?.Add($"批改结果已提交 {_students.FirstOrDefault(st => st.Id == s.StudentId)?.DisplayName}", Severity.Success);
else
Snackbar?.Add("批改结果提交失败", Severity.Error);
});
}
}