This commit is contained in:
SpecialX
2025-06-27 19:03:10 +08:00
parent 14fbe6397a
commit a21ca80782
57 changed files with 3872 additions and 611 deletions

View File

@@ -36,20 +36,22 @@ namespace TechHelper.Context
// Assignment
CreateMap<AssignmentDto, Assignment>().ReverseMap();
CreateMap<Assignment, AssignmentDto>();
CreateMap<AssignmentQuestionDto, AssignmentQuestion>().ReverseMap();
CreateMap<QuestionDto, Question>().ReverseMap();
CreateMap<QuestionContext, QuestionContextDto>().ReverseMap();
CreateMap<AssignmentQuestion, AssignmentQuestionDto>();
CreateMap<Question, QuestionDto>();
CreateMap<AssignmentDto, Assignment>();
CreateMap<AssignmentQuestionDto, AssignmentQuestion>();
// Submission
CreateMap<SubmissionDto, Submission>().ReverseMap();
CreateMap<QuestionDto, Question>();
CreateMap<SubmissionDetailDto, SubmissionDetail>().ReverseMap();
}
}

View File

@@ -57,26 +57,13 @@ namespace TechHelper.Context.Configuration
.HasForeignKey(a => a.CreatorId)
.IsRequired(); // CreatedBy 是必填的,对应 [Required] 在外键属性上
// 关系: Assignment (一) 到 AssignmentClass (多)
// 假设 AssignmentClass 实体包含一个名为 AssignmentId 的外键属性
builder.HasMany(a => a.AssignmentClasses)
.WithOne(ac => ac.Assignment) // AssignmentClass 没有指向 Assignment 的导航属性 (或我们不知道)
.HasForeignKey("AssignmentId") // 指定外键名称为 AssignmentId
.OnDelete(DeleteBehavior.Cascade); // 如果 Assignment 被删除,关联的 AssignmentClass 也会被删除
// 关系: Assignment (一) 到 AssignmentAttachment (多)
// 假设 AssignmentAttachment 实体包含一个名为 AssignmentId 的外键属性
builder.HasMany(a => a.AssignmentAttachments)
.WithOne(aa => aa.Assignment)
.HasForeignKey("AssignmentId")
.OnDelete(DeleteBehavior.Cascade);
// 关系: Assignment (一) 到 Submission (多)
// 假设 Submission 实体包含一个名为 AssignmentId 的外键属性
builder.HasMany(a => a.Submissions)
.WithOne(s => s.Assignment)
.HasForeignKey("AssignmentId")
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(a=>a.ExamStruct)
.WithOne()
.HasForeignKey<Assignment>(a=>a.ExamStructId)
.OnDelete(DeleteBehavior.Cascade);
}
}
}

View File

@@ -42,35 +42,24 @@ namespace TechHelper.Context.Configuration
.HasColumnName("deleted")
.HasDefaultValue(false); // 适用于软删除策略
// 4. 配置导航属性和外键关系
// ---
// 配置 AssignmentQuestion 到 Question 的关系 (多对一)
// 一个 AssignmentQuestion 属于一个 Question。
//
// 假设 `Question` 实体中有一个名为 `AssignmentQuestions` 的 `ICollection<AssignmentQuestion>` 集合属性。
builder.HasOne(aq => aq.Question) // 当前 AssignmentQuestion 有一个 Question
.WithMany(q => q.AssignmentQuestions) // 那个 Question 可以有多个 AssignmentQuestion
.HasForeignKey(aq => aq.QuestionId) // 外键是 AssignmentQuestion.QuestionId
.OnDelete(DeleteBehavior.Cascade); // 当 Question 被删除时,相关的 AssignmentQuestion 也级联删除。
builder.HasOne(aq => aq.Question)
.WithMany(q => q.AssignmentQuestions)
.HasForeignKey(aq => aq.QuestionId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(aq => aq.ParentAssignmentQuestion)
.WithMany(aq => aq.ChildrenAssignmentQuestion)
.HasForeignKey(aq => aq.ParentAssignmentQuestionId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(aq => aq.QuestionContext)
.WithMany(qc => qc.Questions)
.HasForeignKey(aq => aq.QuestionContextId)
.OnDelete(DeleteBehavior.SetNull);
// ---
// 配置 AssignmentQuestion 到 SubmissionDetail 的关系 (一对多)
// 一个 AssignmentQuestion 可以有多个 SubmissionDetail。
//
// 这个关系通常从 "多" 的一方(`SubmissionDetail` 实体)来配置外键。
// 假设 `SubmissionDetail` 实体有一个 `AssignmentQuestionId` 外键和 `AssignmentQuestion` 导航属性。
builder.HasMany(aq => aq.SubmissionDetails) // 当前 AssignmentQuestion 有多个 SubmissionDetail
.WithOne(sd => sd.AssignmentQuestion); // 每一个 SubmissionDetail 都有一个 AssignmentQuestion
// .HasForeignKey(sd => sd.AssignmentQuestionId); // 外键的配置应在 `SubmissionDetailConfiguration` 中进行
}
}
}
}
}

View File

