重构项目结构,移除Assignment相关功能,优化Submission模块
Some checks failed
TechAct / explore-gitea-actions (push) Failing after 12s

This commit is contained in:
SpecialX
2025-10-09 18:57:28 +08:00
parent 403b34a098
commit ac900159ba
289 changed files with 11948 additions and 20150 deletions

View File

@@ -14,7 +14,7 @@ namespace TechHelper.Client.Exam
public class AssignmentCheckQuestion
{
public string Sequence { get; set; } = string.Empty;
public AssignmentQuestionDto AssignmentQuestionDto { get; set; } = new AssignmentQuestionDto();
public ExamQuestionDto ExamQuestionDto { get; set; } = new ExamQuestionDto();
public float Score { get; set; }
}
@@ -42,7 +42,7 @@ namespace TechHelper.Client.Exam
public static class ExamStructExtensions
{
public static AssignmentCheckData GetStruct(this AssignmentDto dto)
public static AssignmentCheckData GetStruct(this ExamDto dto)
{
if (dto == null)
{
@@ -66,7 +66,7 @@ namespace TechHelper.Client.Exam
/// <param name="parentSequence">当前题目组的父级序号(例如:"1", "2.1")。如果为空,则表示顶级题目组。</param>
/// <param name="allQuestions">用于收集所有生成题目项的列表。</param>
private static void GetSeqRecursive(
AssignmentQuestionDto currentGroup,
ExamQuestionDto currentGroup,
string? parentSequence,
List<AssignmentCheckQuestion> allQuestions)
{
@@ -74,7 +74,7 @@ namespace TechHelper.Client.Exam
? $"{parentSequence}.{currentGroup.Index}"
: currentGroup.Index.ToString();
foreach (var subGroup in currentGroup.ChildrenAssignmentQuestion)
foreach (var subGroup in currentGroup.ChildExamQuestions)
{
GetSeqRecursive(subGroup, currentGroupSequence, allQuestions);
}
@@ -83,7 +83,7 @@ namespace TechHelper.Client.Exam
allQuestions.Add(new AssignmentCheckQuestion
{
AssignmentQuestionDto = currentGroup,
ExamQuestionDto = currentGroup,
//Sequence = currentGroupSequence,
Sequence = currentGroup.Sequence,
Score = currentGroup.Score,

View File

@@ -16,18 +16,18 @@ namespace TechHelper.Client.Exam
.Where(line => !string.IsNullOrWhiteSpace(line)).ToList();
}
public static void SeqIndex(this AssignmentDto dto)
public static void SeqIndex(this ExamDto dto)
{
dto.ExamStruct.SeqQGroupIndex();
}
public static void SeqQGroupIndex(this AssignmentQuestionDto dto)
public static void SeqQGroupIndex(this ExamQuestionDto dto)
{
foreach (var sqg in dto.ChildrenAssignmentQuestion)
foreach (var sqg in dto.ChildExamQuestions)
{
sqg.Index = (byte)(dto.ChildrenAssignmentQuestion.IndexOf(sqg) + 1);
sqg.Index = (byte)(dto.ChildExamQuestions.ToList().IndexOf(sqg) + 1);
sqg.SeqQGroupIndex();
}

View File

@@ -1,6 +1,8 @@
using Entities.Contracts; // 假设这些实体合约仍然是必需的
using System.Text.RegularExpressions;
using System.Text;
using Entities.DTO;
using TechHelper.Client.Services;
namespace TechHelper.Client.Exam
{
@@ -41,17 +43,17 @@ namespace TechHelper.Client.Exam
}
}
public class AssignmentEx
public class ExamEx
{
public string Title { get; set; } = "Title";
public string Description { get; set; } = "Description";
public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown;
public AssignmentQuestionEx ExamStruct { get; set; } = new AssignmentQuestionEx();
public TypeCommonDto Subject { get; set; }
public ExamQuestionEx ExamStruct { get; set; } = new ExamQuestionEx();
public List<ParseError> Errors { get; set; } = new List<ParseError>();
}
// 试题的包裹器, 或者 单独作为一个试题结构存在
public class AssignmentQuestionEx
public class ExamQuestionEx
{
public string Title { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
@@ -59,8 +61,8 @@ namespace TechHelper.Client.Exam
public float Score { get; set; }
public string Sequence { get; set; } = string.Empty;
public QuestionEx? Question { get; set; }
public AssignmentStructType Type { get; set; }
public List<AssignmentQuestionEx> ChildrenAssignmentQuestion { get; set; } = new List<AssignmentQuestionEx>();
public TypeCommonDto Type { get; set; }
public List<ExamQuestionEx> ChildrenAssignmentQuestion { get; set; } = new List<ExamQuestionEx>();
public int Priority { get; set; }
}
@@ -85,10 +87,10 @@ namespace TechHelper.Client.Exam
{
public string Pattern { get; set; }
public int Priority { get; set; }
public AssignmentStructType Type { get; set; }
public ExamStructType Type { get; set; }
public Regex Regex { get; private set; }
public RegexPatternConfig(string pattern, int priority, AssignmentStructType type = AssignmentStructType.Question)
public RegexPatternConfig(string pattern, int priority, ExamStructType type = ExamStructType.Question)
{
Pattern = pattern;
Priority = priority;
@@ -113,26 +115,26 @@ namespace TechHelper.Client.Exam
// Group 2: 题目/题组标题内容
// 例如:一. 这是大题一
QuestionPatterns.Add(new RegexPatternConfig(@"^([一二三四五六七八九十]+)[.\、]\s*(.+)", 1, AssignmentStructType.Struct));
QuestionPatterns.Add(new RegexPatternConfig(@"^([一二三四五六七八九十]+)[.\、]\s*(.+)", 1, ExamStructType.Struct));
// 例如:(一) 这是第一子题组
QuestionPatterns.Add(new RegexPatternConfig(@"^\(([一二三四五六七八九十]{1,2}|十[一二三四五六七八九])\)\s*(.+)", 2, AssignmentStructType.Group));
QuestionPatterns.Add(new RegexPatternConfig(@"^\(([一二三四五六七八九十]{1,2}|十[一二三四五六七八九])\)\s*(.+)", 2, ExamStructType.Group));
// 例如1. 这是第一道题目 或 1 这是第一道题目
QuestionPatterns.Add(new RegexPatternConfig(@"^(\d+)\.?\s*(.+)", 3, AssignmentStructType.Question));
QuestionPatterns.Add(new RegexPatternConfig(@"^(\d+)\.?\s*(.+)", 3, ExamStructType.Question));
// 例如:(1). 这是小问一 或 (1) 这是小问一
QuestionPatterns.Add(new RegexPatternConfig(@"^\((\d+)\)\.?\s*(.+)", 4, AssignmentStructType.Question));
QuestionPatterns.Add(new RegexPatternConfig(@"^\((\d+)\)\.?\s*(.+)", 4, ExamStructType.Question));
// 例如:① 这是另一种小问 或 ①. 这是另一种小问 (如果 ① 后面会跟点,这个更通用)
// 如果 ① 后面通常没有点,但您希望它也能匹配,则保留原样或根据实际情况调整
QuestionPatterns.Add(new RegexPatternConfig(@"^[①②③④⑤⑥⑦⑧⑨⑩]+\.?\s*(.+)", 5, AssignmentStructType.Question));
QuestionPatterns.Add(new RegexPatternConfig(@"^[①②③④⑤⑥⑦⑧⑨⑩]+\.?\s*(.+)", 5, ExamStructType.Question));
// 选项模式 (保持不变,使用 AssignmentStructType.Option 区分)
OptionPatterns.Add(new RegexPatternConfig(@"([A-Z]\.)\s*(.*?)(?=[A-Z]\.|$)", 1, AssignmentStructType.Option));
OptionPatterns.Add(new RegexPatternConfig(@"([a-z]\.)\s*(.*?)(?=[a-z]\.|$)", 2, AssignmentStructType.Option));
// 选项模式 (保持不变,使用 ExamStructType.Option 区分)
OptionPatterns.Add(new RegexPatternConfig(@"([A-Z]\.)\s*(.*?)(?=[A-Z]\.|$)", 1, ExamStructType.Option));
OptionPatterns.Add(new RegexPatternConfig(@"([a-z]\.)\s*(.*?)(?=[a-z]\.|$)", 2, ExamStructType.Option));
// 独立的得分正则表达式:匹配行末尾的 "(X分)" 格式
// Group 1: 捕获分数(如 "10" 或 "0.5"
@@ -206,7 +208,7 @@ namespace TechHelper.Client.Exam
_config = config ?? throw new ArgumentNullException(nameof(config), "ExamParserConfig cannot be null.");
}
public AssignmentEx BuildExam(string fullExamText, List<PotentialMatch> allPotentialMatches)
public ExamEx BuildExam(string fullExamText, List<PotentialMatch> allPotentialMatches)
{
if (string.IsNullOrWhiteSpace(fullExamText))
{
@@ -217,7 +219,7 @@ namespace TechHelper.Client.Exam
throw new ArgumentNullException(nameof(allPotentialMatches), "Potential matches list cannot be null.");
}
var assignment = new AssignmentEx();
var assignment = new ExamEx();
try
{
assignment.Title = GetExamTitle(fullExamText);
@@ -228,8 +230,8 @@ namespace TechHelper.Client.Exam
assignment.Title = "未识别试卷标题";
}
var assignmentQuestionStack = new Stack<AssignmentQuestionEx>();
var rootAssignmentQuestion = new AssignmentQuestionEx { Type = AssignmentStructType.Struct, Priority = 0, Title = "Root Exam Structure" };
var assignmentQuestionStack = new Stack<ExamQuestionEx>();
var rootAssignmentQuestion = new ExamQuestionEx { Priority = 0, Title = "Root Exam Structure" };
assignmentQuestionStack.Push(rootAssignmentQuestion);
assignment.ExamStruct = rootAssignmentQuestion;
@@ -270,7 +272,7 @@ namespace TechHelper.Client.Exam
}
}
if (pm.PatternConfig.Type == AssignmentStructType.Option)
if (pm.PatternConfig.Type == ExamStructType.Option)
{
HandleOptionMatch(pm, i, assignmentQuestionStack.Peek(), assignment.Errors);
}
@@ -337,7 +339,7 @@ namespace TechHelper.Client.Exam
return true;
}
private void HandleQuestionGroupMatch(PotentialMatch pm, int index, Stack<AssignmentQuestionEx> assignmentQuestionStack, List<ParseError> errors)
private void HandleQuestionGroupMatch(PotentialMatch pm, int index, Stack<ExamQuestionEx> assignmentQuestionStack, List<ParseError> errors)
{
try
{
@@ -379,24 +381,22 @@ namespace TechHelper.Client.Exam
string seq = pm.RegexMatch.Groups[1].Value.Trim();
seq = string.IsNullOrEmpty(seq) || string.IsNullOrEmpty(sequence) ? seq : " ." + seq;
AssignmentQuestionEx newAssignmentQuestion;
if (pm.PatternConfig.Type == AssignmentStructType.Struct)
ExamQuestionEx newAssignmentQuestion;
if (pm.PatternConfig.Type == ExamStructType.Struct)
{
newAssignmentQuestion = new AssignmentQuestionEx
newAssignmentQuestion = new ExamQuestionEx
{
Title = title,
Score = score,
Sequence = sequence + seq,
Priority = pm.PatternConfig.Priority,
Type = pm.PatternConfig.Type
};
}
else // AssignmentStructType.Question 类型
else // ExamStructType.Question 类型
{
newAssignmentQuestion = new AssignmentQuestionEx
newAssignmentQuestion = new ExamQuestionEx
{
Priority = pm.PatternConfig.Priority,
Type = pm.PatternConfig.Type,
Sequence = sequence + seq,
Score = score,
Question = new QuestionEx
@@ -417,7 +417,7 @@ namespace TechHelper.Client.Exam
}
}
private void HandleOptionMatch(PotentialMatch pm, int index, AssignmentQuestionEx currentAssignmentQuestion, List<ParseError> errors)
private void HandleOptionMatch(PotentialMatch pm, int index, ExamQuestionEx currentAssignmentQuestion, List<ParseError> errors)
{
try
{
@@ -452,7 +452,7 @@ namespace TechHelper.Client.Exam
}
}
private void ProcessQuestionContent(AssignmentQuestionEx question, string contentText, List<ParseError> errors)
private void ProcessQuestionContent(ExamQuestionEx question, string contentText, List<ParseError> errors)
{
if (question?.Question == null)
{
@@ -479,12 +479,14 @@ namespace TechHelper.Client.Exam
public class ExamParser
{
private readonly ExamParserConfig _config;
private readonly ICommonService _commonService;
private readonly ExamDocumentScanner _scanner;
private readonly ExamStructureBuilder _builder;
public ExamParser(ExamParserConfig config)
public ExamParser(ExamParserConfig config, ICommonService commonService)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
_commonService = commonService;
_scanner = new ExamDocumentScanner(_config);
_builder = new ExamStructureBuilder(_config);
}
@@ -494,9 +496,9 @@ namespace TechHelper.Client.Exam
/// </summary>
/// <param name="examPaperText">完整的试卷文本</param>
/// <returns>解析后的 AssignmentEx 对象</returns>
public AssignmentEx ParseExamPaper(string examPaperText)
public ExamEx ParseExamPaper(string examPaperText)
{
var assignment = new AssignmentEx();
var assignment = new ExamEx();
List<PotentialMatch> allPotentialMatches = _scanner.Scan(examPaperText, assignment.Errors);
assignment = _builder.BuildExam(examPaperText, allPotentialMatches);
return assignment;