struct&&assiQues
This commit is contained in:
@@ -1,47 +0,0 @@
|
||||
namespace TechHelper.Services
|
||||
{
|
||||
public class ApiResponse
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public bool Status { get; set; }
|
||||
public object? Result { get; set; }
|
||||
|
||||
private ApiResponse(bool status, string message, object? result)
|
||||
{
|
||||
Status = status;
|
||||
Message = message;
|
||||
Result = result;
|
||||
}
|
||||
|
||||
public ApiResponse(string message, bool status = false)
|
||||
: this(status, message, null) { }
|
||||
|
||||
|
||||
public ApiResponse(bool status, object result)
|
||||
: this(status, string.Empty, result) { }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个表示成功响应的 ApiResponse 实例。
|
||||
/// </summary>
|
||||
/// <param name="message">成功消息。</param>
|
||||
/// <param name="result">可选的返回数据。</param>
|
||||
/// <returns>ApiResponse 实例。</returns>
|
||||
public static ApiResponse Success(string message = "操作成功。", object? result = null)
|
||||
{
|
||||
return new ApiResponse(true, message, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个表示失败响应的 ApiResponse 实例。
|
||||
/// </summary>
|
||||
/// <param name="message">错误消息。</param>
|
||||
/// <param name="result">可选的错误详情或数据。</param>
|
||||
/// <returns>ApiResponse 实例。</returns>
|
||||
public static ApiResponse Error(string message = "操作失败。", object? result = null)
|
||||
{
|
||||
return new ApiResponse(false, message, result);
|
||||
}
|
||||
}
|
||||
}
|
@@ -197,7 +197,7 @@ namespace TechHelper.Services
|
||||
{
|
||||
ClassId = existingClass.Id,
|
||||
TeacherId = existingClass.Id,
|
||||
SubjectTaught = user.SubjectArea.ToString()
|
||||
SubjectTaught = user.SubjectArea
|
||||
};
|
||||
await _work.GetRepository<ClassTeacher>().InsertAsync(classTeacher);
|
||||
|
||||
|
@@ -1,56 +1,149 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MySqlConnector;
|
||||
using Microsoft.VisualBasic;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Context;
|
||||
using TechHelper.Server.Repositories;
|
||||
using TechHelper.Services;
|
||||
using static TechHelper.Context.AutoMapperProFile;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
|
||||
public class ExamService : IExamService
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IRepository<Assignment> _assignmentRepo;
|
||||
private readonly IRepository<AssignmentGroup> _assignmentGroupRepo;
|
||||
private readonly IRepository<AssignmentQuestion> _assignmentQuestionRepo;
|
||||
private readonly IRepository<Question> _questionRepo;
|
||||
public ExamService(IUnitOfWork unitOfWork, IMapper mapper, UserManager<User> userManager)
|
||||
private readonly IExamRepository _examRepository;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ExamService(IUnitOfWork unitOfWork, IExamRepository examRepository, IMapper mapper)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_examRepository = examRepository;
|
||||
_mapper = mapper;
|
||||
_userManager = userManager;
|
||||
|
||||
_assignmentRepo = _unitOfWork.GetRepository<Assignment>();
|
||||
_assignmentGroupRepo = _unitOfWork.GetRepository<AssignmentGroup>();
|
||||
_assignmentQuestionRepo = _unitOfWork.GetRepository<AssignmentQuestion>();
|
||||
_questionRepo = _unitOfWork.GetRepository<Question>();
|
||||
}
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
private readonly UserManager<User> _userManager;
|
||||
|
||||
public async Task<ApiResponse> AddAsync(ExamDto model)
|
||||
public async Task<ApiResponse> CreateExamAsync(AssignmentDto assignmentDto)
|
||||
{
|
||||
try
|
||||
|
||||
Assignment newAssi = _mapper.Map<Assignment>(assignmentDto);
|
||||
|
||||
await _examRepository.AddAsync(newAssi);
|
||||
|
||||
|
||||
var context = _unitOfWork.GetDbContext<ApplicationContext>();
|
||||
|
||||
foreach (var entry in context.ChangeTracker.Entries())
|
||||
{
|
||||
var result = await SaveParsedExam(model);
|
||||
if (result.Status)
|
||||
if (entry.State == Microsoft.EntityFrameworkCore.EntityState.Added)
|
||||
{
|
||||
return ApiResponse.Success("保存试题成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApiResponse.Error($"保存试题数据失败{result.Message}");
|
||||
if(entry.Entity is Question newQues)
|
||||
{
|
||||
newQues.CreatorId = newAssi.CreatorId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
return ApiResponse.Success();
|
||||
}
|
||||
|
||||
private async void ParseStruct(AssignmentStructDto assignmentStruct, Guid ParentID)
|
||||
{
|
||||
|
||||
var newStruct = _mapper.Map<AssignmentStruct>(assignmentStruct);
|
||||
newStruct.ParentStructId = Guid.Empty == ParentID ? null : ParentID;
|
||||
await _examRepository.AddAsync(newStruct);
|
||||
|
||||
|
||||
foreach (var item in assignmentStruct.AssignmentQuestions)
|
||||
{
|
||||
return ApiResponse.Error($"保存试题数据失败: {ex.Message}");
|
||||
var newQuestion = _mapper.Map<Question>(item);
|
||||
//newQuestion.ParentQuestionId = item.ParentQuestion == null ? null : item.ParentQuestion.Id;
|
||||
await _examRepository.AddAsync(newQuestion);
|
||||
|
||||
//await ParseAssignmentQuestion(assignmentStruct, item, newQuestion);
|
||||
}
|
||||
|
||||
|
||||
foreach (var item in assignmentStruct.ChildrenGroups)
|
||||
{
|
||||
ParseStruct(item, assignmentStruct.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ParseAssignmentQuestion(AssignmentStructDto assignmentStruct, QuestionDto item, Question newQuestion)
|
||||
{
|
||||
AssignmentQuestion newAssignQues = new AssignmentQuestion();
|
||||
newAssignQues.QuestionId = newQuestion.Id;
|
||||
newAssignQues.AssignmentStructId = assignmentStruct.Id;
|
||||
newAssignQues.CreatedAt = DateTime.UtcNow;
|
||||
newAssignQues.Score = item.Score;
|
||||
await _examRepository.AddAsync(newAssignQues);
|
||||
}
|
||||
|
||||
private void SetEntityIdsAndRelations(AssignmentStruct group, Guid? assignmentId, Guid creatorId)
|
||||
{
|
||||
group.Id = Guid.NewGuid();
|
||||
group.AssignmentId = assignmentId;
|
||||
|
||||
foreach (var aq in group.AssignmentQuestions)
|
||||
{
|
||||
aq.Id = Guid.NewGuid();
|
||||
aq.AssignmentStructId = group.Id;
|
||||
aq.Question.Id = Guid.NewGuid();
|
||||
aq.Question.CreatorId = creatorId;
|
||||
aq.CreatedAt = DateTime.UtcNow;
|
||||
// ... 其他默认值
|
||||
}
|
||||
|
||||
foreach (var childGroup in group.ChildrenGroups)
|
||||
{
|
||||
// 子题组的 AssignmentId 为 null,通过 ParentGroup 关联
|
||||
SetEntityIdsAndRelations(childGroup, null, creatorId);
|
||||
childGroup.ParentStructId = group.Id;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<AssignmentDto> GetExamByIdAsync(Guid id)
|
||||
{
|
||||
var assignment = await _examRepository.GetFullExamByIdAsync(id);
|
||||
if (assignment == null)
|
||||
{
|
||||
|
||||
throw new InvalidOperationException("");
|
||||
}
|
||||
|
||||
return _mapper.Map<AssignmentDto>(assignment);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<AssignmentDto>> GetAllExamPreviewsAsync(Guid userId)
|
||||
{
|
||||
var assignments = await _examRepository.GetExamPreviewsByUserAsync(userId);
|
||||
return _mapper.Map<IEnumerable<AssignmentDto>>(assignments);
|
||||
}
|
||||
|
||||
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> AddAsync(AssignmentDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> UpdateAsync(AssignmentDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> DeleteAsync(Guid id)
|
||||
@@ -58,392 +151,10 @@ namespace TechHelper.Server.Services
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
Task<ApiResponse> IExamService.GetAllExamPreviewsAsync(Guid userId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await GetExamByIdAsync(id);
|
||||
return result;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取试题数据失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ApiResponse> UpdateAsync(ExamDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<AssignmentGroup>> LoadFullGroupTree(Guid rootGroupId)
|
||||
{
|
||||
var query = @"
|
||||
WITH RECURSIVE GroupTree AS (
|
||||
SELECT
|
||||
ag.*,
|
||||
CAST(ag.`number` AS CHAR(255)) AS path
|
||||
FROM assignment_group ag
|
||||
WHERE ag.id = @rootId
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
c.*,
|
||||
CONCAT(ct.path, '.', c.`number`)
|
||||
FROM assignment_group c
|
||||
INNER JOIN GroupTree ct ON c.parent_group = ct.id
|
||||
)
|
||||
SELECT * FROM GroupTree ORDER BY path;
|
||||
";
|
||||
|
||||
// 执行查询
|
||||
var groups = await _unitOfWork.GetRepository<AssignmentGroup>()
|
||||
.FromSql(query, new MySqlParameter("rootId", rootGroupId))
|
||||
.ToListAsync();
|
||||
|
||||
// 内存中构建树结构
|
||||
var groupDict = groups.ToDictionary(g => g.Id);
|
||||
var root = groupDict[rootGroupId];
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
if (group.ParentGroup != null && groupDict.TryGetValue(group.ParentGroup.Value, out var parent))
|
||||
{
|
||||
parent.ChildAssignmentGroups ??= new List<AssignmentGroup>();
|
||||
parent.ChildAssignmentGroups.Add(group);
|
||||
}
|
||||
}
|
||||
|
||||
return new List<AssignmentGroup> { root };
|
||||
}
|
||||
|
||||
public async Task LoadRecursiveAssignmentGroups(IEnumerable<AssignmentGroup> groups)
|
||||
{
|
||||
foreach (var group in groups.ToList())
|
||||
{
|
||||
|
||||
var loadedGroup = await _unitOfWork.GetRepository<AssignmentGroup>()
|
||||
.GetFirstOrDefaultAsync(
|
||||
predicate: ag => ag.Id == group.Id,
|
||||
include: source => source
|
||||
.Include(ag => ag.AssignmentQuestions.Where(aq => !aq.IsDeleted))
|
||||
.ThenInclude(aq => aq.Question)
|
||||
.Include(ag => ag.ChildAssignmentGroups)
|
||||
);
|
||||
|
||||
if (loadedGroup == null) continue;
|
||||
|
||||
group.ChildAssignmentGroups = loadedGroup.ChildAssignmentGroups;
|
||||
group.AssignmentQuestions = loadedGroup.AssignmentQuestions;
|
||||
|
||||
if (group.ChildAssignmentGroups is { Count: > 0 })
|
||||
{
|
||||
await LoadRecursiveAssignmentGroups(group.ChildAssignmentGroups);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetExamByIdAsync(Guid assignmentId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assignment = await _unitOfWork.GetRepository<Assignment>().GetFirstOrDefaultAsync(
|
||||
predicate: a => a.Id == assignmentId && !a.IsDeleted);
|
||||
|
||||
if (assignment == null)
|
||||
{
|
||||
return ApiResponse.Error($"找不到 ID 为 {assignmentId} 的试卷。");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 获取所有相关题组和题目,并过滤掉已删除的
|
||||
var allGroups = await _unitOfWork.GetRepository<AssignmentGroup>().GetFirstOrDefaultAsync(
|
||||
predicate: ag => ag.AssignmentId == assignmentId && !ag.IsDeleted,
|
||||
include: source => source
|
||||
.Include(ag => ag.ChildAssignmentGroups)
|
||||
);
|
||||
await LoadRecursiveAssignmentGroups(allGroups.ChildAssignmentGroups);
|
||||
|
||||
if (allGroups == null || !allGroups.ChildAssignmentGroups.Any())
|
||||
{
|
||||
// 试卷存在但没有内容,返回一个空的 ExamDto
|
||||
return ApiResponse.Success("试卷没有内容。", new ExamDto
|
||||
{
|
||||
AssignmentId = assignment.Id,
|
||||
AssignmentTitle = assignment.Title,
|
||||
Description = assignment.Description,
|
||||
SubjectArea = assignment.Submissions.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
var rootGroups = allGroups.ChildAssignmentGroups.ToList();
|
||||
|
||||
var rootqg = new QuestionGroupDto();
|
||||
|
||||
foreach (var ag in rootGroups.OrderBy(g => g.Number))
|
||||
{
|
||||
var agDto = MapAssignmentGroupToDto(ag);
|
||||
rootqg.SubQuestionGroups.Add(agDto);
|
||||
}
|
||||
|
||||
|
||||
// 递归映射到 ExamDto
|
||||
var examDto = new ExamDto
|
||||
{
|
||||
AssignmentId = assignment.Id,
|
||||
AssignmentTitle = assignment.Title,
|
||||
Description = assignment.Description,
|
||||
SubjectArea = assignment.Submissions.ToString(),
|
||||
QuestionGroups = rootqg
|
||||
};
|
||||
|
||||
return ApiResponse.Success("试卷信息已成功获取。", examDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取试卷时发生错误: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public QuestionGroupDto MapAssignmentGroupToDto(AssignmentGroup ag)
|
||||
{
|
||||
// 创建当前节点的DTO
|
||||
var dto = new QuestionGroupDto
|
||||
{
|
||||
Title = ag.Title,
|
||||
Score = (int)(ag.TotalPoints ?? 0),
|
||||
Descript = ag.Descript,
|
||||
SubQuestions = ag.AssignmentQuestions?
|
||||
.OrderBy(aq => aq.QuestionNumber)
|
||||
.Select(aq => new SubQuestionDto
|
||||
{
|
||||
Index = aq.QuestionNumber,
|
||||
Stem = aq.Question?.QuestionText,
|
||||
Score = aq.Score ?? 0,
|
||||
SampleAnswer = aq.Question?.CorrectAnswer,
|
||||
QuestionType = aq.Question?.QuestionType.ToString(),
|
||||
DifficultyLevel = aq.Question?.DifficultyLevel.ToString(),
|
||||
Options = new List<OptionDto>() // 根据需要初始化
|
||||
}).ToList() ?? new List<SubQuestionDto>(),
|
||||
SubQuestionGroups = new List<QuestionGroupDto>() // 初始化子集合
|
||||
};
|
||||
|
||||
// 递归处理子组
|
||||
if (ag.ChildAssignmentGroups != null && ag.ChildAssignmentGroups.Count > 0)
|
||||
{
|
||||
foreach (var child in ag.ChildAssignmentGroups.OrderBy(c => c.Number))
|
||||
{
|
||||
var childDto = MapAssignmentGroupToDto(child); // 递归获取子DTO
|
||||
dto.SubQuestionGroups.Add(childDto); // 添加到当前节点的子集合
|
||||
}
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
private List<QuestionGroupDto> MapAssignmentGroupsToDto2(
|
||||
List<AssignmentGroup> currentLevelGroups,
|
||||
IEnumerable<AssignmentGroup> allFetchedGroups)
|
||||
{
|
||||
var dtos = new List<QuestionGroupDto>();
|
||||
|
||||
foreach (var group in currentLevelGroups.OrderBy(g => g.Number))
|
||||
{
|
||||
var groupDto = new QuestionGroupDto
|
||||
{
|
||||
|
||||
Title = group.Title,
|
||||
Score = (int)(group.TotalPoints ?? 0),
|
||||
Descript = group.Descript,
|
||||
SubQuestions = group.AssignmentQuestions
|
||||
.OrderBy(aq => aq.QuestionNumber)
|
||||
.Select(aq => new SubQuestionDto
|
||||
{
|
||||
Index = aq.QuestionNumber,
|
||||
Stem = aq.Question.QuestionText,
|
||||
Score = aq.Score ?? 0,
|
||||
SampleAnswer = aq.Question.CorrectAnswer,
|
||||
QuestionType = aq.Question.QuestionType.ToString(),
|
||||
DifficultyLevel = aq.Question.DifficultyLevel.ToString(),
|
||||
Options = new List<OptionDto>()
|
||||
}).ToList(),
|
||||
// 递归映射子题组
|
||||
SubQuestionGroups = MapAssignmentGroupsToDto2(
|
||||
allFetchedGroups.Where(ag => ag.ParentGroup == group.Id && !ag.IsDeleted).ToList(),
|
||||
allFetchedGroups)
|
||||
};
|
||||
dtos.Add(groupDto);
|
||||
}
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<TechHelper.Services.ApiResponse> SaveParsedExam(ExamDto examData)
|
||||
{
|
||||
// 获取当前登录用户
|
||||
var currentUser = await _userManager.FindByEmailAsync(examData.CreaterEmail);
|
||||
if (currentUser == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到当前登录用户,无法保存试题。");
|
||||
}
|
||||
var currentUserId = currentUser.Id;
|
||||
|
||||
try
|
||||
{
|
||||
Guid assignmentId;
|
||||
|
||||
// 创建新的 Assignment 实体
|
||||
var newAssignment = new Assignment
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Title = examData.AssignmentTitle,
|
||||
Description = examData.Description,
|
||||
SubjectArea = examData.SubjectArea,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = currentUserId,
|
||||
IsDeleted = false
|
||||
};
|
||||
await _assignmentRepo.InsertAsync(newAssignment);
|
||||
assignmentId = newAssignment.Id;
|
||||
|
||||
|
||||
// 从 ExamDto.QuestionGroups 获取根题组。
|
||||
// 确保只有一个根题组,因为您的模型是“试卷只有一个根节点”。
|
||||
if (examData.QuestionGroups == null)
|
||||
{
|
||||
throw new ArgumentException("试卷必须包含且只能包含一个根题组。");
|
||||
}
|
||||
|
||||
await ProcessAndSaveAssignmentGroupsRecursive(
|
||||
examData.QuestionGroups,
|
||||
examData.SubjectArea.ToString(),
|
||||
assignmentId,
|
||||
null, // 根题组没有父级
|
||||
currentUserId);
|
||||
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success("试卷数据已成功保存。", new ExamDto { AssignmentId = assignmentId, AssignmentTitle = examData.AssignmentTitle });
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApiResponse.Success("没有新的试卷数据需要保存。");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"保存试卷数据失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcessAndSaveAssignmentGroupsRecursive(
|
||||
QuestionGroupDto qgDto,
|
||||
string subjectarea,
|
||||
Guid assignmentId,
|
||||
Guid? parentAssignmentGroupId,
|
||||
Guid createdById)
|
||||
{
|
||||
if (qgDto.ValidQuestionGroup)
|
||||
{
|
||||
await SaveQuestionGroup(qgDto);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte groupNumber = 1;
|
||||
|
||||
|
||||
var newAssignmentGroup = new AssignmentGroup
|
||||
{
|
||||
Id = Guid.NewGuid(), // 后端生成 GUID
|
||||
Title = qgDto.Title,
|
||||
Descript = qgDto.Descript,
|
||||
TotalPoints = qgDto.Score,
|
||||
Number = (byte)qgDto.Index,
|
||||
ValidQuestionGroup = qgDto.ValidQuestionGroup,
|
||||
ParentGroup = parentAssignmentGroupId,
|
||||
AssignmentId = parentAssignmentGroupId == null ? assignmentId : (Guid?)null,
|
||||
IsDeleted = false
|
||||
};
|
||||
await _unitOfWork.GetRepository<AssignmentGroup>().InsertAsync(newAssignmentGroup);
|
||||
|
||||
// 处理子题目
|
||||
uint questionNumber = 1;
|
||||
foreach (var sqDto in qgDto.SubQuestions.OrderBy(s => s.Index))
|
||||
{
|
||||
var newQuestion = _mapper.Map<Question>(sqDto);
|
||||
newQuestion.Id = Guid.NewGuid();
|
||||
newQuestion.CreatedBy = createdById;
|
||||
newQuestion.CreatedAt = DateTime.UtcNow;
|
||||
newQuestion.UpdatedAt = DateTime.UtcNow;
|
||||
newQuestion.IsDeleted = false;
|
||||
newQuestion.SubjectArea = EnumMappingHelpers.ParseEnumSafe(subjectarea, SubjectAreaEnum.Unknown);
|
||||
|
||||
await _unitOfWork.GetRepository<Question>().InsertAsync(newQuestion);
|
||||
|
||||
var newAssignmentQuestion = new AssignmentQuestion
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
QuestionId = newQuestion.Id,
|
||||
QuestionNumber = (byte)questionNumber,
|
||||
AssignmentGroupId = newAssignmentGroup.Id,
|
||||
Score = sqDto.Score,
|
||||
IsDeleted = false,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
await _unitOfWork.GetRepository<AssignmentQuestion>().InsertAsync(newAssignmentQuestion);
|
||||
|
||||
questionNumber++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 递归处理子题组
|
||||
// 这里需要遍历 SubQuestionGroups,并对每个子组进行递归调用
|
||||
foreach (var subQgDto in qgDto.SubQuestionGroups.OrderBy(s => s.Index))
|
||||
{
|
||||
await ProcessAndSaveAssignmentGroupsRecursive(
|
||||
subQgDto, // 传入当前的子题组 DTO
|
||||
subjectarea,
|
||||
assignmentId, // 顶层 AssignmentId 依然传递下去,但子组不会直接使用它
|
||||
newAssignmentGroup.Id, // 将当前题组的 ID 作为下一层递归的 parentAssignmentGroupId
|
||||
createdById);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveQuestionGroup(QuestionGroupDto qgDto)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllExamPreview(Guid user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assignments = await _unitOfWork.GetRepository<Assignment>().GetAllAsync(
|
||||
predicate: a => a.CreatedBy == user && !a.IsDeleted);
|
||||
|
||||
if (assignments.Any())
|
||||
{
|
||||
var exam = _mapper.Map<IEnumerable<ExamDto>>(assignments);
|
||||
return ApiResponse.Success(result: exam);
|
||||
}
|
||||
|
||||
return ApiResponse.Error("你还没有创建任何试卷");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"查询出了一点问题 , 详细信息为: {ex.Message}, 请稍后再试");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,123 +0,0 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Server.Repository;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
|
||||
public class ExamService2 : IExamService2
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IExamRepository _examRepository;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ExamService2(IUnitOfWork unitOfWork, IExamRepository examRepository, IMapper mapper)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_examRepository = examRepository;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<Guid> CreateExamAsync(ExamDto examDto, Guid creatorId)
|
||||
{
|
||||
if (examDto.QuestionGroups == null)
|
||||
{
|
||||
throw new ArgumentException("试卷必须包含一个根题组。");
|
||||
}
|
||||
|
||||
// 使用 AutoMapper 将 DTO 映射到实体
|
||||
var assignment = _mapper.Map<Assignment>(examDto);
|
||||
|
||||
// 设置后端生成的属性
|
||||
assignment.Id = Guid.NewGuid();
|
||||
assignment.CreatedBy = creatorId;
|
||||
assignment.CreatedAt = DateTime.UtcNow;
|
||||
|
||||
// 递归设置所有子实体的ID和关联关系
|
||||
SetEntityIdsAndRelations(assignment.AssignmentGroups.First(), assignment.Id, creatorId);
|
||||
|
||||
await _examRepository.AddAsync(assignment);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
return assignment.Id;
|
||||
}
|
||||
|
||||
private void SetEntityIdsAndRelations(AssignmentGroup group, Guid? assignmentId, Guid creatorId)
|
||||
{
|
||||
group.Id = Guid.NewGuid();
|
||||
group.AssignmentId = assignmentId;
|
||||
|
||||
foreach (var aq in group.AssignmentQuestions)
|
||||
{
|
||||
aq.Id = Guid.NewGuid();
|
||||
aq.AssignmentGroupId = group.Id;
|
||||
aq.Question.Id = Guid.NewGuid();
|
||||
aq.Question.CreatedBy = creatorId;
|
||||
aq.CreatedAt = DateTime.UtcNow;
|
||||
// ... 其他默认值
|
||||
}
|
||||
|
||||
foreach (var childGroup in group.ChildAssignmentGroups)
|
||||
{
|
||||
// 子题组的 AssignmentId 为 null,通过 ParentGroup 关联
|
||||
SetEntityIdsAndRelations(childGroup, null, creatorId);
|
||||
childGroup.ParentGroup = group.Id;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ExamDto> GetExamByIdAsync(Guid id)
|
||||
{
|
||||
var assignment = await _examRepository.GetFullExamByIdAsync(id);
|
||||
if (assignment == null)
|
||||
{
|
||||
|
||||
throw new InvalidOperationException("");
|
||||
}
|
||||
|
||||
return _mapper.Map<ExamDto>(assignment);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ExamDto>> GetAllExamPreviewsAsync(Guid userId)
|
||||
{
|
||||
var assignments = await _examRepository.GetExamPreviewsByUserAsync(userId);
|
||||
return _mapper.Map<IEnumerable<ExamDto>>(assignments);
|
||||
}
|
||||
|
||||
public async Task AddAsync(QuestionGroupDto qg)
|
||||
{
|
||||
if (qg.ValidQuestionGroup)
|
||||
{
|
||||
var mapQG = _mapper.Map<QuestionGroup>(qg);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> AddAsync(ExamDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> UpdateAsync(ExamDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -3,7 +3,7 @@ using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IAssignmentGroupService : IBaseService<AssignmentGroup, Guid>
|
||||
public interface IAssignmentGroupService : IBaseService<AssignmentStruct, Guid>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@@ -4,9 +4,23 @@ using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IExamService : IBaseService<ExamDto, Guid>
|
||||
public interface IExamService : IBaseService<AssignmentDto, Guid>
|
||||
{
|
||||
Task<ApiResponse> GetAllExamPreview(Guid user);
|
||||
QuestionGroupDto MapAssignmentGroupToDto(AssignmentGroup ag);
|
||||
/// <summary>
|
||||
/// 根据 ID 获取试卷 DTO。
|
||||
/// </summary>
|
||||
Task<AssignmentDto> GetExamByIdAsync(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定用户的所有试卷预览。
|
||||
/// </summary>
|
||||
Task<ApiResponse> GetAllExamPreviewsAsync(Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的试卷。
|
||||
/// </summary>
|
||||
/// <returns>创建成功的试卷ID</returns>
|
||||
Task<ApiResponse> CreateExamAsync(AssignmentDto examDto);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,26 +0,0 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IExamService2 : IBaseService<ExamDto, Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据 ID 获取试卷 DTO。
|
||||
/// </summary>
|
||||
Task<ExamDto> GetExamByIdAsync(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定用户的所有试卷预览。
|
||||
/// </summary>
|
||||
Task<IEnumerable<ExamDto>> GetAllExamPreviewsAsync(Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的试卷。
|
||||
/// </summary>
|
||||
/// <returns>创建成功的试卷ID</returns>
|
||||
Task<Guid> CreateExamAsync(ExamDto examDto, Guid creatorId);
|
||||
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
using Entities.Contracts;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IQuestionGroupService : IBaseService<QuestionGroup, Guid>
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public class QuestionGroupService : IAssignmentGroupService
|
||||
{
|
||||
|
||||
private readonly IUnitOfWork _work;
|
||||
// 如果不再需要 AutoMapper 进行实体到 DTO 的映射,可以移除 _mapper 字段
|
||||
// 但如果 AutoMapper 在其他服务中用于其他映射,或者将来可能需要,可以保留
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IExamService _examService;
|
||||
|
||||
public QuestionGroupService(IUnitOfWork work, IMapper mapper, IExamService examService)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
_examService = examService;
|
||||
}
|
||||
|
||||
|
||||
public Task<ApiResponse> AddAsync(AssignmentGroup 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> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var result = await _work.GetRepository<AssignmentGroup>().GetFirstOrDefaultAsync(predicate: ag => ag.Id == id);
|
||||
QuestionGroupDto qgd = new QuestionGroupDto();
|
||||
if (result != null)
|
||||
{
|
||||
qgd = _examService.MapAssignmentGroupToDto(result);
|
||||
return ApiResponse.Success(result: qgd);
|
||||
}
|
||||
return ApiResponse.Error("没找到问题组");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"出现了一点问题: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ApiResponse> UpdateAsync(AssignmentGroup model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@@ -31,12 +31,12 @@ namespace TechHelper.Server.Services
|
||||
{
|
||||
// 可以在此处进行业务逻辑校验,例如检查题目是否已存在
|
||||
var existingQuestion = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.QuestionText == model.QuestionText && !q.IsDeleted
|
||||
predicate: q => q.Title == model.Title && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (existingQuestion != null)
|
||||
{
|
||||
return ApiResponse.Error($"题目 '{model.QuestionText}' 已存在,请勿重复添加。");
|
||||
return ApiResponse.Error($"题目 '{model.Title}' 已存在,请勿重复添加。");
|
||||
}
|
||||
|
||||
// 设置创建时间、创建者等通用属性
|
||||
@@ -44,8 +44,7 @@ namespace TechHelper.Server.Services
|
||||
model.CreatedAt = DateTime.UtcNow;
|
||||
model.UpdatedAt = DateTime.UtcNow;
|
||||
model.IsDeleted = false;
|
||||
model.ValidQuestion = true; // 假设新添加的题目默认为有效
|
||||
// model.CreatedBy = ... // 实际应用中,这里应该从当前用户上下文获取
|
||||
|
||||
|
||||
await _work.GetRepository<Question>().InsertAsync(model);
|
||||
await _work.SaveChangesAsync();
|
||||
@@ -90,7 +89,7 @@ namespace TechHelper.Server.Services
|
||||
try
|
||||
{
|
||||
var question = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.QuestionText == title && !q.IsDeleted
|
||||
predicate: q => q.Title == title && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (question == null)
|
||||
@@ -119,10 +118,10 @@ namespace TechHelper.Server.Services
|
||||
var distinctTitles = titles.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
|
||||
|
||||
var existingQuestions = await _work.GetRepository<Question>().GetAllAsync(
|
||||
predicate: q => distinctTitles.Contains(q.QuestionText) && !q.IsDeleted
|
||||
predicate: q => distinctTitles.Contains(q.Title) && !q.IsDeleted
|
||||
);
|
||||
|
||||
var existingQuestionTexts = new HashSet<string>(existingQuestions.Select(q => q.QuestionText), StringComparer.OrdinalIgnoreCase);
|
||||
var existingQuestionTexts = new HashSet<string>(existingQuestions.Select(q => q.Title), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var resultDictionary = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var title in titles)
|
||||
@@ -146,7 +145,7 @@ namespace TechHelper.Server.Services
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
predicate = predicate.And(q => q.QuestionText.Contains(query.Search));
|
||||
predicate = predicate.And(q => q.Title.Contains(query.Search));
|
||||
}
|
||||
|
||||
Func<IQueryable<Question>, IOrderedQueryable<Question>> orderBy = null;
|
||||
@@ -214,12 +213,12 @@ namespace TechHelper.Server.Services
|
||||
|
||||
// 检查更新后的题目文本是否与现有其他题目重复
|
||||
var duplicateCheck = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.Id != model.Id && q.QuestionText == model.QuestionText && !q.IsDeleted
|
||||
predicate: q => q.Id != model.Id && q.Title == model.Title && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (duplicateCheck != null)
|
||||
{
|
||||
return ApiResponse.Error($"题目文本 '{model.QuestionText}' 已被其他题目占用,请修改。");
|
||||
return ApiResponse.Error($"题目文本 '{model.Title}' 已被其他题目占用,请修改。");
|
||||
}
|
||||
|
||||
// 手动复制属性或使用 AutoMapper (如果保留了 _mapper 字段)
|
||||
|
Reference in New Issue
Block a user