@@ -75,16 +75,13 @@ namespace TechHelper.Context.Configuration
builder.HasOne(s => s.Student) // 当前 Submission 有一个 Student (User)
.WithMany(u => u.SubmissionsAsStudent) // 那个 User (Student) 可以有多个 Submission
.HasForeignKey(s => s.StudentId) // 外键是 Submission.StudentId
.OnDelete(DeleteBehavior.Restrict); // 当 User (Student) 被删除时,如果还有其提交的 Submission则会阻止删除。
.OnDelete(DeleteBehavior.Cascade); // 当 User (Student) 被删除时,如果还有其提交的 Submission则会阻止删除。
builder.HasOne(s => s.Grader) // 当前 Submission 有一个 Grader (User),可以是空的
.WithMany(u => u.GradedSubmissions) // 那个 User (Grader) 可以批改多个 Submission
.HasForeignKey(s => s.GraderId) // 外键是 Submission.GradedBy
.OnDelete(DeleteBehavior.SetNull); // 当 User (Grader) 被删除时,如果 GradedBy 是可空的,则将其设置为 NULL。
builder.HasMany(s => s.SubmissionDetails) // 当前 Submission 有多个 SubmissionDetail
.WithOne(sd => sd.Submission); // 每一个 SubmissionDetail 都有一个 Submission
}
}
}

View File

@@ -64,7 +64,7 @@ namespace TechHelper.Context.Configuration
builder.HasOne(sd => sd.Student) // 当前 SubmissionDetail 有一个 User (作为学生)
.WithMany(u => u.SubmissionDetails)
.HasForeignKey(sd => sd.StudentId) // 外键是 SubmissionDetail.StudentId
.OnDelete(DeleteBehavior.Restrict); // 当 User (学生) 被删除时,如果他/她还有提交详情,则会阻止删除。
.OnDelete(DeleteBehavior.Cascade); // 当 User (学生) 被删除时,如果他/她还有提交详情,则会阻止删除。
// 这是一个更安全的选择,以防止意外数据丢失。
builder.HasOne(sd => sd.AssignmentQuestion) // 当前 SubmissionDetail 有一个 AssignmentQuestion

View File

@@ -1,7 +1,10 @@
using Entities.DTO;
using Entities.Contracts;
using Entities.DTO;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.Net;
using System.Security.Claims;
using TechHelper.Services;
namespace TechHelper.Server.Controllers
@@ -11,25 +14,76 @@ namespace TechHelper.Server.Controllers
public class ClassController : ControllerBase
{
private IClassService _classService;
public ClassController(IClassService classService)
private UserManager<User> _userManager;
public ClassController(IClassService classService, UserManager<User> userManager)
{
_classService = classService;
_userManager = userManager;
}
[HttpPost("userRegiste")]
public async Task<IActionResult> UserRegisterToClass(
[FromBody] UserRegistrationToClassDto toClass)
{
var result = await _classService.UserRegister(toClass);
if(!result.Status) return BadRequest(result.Message);
if (!result.Status) return BadRequest(result.Message);
return Ok();
return Ok();
}
[HttpPost("getClassStudents")]
public async Task<IActionResult> GetClassStudents()
{
if (User.IsInRole("Teacher"))
{
var gradeClaim = User.FindFirst("Grade")?.Value;
var classClaim = User.FindFirst("Class")?.Value;
if (string.IsNullOrEmpty(gradeClaim) || string.IsNullOrEmpty(classClaim))
{
return BadRequest("未识别到你加入的班级信息(年级或班级声明缺失)。");
}
if (!byte.TryParse(gradeClaim, out byte grade) || !byte.TryParse(classClaim, out byte cla))
{
return BadRequest("你班级或年级信息格式不正确。");
}
var classDto = new ClassDto
{
Grade = grade,
Class = cla
};
var result = await _classService.GetClassStudents(classDto);
var css = result.Result as ICollection<ClassStudent>;
if(css == null) return BadRequest("你还没有学生");
List<StudentDto> sts = new List<StudentDto>();
css?.ToList().ForEach(s => sts.Add(new StudentDto
{
DisplayName = s.Student.DisplayName,
Id = s.Student.Id,
}));
if (!result.Status)
{
return BadRequest(result.Message);
}
return Ok(sts);
}
else
{
return BadRequest("你没有权限查看,未识别到你的教师身份。");
}
}
[HttpPost("Create")]
public async Task<IActionResult> Create(
[FromBody] ClassDto classDto)

View File

@@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using TechHelper.Server.Services;
using System.Security.Claims;
using TechHelper.Services;
namespace TechHelper.Server.Controllers
@@ -31,7 +32,7 @@ namespace TechHelper.Server.Controllers
[FromBody] AssignmentDto examDto)
{
var user = await _userManager.FindByEmailAsync(User.Identity?.Name ?? "");
if(user == null) return BadRequest("无效的用户");
if (user == null) return BadRequest("无效的用户");
examDto.CreatorId = user.Id;
var result = await _examService.CreateExamAsync(examDto);
@@ -45,6 +46,29 @@ namespace TechHelper.Server.Controllers
}
}
[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)
{
return Ok(result);
}
else
{
return BadRequest(result.Message);
}
}
else
{
return BadRequest("你没有权限修改");
}
}
[HttpGet("get")]
public async Task<IActionResult> GetExamById(Guid id)
{
@@ -58,16 +82,26 @@ namespace TechHelper.Server.Controllers
[HttpGet("getAllPreview")]
public async Task<IActionResult> GetAllExamPreview(string user)
public async Task<IActionResult> GetAllExamPreview()
{
string? userId = User.Identity.Name;
if (User == null) return BadRequest("用户验证失败, 无效用户");
var userid = await _userManager.FindByEmailAsync(user);
if (userid == null) return BadRequest("用户验证失败, 无效用户");
var userid = await _userManager.FindByEmailAsync(User.Identity.Name);
var result = await _examService.GetAllExamPreviewsAsync(userid.Id);
var result = new ApiResponse();
if (User.IsInRole("Teacher"))
{
result = await _examService.GetAllExamPreviewsAsync(userid.Id);
}
else if (User.IsInRole("Student"))
{
result = await _examService.GetAllSubmissionAsync(userid.Id);
}
else
{
return BadRequest("你没有相应的权限");
}
if (result.Status)
{
@@ -76,5 +110,34 @@ namespace TechHelper.Server.Controllers
return BadRequest(result);
}
[HttpGet("getAllSubmission")]
public async Task<IActionResult> GetAllSubmission()
{
if (User == null) return BadRequest("用户验证失败, 无效用户");
var userid = await _userManager.FindByEmailAsync(User.Identity.Name);
var result = await _examService.GetAllSubmissionAsync(userid.Id);
if (result.Status)
{
return Ok(result.Result);
}
return BadRequest(result);
}
[Authorize(Roles = "Teacher")]
[HttpDelete("{guid}")]
public async Task<IActionResult> DeleteAsync(Guid guid)
{
var deleteResult = await _examService.DeleteAsync(guid);
if (deleteResult.Status)
{
return Ok();
}
return BadRequest();
}
}
}

