temp
This commit is contained in:
@@ -73,4 +73,44 @@ namespace Entities.Contracts
|
|||||||
AssignmentAttachments = new HashSet<AssignmentAttachment>();
|
AssignmentAttachments = new HashSet<AssignmentAttachment>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class AssignmentExt
|
||||||
|
{
|
||||||
|
public static Submission ConvertToSubmission(this Assignment assignment, Guid studentId, Guid GraderId)
|
||||||
|
{
|
||||||
|
if (assignment == null) return new Submission();
|
||||||
|
var submission = new Submission();
|
||||||
|
|
||||||
|
submission.StudentId = studentId;
|
||||||
|
submission.SubmissionTime = DateTime.Now;
|
||||||
|
submission.Status = SubmissionStatus.Pending;
|
||||||
|
submission.GraderId = GraderId;
|
||||||
|
submission.AssignmentId = assignment.Id;
|
||||||
|
|
||||||
|
ConvertExamSturctToSubmissionDetails(assignment.ExamStruct, studentId, submission.SubmissionDetails);
|
||||||
|
|
||||||
|
return submission;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void ConvertExamSturctToSubmissionDetails(AssignmentQuestion examStruct, Guid studentId, ICollection<SubmissionDetail> submissions)
|
||||||
|
{
|
||||||
|
if (examStruct == null) return;
|
||||||
|
submissions.Add(new SubmissionDetail
|
||||||
|
{
|
||||||
|
StudentId = studentId,
|
||||||
|
AssignmentQuestionId = examStruct.Id,
|
||||||
|
IsCorrect = true,
|
||||||
|
CreatedAt = DateTime.Now,
|
||||||
|
UpdatedAt = DateTime.Now,
|
||||||
|
Status = SubmissionStatus.Pending,
|
||||||
|
});
|
||||||
|
|
||||||
|
examStruct.ChildrenAssignmentQuestion?.ToList().ForEach(s =>
|
||||||
|
{
|
||||||
|
ConvertExamSturctToSubmissionDetails(s, studentId, submissions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,7 @@ namespace Entities.Contracts
|
|||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[Column("attempt_number")]
|
[Column("attempt_number")]
|
||||||
public Guid AttemptNumber { get; set; }
|
public byte AttemptNumber { get; set; }
|
||||||
|
|
||||||
[Column("submission_time")]
|
[Column("submission_time")]
|
||||||
public DateTime SubmissionTime { get; set; }
|
public DateTime SubmissionTime { get; set; }
|
||||||
|
@@ -51,6 +51,12 @@ namespace Entities.Contracts
|
|||||||
[Column("deleted")]
|
[Column("deleted")]
|
||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("status")]
|
||||||
|
public SubmissionStatus Status { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[ForeignKey(nameof(StudentId))]
|
[ForeignKey(nameof(StudentId))]
|
||||||
public User Student { get; set; }
|
public User Student { get; set; }
|
||||||
|
|
||||||
|
15
Entities/DTO/AssigExamToStudentsDto.cs
Normal file
15
Entities/DTO/AssigExamToStudentsDto.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Entities.DTO
|
||||||
|
{
|
||||||
|
public class AssigExamToStudentsDto
|
||||||
|
{
|
||||||
|
public Guid CreaterId { get; set; }
|
||||||
|
public Guid AssignmentId { get; set; }
|
||||||
|
public List<Guid> StudentIds { get; set; } = new List<Guid>();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using Entities.Contracts;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -15,5 +16,6 @@ namespace Entities.DTO
|
|||||||
public bool? IsCorrect { get; set; }
|
public bool? IsCorrect { get; set; }
|
||||||
public float? PointsAwarded { get; set; }
|
public float? PointsAwarded { get; set; }
|
||||||
public string? TeacherFeedback { get; set; }
|
public string? TeacherFeedback { get; set; }
|
||||||
|
public SubmissionStatus Status { get; set; } = SubmissionStatus.Graded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
Entities/DTO/UserClassRoleDto.cs
Normal file
14
Entities/DTO/UserClassRoleDto.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Entities.DTO
|
||||||
|
{
|
||||||
|
public class UserClassRoleDto
|
||||||
|
{
|
||||||
|
public List<(byte, byte)> ClassInfo { get; set; } = new List<(byte, byte)> ();
|
||||||
|
public string Role { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
34
TechHelper.Client/Pages/Author/RestoreUserRole.razor
Normal file
34
TechHelper.Client/Pages/Author/RestoreUserRole.razor
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
@using TechHelper.Client.Services
|
||||||
|
<MudPaper Height="50" Width="50" Outlined="true">
|
||||||
|
|
||||||
|
<MudButton Variant="Variant.Filled" OnClick="Restore"> Restore Role </MudButton>
|
||||||
|
|
||||||
|
</MudPaper>
|
||||||
|
@code {
|
||||||
|
[Inject]
|
||||||
|
public IAuthenticationClientService Authentication { get; set; }
|
||||||
|
[Inject]
|
||||||
|
public IUserServices UserServices { get; set; }
|
||||||
|
[Inject]
|
||||||
|
public ISnackbar Snackbar { get; set; }
|
||||||
|
private async Task Restore()
|
||||||
|
{
|
||||||
|
var result = await UserServices.RestoreUserInfo();
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
|
||||||
|
Snackbar.Add("更新成功", Severity.Success);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Snackbar.Add("更新失败", Severity.Error);
|
||||||
|
var token = await Authentication.RefreshTokenAsync();
|
||||||
|
if (token != null)
|
||||||
|
Snackbar.Add("刷新令牌成功", Severity.Success);
|
||||||
|
else
|
||||||
|
Snackbar.Add("刷新令牌失败,你可以手动刷新", Severity.Warning);
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -200,7 +200,7 @@ else
|
|||||||
newSubmission.StudentId = student.Id;
|
newSubmission.StudentId = student.Id;
|
||||||
newSubmission.AssignmentId = Assignment.Id;
|
newSubmission.AssignmentId = Assignment.Id;
|
||||||
newSubmission.SubmissionTime = DateTime.Now;
|
newSubmission.SubmissionTime = DateTime.Now;
|
||||||
newSubmission.Status = Entities.Contracts.SubmissionStatus.Submitted;
|
newSubmission.Status = Entities.Contracts.SubmissionStatus.Graded;
|
||||||
|
|
||||||
|
|
||||||
foreach (var row in _questionsForTable)
|
foreach (var row in _questionsForTable)
|
||||||
@@ -225,11 +225,15 @@ else
|
|||||||
submissionDto.ForEach(async s =>
|
submissionDto.ForEach(async s =>
|
||||||
{
|
{
|
||||||
Snackbar?.Add($"正在提交: {_students.FirstOrDefault(std => std.Id == s.StudentId)?.DisplayName} 的试卷", Severity.Info);
|
Snackbar?.Add($"正在提交: {_students.FirstOrDefault(std => std.Id == s.StudentId)?.DisplayName} 的试卷", Severity.Info);
|
||||||
await ExamService.SubmissionAssignment(s);
|
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);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Snackbar?.Add("批改结果已提交(模拟)", Severity.Success);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -50,9 +50,16 @@ else
|
|||||||
isloding = true;
|
isloding = true;
|
||||||
Snackbar.Add("正在加载", Severity.Info);
|
Snackbar.Add("正在加载", Severity.Info);
|
||||||
var result = await ExamService.GetAllExam();
|
var result = await ExamService.GetAllExam();
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
examDtos = result.Result as List<AssignmentDto> ?? new List<AssignmentDto>();
|
examDtos = result.Result as List<AssignmentDto> ?? new List<AssignmentDto>();
|
||||||
isloding = false;
|
|
||||||
Snackbar.Add("加载成功", Severity.Info);
|
Snackbar.Add("加载成功", Severity.Info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Snackbar.Add($"加载失败 {result.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
isloding = false;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -56,3 +56,4 @@ else
|
|||||||
<MudText Class="ma-3 pa-3"> 班级 : @authenticationStateTask.Result.User.FindFirst("Class")?.Value.ToString() </MudText>
|
<MudText Class="ma-3 pa-3"> 班级 : @authenticationStateTask.Result.User.FindFirst("Class")?.Value.ToString() </MudText>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
}
|
}
|
||||||
|
<RestoreUserRole></RestoreUserRole>
|
@@ -45,6 +45,7 @@ builder.Services.AddScoped<IClassServices, ClasssServices>();
|
|||||||
builder.Services.AddScoped<IEmailSender, QEmailSender>();
|
builder.Services.AddScoped<IEmailSender, QEmailSender>();
|
||||||
builder.Services.AddScoped<HttpInterceptorHandlerService>();
|
builder.Services.AddScoped<HttpInterceptorHandlerService>();
|
||||||
builder.Services.AddScoped<IAIService, AiService>();
|
builder.Services.AddScoped<IAIService, AiService>();
|
||||||
|
builder.Services.AddScoped<IUserServices, UserServices>();
|
||||||
builder.Services.AddHttpClient("WebApiClient", client =>
|
builder.Services.AddHttpClient("WebApiClient", client =>
|
||||||
{
|
{
|
||||||
var baseAddress = builder.Configuration.GetSection("ApiConfiguration:BaseAddress").Value;
|
var baseAddress = builder.Configuration.GetSection("ApiConfiguration:BaseAddress").Value;
|
||||||
|
@@ -167,7 +167,7 @@ namespace TechHelper.Client.Services
|
|||||||
// 直接使用注入的 _client 实例
|
// 直接使用注入的 _client 实例
|
||||||
var response = await _client.PostAsJsonAsync("exam/add", assiDto);
|
var response = await _client.PostAsJsonAsync("exam/add", assiDto);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode) // 检查是否是成功的状态码,例如 200 OK, 201 Created 等
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return ApiResponse.Success(message: "试题保存成功。");
|
return ApiResponse.Success(message: "试题保存成功。");
|
||||||
}
|
}
|
||||||
|
9
TechHelper.Client/Services/IUserServices.cs
Normal file
9
TechHelper.Client/Services/IUserServices.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using TechHelper.Services;
|
||||||
|
|
||||||
|
namespace TechHelper.Client.Services
|
||||||
|
{
|
||||||
|
public interface IUserServices
|
||||||
|
{
|
||||||
|
public Task<ApiResponse> RestoreUserInfo();
|
||||||
|
}
|
||||||
|
}
|
24
TechHelper.Client/Services/UserServices.cs
Normal file
24
TechHelper.Client/Services/UserServices.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using TechHelper.Services;
|
||||||
|
|
||||||
|
namespace TechHelper.Client.Services
|
||||||
|
{
|
||||||
|
public class UserServices : IUserServices
|
||||||
|
{
|
||||||
|
private readonly HttpClient _client;
|
||||||
|
|
||||||
|
public UserServices(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
_client = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse> RestoreUserInfo()
|
||||||
|
{
|
||||||
|
var result = await _client.GetAsync("user/restoreUserRole");
|
||||||
|
if (result.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
return ApiResponse.Success();
|
||||||
|
}
|
||||||
|
return ApiResponse.Error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -32,7 +32,8 @@ namespace TechHelper.Context
|
|||||||
.ForMember(dest => dest.EmailConfirmed, opt => opt.Ignore());
|
.ForMember(dest => dest.EmailConfirmed, opt => opt.Ignore());
|
||||||
|
|
||||||
CreateMap<ClassDto, Class>()
|
CreateMap<ClassDto, Class>()
|
||||||
.ForMember(d => d.Number, o => o.MapFrom(src => src.Class)).ReverseMap();
|
.ForMember(d => d.Number, o => o.MapFrom(src => src.Class))
|
||||||
|
.ReverseMap();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -11,14 +11,12 @@ using TechHelper.Services;
|
|||||||
|
|
||||||
namespace TechHelper.Server.Controllers
|
namespace TechHelper.Server.Controllers
|
||||||
{
|
{
|
||||||
[Route("api/exam")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
|
|
||||||
|
|
||||||
public class ExamController : ControllerBase
|
public class ExamController : ControllerBase
|
||||||
{
|
{
|
||||||
private IExamService _examService;
|
private readonly IExamService _examService;
|
||||||
private readonly UserManager<User> _userManager;
|
private readonly UserManager<User> _userManager;
|
||||||
|
|
||||||
public ExamController(IExamService examService, UserManager<User> userManager)
|
public ExamController(IExamService examService, UserManager<User> userManager)
|
||||||
@@ -27,117 +25,202 @@ namespace TechHelper.Server.Controllers
|
|||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建一个新的考试/作业。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="examDto">考试/作业的数据传输对象。</param>
|
||||||
|
/// <returns>新创建的考试/作业信息或错误信息。</returns>
|
||||||
[HttpPost("add")]
|
[HttpPost("add")]
|
||||||
public async Task<IActionResult> AddExam(
|
public async Task<IActionResult> AddExam([FromBody] AssignmentDto examDto)
|
||||||
[FromBody] AssignmentDto examDto)
|
|
||||||
{
|
{
|
||||||
var user = await _userManager.FindByEmailAsync(User.Identity?.Name ?? "");
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
if (user == null) return BadRequest("无效的用户");
|
if (user == null) return NotFound("没有找到用户");
|
||||||
|
|
||||||
examDto.CreatorId = user.Id;
|
examDto.CreatorId = user.Id;
|
||||||
var result = await _examService.CreateExamAsync(examDto);
|
var result = await _examService.CreateExamAsync(examDto);
|
||||||
if (result.Status)
|
|
||||||
{
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return BadRequest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("submission")]
|
|
||||||
public async Task<IActionResult> SubmissionAssignment(
|
|
||||||
[FromBody] SubmissionDto submissionDto)
|
|
||||||
{
|
|
||||||
if (User == null) return BadRequest("无效的用户");
|
|
||||||
if (User.IsInRole("Teacher"))
|
|
||||||
{
|
|
||||||
var result = await _examService.SubmissionAssignment(submissionDto);
|
|
||||||
if (result.Status)
|
if (result.Status)
|
||||||
{
|
{
|
||||||
return Ok(result);
|
return StatusCode(201, result.Result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return BadRequest(result.Message);
|
return BadRequest(result.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提交作业。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="submissionDto">提交的数据传输对象。</param>
|
||||||
|
/// <returns>提交结果或错误信息。</returns>
|
||||||
|
[HttpPost("submission")]
|
||||||
|
[Authorize(Roles = "Student")]
|
||||||
|
public async Task<IActionResult> SubmissionAssignment([FromBody] SubmissionDto submissionDto)
|
||||||
|
{
|
||||||
|
var result = await _examService.SubmissionAssignment(submissionDto);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result.Result);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return BadRequest("你没有权限修改");
|
return BadRequest(result.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("get")]
|
/// <summary>
|
||||||
|
/// 根据ID获取考试/作业详情。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">考试/作业ID。</param>
|
||||||
|
/// <returns>考试/作业详情或未找到错误。</returns>
|
||||||
|
[HttpGet("{id:guid}")]
|
||||||
public async Task<IActionResult> GetExamById(Guid id)
|
public async Task<IActionResult> GetExamById(Guid id)
|
||||||
{
|
{
|
||||||
|
|
||||||
var result = await _examService.GetAsync(id);
|
var result = await _examService.GetAsync(id);
|
||||||
|
|
||||||
if (result.Status)
|
if (result.Status)
|
||||||
|
{
|
||||||
|
if (result.Result == null)
|
||||||
|
{
|
||||||
|
return NotFound("未找到指定的考试/作业。");
|
||||||
|
}
|
||||||
return Ok(result.Result);
|
return Ok(result.Result);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return BadRequest("查找失败");
|
{
|
||||||
|
if (result.Message.Contains("未找到") || result.Message.Contains("not found", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return NotFound(result.Message);
|
||||||
|
}
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有考试/作业的预览信息(教师获取自己创建的,学生获取自己需要提交的)。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>考试/作业预览列表或错误信息。</returns>
|
||||||
[HttpGet("getAllPreview")]
|
[HttpGet("getAllPreview")]
|
||||||
public async Task<IActionResult> GetAllExamPreview()
|
public async Task<IActionResult> GetAllExamPreview()
|
||||||
{
|
{
|
||||||
if (User == null) return BadRequest("用户验证失败, 无效用户");
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
if (user == null) return NotFound("没有找到用户");
|
||||||
|
|
||||||
var userid = await _userManager.FindByEmailAsync(User.Identity.Name);
|
ApiResponse result;
|
||||||
|
|
||||||
|
|
||||||
var result = new ApiResponse();
|
|
||||||
if (User.IsInRole("Teacher"))
|
if (User.IsInRole("Teacher"))
|
||||||
{
|
{
|
||||||
result = await _examService.GetAllExamPreviewsAsync(userid.Id);
|
result = await _examService.GetAllExamPreviewsAsync(user.Id);
|
||||||
}
|
}
|
||||||
else if (User.IsInRole("Student"))
|
else if (User.IsInRole("Student"))
|
||||||
{
|
{
|
||||||
result = await _examService.GetAllSubmissionAsync(userid.Id);
|
result = await _examService.GetAllSubmissionAsync(user.Id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return BadRequest("你没有相应的权限");
|
return Forbid("你没有查看考试预览的权限。");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.Status)
|
if (result.Status)
|
||||||
{
|
{
|
||||||
return Ok(result.Result);
|
return Ok(result.Result);
|
||||||
}
|
}
|
||||||
return BadRequest(result);
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
[HttpGet("getAllSubmission")]
|
/// 获取学生的所有提交记录。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>提交记录列表或错误信息。</returns>
|
||||||
|
[HttpGet("getAllSubmissions")]
|
||||||
|
[Authorize(Roles = "Student")]
|
||||||
public async Task<IActionResult> GetAllSubmission()
|
public async Task<IActionResult> GetAllSubmission()
|
||||||
{
|
{
|
||||||
if (User == null) return BadRequest("用户验证失败, 无效用户");
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
if (user == null) return NotFound("没有找到用户");
|
||||||
|
|
||||||
var userid = await _userManager.FindByEmailAsync(User.Identity.Name);
|
var result = await _examService.GetAllSubmissionAsync(user.Id);
|
||||||
|
|
||||||
var result = await _examService.GetAllSubmissionAsync(userid.Id);
|
|
||||||
|
|
||||||
if (result.Status)
|
if (result.Status)
|
||||||
{
|
{
|
||||||
return Ok(result.Result);
|
return Ok(result.Result);
|
||||||
}
|
}
|
||||||
return BadRequest(result);
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 逻辑删除指定ID的考试/作业。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">要删除的考试/作业ID。</param>
|
||||||
|
/// <returns>操作结果。</returns>
|
||||||
|
[HttpDelete("delete/{id:guid}")]
|
||||||
[Authorize(Roles = "Teacher")]
|
[Authorize(Roles = "Teacher")]
|
||||||
[HttpDelete("{guid}")]
|
public async Task<IActionResult> DeleteAsync(Guid id)
|
||||||
public async Task<IActionResult> DeleteAsync(Guid guid)
|
|
||||||
{
|
{
|
||||||
var deleteResult = await _examService.DeleteAsync(guid);
|
var deleteResult = await _examService.DeleteAsync(id);
|
||||||
|
|
||||||
if (deleteResult.Status)
|
if (deleteResult.Status)
|
||||||
{
|
{
|
||||||
return Ok();
|
return NoContent();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (deleteResult.Message.Contains("未找到") || deleteResult.Message.Contains("not found", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return NotFound(deleteResult.Message);
|
||||||
|
}
|
||||||
|
return BadRequest(deleteResult.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为指定学生指派作业
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="AETSdto"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("assignmentExamToStudent")]
|
||||||
|
[Authorize(Roles = "Teacher")]
|
||||||
|
public async Task<IActionResult> AssignmentExamToStudent([FromBody] AssigExamToStudentsDto AETSdto)
|
||||||
|
{
|
||||||
|
var result = await _examService.AssignmentToStudentsAsync(AETSdto);
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result.Result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为所有学生指派作业
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="AETSdto"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("assignmentExamToStudent/{id:guid}")]
|
||||||
|
[Authorize(Roles = "Teacher")]
|
||||||
|
public async Task<IActionResult> AssignmentExamToAllStudentsAsync(Guid id)
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name ?? "");
|
||||||
|
var result = await _examService.AssignmentToAllStudentsAsync(id, user.Id);
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result.Result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
}
|
}
|
||||||
return BadRequest();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
279
TechHelper.Server/Controllers/SubmissionController.cs
Normal file
279
TechHelper.Server/Controllers/SubmissionController.cs
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
using Entities.Contracts;
|
||||||
|
using Entities.DTO;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using TechHelper.Server.Services;
|
||||||
|
using TechHelper.Services;
|
||||||
|
|
||||||
|
namespace TechHelper.Server.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/submission")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
|
||||||
|
public class SubmissionController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
private readonly ISubmissionServices _submissionServices;
|
||||||
|
|
||||||
|
public SubmissionController(UserManager<User> userManager, ISubmissionServices submissionServices)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_submissionServices = submissionServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前用户的所有错题。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>错题列表或错误信息。</returns>
|
||||||
|
[HttpGet("getAllErrorQuestions")]
|
||||||
|
public async Task<IActionResult> GetAllErrorQuestionsAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound("未找到当前用户信息。");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _submissionServices.GetAllErrorQuestionsAsync(user.Id);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定作业中当前用户的错题。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignmentId">作业ID。</param>
|
||||||
|
/// <returns>错题列表或错误信息。</returns>
|
||||||
|
[HttpGet("getAssignmentErrorQuestions/{assignmentId:guid}")]
|
||||||
|
public async Task<IActionResult> GetAssignmentErrorQuestionsAsync(Guid assignmentId)
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound("未找到当前用户信息。");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _submissionServices.GetAssignmentErrorQuestionsAsync(assignmentId, user.Id);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定作业中当前用户的错题类型分布。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignmentId">作业ID。</param>
|
||||||
|
/// <returns>错题类型分布数据。</returns>
|
||||||
|
[HttpGet("getAssignmentErrorQuestionTypeDistribution/{assignmentId:guid}")]
|
||||||
|
public async Task<IActionResult> GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId)
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound("未找到当前用户信息。");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _submissionServices.GetAssignmentErrorQuestionTypeDisAsync(assignmentId, user.Id);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定作业中所有学生的错题情况概述。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignmentId">作业ID。</param>
|
||||||
|
/// <returns>每个学生的错题统计信息。</returns>
|
||||||
|
[HttpGet("getAssignmentAllStudentsError/{assignmentId:guid}")]
|
||||||
|
[Authorize(Roles = "Teacher")]
|
||||||
|
public async Task<IActionResult> GetAssignmentAllStudentsError(Guid assignmentId)
|
||||||
|
{
|
||||||
|
// 假设当前用户是教师,如果需要验证,可以使用UserManager.IsInRoleAsync
|
||||||
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound("未找到当前用户信息。");
|
||||||
|
}
|
||||||
|
// TODO: 根据实际业务需求,可能需要验证当前用户是否为该作业的教师。
|
||||||
|
// 例如: var isTeacherOfAssignment = await _assignmentService.IsTeacherOfAssignment(assignmentId, user.Id);
|
||||||
|
|
||||||
|
var result = await _submissionServices.GetAssignmentAllStudentsError(assignmentId, user.Id); // 传入当前教师ID
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定作业中哪些学生做错了哪些题目。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignmentId">作业ID。</param>
|
||||||
|
/// <returns>按题目分组的学生错题列表。</returns>
|
||||||
|
[HttpGet("getQuestionErrorStudents/{assignmentId:guid}")]
|
||||||
|
[Authorize(Roles = "Teacher")]
|
||||||
|
public async Task<IActionResult> GetQuestionErrorStudents(Guid assignmentId)
|
||||||
|
{
|
||||||
|
var result = await _submissionServices.GetQuestionErrorStudents(assignmentId);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加一次提交记录。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">提交的数据模型。</param>
|
||||||
|
/// <returns>新创建的提交记录或错误信息。</returns>
|
||||||
|
[HttpPost("add")]
|
||||||
|
public async Task<IActionResult> AddAsync([FromBody] Submission model)
|
||||||
|
{
|
||||||
|
// 可以在这里获取当前用户ID并赋值给 model.StudentId,确保提交人信息正确
|
||||||
|
// var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
// if (user == null) return NotFound("未找到当前用户信息。");
|
||||||
|
// model.StudentId = user.Id;
|
||||||
|
|
||||||
|
var result = await _submissionServices.AddAsync(model);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
// 如果成功,通常返回 201 Created,并包含新资源的URI
|
||||||
|
// 但如果服务层只返回数据,也可以直接 Ok
|
||||||
|
return StatusCode(201, result); // 建议返回 201 Created
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 逻辑删除指定ID的提交记录。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">提交ID。</param>
|
||||||
|
/// <returns>操作结果。</returns>
|
||||||
|
[HttpDelete("delete/{id:guid}")]
|
||||||
|
public async Task<IActionResult> DeleteAsync(Guid id)
|
||||||
|
{
|
||||||
|
// TODO: 在服务层或控制器层添加权限检查:确保删除者有权删除此提交(例如是提交者本人、相关教师或管理员)
|
||||||
|
// var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
// if (user == null) return Unauthorized(); // 或 Forbidden
|
||||||
|
|
||||||
|
var result = await _submissionServices.DeleteAsync(id);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return NoContent(); // 204 No Content,表示删除成功但无内容返回
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有提交记录(支持分页和查询)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">查询参数,包含分页信息。</param>
|
||||||
|
/// <returns>分页的提交记录列表。</returns>
|
||||||
|
[HttpGet("getAll")]
|
||||||
|
[Authorize(Roles = "Admin,Teacher")]
|
||||||
|
public async Task<IActionResult> GetAllAsync([FromQuery] QueryParameter query)
|
||||||
|
{
|
||||||
|
var result = await _submissionServices.GetAllAsync(query);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据ID获取单个提交记录。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">提交ID。</param>
|
||||||
|
/// <returns>单个提交记录或未找到错误。</returns>
|
||||||
|
[HttpGet("{id:guid}")]
|
||||||
|
public async Task<IActionResult> GetAsync(Guid id)
|
||||||
|
{
|
||||||
|
var result = await _submissionServices.GetAsync(id);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新提交记录。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">提交ID。</param>
|
||||||
|
/// <param name="model">要更新的提交数据。</param>
|
||||||
|
/// <returns>更新后的提交记录或错误信息。</returns>
|
||||||
|
[HttpPut("update/{id:guid}")]
|
||||||
|
public async Task<IActionResult> UpdateAsync(Guid id, [FromBody] Submission model)
|
||||||
|
{
|
||||||
|
if (id != model.Id) // 确保路径中的ID和模型中的ID一致
|
||||||
|
{
|
||||||
|
return BadRequest("路由ID与请求体中的ID不匹配。");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 权限检查:确保更新者有权更新此提交
|
||||||
|
// var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
// if (user == null) return Unauthorized();
|
||||||
|
|
||||||
|
var result = await _submissionServices.UpdateAsync(model);
|
||||||
|
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
return BadRequest(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -3,6 +3,7 @@ using Entities.DTO;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using TechHelper.Server.Services;
|
||||||
using TechHelper.Services;
|
using TechHelper.Services;
|
||||||
|
|
||||||
namespace TechHelper.Server.Controllers
|
namespace TechHelper.Server.Controllers
|
||||||
@@ -11,12 +12,14 @@ namespace TechHelper.Server.Controllers
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class UserController : ControllerBase
|
public class UserController : ControllerBase
|
||||||
{
|
{
|
||||||
|
private IUserSerivces _userSerivces;
|
||||||
private IClassService _classService;
|
private IClassService _classService;
|
||||||
private UserManager<User> _userManager;
|
private UserManager<User> _userManager;
|
||||||
public UserController(IClassService classService, UserManager<User> userManager)
|
public UserController(IClassService classService, UserManager<User> userManager, IUserSerivces userSerivces)
|
||||||
{
|
{
|
||||||
_classService = classService;
|
_classService = classService;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
|
_userSerivces = userSerivces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -26,5 +29,22 @@ namespace TechHelper.Server.Controllers
|
|||||||
{
|
{
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("restoreUserRole")]
|
||||||
|
public async Task<IActionResult> RestoreUserRole()
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||||
|
|
||||||
|
if (user == null) return NotFound();
|
||||||
|
if (User.IsInRole("Teacher") || User.IsInRole("Student"))
|
||||||
|
return Ok();
|
||||||
|
var result = await _userSerivces.RestoreUserRoleInformation(user);
|
||||||
|
if (result.Status)
|
||||||
|
return Ok();
|
||||||
|
else
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1254
TechHelper.Server/Migrations/20250630090135__update_submisstion_detail.Designer.cs
generated
Normal file
1254
TechHelper.Server/Migrations/20250630090135__update_submisstion_detail.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||||
|
|
||||||
|
namespace TechHelper.Server.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class _update_submisstion_detail : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("cf16c215-63f8-4962-8ad0-058274ecf944"));
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("e3bff43c-36af-497a-971c-ed0a487bdd38"));
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("f05c125e-e70f-40eb-9e19-6e69c3426849"));
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "status",
|
||||||
|
table: "submission_details",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||||
|
values: new object[,]
|
||||||
|
{
|
||||||
|
{ new Guid("14b8854f-a38b-4e72-878e-31ba2f7528b2"), null, "Teacher", "TEACHER" },
|
||||||
|
{ new Guid("69c3cc0c-b284-433e-8493-9b1e7bd1eb1f"), null, "Student", "STUDENT" },
|
||||||
|
{ new Guid("6ef4d2bb-05da-4c17-9152-4467d86939fc"), null, "Administrator", "ADMINISTRATOR" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("14b8854f-a38b-4e72-878e-31ba2f7528b2"));
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("69c3cc0c-b284-433e-8493-9b1e7bd1eb1f"));
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("6ef4d2bb-05da-4c17-9152-4467d86939fc"));
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "status",
|
||||||
|
table: "submission_details");
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||||
|
values: new object[,]
|
||||||
|
{
|
||||||
|
{ new Guid("cf16c215-63f8-4962-8ad0-058274ecf944"), null, "Administrator", "ADMINISTRATOR" },
|
||||||
|
{ new Guid("e3bff43c-36af-497a-971c-ed0a487bdd38"), null, "Student", "STUDENT" },
|
||||||
|
{ new Guid("f05c125e-e70f-40eb-9e19-6e69c3426849"), null, "Teacher", "TEACHER" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1254
TechHelper.Server/Migrations/20250701095424_atemp_number_convert_to_byte.Designer.cs
generated
Normal file
1254
TechHelper.Server/Migrations/20250701095424_atemp_number_convert_to_byte.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||||
|
|
||||||
|
namespace TechHelper.Server.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class atemp_number_convert_to_byte : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("14b8854f-a38b-4e72-878e-31ba2f7528b2"));
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("69c3cc0c-b284-433e-8493-9b1e7bd1eb1f"));
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("6ef4d2bb-05da-4c17-9152-4467d86939fc"));
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<byte>(
|
||||||
|
name: "attempt_number",
|
||||||
|
table: "submissions",
|
||||||
|
type: "tinyint unsigned",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(Guid),
|
||||||
|
oldType: "char(36)")
|
||||||
|
.OldAnnotation("Relational:Collation", "ascii_general_ci");
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||||
|
values: new object[,]
|
||||||
|
{
|
||||||
|
{ new Guid("379143a2-8d7f-4ef7-b7c0-14701b710f87"), null, "Administrator", "ADMINISTRATOR" },
|
||||||
|
{ new Guid("6d49bb08-97d6-4a38-88a7-8080925b589b"), null, "Student", "STUDENT" },
|
||||||
|
{ new Guid("e330c745-f422-43e3-bcdf-1439ace3c52f"), null, "Teacher", "TEACHER" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("379143a2-8d7f-4ef7-b7c0-14701b710f87"));
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("6d49bb08-97d6-4a38-88a7-8080925b589b"));
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: new Guid("e330c745-f422-43e3-bcdf-1439ace3c52f"));
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<Guid>(
|
||||||
|
name: "attempt_number",
|
||||||
|
table: "submissions",
|
||||||
|
type: "char(36)",
|
||||||
|
nullable: false,
|
||||||
|
collation: "ascii_general_ci",
|
||||||
|
oldClrType: typeof(byte),
|
||||||
|
oldType: "tinyint unsigned");
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||||
|
values: new object[,]
|
||||||
|
{
|
||||||
|
{ new Guid("14b8854f-a38b-4e72-878e-31ba2f7528b2"), null, "Teacher", "TEACHER" },
|
||||||
|
{ new Guid("69c3cc0c-b284-433e-8493-9b1e7bd1eb1f"), null, "Student", "STUDENT" },
|
||||||
|
{ new Guid("6ef4d2bb-05da-4c17-9152-4467d86939fc"), null, "Administrator", "ADMINISTRATOR" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -500,8 +500,8 @@ namespace TechHelper.Server.Migrations
|
|||||||
.HasColumnType("char(36)")
|
.HasColumnType("char(36)")
|
||||||
.HasColumnName("assignment_id");
|
.HasColumnName("assignment_id");
|
||||||
|
|
||||||
b.Property<Guid>("AttemptNumber")
|
b.Property<byte>("AttemptNumber")
|
||||||
.HasColumnType("char(36)")
|
.HasColumnType("tinyint unsigned")
|
||||||
.HasColumnName("attempt_number");
|
.HasColumnName("attempt_number");
|
||||||
|
|
||||||
b.Property<DateTime?>("GradedAt")
|
b.Property<DateTime?>("GradedAt")
|
||||||
@@ -584,6 +584,10 @@ namespace TechHelper.Server.Migrations
|
|||||||
.HasColumnType("float")
|
.HasColumnType("float")
|
||||||
.HasColumnName("points_awarded");
|
.HasColumnName("points_awarded");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("status");
|
||||||
|
|
||||||
b.Property<string>("StudentAnswer")
|
b.Property<string>("StudentAnswer")
|
||||||
.HasColumnType("longtext")
|
.HasColumnType("longtext")
|
||||||
.HasColumnName("student_answer");
|
.HasColumnName("student_answer");
|
||||||
@@ -751,19 +755,19 @@ namespace TechHelper.Server.Migrations
|
|||||||
b.HasData(
|
b.HasData(
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = new Guid("e3bff43c-36af-497a-971c-ed0a487bdd38"),
|
Id = new Guid("6d49bb08-97d6-4a38-88a7-8080925b589b"),
|
||||||
Name = "Student",
|
Name = "Student",
|
||||||
NormalizedName = "STUDENT"
|
NormalizedName = "STUDENT"
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = new Guid("f05c125e-e70f-40eb-9e19-6e69c3426849"),
|
Id = new Guid("e330c745-f422-43e3-bcdf-1439ace3c52f"),
|
||||||
Name = "Teacher",
|
Name = "Teacher",
|
||||||
NormalizedName = "TEACHER"
|
NormalizedName = "TEACHER"
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = new Guid("cf16c215-63f8-4962-8ad0-058274ecf944"),
|
Id = new Guid("379143a2-8d7f-4ef7-b7c0-14701b710f87"),
|
||||||
Name = "Administrator",
|
Name = "Administrator",
|
||||||
NormalizedName = "ADMINISTRATOR"
|
NormalizedName = "ADMINISTRATOR"
|
||||||
});
|
});
|
||||||
|
@@ -87,6 +87,8 @@ builder.Services.AddScoped<IEmailSender, QEmailSender>();
|
|||||||
builder.Services.AddTransient<IUserRegistrationService, UserRegistrationService>();
|
builder.Services.AddTransient<IUserRegistrationService, UserRegistrationService>();
|
||||||
builder.Services.AddScoped<IClassService, ClassService>();
|
builder.Services.AddScoped<IClassService, ClassService>();
|
||||||
builder.Services.AddScoped<IExamService, ExamService>();
|
builder.Services.AddScoped<IExamService, ExamService>();
|
||||||
|
builder.Services.AddScoped<IUserSerivces, UserServices>();
|
||||||
|
builder.Services.AddScoped<ISubmissionServices, SubmissionServices>();
|
||||||
builder.Services.AddScoped<IExamRepository, ExamRepository>();
|
builder.Services.AddScoped<IExamRepository, ExamRepository>();
|
||||||
|
|
||||||
|
|
||||||
|
@@ -101,7 +101,7 @@ namespace TechHelper.Server.Repositories
|
|||||||
var submissions = await _unitOfWork.GetRepository<Submission>().GetAllAsync(predicate: s => s.StudentId == id, include: i => i.Include(s => s.Assignment));
|
var submissions = await _unitOfWork.GetRepository<Submission>().GetAllAsync(predicate: s => s.StudentId == id, include: i => i.Include(s => s.Assignment));
|
||||||
if (submissions == null || !submissions.Any())
|
if (submissions == null || !submissions.Any())
|
||||||
return Enumerable.Empty<Assignment>();
|
return Enumerable.Empty<Assignment>();
|
||||||
return submissions.ToList().Select(s => s.Assignment).Where(a => a != null).Distinct().ToList();
|
return submissions.ToList().Select(s => s.Assignment).Where(a => a != null).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -150,7 +150,7 @@ namespace TechHelper.Services
|
|||||||
var std = await _work.GetRepository<ClassStudent>().GetAllAsync(predicate: user => user.StudentId == id, include: i => i
|
var std = await _work.GetRepository<ClassStudent>().GetAllAsync(predicate: user => user.StudentId == id, include: i => i
|
||||||
.Include(t => t.Class));
|
.Include(t => t.Class));
|
||||||
|
|
||||||
if (tch == null && std == null) return new ApiResponse("你没有加入任何班级。");
|
if (tch == null && std == null) return ApiResponse.Error("你没有加入任何班级。");
|
||||||
|
|
||||||
|
|
||||||
List<Class> result = new List<Class>();
|
List<Class> result = new List<Class>();
|
||||||
@@ -159,6 +159,25 @@ namespace TechHelper.Services
|
|||||||
return ApiResponse.Success(result: result);
|
return ApiResponse.Success(result: result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse> GetUserClassRole(Guid id)
|
||||||
|
{
|
||||||
|
var tch = await _work.GetRepository<ClassTeacher>().GetAllAsync(predicate: user => user.TeacherId == id, include: i => i
|
||||||
|
.Include(t => t.Class));
|
||||||
|
var std = await _work.GetRepository<ClassStudent>().GetAllAsync(predicate: user => user.StudentId == id, include: i => i
|
||||||
|
.Include(t => t.Class));
|
||||||
|
|
||||||
|
if (tch == null && std == null) return ApiResponse.Error("你没有加入任何班级。");
|
||||||
|
|
||||||
|
|
||||||
|
UserClassRoleDto result = new UserClassRoleDto();
|
||||||
|
tch?.ToList().ForEach(c => result.ClassInfo.Add((c.Class.Number, c.Class.Grade)));
|
||||||
|
std?.ToList().ForEach(c => result.ClassInfo.Add((c.Class.Number, c.Class.Grade)));
|
||||||
|
if (tch?.Count > 0) result.Role = "Teacher"; else result.Role = "Student";
|
||||||
|
|
||||||
|
return ApiResponse.Success(result: result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 实现 IBaseService<ClassDto, int>.UpdateAsync
|
// 实现 IBaseService<ClassDto, int>.UpdateAsync
|
||||||
public async Task<ApiResponse> UpdateAsync(ClassDto model)
|
public async Task<ApiResponse> UpdateAsync(ClassDto model)
|
||||||
{
|
{
|
||||||
|
@@ -14,13 +14,17 @@ namespace TechHelper.Server.Services
|
|||||||
{
|
{
|
||||||
private readonly IUnitOfWork _unitOfWork;
|
private readonly IUnitOfWork _unitOfWork;
|
||||||
private readonly IExamRepository _examRepository;
|
private readonly IExamRepository _examRepository;
|
||||||
|
private readonly ISubmissionServices _submissionService;
|
||||||
|
private readonly IClassService _classService;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
public ExamService(IUnitOfWork unitOfWork, IExamRepository examRepository, IMapper mapper)
|
public ExamService(IUnitOfWork unitOfWork, IExamRepository examRepository, IMapper mapper, IClassService classService, ISubmissionServices submissionService)
|
||||||
{
|
{
|
||||||
_unitOfWork = unitOfWork;
|
_unitOfWork = unitOfWork;
|
||||||
_examRepository = examRepository;
|
_examRepository = examRepository;
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
|
_classService = classService;
|
||||||
|
_submissionService = submissionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse> CreateExamAsync(AssignmentDto assignmentDto)
|
public async Task<ApiResponse> CreateExamAsync(AssignmentDto assignmentDto)
|
||||||
@@ -128,7 +132,7 @@ namespace TechHelper.Server.Services
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return ApiResponse.Error("内部问题");
|
return ApiResponse.Error($"内部问题,{ex.Message}, InerException{ex.InnerException}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,14 +156,65 @@ namespace TechHelper.Server.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> AssignmentToAllStudentsAsync(Guid id)
|
public async Task<ApiResponse> AssignmentToAllStudentsAsync(Guid assignmentId, Guid TeacherId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var classes = await _classService.GetUserClass(TeacherId);
|
||||||
|
var classUsrClass = classes.Result as List<Class>;
|
||||||
|
var classDto = _mapper.Map<ClassDto>(classUsrClass?.FirstOrDefault());
|
||||||
|
var cla = await _classService.GetClassStudents(classDto);
|
||||||
|
var assignment = await _examRepository.GetFullExamByIdAsync(assignmentId);
|
||||||
|
if (assignment == null) return ApiResponse.Error("没有找到该试卷");
|
||||||
|
|
||||||
|
var cs = cla.Result as ICollection<ClassStudent>;
|
||||||
|
cs?.ToList().ForEach(async s =>
|
||||||
|
{
|
||||||
|
var subCount = _unitOfWork.GetRepository<Submission>().GetAll(predicate: su => su.AssignmentId == assignmentId && su.StudentId == s.StudentId);
|
||||||
|
|
||||||
|
var submission = assignment.ConvertToSubmission(s.StudentId, TeacherId);
|
||||||
|
submission.AttemptNumber = (byte)(subCount.Count() + 1);
|
||||||
|
await _unitOfWork.GetRepository<Submission>().InsertAsync(submission);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||||
|
{
|
||||||
|
return ApiResponse.Success();
|
||||||
|
}
|
||||||
|
return ApiResponse.Error();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"内部错误, {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> AssignmentToStudentsAsync(Guid assignementId, Guid studentId)
|
public async Task<ApiResponse> AssignmentToStudentsAsync(AssigExamToStudentsDto examToStudentsDto)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var assignment = await _examRepository.GetFullExamByIdAsync(examToStudentsDto.AssignmentId);
|
||||||
|
if (assignment == null) return ApiResponse.Error("没有找到该试卷");
|
||||||
|
|
||||||
|
examToStudentsDto.StudentIds?.ForEach(async s =>
|
||||||
|
{
|
||||||
|
var subCount = _unitOfWork.GetRepository<Submission>().GetAll(predicate: su => su.AssignmentId == examToStudentsDto.AssignmentId && su.StudentId == s);
|
||||||
|
var submission = assignment.ConvertToSubmission(s, examToStudentsDto.CreaterId);
|
||||||
|
submission.AttemptNumber = (byte)(subCount.Count() + 1);
|
||||||
|
await _unitOfWork.GetRepository<Submission>().InsertAsync(submission);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||||
|
{
|
||||||
|
return ApiResponse.Success();
|
||||||
|
}
|
||||||
|
return ApiResponse.Error();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"内部错误, {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse> GetAllSubmissionAsync(Guid id)
|
public async Task<ApiResponse> GetAllSubmissionAsync(Guid id)
|
||||||
|
@@ -7,7 +7,8 @@ namespace TechHelper.Services
|
|||||||
public interface IClassService : IBaseService<ClassDto, Guid>
|
public interface IClassService : IBaseService<ClassDto, Guid>
|
||||||
{
|
{
|
||||||
public Task<ApiResponse> UserRegister(UserRegistrationToClassDto user);
|
public Task<ApiResponse> UserRegister(UserRegistrationToClassDto user);
|
||||||
public Task<ApiResponse> GetUserClass(Guid user);
|
public Task<ApiResponse> GetUserClass(Guid user); // List<Class>
|
||||||
public Task<ApiResponse> GetClassStudents(ClassDto classDto);
|
public Task<ApiResponse> GetUserClassRole(Guid user); // List<UserClassRoleDto>
|
||||||
|
public Task<ApiResponse> GetClassStudents(ClassDto classDto); // Class
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,16 +23,36 @@ namespace TechHelper.Server.Services
|
|||||||
Task<ApiResponse> CreateExamAsync(AssignmentDto examDto);
|
Task<ApiResponse> CreateExamAsync(AssignmentDto examDto);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提交一份试卷
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="submissionDto">提交试卷的完整信息</param>
|
||||||
|
/// <returns></returns>
|
||||||
Task<ApiResponse> SubmissionAssignment(SubmissionDto submissionDto);
|
Task<ApiResponse> SubmissionAssignment(SubmissionDto submissionDto);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为所有学生指定试卷
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"> 试卷ID </param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<ApiResponse> AssignmentToAllStudentsAsync(Guid assignmentId, Guid TeacherId);
|
||||||
|
|
||||||
Task<ApiResponse> AssignmentToAllStudentsAsync(Guid id);
|
/// <summary>
|
||||||
|
/// 为指定学生指派一个试卷
|
||||||
Task<ApiResponse> AssignmentToStudentsAsync(Guid assignementId, Guid studentId);
|
/// </summary>
|
||||||
|
/// <param name="assignementId"></param>
|
||||||
|
/// <param name="studentId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<ApiResponse> AssignmentToStudentsAsync(AssigExamToStudentsDto examToStudentsDto);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取学生所有提交过的试卷
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
Task<ApiResponse> GetAllSubmissionAsync(Guid id);
|
Task<ApiResponse> GetAllSubmissionAsync(Guid id);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,12 +5,60 @@ namespace TechHelper.Server.Services
|
|||||||
{
|
{
|
||||||
public interface ISubmissionServices : IBaseService<Submission, Guid>
|
public interface ISubmissionServices : IBaseService<Submission, Guid>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取指定用户的指定试题的错题。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignmentId">作业ID。</param>
|
||||||
|
/// <param name="userId">用户ID。</param>
|
||||||
|
/// <returns>包含操作结果的ApiResponse。</returns>
|
||||||
Task<ApiResponse> GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId);
|
Task<ApiResponse> GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取指定用户的所有错题。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">用户ID。</param>
|
||||||
|
/// <returns>包含操作结果的ApiResponse。</returns>
|
||||||
Task<ApiResponse> GetAllErrorQuestionsAsync(Guid userId);
|
Task<ApiResponse> GetAllErrorQuestionsAsync(Guid userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取指定作业和用户的错题类型分布。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignmentId">作业ID。</param>
|
||||||
|
/// <param name="userId">用户ID。</param>
|
||||||
|
/// <returns>包含操作结果的ApiResponse。</returns>
|
||||||
Task<ApiResponse> GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId);
|
Task<ApiResponse> GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取指定作业中所有错题的类型分布。(注意:原始方法签名GetAllErrorQuestionTypeDisAsync参数中含有assignmentId,结合方法名推断此处可能应为获取所有错题的类型分布,而非特定作业的,请根据实际业务需求确认是否需要移除assignmentId参数或修改方法名。)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignmentId">作业ID。</param>
|
||||||
|
/// <param name="userId">用户ID。</param>
|
||||||
|
/// <returns>包含操作结果的ApiResponse。</returns>
|
||||||
Task<ApiResponse> GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId);
|
Task<ApiResponse> GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取指定作业中所有学生的错题情况。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignmentId">作业ID。</param>
|
||||||
|
/// <param name="teacherId">教师ID。</param>
|
||||||
|
/// <returns>包含操作结果的ApiResponse。</returns>
|
||||||
Task<ApiResponse> GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId);
|
Task<ApiResponse> GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取指定作业中出现错题的学生列表。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignmentId">作业ID。</param>
|
||||||
|
/// <returns>包含操作结果的ApiResponse。</returns>
|
||||||
Task<ApiResponse> GetQuestionErrorStudents(Guid assignmentId);
|
Task<ApiResponse> GetQuestionErrorStudents(Guid assignmentId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断是否已经存在Submission
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assignment"></param>
|
||||||
|
/// <param name="studentId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<byte> IsHasSubmissionAsync(Guid assignment, Guid studentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,5 +6,7 @@ namespace TechHelper.Server.Services
|
|||||||
public interface IUserSerivces : IBaseService<User, Guid>
|
public interface IUserSerivces : IBaseService<User, Guid>
|
||||||
{
|
{
|
||||||
Task<ApiResponse> GetStudentDetailInfo(Guid userId);
|
Task<ApiResponse> GetStudentDetailInfo(Guid userId);
|
||||||
|
Task<ApiResponse> RestoreUserRoleInformation(User user);
|
||||||
|
Task<ApiResponse> VerifyUserInformation(Guid userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Entities.Contracts;
|
using Entities.Contracts;
|
||||||
|
using Entities.DTO;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using SharedDATA.Api;
|
using SharedDATA.Api;
|
||||||
|
using SharedDATA.Context;
|
||||||
using TechHelper.Services;
|
using TechHelper.Services;
|
||||||
|
|
||||||
namespace TechHelper.Server.Services
|
namespace TechHelper.Server.Services
|
||||||
@@ -21,71 +23,329 @@ namespace TechHelper.Server.Services
|
|||||||
_submissionDetailRepository = _unitOfWork.GetRepository<SubmissionDetail>();
|
_submissionDetailRepository = _unitOfWork.GetRepository<SubmissionDetail>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> AddAsync(Submission model)
|
public async Task<ApiResponse> AddAsync(Submission model)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
model.SubmissionTime = DateTime.Now;
|
||||||
|
model.IsDeleted = false;
|
||||||
|
|
||||||
|
await _submissionRepository.InsertAsync(model);
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
|
||||||
|
var result = _mapper.Map<SubmissionDto>(model);
|
||||||
|
return ApiResponse.Success("提交成功。", result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"添加提交失败: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> DeleteAsync(Guid id)
|
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var submission = await _submissionRepository.GetFirstOrDefaultAsync(predicate: s => s.Id == id);
|
||||||
|
if (submission == null)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error("未找到要删除的提交。", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
submission.IsDeleted = true;
|
||||||
|
_submissionRepository.Update(submission);
|
||||||
|
|
||||||
|
var submissionDetails = await _submissionDetailRepository.GetPagedListAsync(predicate: sd => sd.SubmissionId == id);
|
||||||
|
foreach (var detail in submissionDetails.Items)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
detail.IsDeleted = true;
|
||||||
|
_submissionDetailRepository.Update(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
return ApiResponse.Success("提交及相关详情删除成功。", null);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"删除提交失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pagedSubmissions = await _submissionRepository.GetPagedListAsync(
|
||||||
|
pageIndex: query.PageIndex,
|
||||||
|
pageSize: query.PageSize,
|
||||||
|
orderBy: s => s.OrderByDescending(s => s.SubmissionTime),
|
||||||
|
predicate: s => !s.IsDeleted,
|
||||||
|
include: i => i.Include(s => s.Student)
|
||||||
|
.Include(s => s.Assignment));
|
||||||
|
|
||||||
|
var submissionDtos = _mapper.Map<List<SubmissionDto>>(pagedSubmissions.Items);
|
||||||
|
|
||||||
|
return ApiResponse.Success("获取所有提交成功。", new PagedList<SubmissionDto>
|
||||||
|
{
|
||||||
|
PageIndex = pagedSubmissions.PageIndex,
|
||||||
|
PageSize = pagedSubmissions.PageSize,
|
||||||
|
TotalCount = pagedSubmissions.TotalCount,
|
||||||
|
TotalPages = pagedSubmissions.TotalPages,
|
||||||
|
Items = submissionDtos
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"获取所有提交失败: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse> GetAllErrorQuestionsAsync(Guid userId)
|
public async Task<ApiResponse> GetAllErrorQuestionsAsync(Guid userId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(predicate: sd => sd.StudentId == userId && sd.IsCorrect == false,
|
|
||||||
|
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||||
|
predicate: sd => sd.StudentId == userId && sd.IsCorrect == false &&
|
||||||
|
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||||
include: i => i
|
include: i => i
|
||||||
.Include(s => s.AssignmentQuestion)
|
.Include(s => s.AssignmentQuestion)
|
||||||
.ThenInclude(aq => aq.Question));
|
.ThenInclude(aq => aq.Question));
|
||||||
var errorQuestion = errorSDs.Items.Select(sd => sd.AssignmentQuestion).ToList();
|
|
||||||
return ApiResponse.Success();
|
var errorQuestions = errorSDs.Items.Select(sd => sd.AssignmentQuestion.Question)
|
||||||
|
.Where(q => q != null)
|
||||||
|
.DistinctBy(q => q.Id)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
|
||||||
|
var result = _mapper.Map<List<QuestionDto>>(errorQuestions);
|
||||||
|
return ApiResponse.Success("获取所有错题成功。", result);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return ApiResponse.Error();
|
return ApiResponse.Error($"获取所有错题失败: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId)
|
public async Task<ApiResponse> GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||||
|
predicate: sd => sd.Submission.AssignmentId == assignmentId &&
|
||||||
|
sd.StudentId == userId &&
|
||||||
|
sd.IsCorrect == false &&
|
||||||
|
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||||
|
include: i => i
|
||||||
|
.Include(s => s.AssignmentQuestion)
|
||||||
|
.ThenInclude(aq => aq.Question));
|
||||||
|
|
||||||
|
// 对错题按类型进行分组计数
|
||||||
|
var errorTypeDistribution = errorSDs.Items
|
||||||
|
.Where(sd => sd.AssignmentQuestion?.Question != null)
|
||||||
|
.GroupBy(sd => sd.AssignmentQuestion.Question.Type)
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
QuestionType = g.Key.ToString(),
|
||||||
|
Count = g.Count()
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return ApiResponse.Success("获取错题类型分布成功。", errorTypeDistribution);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"获取错题类型分布失败: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId)
|
public async Task<ApiResponse> GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var submissionDetails = await _submissionDetailRepository.GetPagedListAsync(
|
||||||
|
predicate: sd => sd.Submission.AssignmentId == assignmentId &&
|
||||||
|
sd.IsCorrect == false &&
|
||||||
|
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||||
|
include: i => i.Include(sd => sd.Student));
|
||||||
|
|
||||||
|
|
||||||
|
var studentsErrorSummary = submissionDetails.Items
|
||||||
|
.Where(sd => sd.Student != null)
|
||||||
|
.GroupBy(sd => new { sd.StudentId, sd.Student.UserName })
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
StudentId = g.Key.StudentId,
|
||||||
|
StudentName = g.Key.UserName,
|
||||||
|
ErrorQuestionCount = g.Count()
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return ApiResponse.Success("获取作业中所有学生的错题情况成功。", studentsErrorSummary);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"获取作业中所有学生的错题情况失败: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId)
|
public async Task<ApiResponse> GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||||
|
predicate: sd => sd.Submission.AssignmentId == assignmentId &&
|
||||||
|
sd.StudentId == userId &&
|
||||||
|
sd.IsCorrect == false &&
|
||||||
|
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||||
|
include: i => i
|
||||||
|
.Include(s => s.AssignmentQuestion)
|
||||||
|
.ThenInclude(aq => aq.Question));
|
||||||
|
|
||||||
|
var errorQuestions = errorSDs.Items.Select(sd => sd.AssignmentQuestion.Question)
|
||||||
|
.Where(q => q != null)
|
||||||
|
.DistinctBy(q => q.Id)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var result = _mapper.Map<List<QuestionDto>>(errorQuestions);
|
||||||
|
return ApiResponse.Success("获取指定作业错题成功。", result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"获取指定作业错题失败: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId)
|
public async Task<ApiResponse> GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||||
|
predicate: sd => sd.Submission.AssignmentId == assignmentId &&
|
||||||
|
sd.StudentId == userId &&
|
||||||
|
sd.IsCorrect == false &&
|
||||||
|
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||||
|
include: i => i
|
||||||
|
.Include(s => s.AssignmentQuestion)
|
||||||
|
.ThenInclude(aq => aq.Question));
|
||||||
|
|
||||||
|
var errorTypeDistribution = errorSDs.Items
|
||||||
|
.Where(sd => sd.AssignmentQuestion?.Question != null)
|
||||||
|
.GroupBy(sd => sd.AssignmentQuestion.Question.Type)
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
QuestionType = g.Key.ToString(),
|
||||||
|
Count = g.Count()
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return ApiResponse.Success("获取指定作业错题类型分布成功。", errorTypeDistribution);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"获取指定作业错题类型分布失败: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> GetAsync(Guid id)
|
public async Task<ApiResponse> GetAsync(Guid id)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var submission = await _submissionRepository.GetFirstOrDefaultAsync(
|
||||||
|
predicate: s => s.Id == id && !s.IsDeleted,
|
||||||
|
include: i => i.Include(s => s.Student)
|
||||||
|
.Include(s => s.Assignment)
|
||||||
|
.Include(s => s.Grader)
|
||||||
|
.Include(s => s.SubmissionDetails)
|
||||||
|
.ThenInclude(sd => sd.AssignmentQuestion)
|
||||||
|
.ThenInclude(aq => aq.Question));
|
||||||
|
|
||||||
|
if (submission == null)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error("未找到提交。", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> GetQuestionErrorStudents(Guid assignmentId)
|
var submissionDto = _mapper.Map<SubmissionDto>(submission);
|
||||||
|
return ApiResponse.Success("获取提交成功。", submissionDto);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return ApiResponse.Error($"获取提交失败: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> UpdateAsync(Submission model)
|
public async Task<ApiResponse> GetQuestionErrorStudents(Guid assignmentQuestionId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var errorSubmissionDetails = await _submissionDetailRepository.GetPagedListAsync(
|
||||||
|
predicate: sd => sd.AssignmentQuestionId == assignmentQuestionId &&
|
||||||
|
sd.IsCorrect == false &&
|
||||||
|
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||||
|
include: i => i
|
||||||
|
.Include(sd => sd.Student)
|
||||||
|
.Include(sd => sd.AssignmentQuestion)
|
||||||
|
.ThenInclude(aq => aq.Question));
|
||||||
|
|
||||||
|
|
||||||
|
var errorStudentsByQuestion = errorSubmissionDetails.Items
|
||||||
|
.Where(sd => sd.AssignmentQuestion?.Question != null && sd.Student != null)
|
||||||
|
.GroupBy(sd => new { sd.AssignmentQuestionId, sd.AssignmentQuestion.Question.Title })
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
AssignmentQuestionId = g.Key.AssignmentQuestionId,
|
||||||
|
QuestionTitle = g.Key.Title,
|
||||||
|
ErrorStudents = g.Select(sd => new
|
||||||
|
{
|
||||||
|
StudentId = sd.StudentId,
|
||||||
|
StudentName = sd.Student.UserName
|
||||||
|
}).Distinct().ToList()
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return ApiResponse.Success("获取出现错题的学生成功。", errorStudentsByQuestion);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"获取出现错题的学生失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<byte> IsHasSubmissionAsync(Guid assignment, Guid studentId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _unitOfWork.GetRepository<Submission>().GetAllAsync(predicate: s => s.AssignmentId == assignment && s.StudentId == studentId);
|
||||||
|
return (byte)result.Count;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse> UpdateAsync(Submission model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var existingSubmission = await _submissionRepository.GetFirstOrDefaultAsync(predicate: s => s.Id == model.Id && !s.IsDeleted);
|
||||||
|
if (existingSubmission == null)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error("未找到要更新的提交。", 404);
|
||||||
|
}
|
||||||
|
_mapper.Map(model, existingSubmission);
|
||||||
|
|
||||||
|
|
||||||
|
_submissionRepository.Update(existingSubmission);
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
|
||||||
|
var result = _mapper.Map<SubmissionDto>(existingSubmission);
|
||||||
|
return ApiResponse.Success("更新提交成功。", result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return ApiResponse.Error($"更新提交失败: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,25 @@
|
|||||||
using Entities.Contracts;
|
using Entities.Contracts;
|
||||||
|
using Entities.DTO;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using SharedDATA.Api;
|
||||||
using TechHelper.Services;
|
using TechHelper.Services;
|
||||||
|
|
||||||
namespace TechHelper.Server.Services
|
namespace TechHelper.Server.Services
|
||||||
{
|
{
|
||||||
public class UserServices : IUserSerivces
|
public class UserServices : IUserSerivces
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private readonly IUnitOfWork _unitOfWork;
|
||||||
|
private readonly IClassService _classService;
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
|
||||||
|
public UserServices(IUnitOfWork unitOfWork, IClassService classService, UserManager<User> userManager)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_classService = classService;
|
||||||
|
_userManager = userManager;
|
||||||
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> AddAsync(User model)
|
public Task<ApiResponse> AddAsync(User model)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -30,9 +45,33 @@ namespace TechHelper.Server.Services
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse> RestoreUserRoleInformation(User user)
|
||||||
|
{
|
||||||
|
var result = await _classService.GetUserClassRole(user.Id);
|
||||||
|
if (result.Status)
|
||||||
|
{
|
||||||
|
var classRole = result.Result as UserClassRoleDto;
|
||||||
|
if (classRole != null)
|
||||||
|
{
|
||||||
|
if (!await _userManager.IsInRoleAsync(user, classRole.Role))
|
||||||
|
{
|
||||||
|
await _userManager.AddToRoleAsync(user, classRole.Role);
|
||||||
|
|
||||||
|
return ApiResponse.Success();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ApiResponse.Error();
|
||||||
|
}
|
||||||
|
|
||||||
public Task<ApiResponse> UpdateAsync(User model)
|
public Task<ApiResponse> UpdateAsync(User model)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<ApiResponse> VerifyUserInformation(Guid userId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user