From e26881ec2fa9a255bc0d8537c1cd45897ad8bffe Mon Sep 17 00:00:00 2001 From: SpecialX <47072643+wangxiner55@users.noreply.github.com> Date: Wed, 11 Jun 2025 15:02:20 +0800 Subject: [PATCH] exam_service --- Entities/Contracts/AssignmentGroup.cs | 12 +- Entities/Contracts/AssignmentQuestion.cs | 12 +- Entities/Contracts/Question.cs | 3 + Entities/DTO/ApiResponse.cs | 38 +- Entities/DTO/ExamDto.cs | 23 +- TechHelper.Client/Exam/Exam.cs | 410 +++---- TechHelper.Client/Exam/Exam/ExamParse.cs | 627 ---------- .../Exam/Exam/QuestionCard.razor | 43 - .../Exam/SubMajorQuestionGroupDisplay.razor | 43 - .../Exam/ExamPaperExtensions .cs | 220 ++++ TechHelper.Client/Exam/ExamParse.cs | 740 +++++++++++ TechHelper.Client/Exam/ExamService.cs | 49 +- TechHelper.Client/Exam/IExamService.cs | 3 + .../HttpInterceptorHandlerService.cs | 1 - TechHelper.Client/Layout/MainLayout.razor | 37 +- TechHelper.Client/Layout/NavBar.razor | 4 +- .../Layout/RedirectToLogin.razor | 2 +- .../Pages/Author/Registration.razor | 4 - TechHelper.Client/Pages/Editor/Test.razor | 50 - .../Pages/Editor/TextEditor.razor | 50 + .../Pages/Exam/ChoiceQuestion.razor | 1 - TechHelper.Client/Pages/Exam/ExamCreate.razor | 132 ++ TechHelper.Client/Pages/Exam/ExamEdit.razor | 15 + .../Pages/Exam/ExamGroupView.razor | 48 + .../Pages/Exam/ExamManager.razor | 55 + .../Pages/Exam/ExamPreview.razor | 37 + TechHelper.Client/Pages/Exam/ExamView.razor | 23 + TechHelper.Client/Pages/Exam/Index.razor | 7 + .../Pages/Exam/ParseRoleConfig.razor | 127 ++ .../Pages/Exam/QuestionBase.razor | 11 - .../Pages/Exam/QuestionCard.razor | 36 + .../Pages/Exam/QuestionGroup.razor | 4 - .../Pages/Exam/QuestionGroupDisplay.razor | 69 -- TechHelper.Client/Pages/Exam/_Imports.razor | 2 + TechHelper.Client/Pages/Home.razor | 97 ++ TechHelper.Client/Program.cs | 11 + TechHelper.Client/Shared/ExamLayout.razor | 18 + TechHelper.Client/Shared/ExamNavMenu.razor | 22 + TechHelper.Client/TechHelper.Client.csproj | 8 + .../Context/AutoMapperProFile.cs | 27 +- .../AssignmentGroupConfiguration.cs | 6 +- .../AssignmentQuestionConfiguration.cs | 2 +- .../Controllers/ExamController.cs | 74 ++ ...ner.cs => 20250610025325_init.Designer.cs} | 27 +- ...8090233_init.cs => 20250610025325_init.cs} | 34 +- ...025810_assignment-not_required.Designer.cs | 1091 +++++++++++++++++ .../20250610025810_assignment-not_required.cs | 93 ++ .../ApplicationContextModelSnapshot.cs | 27 +- TechHelper.Server/Program.cs | 2 + TechHelper.Server/Services/ExamService.cs | 203 ++- TechHelper.Server/Services/IExamService.cs | 2 +- TechHelper.Server/appsettings.json | 2 +- 52 files changed, 3510 insertions(+), 1174 deletions(-) delete mode 100644 TechHelper.Client/Exam/Exam/ExamParse.cs delete mode 100644 TechHelper.Client/Exam/Exam/QuestionCard.razor delete mode 100644 TechHelper.Client/Exam/Exam/SubMajorQuestionGroupDisplay.razor create mode 100644 TechHelper.Client/Exam/ExamPaperExtensions .cs create mode 100644 TechHelper.Client/Exam/ExamParse.cs delete mode 100644 TechHelper.Client/Pages/Editor/Test.razor create mode 100644 TechHelper.Client/Pages/Editor/TextEditor.razor delete mode 100644 TechHelper.Client/Pages/Exam/ChoiceQuestion.razor create mode 100644 TechHelper.Client/Pages/Exam/ExamCreate.razor create mode 100644 TechHelper.Client/Pages/Exam/ExamEdit.razor create mode 100644 TechHelper.Client/Pages/Exam/ExamGroupView.razor create mode 100644 TechHelper.Client/Pages/Exam/ExamManager.razor create mode 100644 TechHelper.Client/Pages/Exam/ExamPreview.razor create mode 100644 TechHelper.Client/Pages/Exam/ExamView.razor create mode 100644 TechHelper.Client/Pages/Exam/Index.razor create mode 100644 TechHelper.Client/Pages/Exam/ParseRoleConfig.razor delete mode 100644 TechHelper.Client/Pages/Exam/QuestionBase.razor create mode 100644 TechHelper.Client/Pages/Exam/QuestionCard.razor delete mode 100644 TechHelper.Client/Pages/Exam/QuestionGroup.razor delete mode 100644 TechHelper.Client/Pages/Exam/QuestionGroupDisplay.razor create mode 100644 TechHelper.Client/Pages/Exam/_Imports.razor create mode 100644 TechHelper.Client/Shared/ExamLayout.razor create mode 100644 TechHelper.Client/Shared/ExamNavMenu.razor create mode 100644 TechHelper.Server/Controllers/ExamController.cs rename TechHelper.Server/Migrations/{20250528090233_init.Designer.cs => 20250610025325_init.Designer.cs} (97%) rename TechHelper.Server/Migrations/{20250528090233_init.cs => 20250610025325_init.cs} (96%) create mode 100644 TechHelper.Server/Migrations/20250610025810_assignment-not_required.Designer.cs create mode 100644 TechHelper.Server/Migrations/20250610025810_assignment-not_required.cs diff --git a/Entities/Contracts/AssignmentGroup.cs b/Entities/Contracts/AssignmentGroup.cs index f909797..623fa7d 100644 --- a/Entities/Contracts/AssignmentGroup.cs +++ b/Entities/Contracts/AssignmentGroup.cs @@ -15,10 +15,9 @@ namespace Entities.Contracts [Column("id")] public Guid Id { get; set; } - [Required] [Column("assignment")] [ForeignKey("Assignment")] - public Guid AssignmentId { get; set; } + public Guid? AssignmentId { get; set; } [Required] [Column("title")] @@ -31,7 +30,7 @@ namespace Entities.Contracts [Column("total_points")] - public decimal? TotalPoints { get; set; } + public float? TotalPoints { get; set; } [Column("number")] public byte Number { get; set; } @@ -42,9 +41,12 @@ namespace Entities.Contracts [Column("deleted")] public bool IsDeleted { get; set; } + [Column("valid_question_group")] + public bool ValidQuestionGroup { get; set; } + // Navigation Properties - public Assignment Assignment { get; set; } - public AssignmentGroup ParentAssignmentGroup { get; set;} + public Assignment? Assignment { get; set; } + public AssignmentGroup? ParentAssignmentGroup { get; set;} public ICollection ChildAssignmentGroups { get; set; } public ICollection AssignmentQuestions { get; set; } diff --git a/Entities/Contracts/AssignmentQuestion.cs b/Entities/Contracts/AssignmentQuestion.cs index 2e0ca0e..d36e5f6 100644 --- a/Entities/Contracts/AssignmentQuestion.cs +++ b/Entities/Contracts/AssignmentQuestion.cs @@ -21,21 +21,23 @@ namespace Entities.Contracts [ForeignKey("Question")] public Guid QuestionId { get; set; } + [Required] + [Column("group_id")] + [ForeignKey("AssignmentGroup")] + public Guid AssignmentGroupId { get; set; } + + [Required] [Column("question_number")] public byte QuestionNumber { get; set; } + [Column("created_at")] public DateTime CreatedAt { get; set; } [Column("score")] public float? Score { get; set; } - [Required] - [Column("detail_id")] - [ForeignKey("AssignmentGroup")] - public Guid AssignmentGroupId { get; set; } - [Column("deleted")] public bool IsDeleted { get; set; } diff --git a/Entities/Contracts/Question.cs b/Entities/Contracts/Question.cs index e09c247..fc2f7c8 100644 --- a/Entities/Contracts/Question.cs +++ b/Entities/Contracts/Question.cs @@ -50,6 +50,9 @@ namespace Entities.Contracts [Column("deleted")] public bool IsDeleted { get; set; } + [Column("valid_question")] + public bool ValidQuestion { get; set; } + // Navigation Properties public User Creator { get; set; } public ICollection AssignmentQuestions { get; set; } diff --git a/Entities/DTO/ApiResponse.cs b/Entities/DTO/ApiResponse.cs index cb05d8b..234c81f 100644 --- a/Entities/DTO/ApiResponse.cs +++ b/Entities/DTO/ApiResponse.cs @@ -3,21 +3,47 @@ public class ApiResponse { public ApiResponse(string message, bool status = false) - { - this.Message = message; - this.Status = status; - } + : this(status, message, null) { } + public ApiResponse(bool status, object result) + : this(status, string.Empty, result) { } + + + + /// + /// 创建一个表示成功响应的 ApiResponse 实例。 + /// + /// 成功消息。 + /// 可选的返回数据。 + /// ApiResponse 实例。 + public static ApiResponse Success(string message = "操作成功。", object? result = null) { - this.Status = status; - this.Result = result; + return new ApiResponse(true, message, result); + } + + /// + /// 创建一个表示失败响应的 ApiResponse 实例。 + /// + /// 错误消息。 + /// 可选的错误详情或数据。 + /// ApiResponse 实例。 + public static ApiResponse Error(string message = "操作失败。", object? result = null) + { + return new ApiResponse(false, message, result); } public ApiResponse() { } + private ApiResponse(bool status, string message, object? result) + { + Status = status; + Message = message; + Result = result; + } + public string Message { get; set; } public bool Status { get; set; } diff --git a/Entities/DTO/ExamDto.cs b/Entities/DTO/ExamDto.cs index 0a95e1a..6f0229d 100644 --- a/Entities/DTO/ExamDto.cs +++ b/Entities/DTO/ExamDto.cs @@ -3,31 +3,33 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Xml.Serialization; namespace Entities.DTO { public class ExamDto { public Guid? AssignmentId { get; set; } + public string CreaterEmail { get; set; } public string AssignmentTitle { get; set; } = string.Empty; public string Description { get; set; } public string SubjectArea { get; set; } - public List QuestionGroups { get; set; } = new List(); + public QuestionGroupDto QuestionGroups { get; set; } = new QuestionGroupDto(); } public class QuestionGroupDto { - public int Index { get; set; } + public byte Index { get; set; } - public string Title { get; set; } + public string? Title { get; set; } - public int Score { get; set; } - - public string QuestionReference { get; set; } + public float Score { get; set; } + public string? Descript { get; set; } public List SubQuestions { get; set; } = new List(); public List SubQuestionGroups { get; set; } = new List(); + public bool ValidQuestionGroup { get; set; } = false; } public class SubQuestionDto @@ -35,16 +37,17 @@ namespace Entities.DTO public byte Index { get; set; } - public string Stem { get; set; } + public string? Stem { get; set; } public float Score { get; set; } public List Options { get; set; } = new List(); - public string SampleAnswer { get; set; } + public string? SampleAnswer { get; set; } - public string QuestionType { get; set; } - public string DifficultyLevel { get; set; } + public string? QuestionType { get; set; } + public string? DifficultyLevel { get; set; } + public bool ValidQuestion { get; set; } = false; } diff --git a/TechHelper.Client/Exam/Exam.cs b/TechHelper.Client/Exam/Exam.cs index 0737646..26f6e50 100644 --- a/TechHelper.Client/Exam/Exam.cs +++ b/TechHelper.Client/Exam/Exam.cs @@ -6,244 +6,244 @@ using System.IO; // 用于 XML 反序列化 namespace TechHelper.Client.Exam { - [XmlRoot("EP")] - public class StringsList - { + //[XmlRoot("EP")] + //public class StringsList + //{ - [XmlElement("Q")] - public List Items { get; set; } - } + // [XmlElement("Q")] + // public List Items { get; set; } + //} - // XML 根元素 - [XmlRoot("EP")] - public class ExamPaper - { - // XML 特性: 包含 列表 - [XmlArray("QGs")] - [XmlArrayItem("QG")] - [JsonProperty("QuestionGroups")] - public List QuestionGroups { get; set; } = new List(); - } + //// XML 根元素 + //[XmlRoot("EP")] + //public class ExamPaper + //{ + // // XML 特性: 包含 列表 + // [XmlArray("QGs")] + // [XmlArrayItem("QG")] + // [JsonProperty("QuestionGroups")] + // public List QuestionGroups { get; set; } = new List(); + //} - [XmlRoot("QG")] - public class QuestionGroup - { - // JSON 特性 - [JsonProperty("题号")] - // XML 特性:作为 属性 - [XmlAttribute("Id")] - public byte Id { get; set; } + //[XmlRoot("QG")] + //public class QuestionGroup + //{ + // // JSON 特性 + // [JsonProperty("题号")] + // // XML 特性:作为 属性 + // [XmlAttribute("Id")] + // public byte Id { get; set; } - [JsonProperty("标题")] - [XmlElement("T")] // T for Title - public string Title { get; set; } + // [JsonProperty("标题")] + // [XmlElement("T")] // T for Title + // public string Title { get; set; } - [JsonProperty("分值")] - [XmlAttribute("S")] // S for Score - public int Score { get; set; } + // [JsonProperty("分值")] + // [XmlAttribute("S")] // S for Score + // public int Score { get; set; } - [JsonProperty("题目引用")] - [XmlElement("QR")] // QR for QuestionReference,作为 元素 - public string QuestionReference { get; set; } = ""; // 初始化为空字符串 + // [JsonProperty("题目引用")] + // [XmlElement("QR")] // QR for QuestionReference,作为 元素 + // public string QuestionReference { get; set; } = ""; // 初始化为空字符串 - [JsonProperty("子题目")] - [XmlArray("SQs")] // SQs 包含 列表 - [XmlArrayItem("SQ")] - public List SubQuestions { get; set; } = new List(); + // [JsonProperty("子题目")] + // [XmlArray("SQs")] // SQs 包含 列表 + // [XmlArrayItem("SQ")] + // public List SubQuestions { get; set; } = new List(); - [JsonProperty("子题组")] - [XmlArray("SQGs")] // SQGs 包含 列表 (嵌套题组) - [XmlArrayItem("QG")] - public List SubQuestionGroups { get; set; } = new List(); - } + // [JsonProperty("子题组")] + // [XmlArray("SQGs")] // SQGs 包含 列表 (嵌套题组) + // [XmlArrayItem("QG")] + // public List SubQuestionGroups { get; set; } = new List(); + //} - // 子题目类 - public class SubQuestion - { + //// 子题目类 + //public class SubQuestion + //{ - [JsonProperty("子题号")] - [XmlAttribute("Id")] // Id for SubId - public byte SubId { get; set; } + // [JsonProperty("子题号")] + // [XmlAttribute("Id")] // Id for SubId + // public byte SubId { get; set; } - [JsonProperty("题干")] - [XmlElement("T")] // T for Text (Stem) - public string Stem { get; set; } + // [JsonProperty("题干")] + // [XmlElement("T")] // T for Text (Stem) + // public string Stem { get; set; } - [JsonProperty("分值")] - [XmlAttribute("S")] // S for Score - public int Score { get; set; } // 分值通常为整数 + // [JsonProperty("分值")] + // [XmlAttribute("S")] // S for Score + // public int Score { get; set; } // 分值通常为整数 - [JsonProperty("选项")] - [XmlArray("Os")] // Os 包含 列表 - [XmlArrayItem("O")] - public List