View File

@@ -0,0 +1,30 @@
using Entities.Contracts;
using Entities.DTO;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using TechHelper.Services;
namespace TechHelper.Server.Controllers
{
[Route("api/user")]
[ApiController]
public class UserController : ControllerBase
{
private IClassService _classService;
private UserManager<User> _userManager;
public UserController(IClassService classService, UserManager<User> userManager)
{
_classService = classService;
_userManager = userManager;
}
[HttpPost("get")]
public async Task<IActionResult> GetAsync(
[FromBody] UserRegistrationToClassDto toClass)
{
return Ok();
}
}
}

View File

@@ -1,95 +0,0 @@
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 up : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_class_teachers_AspNetUsers_teacher_id",
table: "class_teachers");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("8b814a50-fd96-4bfa-a666-b247c0f13e22"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("ab2c8f8c-1ade-4ff5-9eb4-2925a89567b1"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("c6f92bbf-190f-47a5-b4d6-ed6874a378e8"));
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ new Guid("195b19c5-fd30-455c-9f38-9842b44bf5c3"), null, "Teacher", "TEACHER" },
{ new Guid("53cc63db-74bc-47a8-b71a-7e120d4018a9"), null, "Administrator", "ADMINISTRATOR" },
{ new Guid("a203eb76-97f0-418f-bc06-9549297d2ac3"), null, "Student", "STUDENT" }
});
migrationBuilder.AddForeignKey(
name: "FK_class_teachers_AspNetUsers_teacher_id",
table: "class_teachers",
column: "teacher_id",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_class_teachers_AspNetUsers_teacher_id",
table: "class_teachers");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("195b19c5-fd30-455c-9f38-9842b44bf5c3"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("53cc63db-74bc-47a8-b71a-7e120d4018a9"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("a203eb76-97f0-418f-bc06-9549297d2ac3"));
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ new Guid("8b814a50-fd96-4bfa-a666-b247c0f13e22"), null, "Administrator", "ADMINISTRATOR" },
{ new Guid("ab2c8f8c-1ade-4ff5-9eb4-2925a89567b1"), null, "Student", "STUDENT" },
{ new Guid("c6f92bbf-190f-47a5-b4d6-ed6874a378e8"), null, "Teacher", "TEACHER" }
});
migrationBuilder.AddForeignKey(
name: "FK_class_teachers_AspNetUsers_teacher_id",
table: "class_teachers",
column: "teacher_id",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}
}

View File

