Files
TechHelper/TechHelper.Client/Pages/Exam/ExamCheck.razor
2025-06-20 15:37:39 +08:00

224 lines
8.5 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">试卷批改预览: @ExamDto.AssignmentTitle</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" 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>
<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>
}
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; } // 从路由获取的试卷ID
[Inject]
public IExamService ExamService { get; set; } // 注入试卷服务
[Inject]
private ISnackbar Snackbar { get; set; } // 注入 Snackbar 用于消息提示
[Inject]
private NavigationManager Navigation { get; set; } // 注入导航管理器
private MudTable<QuestionRowData> _table = new(); // MudTable 实例引用
private ExamDto ExamDto { get; set; } = new ExamDto(); // 原始试卷数据
private ExamStruct _examStruct = new ExamStruct(); // 处理后的试卷结构,包含带序号的题目
private List<Student> _students = new List<Student>(); // 临时生成的学生列表
private List<QuestionRowData> _questionsForTable = new List<QuestionRowData>(); // 用于 MudTable 的数据源
private bool _isLoading = true; // 加载状态
// 在组件初始化时加载数据
protected override async Task OnInitializedAsync()
{
_isLoading = true;
await LoadExamData();
GenerateTemporaryStudentsAndAnswers(); // 生成学生和初始作答数据
_isLoading = false;
}
// 加载试卷数据的方法
private async Task LoadExamData()
{
if (Guid.TryParse(ExamId, out Guid parsedExamId))
{
try
{
var result = await ExamService.GetExam(parsedExamId);
if (result.Status)
{
ExamDto = result.Result as ExamDto ?? new ExamDto();
_examStruct = ExamDto.GetStruct(); // 将 ExamDto 转换为 ExamStruct
}
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 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>()
};
// 为每个学生随机生成初始的对错状态
var random = new Random();
foreach (var student in _students)
{
// 模拟随机对错50%的概率
rowData.StudentAnswers[student.Id] = random.Next(0, 2) == 1;
}
return rowData;
}).ToList();
}
// 当某个学生的某个题目的作答状态改变时触发
private void OnAnswerChanged(string questionSequence, Guid studentId, bool isCorrect)
{
// 可以在这里添加额外的逻辑,例如记录更改
Console.WriteLine($"题目 {questionSequence}, 学生 {studentId} 的答案变为: {isCorrect}");
// 由于是 @bind-Checked数据模型已经自动更新这里只是日志
}
// 计算某个学生的总分
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
}
}