@@ -12,8 +12,8 @@ using TechHelper.Context;
namespace TechHelper.Server.Migrations
{
[DbContext(typeof(ApplicationContext))]
[Migration("20250625032845_up")]
partial class up
[Migration("20250626073834_init")]
partial class init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -512,7 +512,6 @@ namespace TechHelper.Server.Migrations
.HasColumnName("deleted");
b.Property<string>("OverallFeedback")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("overall_feedback");
@@ -579,7 +578,6 @@ namespace TechHelper.Server.Migrations
.HasColumnName("points_awarded");
b.Property<string>("StudentAnswer")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("student_answer");
@@ -592,7 +590,6 @@ namespace TechHelper.Server.Migrations
.HasColumnName("submission_id");
b.Property<string>("TeacherFeedback")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("teacher_feedback");
@@ -747,19 +744,19 @@ namespace TechHelper.Server.Migrations
b.HasData(
new
{
Id = new Guid("a203eb76-97f0-418f-bc06-9549297d2ac3"),
Id = new Guid("3cfe35e8-73d5-4170-9856-f1d078554822"),
Name = "Student",
NormalizedName = "STUDENT"
},
new
{
Id = new Guid("195b19c5-fd30-455c-9f38-9842b44bf5c3"),
Id = new Guid("754c4967-6af2-4a81-b970-1e90a3a269b3"),
Name = "Teacher",
NormalizedName = "TEACHER"
},
new
{
Id = new Guid("53cc63db-74bc-47a8-b71a-7e120d4018a9"),
Id = new Guid("8546457c-185c-4b79-bece-bc21e41d02e7"),
Name = "Administrator",
NormalizedName = "ADMINISTRATOR"
});

View File

@@ -323,7 +323,7 @@ namespace TechHelper.Server.Migrations
column: x => x.teacher_id,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_class_teachers_classes_class_id",
column: x => x.class_id,
@@ -565,7 +565,7 @@ namespace TechHelper.Server.Migrations
attempt_number = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
submission_time = table.Column<DateTime>(type: "datetime(6)", nullable: false),
overall_grade = table.Column<float>(type: "float", precision: 5, scale: 2, nullable: true),
overall_feedback = table.Column<string>(type: "longtext", nullable: false)
overall_feedback = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
graded_by = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
graded_at = table.Column<DateTime>(type: "datetime(6)", nullable: true),
@@ -604,11 +604,11 @@ namespace TechHelper.Server.Migrations
submission_id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
student_id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
assignment_question_id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
student_answer = table.Column<string>(type: "longtext", nullable: false)
student_answer = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
is_correct = table.Column<bool>(type: "tinyint(1)", nullable: true),
points_awarded = table.Column<float>(type: "float", precision: 5, scale: 2, nullable: true),
teacher_feedback = table.Column<string>(type: "longtext", nullable: false)
teacher_feedback = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
created_at = table.Column<DateTime>(type: "datetime(6)", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
@@ -644,9 +644,9 @@ namespace TechHelper.Server.Migrations
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ new Guid("8b814a50-fd96-4bfa-a666-b247c0f13e22"), null, "Administrator", "ADMINISTRATOR" },
{ new Guid("ab2c8f8c-1ade-4ff5-9eb4-2925a89567b1"), null, "Student", "STUDENT" },
{ new Guid("c6f92bbf-190f-47a5-b4d6-ed6874a378e8"), null, "Teacher", "TEACHER" }
{ new Guid("3cfe35e8-73d5-4170-9856-f1d078554822"), null, "Student", "STUDENT" },
{ new Guid("754c4967-6af2-4a81-b970-1e90a3a269b3"), null, "Teacher", "TEACHER" },
{ new Guid("8546457c-185c-4b79-bece-bc21e41d02e7"), null, "Administrator", "ADMINISTRATOR" }
});
migrationBuilder.CreateIndex(

View File

@@ -12,8 +12,8 @@ using TechHelper.Context;
namespace TechHelper.Server.Migrations
{
[DbContext(typeof(ApplicationContext))]
[Migration("20250624103910_init")]
partial class init
[Migration("20250627101025_upd")]
partial class upd
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -198,6 +198,11 @@ namespace TechHelper.Server.Migrations
.HasColumnType("float")
.HasColumnName("score");
b.Property<string>("Sequence")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("sequence");
b.Property<byte>("StructType")
.HasColumnType("tinyint unsigned")
.HasColumnName("group_state");
@@ -512,7 +517,6 @@ namespace TechHelper.Server.Migrations
.HasColumnName("deleted");
b.Property<string>("OverallFeedback")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("overall_feedback");
@@ -579,7 +583,6 @@ namespace TechHelper.Server.Migrations
.HasColumnName("points_awarded");
b.Property<string>("StudentAnswer")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("student_answer");
@@ -592,7 +595,6 @@ namespace TechHelper.Server.Migrations
.HasColumnName("submission_id");
b.Property<string>("TeacherFeedback")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("teacher_feedback");
@@ -747,19 +749,19 @@ namespace TechHelper.Server.Migrations
b.HasData(
new
{
Id = new Guid("ab2c8f8c-1ade-4ff5-9eb4-2925a89567b1"),
Id = new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9"),
Name = "Student",
NormalizedName = "STUDENT"
},
new
{
Id = new Guid("c6f92bbf-190f-47a5-b4d6-ed6874a378e8"),
Id = new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236"),
Name = "Teacher",
NormalizedName = "TEACHER"
},
new
{
Id = new Guid("8b814a50-fd96-4bfa-a666-b247c0f13e22"),
Id = new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453"),
Name = "Administrator",
NormalizedName = "ADMINISTRATOR"
});
@@ -925,7 +927,8 @@ namespace TechHelper.Server.Migrations
{
b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion")
.WithMany("ChildrenAssignmentQuestion")
.HasForeignKey("ParentAssignmentQuestionId");
.HasForeignKey("ParentAssignmentQuestionId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext")
.WithMany("Questions")
@@ -985,7 +988,7 @@ namespace TechHelper.Server.Migrations
b.HasOne("Entities.Contracts.User", "Teacher")
.WithMany("TaughtClassesLink")
.HasForeignKey("TeacherId")
.OnDelete(DeleteBehavior.Restrict)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Class");
@@ -1067,7 +1070,7 @@ namespace TechHelper.Server.Migrations
b.HasOne("Entities.Contracts.User", "Student")
.WithMany("SubmissionsAsStudent")
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Restrict)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Assignment");
@@ -1088,7 +1091,7 @@ namespace TechHelper.Server.Migrations
b.HasOne("Entities.Contracts.User", "Student")
.WithMany("SubmissionDetails")
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Restrict)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Entities.Contracts.Submission", "Submission")

View File

@@ -0,0 +1,153 @@
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 upd : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_assignment_questions_assignment_questions_parent_question_gr~",
table: "assignment_questions");
migrationBuilder.DropForeignKey(
name: "FK_submission_details_AspNetUsers_student_id",
table: "submission_details");
migrationBuilder.DropForeignKey(
name: "FK_submissions_AspNetUsers_student_id",
table: "submissions");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("3cfe35e8-73d5-4170-9856-f1d078554822"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("754c4967-6af2-4a81-b970-1e90a3a269b3"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("8546457c-185c-4b79-bece-bc21e41d02e7"));
migrationBuilder.AddColumn<string>(
name: "sequence",
table: "assignment_questions",
type: "longtext",
nullable: false)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236"), null, "Teacher", "TEACHER" },
{ new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453"), null, "Administrator", "ADMINISTRATOR" },
{ new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9"), null, "Student", "STUDENT" }
});
migrationBuilder.AddForeignKey(
name: "FK_assignment_questions_assignment_questions_parent_question_gr~",
table: "assignment_questions",
column: "parent_question_group_id",
principalTable: "assignment_questions",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_submission_details_AspNetUsers_student_id",
table: "submission_details",
column: "student_id",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_submissions_AspNetUsers_student_id",
table: "submissions",
column: "student_id",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_assignment_questions_assignment_questions_parent_question_gr~",
table: "assignment_questions");
migrationBuilder.DropForeignKey(
name: "FK_submission_details_AspNetUsers_student_id",
table: "submission_details");
migrationBuilder.DropForeignKey(
name: "FK_submissions_AspNetUsers_student_id",
table: "submissions");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9"));
migrationBuilder.DropColumn(
name: "sequence",
table: "assignment_questions");
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ new Guid("3cfe35e8-73d5-4170-9856-f1d078554822"), null, "Student", "STUDENT" },
{ new Guid("754c4967-6af2-4a81-b970-1e90a3a269b3"), null, "Teacher", "TEACHER" },
{ new Guid("8546457c-185c-4b79-bece-bc21e41d02e7"), null, "Administrator", "ADMINISTRATOR" }
});
migrationBuilder.AddForeignKey(
name: "FK_assignment_questions_assignment_questions_parent_question_gr~",
table: "assignment_questions",
column: "parent_question_group_id",
principalTable: "assignment_questions",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "FK_submission_details_AspNetUsers_student_id",
table: "submission_details",
column: "student_id",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_submissions_AspNetUsers_student_id",
table: "submissions",
column: "student_id",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,71 @@
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 upde : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9"));
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ new Guid("c0f247ab-b12a-432e-8ce7-d0e28811957e"), null, "Student", "STUDENT" },
{ new Guid("f282e759-deb5-4366-aaf1-51366131cf75"), null, "Administrator", "ADMINISTRATOR" },
{ new Guid("f9eeea07-eeda-4bbe-a2e4-6aef2f3c7c9a"), null, "Teacher", "TEACHER" }
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("c0f247ab-b12a-432e-8ce7-d0e28811957e"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("f282e759-deb5-4366-aaf1-51366131cf75"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("f9eeea07-eeda-4bbe-a2e4-6aef2f3c7c9a"));
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236"), null, "Teacher", "TEACHER" },
{ new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453"), null, "Administrator", "ADMINISTRATOR" },
{ new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9"), null, "Student", "STUDENT" }
});
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
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 updedd : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("c0f247ab-b12a-432e-8ce7-d0e28811957e"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("f282e759-deb5-4366-aaf1-51366131cf75"));
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: new Guid("f9eeea07-eeda-4bbe-a2e4-6aef2f3c7c9a"));
migrationBuilder.AddColumn<Guid>(
name: "AssignmentId",
table: "assignment_questions",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
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" }
});
migrationBuilder.CreateIndex(
name: "IX_assignment_questions_AssignmentId",
table: "assignment_questions",
column: "AssignmentId");
migrationBuilder.AddForeignKey(
name: "FK_assignment_questions_assignments_AssignmentId",
table: "assignment_questions",
column: "AssignmentId",
principalTable: "assignments",
principalColumn: "id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_assignment_questions_assignments_AssignmentId",
table: "assignment_questions");
migrationBuilder.DropIndex(
name: "IX_assignment_questions_AssignmentId",
table: "assignment_questions");
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.DropColumn(
name: "AssignmentId",
table: "assignment_questions");
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ new Guid("c0f247ab-b12a-432e-8ce7-d0e28811957e"), null, "Student", "STUDENT" },
{ new Guid("f282e759-deb5-4366-aaf1-51366131cf75"), null, "Administrator", "ADMINISTRATOR" },
{ new Guid("f9eeea07-eeda-4bbe-a2e4-6aef2f3c7c9a"), null, "Teacher", "TEACHER" }
});
}
}
}

View File

@@ -165,6 +165,9 @@ namespace TechHelper.Server.Migrations
.HasColumnType("char(36)")
.HasColumnName("id");
b.Property<Guid?>("AssignmentId")
.HasColumnType("char(36)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)")
.HasColumnName("created_at");
@@ -195,6 +198,11 @@ namespace TechHelper.Server.Migrations
.HasColumnType("float")
.HasColumnName("score");
b.Property<string>("Sequence")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("sequence");
b.Property<byte>("StructType")
.HasColumnType("tinyint unsigned")
.HasColumnName("group_state");
@@ -206,6 +214,8 @@ namespace TechHelper.Server.Migrations
b.HasKey("Id");
b.HasIndex("AssignmentId");
b.HasIndex("ParentAssignmentQuestionId");
b.HasIndex("QuestionContextId");
@@ -509,7 +519,6 @@ namespace TechHelper.Server.Migrations
.HasColumnName("deleted");
b.Property<string>("OverallFeedback")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("overall_feedback");
@@ -576,7 +585,6 @@ namespace TechHelper.Server.Migrations
.HasColumnName("points_awarded");
b.Property<string>("StudentAnswer")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("student_answer");
@@ -589,7 +597,6 @@ namespace TechHelper.Server.Migrations
.HasColumnName("submission_id");
b.Property<string>("TeacherFeedback")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("teacher_feedback");
@@ -744,19 +751,19 @@ namespace TechHelper.Server.Migrations
b.HasData(
new
{
Id = new Guid("a203eb76-97f0-418f-bc06-9549297d2ac3"),
Id = new Guid("e3bff43c-36af-497a-971c-ed0a487bdd38"),
Name = "Student",
NormalizedName = "STUDENT"
},
new
{
Id = new Guid("195b19c5-fd30-455c-9f38-9842b44bf5c3"),
Id = new Guid("f05c125e-e70f-40eb-9e19-6e69c3426849"),
Name = "Teacher",
NormalizedName = "TEACHER"
},
new
{
Id = new Guid("53cc63db-74bc-47a8-b71a-7e120d4018a9"),
Id = new Guid("cf16c215-63f8-4962-8ad0-058274ecf944"),
Name = "Administrator",
NormalizedName = "ADMINISTRATOR"
});
@@ -874,7 +881,7 @@ namespace TechHelper.Server.Migrations
.IsRequired();
b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct")
.WithOne("Assignment")
.WithOne()
.HasForeignKey("Entities.Contracts.Assignment", "ExamStructId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
@@ -920,9 +927,14 @@ namespace TechHelper.Server.Migrations
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
{
b.HasOne("Entities.Contracts.Assignment", "Assignment")
.WithMany()
.HasForeignKey("AssignmentId");
b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion")
.WithMany("ChildrenAssignmentQuestion")
.HasForeignKey("ParentAssignmentQuestionId");
.HasForeignKey("ParentAssignmentQuestionId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext")
.WithMany("Questions")
@@ -934,6 +946,8 @@ namespace TechHelper.Server.Migrations
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Assignment");
b.Navigation("ParentAssignmentQuestion");
b.Navigation("Question");
@@ -1064,7 +1078,7 @@ namespace TechHelper.Server.Migrations
b.HasOne("Entities.Contracts.User", "Student")
.WithMany("SubmissionsAsStudent")
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Restrict)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Assignment");
@@ -1085,7 +1099,7 @@ namespace TechHelper.Server.Migrations
b.HasOne("Entities.Contracts.User", "Student")
.WithMany("SubmissionDetails")
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Restrict)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Entities.Contracts.Submission", "Submission")
@@ -1163,8 +1177,6 @@ namespace TechHelper.Server.Migrations
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
{
b.Navigation("Assignment");
b.Navigation("ChildrenAssignmentQuestion");
b.Navigation("SubmissionDetails");

View File

@@ -12,6 +12,7 @@ using TechHelper.Features;
using TechHelper.Services;
using TechHelper.Server.Services;
using TechHelper.Server.Repositories;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
@@ -90,7 +91,35 @@ builder.Services.AddScoped<IExamRepository, ExamRepository>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Your API Name", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 12345abcdef\"",
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] {}
}
});
});
builder.Services.AddCors(options =>

View File

@@ -17,7 +17,7 @@ namespace TechHelper.Server.Repositories
{
_unitOfWork = unitOfWork;
_assignmentRepo = _unitOfWork.GetRepository<Assignment>();
_assignQuestionRepo = _unitOfWork.GetRepository<AssignmentQuestion>();
_assignQuestionRepo = _unitOfWork.GetRepository<AssignmentQuestion>();
}
public async Task<Assignment?> GetFullExamByIdAsync(Guid assignmentId)
@@ -29,18 +29,18 @@ namespace TechHelper.Server.Repositories
i => i.Include(a => a.ExamStruct)
);
result.ExamStruct = await GetNeed(result.ExamStructId)?? null;
result.ExamStruct = await GetNeed(result.ExamStructId) ?? null;
return result;
}
public async Task<AssignmentQuestion?> GetNeed(Guid id)
public async Task<AssignmentQuestion?> GetNeed(Guid id)
{
var result = await _assignQuestionRepo.GetFirstOrDefaultAsync(
predicate: aq => aq.Id == id,
include: i => i
.Include(aq => aq.ChildrenAssignmentQuestion)
.Include(aq => aq.ChildrenAssignmentQuestion)
.Include(aq => aq.Question)
.ThenInclude(q => q.Lesson)
.Include(aq => aq.Question)
@@ -55,13 +55,13 @@ namespace TechHelper.Server.Repositories
var loadedChildren = new List<AssignmentQuestion>();
foreach (var child in result.ChildrenAssignmentQuestion)
{
var loadedChild = await GetNeed(child.Id);
var loadedChild = await GetNeed(child.Id);
if (loadedChild != null)
{
loadedChildren.Add(loadedChild);
}
}
result.ChildrenAssignmentQuestion = loadedChildren;
result.ChildrenAssignmentQuestion = loadedChildren;
return result;
}
@@ -90,5 +90,18 @@ namespace TechHelper.Server.Repositories
public async Task AddAsync(AssignmentClass assignment)
{
}
public async Task AddAsync(Submission submission)
{
await _unitOfWork.GetRepository<Submission>().InsertAsync(submission);
}
public async Task<IEnumerable<Assignment>> GetAllSubmissionPreviewsByUserAsync(Guid id)
{
var submissions = await _unitOfWork.GetRepository<Submission>().GetAllAsync(predicate: s => s.StudentId == id, include: i => i.Include(s => s.Assignment));
if (submissions == null || !submissions.Any())
return Enumerable.Empty<Assignment>();
return submissions.ToList().Select(s => s.Assignment).Where(a => a != null).Distinct().ToList();
}
}
}

View File

@@ -1,4 +1,5 @@
using Entities.Contracts;
using Entities.DTO;
namespace TechHelper.Server.Repositories
{
@@ -23,6 +24,7 @@ namespace TechHelper.Server.Repositories
/// </summary>
/// <param name="assignment">要添加的试卷实体。</param>
Task AddAsync(Assignment assignment);
Task AddAsync(Submission submission);
@@ -32,6 +34,6 @@ namespace TechHelper.Server.Repositories
Task AddAsync(Question assignment);
Task AddAsync(AssignmentClass assignment);
Task<IEnumerable<Assignment>> GetAllSubmissionPreviewsByUserAsync(Guid id);
}
}

View File

@@ -67,15 +67,13 @@ namespace TechHelper.Services
}
}
// 实现 IBaseService<ClassDto, int>.GetAllAsync
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
{
try
{
var repository = _work.GetRepository<Class>();
// 构建查询条件 (可根据 QueryParameter.Search 进行筛选)
Func<IQueryable<Class>, IOrderedQueryable<Class>> orderBy = null; // 默认不排序
Func<IQueryable<Class>, IOrderedQueryable<Class>> orderBy = null;
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
{
// 在 Name 字段中进行模糊搜索
@@ -127,9 +125,22 @@ namespace TechHelper.Services
}
}
public Task<ApiResponse> GetClassStudents(ClassDto classDto)
public async Task<ApiResponse> GetClassStudents(ClassDto classDto)
{
throw new NotImplementedException();
try
{
var result = await _work.GetRepository<Class>().GetFirstOrDefaultAsync(predicate:
c => c.Grade == classDto.Grade && c.Number == classDto.Class,
include: i => i
.Include(c => c.ClassStudents)
.ThenInclude(cs => cs.Student));
return ApiResponse.Success(result: result.ClassStudents);
}
catch (Exception ex)
{
return ApiResponse.Error($"获取学生列表错误, {ex.Message}, {ex.InnerException}");
}
}
public async Task<ApiResponse> GetUserClass(Guid id)
@@ -185,9 +196,6 @@ namespace TechHelper.Services
var existingClass = await _work.GetRepository<Class>().GetFirstOrDefaultAsync(
predicate: (c => c.Number == user.ClassId && c.Grade == user.GradeId));
// finduser and usrinfo are redundant if they are for the same user.
// Let's just use usrinfo
// var finduser = await _userManager.FindByEmailAsync(user.User);
if (existingClass == null || usrinfo == null) // Simplified check
{

View File

@@ -57,7 +57,7 @@ namespace TechHelper.Server.Services
}
catch (Exception ex)
{
return ApiResponse.Error(ex.Message);
return ApiResponse.Error(ex.Message);
}
}
@@ -78,7 +78,7 @@ namespace TechHelper.Server.Services
public async Task<ApiResponse> GetAllExamPreviewsAsync(Guid userId)
{
var assignments = await _examRepository.GetExamPreviewsByUserAsync(userId);
var result = _mapper.Map<List<AssignmentDto>>(assignments);
var result = _mapper.Map<List<AssignmentDto>>(assignments);
return ApiResponse.Success(result: result);
}
@@ -109,11 +109,72 @@ namespace TechHelper.Server.Services
throw new NotImplementedException();
}
public Task<ApiResponse> DeleteAsync(Guid id)
public async Task<ApiResponse> DeleteAsync(Guid id)
{
try
{
var assignment = await _unitOfWork.GetRepository<Assignment>().GetFirstOrDefaultAsync(predicate: a => a.Id == id);
if (assignment == null) return ApiResponse.Error("找不到该试卷");
_unitOfWork.GetRepository<Assignment>().Delete(id);
_unitOfWork.GetRepository<AssignmentQuestion>().Delete(assignment.ExamStructId);
if (await _unitOfWork.SaveChangesAsync() > 0)
{
return ApiResponse.Success();
}
return ApiResponse.Error("删除失败");
}
catch (Exception ex)
{
return ApiResponse.Error("内部问题");
}
}
public async Task<ApiResponse> SubmissionAssignment(SubmissionDto submissionDto)
{
try
{
var submission = _mapper.Map<Submission>(submissionDto);
await _examRepository.AddAsync(submission);
if (await _unitOfWork.SaveChangesAsync() > 0)
{
return ApiResponse.Success("保存成功");
}
return ApiResponse.Error("保存失败");
}
catch (Exception ex)
{
return ApiResponse.Error($"出现了错误,{ex.Message} innerEx:{ex.InnerException}");
}
}
public Task<ApiResponse> AssignmentToAllStudentsAsync(Guid id)
{
throw new NotImplementedException();
}
public Task<ApiResponse> AssignmentToStudentsAsync(Guid assignementId, Guid studentId)
{
throw new NotImplementedException();
}
public async Task<ApiResponse> GetAllSubmissionAsync(Guid id)
{
try
{
var result = await _examRepository.GetAllSubmissionPreviewsByUserAsync(id);
var allExam = _mapper.Map<List<AssignmentDto>>(result);
return ApiResponse.Success(result: allExam);
}
catch (Exception ex)
{
return ApiResponse.Error($"Submission 内部错误, {ex.Message}");
}
}
}
}

View File

@@ -2,10 +2,10 @@
{
public interface IBaseService<T, TId>
{
Task<TechHelper.Services.ApiResponse> GetAllAsync(QueryParameter query);
Task<TechHelper.Services.ApiResponse> GetAsync(TId id);
Task<TechHelper.Services.ApiResponse> AddAsync(T model);
Task<TechHelper.Services.ApiResponse> UpdateAsync(T model);
Task<TechHelper.Services.ApiResponse> DeleteAsync(TId id);
Task<ApiResponse> GetAllAsync(QueryParameter query);
Task<ApiResponse> GetAsync(TId id);
Task<ApiResponse> AddAsync(T model);
Task<ApiResponse> UpdateAsync(T model);
Task<ApiResponse> DeleteAsync(TId id);
}
}

View File

@@ -22,5 +22,17 @@ namespace TechHelper.Server.Services
/// <returns>创建成功的试卷ID</returns>
Task<ApiResponse> CreateExamAsync(AssignmentDto examDto);
Task<ApiResponse> SubmissionAssignment(SubmissionDto submissionDto);
Task<ApiResponse> AssignmentToAllStudentsAsync(Guid id);
Task<ApiResponse> AssignmentToStudentsAsync(Guid assignementId, Guid studentId);
Task<ApiResponse> GetAllSubmissionAsync(Guid id);
}
}

View File

@@ -0,0 +1,16 @@
using Entities.Contracts;
using TechHelper.Services;
namespace TechHelper.Server.Services
{
public interface ISubmissionServices : IBaseService<Submission, Guid>
{
Task<ApiResponse> GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId);
Task<ApiResponse> GetAllErrorQuestionsAsync(Guid userId);
Task<ApiResponse> GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId);
Task<ApiResponse> GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId);
Task<ApiResponse> GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId);
Task<ApiResponse> GetQuestionErrorStudents(Guid assignmentId);
}
}

View File

@@ -0,0 +1,10 @@
using Entities.Contracts;
using TechHelper.Services;
namespace TechHelper.Server.Services
{
public interface IUserSerivces : IBaseService<User, Guid>
{
Task<ApiResponse> GetStudentDetailInfo(Guid userId);
}
}

View File

@@ -0,0 +1,91 @@
using AutoMapper;
using Entities.Contracts;
using Microsoft.EntityFrameworkCore;
using SharedDATA.Api;
using TechHelper.Services;
namespace TechHelper.Server.Services
{
public class SubmissionServices : ISubmissionServices
{
private readonly IUnitOfWork _unitOfWork;
private readonly IMapper _mapper;
private readonly IRepository<Submission> _submissionRepository;
private readonly IRepository<SubmissionDetail> _submissionDetailRepository;
public SubmissionServices(IMapper mapper, IUnitOfWork unitOfWork)
{
_mapper = mapper;
_unitOfWork = unitOfWork;
_submissionRepository = _unitOfWork.GetRepository<Submission>();
_submissionDetailRepository = _unitOfWork.GetRepository<SubmissionDetail>();
}
public Task<ApiResponse> AddAsync(Submission model)
{
throw new NotImplementedException();
}
public Task<ApiResponse> DeleteAsync(Guid id)
{
throw new NotImplementedException();
}
public Task<ApiResponse> GetAllAsync(QueryParameter query)
{
throw new NotImplementedException();
}
public async Task<ApiResponse> GetAllErrorQuestionsAsync(Guid userId)
{
try
{
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(predicate: sd => sd.StudentId == userId && sd.IsCorrect == false,
include: i => i
.Include(s => s.AssignmentQuestion)
.ThenInclude(aq => aq.Question));
var errorQuestion = errorSDs.Items.Select(sd => sd.AssignmentQuestion).ToList();
return ApiResponse.Success();
}
catch (Exception ex)
{
return ApiResponse.Error();
}
}
public Task<ApiResponse> GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId)
{
throw new NotImplementedException();
}
public Task<ApiResponse> GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId)
{
throw new NotImplementedException();
}
public Task<ApiResponse> GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId)
{
throw new NotImplementedException();
}
public Task<ApiResponse> GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId)
{
throw new NotImplementedException();
}
public Task<ApiResponse> GetAsync(Guid id)
{
throw new NotImplementedException();
}
public Task<ApiResponse> GetQuestionErrorStudents(Guid assignmentId)
{
throw new NotImplementedException();
}
public Task<ApiResponse> UpdateAsync(Submission model)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,38 @@
using Entities.Contracts;
using TechHelper.Services;
namespace TechHelper.Server.Services
{
public class UserServices : IUserSerivces
{
public Task<ApiResponse> AddAsync(User model)
{
throw new NotImplementedException();
}
public Task<ApiResponse> DeleteAsync(Guid id)
{
throw new NotImplementedException();
}
public Task<ApiResponse> GetAllAsync(QueryParameter query)
{
throw new NotImplementedException();
}
public Task<ApiResponse> GetAsync(Guid id)
{
throw new NotImplementedException();
}
public Task<ApiResponse> GetStudentDetailInfo(Guid userId)
{
throw new NotImplementedException();
}
public Task<ApiResponse> UpdateAsync(User model)
{
throw new NotImplementedException();
}
}
}