From 95fb44b0b5ad9addd13a1bf25400a2bcb3c56991 Mon Sep 17 00:00:00 2001 From: snow Date: Fri, 30 Jan 2026 09:36:49 +0800 Subject: [PATCH 1/6] add delete --- .../UserExams/UserExamAdminAppService.cs | 38 +++++++++---- .../KnowledgePointAdminAppService.cs | 19 ++++--- ...gementAdminApplicationAutoMapperProfile.cs | 3 - .../Papers/PaperAdminAppService.cs | 6 +- .../QuestionBankAdminAppService.cs | 49 +++++++--------- .../Questions/QuestionAdminAppService.cs | 3 +- .../UserExams/UserExamAppService.cs | 38 +++++++++---- .../Favorites/FavoriteAppService.cs | 2 +- .../ExamDomainErrorCodes.cs | 1 + .../Localization/Exam/zh-Hans.json | 2 + .../ExamManagement/Exams/IExamRepository.cs | 3 + .../IUserExamQuestionRepository.cs | 15 ----- .../UserExamQuestions/UserExamQuestion.cs | 3 - .../UserExamQuestionWithDetails.cs | 53 ----------------- .../UserExams/UserExamManager.cs | 12 +--- .../KnowledgePoints/KnowledgePointManager.cs | 18 ++++++ .../Mistakes/IMistakeRepository.cs | 7 +++ .../IPaperQuestionRuleRepository.cs | 15 ----- .../PaperQuestionRuleWithDetails.cs | 57 ------------------- .../IPaperQuestionRepository.cs | 20 ------- .../PaperSections/IPaperSectionRepository.cs | 18 ------ .../Papers/IPaperRepository.cs | 5 +- .../PaperManagement/Papers/Paper.cs | 1 - .../PaperManagement/Papers/PaperManager.cs | 19 ++++++- .../Papers/PaperNameAlreadyExistException.cs | 3 +- .../PaperQuestion.cs | 5 +- .../PaperQuestionRule.cs | 2 +- .../{PaperSections => Papers}/PaperSection.cs | 3 +- .../Papers/PaperUsedByExamException.cs | 12 ++++ .../QuestionBanks/QuestionBankManager.cs | 28 +++++++-- .../IQuestionKnowledgePointRepository.cs | 14 +++++ .../Questions/IQuestionRepository.cs | 8 +++ .../Questions/QuestionManager.cs | 32 +++++++++-- .../QuestionOptions/QuestionOption.cs | 2 +- .../EntityFrameworkCore/ExamDbContext.cs | 1 - .../ExamManagement/Exams/ExamRepository.cs | 13 ++++- .../UserExamQuestionRepository.cs | 12 ---- .../EntityFrameworkCore/IExamDbContext.cs | 2 - .../Mistakes/MistakeRepository.cs | 5 ++ .../PaperQuestionRuleRepository.cs | 20 ------- .../PaperQuestions/PaperQuestionRepository.cs | 37 ------------ .../PaperQuestions/PaperSectionRepository.cs | 30 ---------- .../PaperManagement/Papers/PaperRepository.cs | 12 +++- .../QuestionKnowledgePointRepository.cs | 10 ++++ .../Questions/QuestionRepository.cs | 5 ++ .../ExamDbContextInUnitTest.cs | 2 - 46 files changed, 278 insertions(+), 387 deletions(-) delete mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/IUserExamQuestionRepository.cs delete mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/UserExamQuestionWithDetails.cs create mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/KnowledgePoints/KnowledgePointManager.cs delete mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/IPaperQuestionRuleRepository.cs delete mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/PaperQuestionRuleWithDetails.cs delete mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestions/IPaperQuestionRepository.cs delete mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperSections/IPaperSectionRepository.cs rename aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/{PaperQuestions => Papers}/PaperQuestion.cs (86%) rename aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/{PaperQuestionRules => Papers}/PaperQuestionRule.cs (96%) rename aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/{PaperSections => Papers}/PaperSection.cs (97%) create mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperUsedByExamException.cs delete mode 100644 aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamManagement/UserExamQuestions/UserExamQuestionRepository.cs delete mode 100644 aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestionRules/PaperQuestionRuleRepository.cs delete mode 100644 aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestions/PaperQuestionRepository.cs delete mode 100644 aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestions/PaperSectionRepository.cs diff --git a/aspnet-core/src/SuperAbp.Exam.Admin.Application/ExamManagement/UserExams/UserExamAdminAppService.cs b/aspnet-core/src/SuperAbp.Exam.Admin.Application/ExamManagement/UserExams/UserExamAdminAppService.cs index 22e38c84..1d9389d7 100644 --- a/aspnet-core/src/SuperAbp.Exam.Admin.Application/ExamManagement/UserExams/UserExamAdminAppService.cs +++ b/aspnet-core/src/SuperAbp.Exam.Admin.Application/ExamManagement/UserExams/UserExamAdminAppService.cs @@ -1,18 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Volo.Abp.Application.Dtos; +using SuperAbp.Exam.Admin.ExamManagement.Exams; +using SuperAbp.Exam.ExamManagement.Exams; +using SuperAbp.Exam.ExamManagement.UserExamQuestions; using SuperAbp.Exam.ExamManagement.UserExams; using SuperAbp.Exam.KnowledgePoints; using SuperAbp.Exam.QuestionManagement.Questions; +using SuperAbp.Exam.QuestionManagement.Questions.QuestionOptions; +using System; +using System.Collections.Generic; using System.Linq; -using SuperAbp.Exam.ExamManagement.Exams; -using SuperAbp.Exam.ExamManagement.UserExamQuestions; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Data; using Volo.Abp.Identity; using Volo.Abp.Users; -using Volo.Abp; -using SuperAbp.Exam.QuestionManagement.Questions.QuestionOptions; -using SuperAbp.Exam.Admin.ExamManagement.Exams; namespace SuperAbp.Exam.Admin.ExamManagement.UserExams; @@ -21,13 +22,15 @@ public class UserExamAdminAppService(IUserExamRepository userExamRepository, IIdentityUserRepository userRepository, IExamRepository examRepository, QuestionManager questionManager, - UserExamManager userExamManager) : ExamAppService, IUserExamAdminAppService + UserExamManager userExamManager, + IDataFilter softDeleteFilter) : ExamAppService, IUserExamAdminAppService { protected IQuestionRepository QuestionRepository { get; } = questionRepository; public IIdentityUserRepository UserRepository { get; } = userRepository; public IExamRepository ExamRepository { get; } = examRepository; protected QuestionManager QuestionManager { get; } = questionManager; public UserExamManager UserExamManager { get; } = userExamManager; + public IDataFilter SoftDeleteFilter { get; } = softDeleteFilter; protected IUserExamRepository UserExamRepository { get; } = userExamRepository; public async Task> GetListAsync(GetUserExamsInput input) @@ -46,7 +49,20 @@ public async Task GetAsync(Guid id) Examination examination = await ExamRepository.GetAsync(userExam.ExamId); IdentityUser user = await UserRepository.GetAsync(userExam.UserId); List questionIds = userExam.Sections.SelectMany(s => s.Questions).Select(q => q.QuestionId).ToList(); - List questions = await QuestionRepository.GetByIdsAsync(questionIds); + + List questions; + if (userExam.IsSubmitted()) + { + using (SoftDeleteFilter.Disable()) + { + questions = await QuestionRepository.GetByIdsAsync(questionIds); + } + } + else + { + questions = await QuestionRepository.GetByIdsAsync(questionIds); + } + UserExamDetailDto dto = ObjectMapper.Map(userExam); dto.ReviewMode = examination.ReviewMode.Value; dto.ExamStatus = examination.Status.Value; diff --git a/aspnet-core/src/SuperAbp.Exam.Admin.Application/KnowledgePoints/KnowledgePointAdminAppService.cs b/aspnet-core/src/SuperAbp.Exam.Admin.Application/KnowledgePoints/KnowledgePointAdminAppService.cs index 4e53c80d..bc1d382c 100644 --- a/aspnet-core/src/SuperAbp.Exam.Admin.Application/KnowledgePoints/KnowledgePointAdminAppService.cs +++ b/aspnet-core/src/SuperAbp.Exam.Admin.Application/KnowledgePoints/KnowledgePointAdminAppService.cs @@ -11,11 +11,15 @@ namespace SuperAbp.Exam.Admin.KnowledgePoints; [Authorize(ExamPermissions.KnowledgePoints.Default)] -public class KnowledgePointAdminAppService(IKnowledgePointRepository knowledgePointRepository) : ExamAppService, IKnowledgePointAdminAppService +public class KnowledgePointAdminAppService(IKnowledgePointRepository knowledgePointRepository, + KnowledgePointManager knowledgePointManager) : ExamAppService, IKnowledgePointAdminAppService { + public IKnowledgePointRepository KnowledgePointRepository { get; } = knowledgePointRepository; + public KnowledgePointManager KnowledgePointManager { get; } = knowledgePointManager; + public async Task> GetAllAsync(GetKnowledgePointsInput input) { - List knowledgePoints = await knowledgePointRepository.GetListAsync(input.Name); + List knowledgePoints = await KnowledgePointRepository.GetListAsync(input.Name); List dtos = BuildTree(knowledgePoints); return new ListResultDto(dtos); } @@ -46,7 +50,7 @@ private List BuildTreeNodes(Guid parentId, Dictionary GetEditorAsync(Guid id) { - KnowledgePoint category = await knowledgePointRepository.GetAsync(id); + KnowledgePoint category = await KnowledgePointRepository.GetAsync(id); return ObjectMapper.Map(category); } @@ -54,22 +58,23 @@ public async Task GetEditorAsync(Guid id) public async Task CreateAsync(KnowledgePointCreateDto input) { KnowledgePoint category = new(GuidGenerator.Create(), input.Name, input.ParentId); - await knowledgePointRepository.InsertAsync(category); + await KnowledgePointRepository.InsertAsync(category); return category.Id; } [Authorize(ExamPermissions.KnowledgePoints.Update)] public async Task UpdateAsync(Guid id, KnowledgePointUpdateDto input) { - KnowledgePoint category = await knowledgePointRepository.GetAsync(id); + KnowledgePoint category = await KnowledgePointRepository.GetAsync(id); category.Name = input.Name; category.ParentId = input.ParentId; - await knowledgePointRepository.UpdateAsync(category); + await KnowledgePointRepository.UpdateAsync(category); } [Authorize(ExamPermissions.KnowledgePoints.Delete)] public async Task DeleteAsync(Guid id) { - await knowledgePointRepository.DeleteAsync(id); + KnowledgePoint knowledgePoint = await KnowledgePointRepository.GetAsync(id); + await KnowledgePointManager.DeleteAsync(knowledgePoint); } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Admin.Application/PaperManagement/ExamManagementAdminApplicationAutoMapperProfile.cs b/aspnet-core/src/SuperAbp.Exam.Admin.Application/PaperManagement/ExamManagementAdminApplicationAutoMapperProfile.cs index f294d399..f244270a 100644 --- a/aspnet-core/src/SuperAbp.Exam.Admin.Application/PaperManagement/ExamManagementAdminApplicationAutoMapperProfile.cs +++ b/aspnet-core/src/SuperAbp.Exam.Admin.Application/PaperManagement/ExamManagementAdminApplicationAutoMapperProfile.cs @@ -2,9 +2,7 @@ using SuperAbp.Exam.Admin.PaperManagement.PaperQuestionRules; using SuperAbp.Exam.Admin.PaperManagement.Papers; using SuperAbp.Exam.PaperManagement.PaperQuestionRules; -using SuperAbp.Exam.PaperManagement.PaperQuestions; using SuperAbp.Exam.PaperManagement.Papers; -using SuperAbp.Exam.PaperManagement.PaperSections; using System.Linq; using static SuperAbp.Exam.Admin.PaperManagement.Papers.PaperCreateOrUpdateDtoBase; using static SuperAbp.Exam.Admin.PaperManagement.Papers.PaperCreateOrUpdateDtoBase.PaperSectionDto; @@ -42,7 +40,6 @@ public ExamManagementAdminApplicationAutoMapperProfile() CreateMap(); CreateMap(); - CreateMap(); CreateMap(); CreateMap(); diff --git a/aspnet-core/src/SuperAbp.Exam.Admin.Application/PaperManagement/Papers/PaperAdminAppService.cs b/aspnet-core/src/SuperAbp.Exam.Admin.Application/PaperManagement/Papers/PaperAdminAppService.cs index f92433f7..ceec7c63 100644 --- a/aspnet-core/src/SuperAbp.Exam.Admin.Application/PaperManagement/Papers/PaperAdminAppService.cs +++ b/aspnet-core/src/SuperAbp.Exam.Admin.Application/PaperManagement/Papers/PaperAdminAppService.cs @@ -1,7 +1,5 @@ using Microsoft.AspNetCore.Authorization; -using SuperAbp.Exam.PaperManagement.PaperQuestions; using SuperAbp.Exam.PaperManagement.Papers; -using SuperAbp.Exam.PaperManagement.PaperSections; using SuperAbp.Exam.Permissions; using SuperAbp.Exam.QuestionManagement.Questions; using System; @@ -171,8 +169,8 @@ protected virtual void CreateOrUpdatePaperQuestion(Paper paper, PaperSectionDto[ [Authorize(ExamPermissions.Papers.Delete)] public virtual async Task DeleteAsync(Guid id) { - // TODO: 如何同时删除子实体? - await paperRepository.DeleteAsync(id); + Paper paper = await paperRepository.GetAsync(id); + await paperManager.DeleteAsync(paper); } /// diff --git a/aspnet-core/src/SuperAbp.Exam.Admin.Application/QuestionManagement/QuestionBanks/QuestionBankAdminAppService.cs b/aspnet-core/src/SuperAbp.Exam.Admin.Application/QuestionManagement/QuestionBanks/QuestionBankAdminAppService.cs index cee40d7e..3744f219 100644 --- a/aspnet-core/src/SuperAbp.Exam.Admin.Application/QuestionManagement/QuestionBanks/QuestionBankAdminAppService.cs +++ b/aspnet-core/src/SuperAbp.Exam.Admin.Application/QuestionManagement/QuestionBanks/QuestionBankAdminAppService.cs @@ -12,22 +12,28 @@ namespace SuperAbp.Exam.Admin.QuestionManagement.QuestionBanks [Authorize(ExamPermissions.QuestionBanks.Default)] public class QuestionBankAdminAppService( QuestionBankManager questionRepoManager, + QuestionBankManager questionBankManager, IQuestionBankRepository questionBankRepository, IQuestionRepository questionRepository) : ExamAppService, IQuestionBankAdminAppService { + protected QuestionBankManager QuestionRepoManager { get; } = questionRepoManager; + protected QuestionBankManager QuestionBankManager { get; } = questionBankManager; + protected IQuestionBankRepository QuestionBankRepository { get; } = questionBankRepository; + protected IQuestionRepository QuestionRepository { get; } = questionRepository; + public virtual async Task GetAsync(Guid id) { - QuestionBank entity = await questionBankRepository.GetAsync(id); + QuestionBank entity = await QuestionBankRepository.GetAsync(id); return ObjectMapper.Map(entity); } public virtual async Task> GetListAsync(GetQuestionBanksInput input) { - long totalCount = await questionBankRepository.GetCountAsync(input.Title); + long totalCount = await QuestionBankRepository.GetCountAsync(input.Title); - var entities = await questionBankRepository + var entities = await QuestionBankRepository .GetListAsync(input.Sorting ?? QuestionBankConsts.DefaultSorting, input.SkipCount, input.MaxResultCount, input.Title); @@ -35,10 +41,10 @@ public virtual async Task> GetListAsync(GetQ foreach (var item in entities) { var dto = ObjectMapper.Map(item); - dto.SingleCount = await questionRepository.GetCountAsync(questionBankIds: new List { item.Id }, questionType: QuestionType.SingleSelect); - dto.JudgeCount = await questionRepository.GetCountAsync(questionBankIds: new List { item.Id }, questionType: QuestionType.Judge); - dto.MultiCount = await questionRepository.GetCountAsync(questionBankIds: new List { item.Id }, questionType: QuestionType.MultiSelect); - dto.BlankCount = await questionRepository.GetCountAsync(questionBankIds: new List { item.Id }, questionType: QuestionType.FillInTheBlanks); + dto.SingleCount = await QuestionRepository.GetCountAsync(questionBankIds: new List { item.Id }, questionType: QuestionType.SingleSelect); + dto.JudgeCount = await QuestionRepository.GetCountAsync(questionBankIds: new List { item.Id }, questionType: QuestionType.Judge); + dto.MultiCount = await QuestionRepository.GetCountAsync(questionBankIds: new List { item.Id }, questionType: QuestionType.MultiSelect); + dto.BlankCount = await QuestionRepository.GetCountAsync(questionBankIds: new List { item.Id }, questionType: QuestionType.FillInTheBlanks); dtos.Add(dto); } return new PagedResultDto(totalCount, dtos); @@ -46,7 +52,7 @@ public virtual async Task> GetListAsync(GetQ public virtual async Task GetEditorAsync(Guid id) { - QuestionBank entity = await questionBankRepository.GetAsync(id); + QuestionBank entity = await QuestionBankRepository.GetAsync(id); return ObjectMapper.Map(entity); } @@ -54,41 +60,28 @@ public virtual async Task GetEditorAsync(Guid id [Authorize(ExamPermissions.QuestionBanks.Create)] public virtual async Task CreateAsync(QuestionBankCreateDto input) { - QuestionBank repository = await questionRepoManager.CreateAsync(input.Title); + QuestionBank repository = await QuestionRepoManager.CreateAsync(input.Title); repository.Remark = input.Remark; - repository = await questionBankRepository.InsertAsync(repository); + repository = await QuestionBankRepository.InsertAsync(repository); return ObjectMapper.Map(repository); } [Authorize(ExamPermissions.QuestionBanks.Update)] public virtual async Task UpdateAsync(Guid id, QuestionBankUpdateDto input) { - QuestionBank repository = await questionBankRepository.GetAsync(id); - await questionRepoManager.SetTitleAsync(repository, input.Title); + QuestionBank repository = await QuestionBankRepository.GetAsync(id); + await QuestionRepoManager.SetTitleAsync(repository, input.Title); repository.Remark = input.Remark; - repository = await questionBankRepository.UpdateAsync(repository); + repository = await QuestionBankRepository.UpdateAsync(repository); return ObjectMapper.Map(repository); } [Authorize(ExamPermissions.QuestionBanks.Delete)] public virtual async Task DeleteAsync(Guid id) { - await questionBankRepository.DeleteAsync(id); - } - - /// - /// 规范最大记录数 - /// - /// 参数 - /// - private async Task NormalizeMaxResultCountAsync(PagedAndSortedResultRequestDto input) - { - var maxPageSize = (await SettingProvider.GetOrNullAsync(QuestionBankSettings.MaxPageSize))?.To(); - if (maxPageSize.HasValue && input.MaxResultCount > maxPageSize.Value) - { - input.MaxResultCount = maxPageSize.Value; - } + QuestionBank questionBank = await QuestionBankRepository.GetAsync(id); + await QuestionBankManager.DeleteAsync(questionBank); } } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Admin.Application/QuestionManagement/Questions/QuestionAdminAppService.cs b/aspnet-core/src/SuperAbp.Exam.Admin.Application/QuestionManagement/Questions/QuestionAdminAppService.cs index e4a07112..76bee139 100644 --- a/aspnet-core/src/SuperAbp.Exam.Admin.Application/QuestionManagement/Questions/QuestionAdminAppService.cs +++ b/aspnet-core/src/SuperAbp.Exam.Admin.Application/QuestionManagement/Questions/QuestionAdminAppService.cs @@ -169,7 +169,8 @@ protected virtual void CreateOrUpdateAnswer(Question question, QuestionCreateOrU [Authorize(ExamPermissions.Questions.Delete)] public virtual async Task DeleteAsync(Guid id) { - await questionRepository.DeleteAsync(id); + Question question = await questionRepository.GetAsync(id); + await questionManager.DeleteAsync(question); } [Authorize(ExamPermissions.Questions.Delete)] diff --git a/aspnet-core/src/SuperAbp.Exam.Application/ExamManagement/UserExams/UserExamAppService.cs b/aspnet-core/src/SuperAbp.Exam.Application/ExamManagement/UserExams/UserExamAppService.cs index 5648f536..a0bf43b2 100644 --- a/aspnet-core/src/SuperAbp.Exam.Application/ExamManagement/UserExams/UserExamAppService.cs +++ b/aspnet-core/src/SuperAbp.Exam.Application/ExamManagement/UserExams/UserExamAppService.cs @@ -1,24 +1,26 @@ using Microsoft.AspNetCore.Authorization; using SuperAbp.Exam.ExamManagement.Exams; +using SuperAbp.Exam.ExamManagement.UserExamQuestions; +using SuperAbp.Exam.Jobs.UserExamCreateQuestion; +using SuperAbp.Exam.KnowledgePoints; +using SuperAbp.Exam.Mistakes; +using SuperAbp.Exam.MistakesReviews.Events; using SuperAbp.Exam.QuestionManagement.Questions; +using SuperAbp.Exam.QuestionManagement.Questions.QuestionOptions; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using SuperAbp.Exam.ExamManagement.UserExamQuestions; -using SuperAbp.Exam.Jobs.UserExamCreateQuestion; +using Volo.Abp; using Volo.Abp.Application.Dtos; -using Volo.Abp.Timing; -using Volo.Abp.Users; -using SuperAbp.Exam.KnowledgePoints; using Volo.Abp.BackgroundJobs; +using Volo.Abp.Data; using Volo.Abp.EventBus.Local; -using SuperAbp.Exam.MistakesReviews.Events; +using Volo.Abp.Timing; +using Volo.Abp.Users; using static SuperAbp.Exam.ExamManagement.UserExams.UserExamDetailDto; using static SuperAbp.Exam.ExamManagement.UserExams.UserExamDetailDto.SectionDto; using static SuperAbp.Exam.ExamManagement.UserExams.UserExamDetailDto.SectionDto.QuestionDto; -using SuperAbp.Exam.QuestionManagement.Questions.QuestionOptions; -using SuperAbp.Exam.Mistakes; namespace SuperAbp.Exam.ExamManagement.UserExams { @@ -32,12 +34,15 @@ public class UserExamAppService( QuestionManager questionManager, IMistakeRepository mistakesReviewRepository, IBackgroundJobManager backgroundJobManager, + IDataFilter softDeleteFilter, ILocalEventBus localEventBus) : ExamAppService, IUserExamAppService { protected IUserExamRepository UserExamRepository { get; } = userExamRepository; protected IExamRepository ExamRepository { get; } = examRepository; + protected IMistakeRepository MistakesReviewRepository { get; } = mistakesReviewRepository; protected IBackgroundJobManager BackgroundJobManager { get; } = backgroundJobManager; + protected IDataFilter SoftDeleteFilter { get; } = softDeleteFilter; public async Task GetUnfinishedAsync() { @@ -48,9 +53,21 @@ public class UserExamAppService( public virtual async Task GetAsync(Guid id) { UserExam userExam = await UserExamRepository.GetAsync(id); - Examination exam = await examRepository.GetAsync(userExam.ExamId); + Examination exam = await ExamRepository.GetAsync(userExam.ExamId); List questionIds = userExam.Sections.SelectMany(s => s.Questions).Select(q => q.QuestionId).ToList(); - List questions = await questionRepository.GetByIdsAsync(questionIds); + List questions; + if (userExam.IsSubmitted()) + { + using (SoftDeleteFilter.Disable()) + { + questions = await questionRepository.GetByIdsAsync(questionIds); + } + } + else + { + questions = await questionRepository.GetByIdsAsync(questionIds); + } + UserExamDetailDto dto = ObjectMapper.Map(userExam); dto.ExamName = exam.Name; dto.AnswerMode = exam.AnswerMode; @@ -61,6 +78,7 @@ public virtual async Task GetAsync(Guid id) { endTime = exam.EndTime.Value; } + dto.EndTime = endTime; } else diff --git a/aspnet-core/src/SuperAbp.Exam.Application/Favorites/FavoriteAppService.cs b/aspnet-core/src/SuperAbp.Exam.Application/Favorites/FavoriteAppService.cs index d198b7ab..29313ffa 100644 --- a/aspnet-core/src/SuperAbp.Exam.Application/Favorites/FavoriteAppService.cs +++ b/aspnet-core/src/SuperAbp.Exam.Application/Favorites/FavoriteAppService.cs @@ -40,7 +40,7 @@ public async Task CreateAsync(Guid questionId) return; } - Favorite favorite = new Favorite(GuidGenerator.Create(), questionId, CurrentUser.GetId(), Clock.Now); + Favorite favorite = new(GuidGenerator.Create(), questionId, CurrentUser.GetId(), Clock.Now); await favoriteRepository.InsertAsync(favorite); } diff --git a/aspnet-core/src/SuperAbp.Exam.Domain.Shared/ExamDomainErrorCodes.cs b/aspnet-core/src/SuperAbp.Exam.Domain.Shared/ExamDomainErrorCodes.cs index be286c1a..b1844be5 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain.Shared/ExamDomainErrorCodes.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain.Shared/ExamDomainErrorCodes.cs @@ -23,6 +23,7 @@ public static class Papers { public const string NameAlreadyExists = "Exam:Paper:0001"; public const string SectionOrderAlreadyExist = "Exam:Paper:0002"; + public const string PaperUsedByExam = "Exam:Paper:0003"; } public static class PaperSections diff --git a/aspnet-core/src/SuperAbp.Exam.Domain.Shared/Localization/Exam/zh-Hans.json b/aspnet-core/src/SuperAbp.Exam.Domain.Shared/Localization/Exam/zh-Hans.json index 7a5b864c..15ca2c19 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain.Shared/Localization/Exam/zh-Hans.json +++ b/aspnet-core/src/SuperAbp.Exam.Domain.Shared/Localization/Exam/zh-Hans.json @@ -184,6 +184,8 @@ "Exam:QuestionBank:0001": "问题类别已存在", "Exam:QuestionAnswer:0001": "答案已存在", "Exam:Paper:0001": "试卷已存在", + "Exam:Paper:0002": "排序已存在", + "Exam:Paper:0003": "存在关联的考试", "Exam:UserExams:0001": "用户存在未完成的考试", "Exam:UserExams:0002": "用户考试未完成", "Exam:UserExams:0003": "用户考试状态无效", diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/Exams/IExamRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/Exams/IExamRepository.cs index 39ad5fe6..bc730e1c 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/Exams/IExamRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/Exams/IExamRepository.cs @@ -1,4 +1,6 @@ using System; +using System.Threading; +using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; namespace SuperAbp.Exam.ExamManagement.Exams @@ -8,5 +10,6 @@ namespace SuperAbp.Exam.ExamManagement.Exams /// public interface IExamRepository : IRepository { + Task ExistsByPaperIdAsync(Guid paperId, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/IUserExamQuestionRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/IUserExamQuestionRepository.cs deleted file mode 100644 index bd756cb9..00000000 --- a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/IUserExamQuestionRepository.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Repositories; - -namespace SuperAbp.Exam.ExamManagement.UserExamQuestions -{ - /// - /// 用户考题 - /// - public interface IUserExamQuestionRepository : IRepository - { - } -} \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/UserExamQuestion.cs b/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/UserExamQuestion.cs index 2ffd1fa3..d8a03b93 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/UserExamQuestion.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/UserExamQuestion.cs @@ -1,11 +1,8 @@ using SuperAbp.Exam.ExamManagement.UserExamQuestionReviews; -using SuperAbp.Exam.ExamManagement.UserExams; -using SuperAbp.Exam.MistakesReviews.Events; using System; using System.Collections.Generic; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; -using static Volo.Abp.Identity.Settings.IdentitySettingNames; namespace SuperAbp.Exam.ExamManagement.UserExamQuestions; diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/UserExamQuestionWithDetails.cs b/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/UserExamQuestionWithDetails.cs deleted file mode 100644 index 6b339777..00000000 --- a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExamQuestions/UserExamQuestionWithDetails.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using SuperAbp.Exam.QuestionManagement.Questions; - -namespace SuperAbp.Exam.ExamManagement.UserExamQuestions; - -public class UserExamQuestionWithDetails -{ - public Guid Id { get; set; } - - /// - /// 正确 - /// - public bool? Right { get; set; } - - /// - /// 得分 - /// - public decimal? Score { get; set; } - - public Guid QuestionId { get; set; } - public required QuestionType QuestionType { get; set; } - - /// - /// 题干 - /// - public required string Question { get; set; } - - public string? QuestionReviewReason { get; set; } - - /// - /// 解析 - /// - public string? QuestionAnalysis { get; set; } - - public decimal QuestionScore { get; set; } - - public string? Answers { get; set; } - - public List QuestionOptions { get; set; } = []; - - public class Questionption - { - public Guid Id { get; set; } - - /// - /// 答案 - /// - public required string Content { get; set; } - - public bool Right { get; set; } - } -} \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExams/UserExamManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExams/UserExamManager.cs index ddc4549f..319d8ab4 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExams/UserExamManager.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/ExamManagement/UserExams/UserExamManager.cs @@ -1,8 +1,6 @@ using SuperAbp.Exam.ExamManagement.Exams; using SuperAbp.Exam.ExamManagement.UserExamQuestions; -using SuperAbp.Exam.PaperManagement.PaperQuestionRules; using SuperAbp.Exam.PaperManagement.Papers; -using SuperAbp.Exam.PaperManagement.PaperSections; using SuperAbp.Exam.QuestionManagement.Questions; using System; using System.Collections.Generic; @@ -18,11 +16,8 @@ public class UserExamManager( IExamRepository examRepository, IQuestionRepository questionRepository, IPaperRepository paperRepository, - IPaperQuestionRuleRepository paperQuestionRuleRepository, IUserExamRepository userExamRepository, - ILocalEventBus eventBus, - IUserExamQuestionRepository userExamQuestionRepository, - IPaperSectionRepository paperSectionRepository) + ILocalEventBus eventBus) : DomainService { public async Task CreateAsync(Guid examId, Guid userId) @@ -68,11 +63,10 @@ public async Task CreateQuestionsAsync(Guid userExamId) Examination exam = await examRepository.GetAsync(userExam.ExamId); Paper paper = await paperRepository.GetAsync(exam.PaperId); - List sections = await paperSectionRepository.GetListByPaperIdAsync(paper.Id); int sectionIndex = 0; - int totalSections = sections.Count; + int totalSections = paper.PaperSections.Count; - foreach (var section in sections) + foreach (var section in paper.PaperSections) { sectionIndex++; diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/KnowledgePoints/KnowledgePointManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/KnowledgePoints/KnowledgePointManager.cs new file mode 100644 index 00000000..f2033744 --- /dev/null +++ b/aspnet-core/src/SuperAbp.Exam.Domain/KnowledgePoints/KnowledgePointManager.cs @@ -0,0 +1,18 @@ +using SuperAbp.Exam.QuestionManagement.QuestionKnowledgePoints; +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; + +namespace SuperAbp.Exam.KnowledgePoints; + +public class KnowledgePointManager(IKnowledgePointRepository knowledgePointRepository, + IQuestionKnowledgePointRepository questionKnowledgePointRepository) : DomainService +{ + public IKnowledgePointRepository KnowledgePointRepository { get; } = knowledgePointRepository; + public IQuestionKnowledgePointRepository QuestionKnowledgePointRepository { get; } = questionKnowledgePointRepository; + + public virtual async Task DeleteAsync(KnowledgePoint knowledgePoint) + { + await QuestionKnowledgePointRepository.DeleteByKnowledgePointIdAsync(knowledgePoint.Id); + await KnowledgePointRepository.DeleteAsync(knowledgePoint); + } +} \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/Mistakes/IMistakeRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/Mistakes/IMistakeRepository.cs index 657c3f7e..366d1aca 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/Mistakes/IMistakeRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/Mistakes/IMistakeRepository.cs @@ -13,4 +13,11 @@ Task> GetListAsync(string? sorting = null, int skipCoun Guid? userId = null, string? questionContent = null, QuestionType? questionType = null, CancellationToken cancellationToken = default); Task CountAsync(Guid? userId, string? questionContent = null, QuestionType? questionType = null, CancellationToken cancellationToken = default); + + /// + /// 删除 + /// + /// 题目Id + /// + Task DeleteByQuestionIdAsync(Guid questionId); } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/IPaperQuestionRuleRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/IPaperQuestionRuleRepository.cs deleted file mode 100644 index e2ad6a2b..00000000 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/IPaperQuestionRuleRepository.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Repositories; - -namespace SuperAbp.Exam.PaperManagement.PaperQuestionRules -{ - /// - /// 考试题库 - /// - public interface IPaperQuestionRuleRepository : IRepository - { - } -} \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/PaperQuestionRuleWithDetails.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/PaperQuestionRuleWithDetails.cs deleted file mode 100644 index 333aa867..00000000 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/PaperQuestionRuleWithDetails.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; - -namespace SuperAbp.Exam.PaperManagement.PaperQuestionRules; - -public class PaperQuestionRuleWithDetails -{ - public Guid Id { get; set; } - - public required string QuestionBank { get; set; } - - /// - /// 题库Id - /// - public Guid QuestionBankId { get; set; } - - /// - /// 单选数量 - /// - public int? SingleCount { get; set; } - - /// - /// 单选分数 - /// - public decimal? SingleScore { get; set; } - - /// - /// 多选数量 - /// - public int? MultiCount { get; set; } - - /// - /// 多选分数 - /// - public decimal? MultiScore { get; set; } - - /// - /// 判断数量 - /// - public int? JudgeCount { get; set; } - - /// - /// 判断分数 - /// - public decimal? JudgeScore { get; set; } - - /// - /// 填空数量 - /// - public int? BlankCount { get; set; } - - /// - /// 填空分数 - /// - public decimal? BlankScore { get; set; } - - public DateTime CreationTime { get; set; } -} \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestions/IPaperQuestionRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestions/IPaperQuestionRepository.cs deleted file mode 100644 index d30a8728..00000000 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestions/IPaperQuestionRepository.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Repositories; - -namespace SuperAbp.Exam.PaperManagement.PaperQuestions -{ - /// - /// 试卷题目 - /// - public interface IPaperQuestionRepository : IRepository - { - Task> GetListByPaperSectionIdAsync(Guid paperSectionId, CancellationToken cancellationToken = default); - - Task> GetListByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default); - - Task GetByPaperSectionIdAndQuestionIdAsync(Guid paperSectionId, Guid questionId, CancellationToken cancellationToken = default); - } -} diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperSections/IPaperSectionRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperSections/IPaperSectionRepository.cs deleted file mode 100644 index 756f5652..00000000 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperSections/IPaperSectionRepository.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Repositories; - -namespace SuperAbp.Exam.PaperManagement.PaperSections -{ - /// - /// 试卷大题 - /// - public interface IPaperSectionRepository : IRepository - { - Task> GetListByPaperIdAsync(Guid paperId, CancellationToken cancellationToken = default); - - Task GetByPaperIdAndOrderAsync(Guid paperId, int order, CancellationToken cancellationToken = default); - } -} diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs index a2f4cc99..14c4c4bd 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs @@ -6,9 +6,10 @@ namespace SuperAbp.Exam.PaperManagement.Papers; /// -/// 考试 +/// 试卷 /// public interface IPaperRepository : IRepository { - Task NameExistsAsync(string content, CancellationToken cancellationToken = default); + Task NameExistsAsync(string name, CancellationToken cancellationToken = default); + Task RemovePaperQuestionsByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs index fa7b4a61..30cec73b 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs @@ -1,5 +1,4 @@ using SuperAbp.Exam.PaperManagement.PaperQuestionRules; -using SuperAbp.Exam.PaperManagement.PaperSections; using SuperAbp.Exam.QuestionManagement.Questions; using System; using System.Collections.Generic; diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs index 58f43b45..ddd85c7d 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs @@ -1,11 +1,16 @@ -using System.Threading.Tasks; +using SuperAbp.Exam.ExamManagement.Exams; +using System; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Services; namespace SuperAbp.Exam.PaperManagement.Papers; -public class PaperManager(IPaperRepository paperRepository) : DomainService +public class PaperManager(IPaperRepository paperRepository, + IExamRepository examRepository) : DomainService { protected IPaperRepository PaperRepository { get; } = paperRepository; + protected IExamRepository ExamRepository { get; } = examRepository; public virtual async Task CreateAsync(PaperType paperType, string name, bool manualReview) { @@ -31,4 +36,14 @@ protected virtual async Task CheckNameAsync(string name) throw new PaperNameAlreadyExistException(name); } } + + public virtual async Task DeleteAsync(Paper paper) + { + if (await examRepository.ExistsByPaperIdAsync(paper.Id)) + { + throw new PaperUsedByExamException(); + } + paper.PaperSections.Clear(); + await PaperRepository.DeleteAsync(paper); + } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperNameAlreadyExistException.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperNameAlreadyExistException.cs index 76836a84..b217e492 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperNameAlreadyExistException.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperNameAlreadyExistException.cs @@ -1,5 +1,4 @@ -using SuperAbp.Exam.QuestionManagement.Questions; -using Volo.Abp; +using Volo.Abp; namespace SuperAbp.Exam.PaperManagement.Papers; diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestions/PaperQuestion.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperQuestion.cs similarity index 86% rename from aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestions/PaperQuestion.cs rename to aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperQuestion.cs index e0e2b490..fd25f81e 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestions/PaperQuestion.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperQuestion.cs @@ -1,11 +1,10 @@ -using SuperAbp.Exam.PaperManagement.PaperSections; -using System; +using System; using Volo.Abp; using Volo.Abp.Auditing; using Volo.Abp.Domain.Entities; using Volo.Abp.MultiTenancy; -namespace SuperAbp.Exam.PaperManagement.PaperQuestions; +namespace SuperAbp.Exam.PaperManagement.Papers; /// /// 试卷题目 diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/PaperQuestionRule.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperQuestionRule.cs similarity index 96% rename from aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/PaperQuestionRule.cs rename to aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperQuestionRule.cs index 4f5889ef..fa2060d9 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperQuestionRules/PaperQuestionRule.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperQuestionRule.cs @@ -1,4 +1,4 @@ -using SuperAbp.Exam.PaperManagement.PaperSections; +using SuperAbp.Exam.PaperManagement.Papers; using SuperAbp.Exam.QuestionManagement.Questions; using System; using Volo.Abp; diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperSections/PaperSection.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs similarity index 97% rename from aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperSections/PaperSection.cs rename to aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs index 35758bf6..f9f7225e 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/PaperSections/PaperSection.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs @@ -1,5 +1,4 @@ using SuperAbp.Exam.PaperManagement.PaperQuestionRules; -using SuperAbp.Exam.PaperManagement.PaperQuestions; using SuperAbp.Exam.QuestionManagement.Questions; using System; using System.Collections.Generic; @@ -12,7 +11,7 @@ using Volo.Abp.Domain.Entities; using Volo.Abp.MultiTenancy; -namespace SuperAbp.Exam.PaperManagement.PaperSections; +namespace SuperAbp.Exam.PaperManagement.Papers; /// /// 试卷大题 diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperUsedByExamException.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperUsedByExamException.cs new file mode 100644 index 00000000..8e667f56 --- /dev/null +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperUsedByExamException.cs @@ -0,0 +1,12 @@ +using System; +using Volo.Abp; + +namespace SuperAbp.Exam.PaperManagement.Papers; + +[Serializable] +public class PaperUsedByExamException : BusinessException +{ + public PaperUsedByExamException() : base(ExamDomainErrorCodes.Papers.PaperUsedByExam) + { + } +} \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/QuestionBanks/QuestionBankManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/QuestionBanks/QuestionBankManager.cs index bf854221..3d8483eb 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/QuestionBanks/QuestionBankManager.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/QuestionBanks/QuestionBankManager.cs @@ -1,11 +1,17 @@ -using System.Threading.Tasks; +using SuperAbp.Exam.QuestionManagement.Questions; +using System.Collections.Generic; +using System.Threading.Tasks; using Volo.Abp.Domain.Services; namespace SuperAbp.Exam.QuestionManagement.QuestionBanks; -public class QuestionBankManager(IQuestionBankRepository questionBankRepository) : DomainService +public class QuestionBankManager(IQuestionBankRepository questionBankRepository, + IQuestionRepository questionRepository, + QuestionManager questionManager) : DomainService { protected IQuestionBankRepository QuestionBankRepository { get; } = questionBankRepository; + protected IQuestionRepository QuestionRepository { get; } = questionRepository; + protected QuestionManager QuestionManager { get; } = questionManager; public virtual async Task CreateAsync(string title) { @@ -17,19 +23,19 @@ public virtual async Task CreateAsync(string title) /// /// 设置标题 /// - /// + /// 题库 /// 标题 /// 标题已存在 /// - public virtual async Task SetTitleAsync(QuestionBank repo, string title) + public virtual async Task SetTitleAsync(QuestionBank questionBank, string title) { - if (title == repo.Title) + if (title == questionBank.Title) { return; } await CheckTitleAsync(title); - repo.Title = title; + questionBank.Title = title; } protected virtual async Task CheckTitleAsync(string title) @@ -39,4 +45,14 @@ protected virtual async Task CheckTitleAsync(string title) throw new QuestionBankTitleAlreadyExistException(title); } } + + public virtual async Task DeleteAsync(QuestionBank questionBank) + { + List questions = await QuestionRepository.GetListAsync(q => q.QuestionBankId == questionBank.Id); + foreach (var question in questions) + { + await QuestionManager.DeleteAsync(question); + } + await QuestionBankRepository.DeleteAsync(questionBank); + } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/QuestionKnowledgePoints/IQuestionKnowledgePointRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/QuestionKnowledgePoints/IQuestionKnowledgePointRepository.cs index b5c39b82..85a48af3 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/QuestionKnowledgePoints/IQuestionKnowledgePointRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/QuestionKnowledgePoints/IQuestionKnowledgePointRepository.cs @@ -9,4 +9,18 @@ namespace SuperAbp.Exam.QuestionManagement.QuestionKnowledgePoints; public interface IQuestionKnowledgePointRepository : IRepository { Task> GetByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default); + + /// + /// 删除 + /// + /// 题目Id + /// + Task DeleteByQuestionIdAsync(Guid questionId); + + /// + /// 删除 + /// + /// 知识点Id + /// + Task DeleteByKnowledgePointIdAsync(Guid knowledgePointId); } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/IQuestionRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/IQuestionRepository.cs index 319c902b..8682644c 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/IQuestionRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/IQuestionRepository.cs @@ -94,4 +94,12 @@ Task> GetRandomListAsync( Task AnyAsync(Guid questionRepositoryId, Guid questionId, CancellationToken cancellationToken = default); Task ContentExistsAsync(string content, CancellationToken cancellationToken = default); + + /// + /// 删除 + /// + /// 题库Id + /// + /// + Task DeleteByQuestionBankIdAsync(Guid questionBankId, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionManager.cs index dca779f3..030d6575 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionManager.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionManager.cs @@ -2,28 +2,39 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using SuperAbp.Exam.Favorites; using SuperAbp.Exam.KnowledgePoints; +using SuperAbp.Exam.Mistakes; +using SuperAbp.Exam.PaperManagement.Papers; using SuperAbp.Exam.QuestionManagement.QuestionKnowledgePoints; using Volo.Abp.Domain.Services; namespace SuperAbp.Exam.QuestionManagement.Questions; -public class QuestionManager(IQuestionRepository questionRepository, IQuestionKnowledgePointRepository questionKnowledgePointRepository, IKnowledgePointRepository knowledgePointRepository) : DomainService +public class QuestionManager(IQuestionRepository questionRepository, + IQuestionKnowledgePointRepository questionKnowledgePointRepository, + IKnowledgePointRepository knowledgePointRepository, + IFavoriteRepository favoriteRepository, + IMistakeRepository mistakeRepository, + IPaperRepository paperRepository) : DomainService { protected IQuestionRepository QuestionRepository { get; } = questionRepository; protected IQuestionKnowledgePointRepository QuestionKnowledgePointRepository { get; } = questionKnowledgePointRepository; - public IKnowledgePointRepository KnowledgePointRepository { get; } = knowledgePointRepository; + protected IKnowledgePointRepository KnowledgePointRepository { get; } = knowledgePointRepository; + protected IFavoriteRepository FavoriteRepository { get; } = favoriteRepository; + protected IMistakeRepository MistakeRepository { get; } = mistakeRepository; + protected IPaperRepository PaperRepository { get; } = paperRepository; - public async Task> GetKnowledgePointIdsAsync(Guid questionId) + public virtual async Task> GetKnowledgePointIdsAsync(Guid questionId) { List points = await QuestionKnowledgePointRepository.GetByQuestionIdAsync(questionId); return points.Select(p => p.KnowledgePointId).ToList(); } - public async Task> GetKnowledgePointsAsync(Guid questionId) + public virtual async Task> GetKnowledgePointsAsync(Guid questionId) { return await KnowledgePointRepository.GetByQuestionIdAsync(questionId); } @@ -74,4 +85,17 @@ protected virtual async Task CheckContentAsync(string content) throw new QuestionContentAlreadyExistException(content); } } + + public virtual async Task DeleteAsync(Question question) + { + question.Options.Clear(); + await QuestionKnowledgePointRepository.DeleteByQuestionIdAsync(question.Id); + await FavoriteRepository.DeleteByQuestionIdAsync(question.Id); + await MistakeRepository.DeleteByQuestionIdAsync(question.Id); + + await PaperRepository.RemovePaperQuestionsByQuestionIdAsync(question.Id); + + await QuestionRepository.UpdateAsync(question); + await QuestionRepository.DeleteAsync(question); + } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionOptions/QuestionOption.cs b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionOptions/QuestionOption.cs index dd8da494..4fd26865 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionOptions/QuestionOption.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionOptions/QuestionOption.cs @@ -6,7 +6,7 @@ namespace SuperAbp.Exam.QuestionManagement.Questions.QuestionOptions; /// -/// 答案 +/// 选项 /// public class QuestionOption : FullAuditedEntity, IMultiTenant { diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamDbContext.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamDbContext.cs index 49b0e797..e373b625 100644 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamDbContext.cs +++ b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamDbContext.cs @@ -27,7 +27,6 @@ using SuperAbp.Exam.QuestionManagement.QuestionBanks; using SuperAbp.Exam.KnowledgePoints; using SuperAbp.Exam.QuestionManagement.QuestionKnowledgePoints; -using SuperAbp.Exam.PaperManagement.PaperQuestions; using SuperAbp.Exam.PaperManagement.PaperSections; using SuperAbp.Exam.QuestionManagement.Questions.QuestionOptions; diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamManagement/Exams/ExamRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamManagement/Exams/ExamRepository.cs index 33303324..2818344e 100644 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamManagement/Exams/ExamRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamManagement/Exams/ExamRepository.cs @@ -1,7 +1,10 @@ -using System; +using Microsoft.EntityFrameworkCore; +using SuperAbp.Exam.ExamManagement.Exams; +using System; +using System.Threading; +using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; -using SuperAbp.Exam.ExamManagement.Exams; namespace SuperAbp.Exam.EntityFrameworkCore.ExamManagement.Exams { @@ -11,6 +14,10 @@ namespace SuperAbp.Exam.EntityFrameworkCore.ExamManagement.Exams public class ExamRepository(IDbContextProvider dbContextProvider) : EfCoreRepository(dbContextProvider), IExamRepository { - // TODO:编写仓储代码 + public async Task ExistsByPaperIdAsync(Guid paperId, CancellationToken cancellationToken = default) + { + var dbSet = await GetDbSetAsync(); + return await dbSet.AnyAsync(q => q.PaperId == paperId, cancellationToken); + } } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamManagement/UserExamQuestions/UserExamQuestionRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamManagement/UserExamQuestions/UserExamQuestionRepository.cs deleted file mode 100644 index 5d379ee4..00000000 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/ExamManagement/UserExamQuestions/UserExamQuestionRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using Volo.Abp.Domain.Repositories.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore; -using SuperAbp.Exam.ExamManagement.UserExamQuestions; - -namespace SuperAbp.Exam.EntityFrameworkCore.ExamManagement.UserExamQuestions -{ - public class UserExamQuestionRepository(IDbContextProvider dbContextProvider) - : EfCoreRepository(dbContextProvider), IUserExamQuestionRepository - { - } -} \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/IExamDbContext.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/IExamDbContext.cs index dc2b6434..ee68973c 100644 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/IExamDbContext.cs +++ b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/IExamDbContext.cs @@ -7,9 +7,7 @@ using SuperAbp.Exam.KnowledgePoints; using SuperAbp.Exam.Mistakes; using SuperAbp.Exam.PaperManagement.PaperQuestionRules; -using SuperAbp.Exam.PaperManagement.PaperQuestions; using SuperAbp.Exam.PaperManagement.Papers; -using SuperAbp.Exam.PaperManagement.PaperSections; using SuperAbp.Exam.QuestionManagement.QuestionBanks; using SuperAbp.Exam.QuestionManagement.QuestionKnowledgePoints; using SuperAbp.Exam.QuestionManagement.Questions; diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/Mistakes/MistakeRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/Mistakes/MistakeRepository.cs index b3b2a858..7f7a7a27 100644 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/Mistakes/MistakeRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/Mistakes/MistakeRepository.cs @@ -52,4 +52,9 @@ join question in questionQueryable on mistake.QuestionId equals question.Id .WhereIf(!string.IsNullOrWhiteSpace(questionContent), f => f.QuestionContent.Contains(questionContent)) .WhereIf(questionType is not null, f => f.QuestionType == questionType); } + + public async Task DeleteByQuestionIdAsync(Guid questionId) + { + await DeleteAsync(m => m.QuestionId == questionId); + } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestionRules/PaperQuestionRuleRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestionRules/PaperQuestionRuleRepository.cs deleted file mode 100644 index 56df7798..00000000 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestionRules/PaperQuestionRuleRepository.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Dynamic.Core; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using SuperAbp.Exam.PaperManagement.PaperQuestionRules; -using Volo.Abp.Domain.Repositories.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore; - -namespace SuperAbp.Exam.EntityFrameworkCore.PaperManagement.PaperQuestionRules; - -/// -/// 考试题库 -/// -public class PaperQuestionRuleRepository(IDbContextProvider dbContextProvider) - : EfCoreRepository(dbContextProvider), IPaperQuestionRuleRepository -{ -} \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestions/PaperQuestionRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestions/PaperQuestionRepository.cs deleted file mode 100644 index 079aa76b..00000000 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestions/PaperQuestionRepository.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Dynamic.Core; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using SuperAbp.Exam.PaperManagement.PaperQuestions; -using Volo.Abp.Domain.Repositories.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore; - -namespace SuperAbp.Exam.EntityFrameworkCore.PaperManagement.PaperQuestions; - -public class PaperQuestionRepository(IDbContextProvider dbContextProvider) - : EfCoreRepository(dbContextProvider), IPaperQuestionRepository -{ - public async Task> GetListByPaperSectionIdAsync(Guid paperSectionId, CancellationToken cancellationToken = default) - { - return await (await GetQueryableAsync()) - .Where(p => p.PaperSectionId == paperSectionId) - .OrderBy(p => p.Order) - .ToListAsync(cancellationToken); - } - - public async Task> GetListByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default) - { - return await (await GetQueryableAsync()) - .Where(p => p.QuestionId == questionId) - .ToListAsync(cancellationToken); - } - - public async Task GetByPaperSectionIdAndQuestionIdAsync(Guid paperSectionId, Guid questionId, CancellationToken cancellationToken = default) - { - return await (await GetQueryableAsync()) - .FirstOrDefaultAsync(p => p.PaperSectionId == paperSectionId && p.QuestionId == questionId, cancellationToken); - } -} diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestions/PaperSectionRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestions/PaperSectionRepository.cs deleted file mode 100644 index 3de82276..00000000 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/PaperQuestions/PaperSectionRepository.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Dynamic.Core; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using SuperAbp.Exam.PaperManagement.PaperSections; -using Volo.Abp.Domain.Repositories.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore; - -namespace SuperAbp.Exam.EntityFrameworkCore.PaperManagement.PaperQuestions; - -public class PaperSectionRepository(IDbContextProvider dbContextProvider) - : EfCoreRepository(dbContextProvider), IPaperSectionRepository -{ - public async Task> GetListByPaperIdAsync(Guid paperId, CancellationToken cancellationToken = default) - { - return await (await GetQueryableAsync()) - .Where(p => p.PaperId == paperId) - .OrderBy(p => p.Order) - .ToListAsync(cancellationToken); - } - - public async Task GetByPaperIdAndOrderAsync(Guid paperId, int order, CancellationToken cancellationToken = default) - { - return await (await GetQueryableAsync()) - .FirstOrDefaultAsync(p => p.PaperId == paperId && p.Order == order, cancellationToken); - } -} diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs index 16fedb5a..f213e852 100644 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs @@ -9,7 +9,7 @@ namespace SuperAbp.Exam.EntityFrameworkCore.PaperManagement.Papers; /// -/// 考试 +/// 试卷 /// public class PaperRepository(IDbContextProvider dbContextProvider) : EfCoreRepository(dbContextProvider), IPaperRepository @@ -18,4 +18,14 @@ public async Task NameExistsAsync(string name, CancellationToken cancellat { return await (await GetQueryableAsync()).AnyAsync(e => e.Name == name, cancellationToken); } + + public async Task RemovePaperQuestionsByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(cancellationToken); + var paperQuestions = await dbContext.PaperQuestions + .Where(pq => pq.QuestionId == questionId) + .ToListAsync(cancellationToken); + + dbContext.PaperQuestions.RemoveRange(paperQuestions); + } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/QuestionManagement/QuestionKnowledgePoints/QuestionKnowledgePointRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/QuestionManagement/QuestionKnowledgePoints/QuestionKnowledgePointRepository.cs index d3da5b52..62d359f0 100644 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/QuestionManagement/QuestionKnowledgePoints/QuestionKnowledgePointRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/QuestionManagement/QuestionKnowledgePoints/QuestionKnowledgePointRepository.cs @@ -15,4 +15,14 @@ public async Task> GetByQuestionIdAsync(Guid questi { return await GetListAsync(qk => qk.QuestionId == questionId, cancellationToken: cancellationToken); } + + public async Task DeleteByQuestionIdAsync(Guid questionId) + { + await DeleteAsync(qk => qk.QuestionId == questionId); + } + + public async Task DeleteByKnowledgePointIdAsync(Guid knowledgePointId) + { + await DeleteAsync(qk => qk.KnowledgePointId == knowledgePointId); + } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/QuestionManagement/Questions/QuestionRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/QuestionManagement/Questions/QuestionRepository.cs index 2901e9bc..a6a809f1 100644 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/QuestionManagement/Questions/QuestionRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/QuestionManagement/Questions/QuestionRepository.cs @@ -174,4 +174,9 @@ public async Task ContentExistsAsync(string content, CancellationToken can { return await (await GetDbSetAsync()).AnyAsync(x => x.Content == content, cancellationToken); } + + public async Task DeleteByQuestionBankIdAsync(Guid questionBankId, CancellationToken cancellationToken = default) + { + await DeleteAsync(q => q.QuestionBankId == questionBankId); + } } \ No newline at end of file diff --git a/aspnet-core/test/SuperAbp.Exam.EntityFrameworkCore.Tests/EntityFrameworkCore/ExamDbContextInUnitTest.cs b/aspnet-core/test/SuperAbp.Exam.EntityFrameworkCore.Tests/EntityFrameworkCore/ExamDbContextInUnitTest.cs index d96d13e2..d428688d 100644 --- a/aspnet-core/test/SuperAbp.Exam.EntityFrameworkCore.Tests/EntityFrameworkCore/ExamDbContextInUnitTest.cs +++ b/aspnet-core/test/SuperAbp.Exam.EntityFrameworkCore.Tests/EntityFrameworkCore/ExamDbContextInUnitTest.cs @@ -8,9 +8,7 @@ using SuperAbp.Exam.KnowledgePoints; using SuperAbp.Exam.Mistakes; using SuperAbp.Exam.PaperManagement.PaperQuestionRules; -using SuperAbp.Exam.PaperManagement.PaperQuestions; using SuperAbp.Exam.PaperManagement.Papers; -using SuperAbp.Exam.PaperManagement.PaperSections; using SuperAbp.Exam.QuestionManagement.QuestionBanks; using SuperAbp.Exam.QuestionManagement.QuestionKnowledgePoints; using SuperAbp.Exam.QuestionManagement.QuestionOptions; From f0b7fef844038d9783aaea34437571508f008aac Mon Sep 17 00:00:00 2001 From: snow Date: Fri, 30 Jan 2026 16:34:05 +0800 Subject: [PATCH 2/6] delete --- .../Questions/QuestionDeletedEvent.cs | 12 ++++++++ .../Events/QuestionDeletedEventHandler.cs | 19 ++++++++++++ .../Events/QuestionDeletedEventHandler.cs | 19 ++++++++++++ .../Events/QuestionDeletedEventHandler.cs | 21 +++++++++++++ .../Papers/IPaperRepository.cs | 7 ++++- .../PaperManagement/Papers/Paper.cs | 18 +++++++++++ .../PaperManagement/Papers/PaperManager.cs | 30 +++++++++++++++++-- .../Questions/QuestionManager.cs | 23 +++++++------- .../PaperManagement/Papers/PaperRepository.cs | 17 +++++++---- 9 files changed, 145 insertions(+), 21 deletions(-) create mode 100644 aspnet-core/src/SuperAbp.Exam.Domain.Shared/QuestionManagement/Questions/QuestionDeletedEvent.cs create mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/Favorites/Events/QuestionDeletedEventHandler.cs create mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/Mistakes/Events/QuestionDeletedEventHandler.cs create mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Events/QuestionDeletedEventHandler.cs diff --git a/aspnet-core/src/SuperAbp.Exam.Domain.Shared/QuestionManagement/Questions/QuestionDeletedEvent.cs b/aspnet-core/src/SuperAbp.Exam.Domain.Shared/QuestionManagement/Questions/QuestionDeletedEvent.cs new file mode 100644 index 00000000..8952c343 --- /dev/null +++ b/aspnet-core/src/SuperAbp.Exam.Domain.Shared/QuestionManagement/Questions/QuestionDeletedEvent.cs @@ -0,0 +1,12 @@ +using System; + +namespace SuperAbp.Exam.QuestionManagement.Questions; + +/// +/// 题目已删除事件 +/// +public class QuestionDeletedEvent +{ + public Guid QuestionId { get; set; } + public Guid? TenantId { get; set; } +} diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/Favorites/Events/QuestionDeletedEventHandler.cs b/aspnet-core/src/SuperAbp.Exam.Domain/Favorites/Events/QuestionDeletedEventHandler.cs new file mode 100644 index 00000000..6c3c2697 --- /dev/null +++ b/aspnet-core/src/SuperAbp.Exam.Domain/Favorites/Events/QuestionDeletedEventHandler.cs @@ -0,0 +1,19 @@ +using SuperAbp.Exam.QuestionManagement.Questions; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; + +namespace SuperAbp.Exam.Favorites.Events; + +/// +/// 题目删除事件处理器 - 清理收藏关联数据 +/// +public class QuestionDeletedEventHandler( + IFavoriteRepository favoriteRepository) + : ILocalEventHandler, ITransientDependency +{ + public async Task HandleEventAsync(QuestionDeletedEvent eventData) + { + await favoriteRepository.DeleteByQuestionIdAsync(eventData.QuestionId); + } +} diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/Mistakes/Events/QuestionDeletedEventHandler.cs b/aspnet-core/src/SuperAbp.Exam.Domain/Mistakes/Events/QuestionDeletedEventHandler.cs new file mode 100644 index 00000000..9eaf56b2 --- /dev/null +++ b/aspnet-core/src/SuperAbp.Exam.Domain/Mistakes/Events/QuestionDeletedEventHandler.cs @@ -0,0 +1,19 @@ +using SuperAbp.Exam.QuestionManagement.Questions; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; + +namespace SuperAbp.Exam.Mistakes.Events; + +/// +/// 题目删除事件处理器 - 清理错题本关联数据 +/// +public class QuestionDeletedEventHandler( + IMistakeRepository mistakeRepository) + : ILocalEventHandler, ITransientDependency +{ + public async Task HandleEventAsync(QuestionDeletedEvent eventData) + { + await mistakeRepository.DeleteByQuestionIdAsync(eventData.QuestionId); + } +} diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Events/QuestionDeletedEventHandler.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Events/QuestionDeletedEventHandler.cs new file mode 100644 index 00000000..ba9c1f70 --- /dev/null +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Events/QuestionDeletedEventHandler.cs @@ -0,0 +1,21 @@ +using SuperAbp.Exam.PaperManagement.Papers; +using SuperAbp.Exam.QuestionManagement.Questions; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; + +namespace SuperAbp.Exam.PaperManagement.Events; + +/// +/// 题目删除事件处理器 - 清理试卷关联数据 +/// +public class QuestionDeletedEventHandler( + PaperManager paperManager) + : ILocalEventHandler, ITransientDependency +{ + public async Task HandleEventAsync(QuestionDeletedEvent eventData) + { + // 通过 Manager 的方法处理,确保聚合根的完整性 + await paperManager.RemoveQuestionFromAllPapersAsync(eventData.QuestionId, eventData.TenantId); + } +} diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs index 14c4c4bd..d83c7097 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; @@ -11,5 +12,9 @@ namespace SuperAbp.Exam.PaperManagement.Papers; public interface IPaperRepository : IRepository { Task NameExistsAsync(string name, CancellationToken cancellationToken = default); - Task RemovePaperQuestionsByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default); + + /// + /// 获取包含指定题目的试卷列表 + /// + Task> GetPapersByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs index 30cec73b..3590c2df 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs @@ -122,6 +122,24 @@ public Paper RemoveQuestion(Guid sectionId, Guid questionId) return this; } + public Paper RemoveQuestionByQuestionId(Guid questionId) + { + foreach (var section in PaperSections) + { + var questionsToRemove = section.PaperQuestions + .Where(pq => pq.QuestionId == questionId) + .ToList(); + + foreach (var question in questionsToRemove) + { + section.PaperQuestions.Remove(question); + } + } + + RecalculateTotals(); + return this; + } + public Paper AddRule(Guid sectionId, Guid ruleId, Guid questionBankId, QuestionType questionType, int count, decimal score, Guid? knowledgePointId = null) { PaperSection section = GetSection(sectionId); diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs index ddd85c7d..937fb347 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs @@ -1,5 +1,7 @@ using SuperAbp.Exam.ExamManagement.Exams; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Services; @@ -9,8 +11,8 @@ namespace SuperAbp.Exam.PaperManagement.Papers; public class PaperManager(IPaperRepository paperRepository, IExamRepository examRepository) : DomainService { - protected IPaperRepository PaperRepository { get; } = paperRepository; - protected IExamRepository ExamRepository { get; } = examRepository; + protected IPaperRepository PaperRepository => paperRepository; + protected IExamRepository ExamRepository => examRepository; public virtual async Task CreateAsync(PaperType paperType, string name, bool manualReview) { @@ -46,4 +48,28 @@ public virtual async Task DeleteAsync(Paper paper) paper.PaperSections.Clear(); await PaperRepository.DeleteAsync(paper); } + + /// + /// 移除题目在所有试卷中的引用 + /// 用于题目删除时的清理工作,通过聚合根的方法确保数据一致性 + /// + public virtual async Task RemoveQuestionFromAllPapersAsync(Guid questionId, Guid? tenantId = null) + { + // 获取所有包含该题目的试卷 + var papers = await PaperRepository.GetPapersByQuestionIdAsync(questionId); + + if (papers.Count == 0) + { + return; + } + + // 批量处理:通过聚合根的方法移除题目引用,确保统计数据正确更新 + foreach (var paper in papers) + { + paper.RemoveQuestionByQuestionId(questionId); + } + + // 批量更新,提高性能 + await PaperRepository.UpdateManyAsync(papers); + } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionManager.cs index 030d6575..85f79ee9 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionManager.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/QuestionManagement/Questions/QuestionManager.cs @@ -2,21 +2,18 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using SuperAbp.Exam.Favorites; using SuperAbp.Exam.KnowledgePoints; -using SuperAbp.Exam.Mistakes; -using SuperAbp.Exam.PaperManagement.Papers; using SuperAbp.Exam.QuestionManagement.QuestionKnowledgePoints; using Volo.Abp.Domain.Services; +using Volo.Abp.EventBus.Local; namespace SuperAbp.Exam.QuestionManagement.Questions; -public class QuestionManager(IQuestionRepository questionRepository, +public class QuestionManager( + IQuestionRepository questionRepository, IQuestionKnowledgePointRepository questionKnowledgePointRepository, IKnowledgePointRepository knowledgePointRepository, - IFavoriteRepository favoriteRepository, - IMistakeRepository mistakeRepository, - IPaperRepository paperRepository) : DomainService + ILocalEventBus localEventBus) : DomainService { protected IQuestionRepository QuestionRepository { get; } = questionRepository; @@ -24,9 +21,7 @@ public class QuestionManager(IQuestionRepository questionRepository, questionKnowledgePointRepository; protected IKnowledgePointRepository KnowledgePointRepository { get; } = knowledgePointRepository; - protected IFavoriteRepository FavoriteRepository { get; } = favoriteRepository; - protected IMistakeRepository MistakeRepository { get; } = mistakeRepository; - protected IPaperRepository PaperRepository { get; } = paperRepository; + protected ILocalEventBus LocalEventBus { get; } = localEventBus; public virtual async Task> GetKnowledgePointIdsAsync(Guid questionId) { @@ -90,10 +85,12 @@ public virtual async Task DeleteAsync(Question question) { question.Options.Clear(); await QuestionKnowledgePointRepository.DeleteByQuestionIdAsync(question.Id); - await FavoriteRepository.DeleteByQuestionIdAsync(question.Id); - await MistakeRepository.DeleteByQuestionIdAsync(question.Id); - await PaperRepository.RemovePaperQuestionsByQuestionIdAsync(question.Id); + await LocalEventBus.PublishAsync(new QuestionDeletedEvent + { + QuestionId = question.Id, + TenantId = question.TenantId + }); await QuestionRepository.UpdateAsync(question); await QuestionRepository.DeleteAsync(question); diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs index f213e852..ce468110 100644 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; @@ -19,13 +21,18 @@ public async Task NameExistsAsync(string name, CancellationToken cancellat return await (await GetQueryableAsync()).AnyAsync(e => e.Name == name, cancellationToken); } - public async Task RemovePaperQuestionsByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default) + public async Task> GetPapersByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default) { - var dbContext = await GetDbContextAsync(cancellationToken); - var paperQuestions = await dbContext.PaperQuestions - .Where(pq => pq.QuestionId == questionId) + var dbContext = await GetDbContextAsync(); + + var papers = await dbContext.Papers + .Where(p => p.PaperSections + .Any(s => s.PaperQuestions + .Any(pq => pq.QuestionId == questionId))) + .Include(p => p.PaperSections) + .ThenInclude(s => s.PaperQuestions) .ToListAsync(cancellationToken); - dbContext.PaperQuestions.RemoveRange(paperQuestions); + return papers; } } \ No newline at end of file From d5ec1152fc2e7e38875a7d1c2408ac14ae18b055 Mon Sep 17 00:00:00 2001 From: snow Date: Fri, 30 Jan 2026 17:18:27 +0800 Subject: [PATCH 3/6] knowledge delete --- .../KnowledgePointDeletedEvent.cs | 12 ++++++++++ .../KnowledgePoints/KnowledgePointManager.cs | 18 +++++++++++---- .../KnowledgePointDeletedEventHandler.cs | 22 +++++++++++++++++++ .../Papers/IPaperRepository.cs | 5 +++++ .../PaperManagement/Papers/Paper.cs | 14 ++++++++++++ .../PaperManagement/Papers/PaperManager.cs | 21 ++++++++++++++++++ .../PaperManagement/Papers/PaperSection.cs | 17 ++++++++++++++ .../PaperManagement/Papers/PaperRepository.cs | 15 +++++++++++++ 8 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 aspnet-core/src/SuperAbp.Exam.Domain.Shared/KnowledgePoints/KnowledgePointDeletedEvent.cs create mode 100644 aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Events/KnowledgePointDeletedEventHandler.cs diff --git a/aspnet-core/src/SuperAbp.Exam.Domain.Shared/KnowledgePoints/KnowledgePointDeletedEvent.cs b/aspnet-core/src/SuperAbp.Exam.Domain.Shared/KnowledgePoints/KnowledgePointDeletedEvent.cs new file mode 100644 index 00000000..c8076f10 --- /dev/null +++ b/aspnet-core/src/SuperAbp.Exam.Domain.Shared/KnowledgePoints/KnowledgePointDeletedEvent.cs @@ -0,0 +1,12 @@ +using System; + +namespace SuperAbp.Exam.KnowledgePoints; + +/// +/// 知识点已删除事件 +/// +public class KnowledgePointDeletedEvent +{ + public Guid KnowledgePointId { get; set; } + public Guid? TenantId { get; set; } +} diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/KnowledgePoints/KnowledgePointManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/KnowledgePoints/KnowledgePointManager.cs index f2033744..54280c39 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/KnowledgePoints/KnowledgePointManager.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/KnowledgePoints/KnowledgePointManager.cs @@ -1,18 +1,28 @@ using SuperAbp.Exam.QuestionManagement.QuestionKnowledgePoints; using System.Threading.Tasks; using Volo.Abp.Domain.Services; +using Volo.Abp.EventBus.Local; namespace SuperAbp.Exam.KnowledgePoints; -public class KnowledgePointManager(IKnowledgePointRepository knowledgePointRepository, - IQuestionKnowledgePointRepository questionKnowledgePointRepository) : DomainService +public class KnowledgePointManager( + IKnowledgePointRepository knowledgePointRepository, + IQuestionKnowledgePointRepository questionKnowledgePointRepository, + ILocalEventBus localEventBus) : DomainService { - public IKnowledgePointRepository KnowledgePointRepository { get; } = knowledgePointRepository; - public IQuestionKnowledgePointRepository QuestionKnowledgePointRepository { get; } = questionKnowledgePointRepository; + protected IKnowledgePointRepository KnowledgePointRepository => knowledgePointRepository; + protected IQuestionKnowledgePointRepository QuestionKnowledgePointRepository => questionKnowledgePointRepository; public virtual async Task DeleteAsync(KnowledgePoint knowledgePoint) { await QuestionKnowledgePointRepository.DeleteByKnowledgePointIdAsync(knowledgePoint.Id); + + await localEventBus.PublishAsync(new KnowledgePointDeletedEvent + { + KnowledgePointId = knowledgePoint.Id, + TenantId = knowledgePoint.TenantId + }); + await KnowledgePointRepository.DeleteAsync(knowledgePoint); } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Events/KnowledgePointDeletedEventHandler.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Events/KnowledgePointDeletedEventHandler.cs new file mode 100644 index 00000000..59cc1f9d --- /dev/null +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Events/KnowledgePointDeletedEventHandler.cs @@ -0,0 +1,22 @@ +using SuperAbp.Exam.KnowledgePoints; +using SuperAbp.Exam.PaperManagement.Papers; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; + +namespace SuperAbp.Exam.PaperManagement.Events; + +/// +/// 知识点删除事件处理器 +/// +public class KnowledgePointDeletedEventHandler( + PaperManager paperManager) + : ILocalEventHandler, ITransientDependency +{ + public async Task HandleEventAsync(KnowledgePointDeletedEvent eventData) + { + await paperManager.RemoveKnowledgePointFromAllPapersAsync( + eventData.KnowledgePointId, + eventData.TenantId); + } +} \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs index d83c7097..a2a49383 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/IPaperRepository.cs @@ -17,4 +17,9 @@ public interface IPaperRepository : IRepository /// 获取包含指定题目的试卷列表 /// Task> GetPapersByQuestionIdAsync(Guid questionId, CancellationToken cancellationToken = default); + + /// + /// 获取包含指定知识点的试卷列表 + /// + Task> GetPapersByKnowledgePointIdAsync(Guid knowledgePointId, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs index 3590c2df..d7608dc9 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs @@ -181,6 +181,20 @@ private PaperSection GetSection(Guid sectionId) ?? throw new EntityNotFoundException(typeof(PaperSection), sectionId); } + /// + /// 根据知识点ID移除相关的抽题规则 + /// 用于知识点删除时的清理工作 + /// + public Paper RemoveRulesByKnowledgePointId(Guid knowledgePointId) + { + foreach (var section in PaperSections) + { + section.RemoveRulesByKnowledgePointId(knowledgePointId); + } + RecalculateTotals(); + return this; + } + private void RecalculateTotals() { Score = PaperSections.Sum(s => s.TotalScore); diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs index 937fb347..6faaa274 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs @@ -72,4 +72,25 @@ public virtual async Task RemoveQuestionFromAllPapersAsync(Guid questionId, Guid // 批量更新,提高性能 await PaperRepository.UpdateManyAsync(papers); } + + /// + /// 移除知识点在所有试卷规则中的引用 + /// 用于知识点删除时的清理工作,通过聚合根的方法确保数据一致性 + /// + public virtual async Task RemoveKnowledgePointFromAllPapersAsync(Guid knowledgePointId, Guid? tenantId = null) + { + var papers = await PaperRepository.GetPapersByKnowledgePointIdAsync(knowledgePointId); + + if (papers.Count == 0) + { + return; + } + + foreach (var paper in papers) + { + paper.RemoveRulesByKnowledgePointId(knowledgePointId); + } + + await PaperRepository.UpdateManyAsync(papers); + } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs index f9f7225e..f7f58376 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs @@ -145,6 +145,23 @@ public void RemoveRule(Guid reuleId) RecalculateTotals(); } + /// + /// 根据知识点ID移除相关的抽题规则 + /// 用于知识点删除时的清理工作 + /// + public void RemoveRulesByKnowledgePointId(Guid knowledgePointId) + { + var rulesToRemove = PaperQuestionRules + .Where(r => r.KnowledgePointId == knowledgePointId) + .ToList(); + + foreach (var rule in rulesToRemove) + { + PaperQuestionRules.Remove(rule); + } + RecalculateTotals(); + } + private PaperQuestionRule GetPaperQuestionRule(Guid ruleId) { PaperQuestionRule? rule = PaperQuestionRules.SingleOrDefault(q => q.Id == ruleId); diff --git a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs index ce468110..ffcdd9b5 100644 --- a/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs +++ b/aspnet-core/src/SuperAbp.Exam.EntityFrameworkCore/EntityFrameworkCore/PaperManagement/Papers/PaperRepository.cs @@ -35,4 +35,19 @@ public async Task> GetPapersByQuestionIdAsync(Guid questionId, Cance return papers; } + + public async Task> GetPapersByKnowledgePointIdAsync(Guid knowledgePointId, CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + + var papers = await dbContext.Papers + .Where(p => p.PaperSections + .Any(s => s.PaperQuestionRules + .Any(r => r.KnowledgePointId == knowledgePointId))) + .Include(p => p.PaperSections) + .ThenInclude(s => s.PaperQuestionRules) + .ToListAsync(cancellationToken); + + return papers; + } } \ No newline at end of file From 98fecfef04750b5b818e126e3e00a357388e707b Mon Sep 17 00:00:00 2001 From: snow Date: Mon, 2 Feb 2026 14:16:53 +0800 Subject: [PATCH 4/6] fix bugs --- .../paper-management/paper/edit/paper-random.component.ts | 3 ++- .../routes/sys/knowledge-point/knowledge-point.component.ts | 4 +--- .../src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs | 4 ++-- .../PaperManagement/Papers/PaperManager.cs | 5 ----- .../PaperManagement/Papers/PaperSection.cs | 4 ++-- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/angular-admin/src/app/routes/paper-management/paper/edit/paper-random.component.ts b/angular-admin/src/app/routes/paper-management/paper/edit/paper-random.component.ts index 8df819b0..6d1eb1b6 100644 --- a/angular-admin/src/app/routes/paper-management/paper/edit/paper-random.component.ts +++ b/angular-admin/src/app/routes/paper-management/paper/edit/paper-random.component.ts @@ -244,6 +244,7 @@ export class PaperManagementPaperRandomEditComponent implements OnInit { this.currentSectionIndex = sectionIndex; const section = this.sections.at(sectionIndex); const rulesArray = section.get('paperQuestionRules') as FormArray; + const scoreEach = section.get('scoreEach')?.value || 0; // Prepare selected rules from FormArray for the modal const selectedRules = rulesArray.controls.map(control => ({ @@ -274,7 +275,7 @@ export class PaperManagementPaperRandomEditComponent implements OnInit { questionBankId: result.questionBankId, questionType: result.questionType, count: result.count, - score: 0, + score: scoreEach, questionBankName: '', questionTypeName: '', knowledgePointId: result.knowledgePointId diff --git a/angular-admin/src/app/routes/sys/knowledge-point/knowledge-point.component.ts b/angular-admin/src/app/routes/sys/knowledge-point/knowledge-point.component.ts index c09e1d90..43545d00 100644 --- a/angular-admin/src/app/routes/sys/knowledge-point/knowledge-point.component.ts +++ b/angular-admin/src/app/routes/sys/knowledge-point/knowledge-point.component.ts @@ -126,9 +126,7 @@ export class SysKnowledgePointComponent implements OnInit { } delete(record) { this.knowledgePointService.delete(record.id).subscribe(response => { - this.messageService.success(this.localizationService.instant('Exam::DeletedSuccessfully', record.name)); - // tslint:disable-next-line: no-non-null-assertion - this.knowledgePoints = this.knowledgePoints.filter(item => item.id !== record.id); + this.getList(); }); } } diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs index d7608dc9..d848c042 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/Paper.cs @@ -197,7 +197,7 @@ public Paper RemoveRulesByKnowledgePointId(Guid knowledgePointId) private void RecalculateTotals() { - Score = PaperSections.Sum(s => s.TotalScore); - TotalQuestionCount = PaperSections.Sum(s => s.TotalCount); + Score = PaperSections?.Sum(s => s.TotalScore) ?? 0; + TotalQuestionCount = PaperSections?.Sum(s => s.TotalCount) ?? 0; } } \ No newline at end of file diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs index 6faaa274..57d8f748 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperManager.cs @@ -51,11 +51,9 @@ public virtual async Task DeleteAsync(Paper paper) /// /// 移除题目在所有试卷中的引用 - /// 用于题目删除时的清理工作,通过聚合根的方法确保数据一致性 /// public virtual async Task RemoveQuestionFromAllPapersAsync(Guid questionId, Guid? tenantId = null) { - // 获取所有包含该题目的试卷 var papers = await PaperRepository.GetPapersByQuestionIdAsync(questionId); if (papers.Count == 0) @@ -63,19 +61,16 @@ public virtual async Task RemoveQuestionFromAllPapersAsync(Guid questionId, Guid return; } - // 批量处理:通过聚合根的方法移除题目引用,确保统计数据正确更新 foreach (var paper in papers) { paper.RemoveQuestionByQuestionId(questionId); } - // 批量更新,提高性能 await PaperRepository.UpdateManyAsync(papers); } /// /// 移除知识点在所有试卷规则中的引用 - /// 用于知识点删除时的清理工作,通过聚合根的方法确保数据一致性 /// public virtual async Task RemoveKnowledgePointFromAllPapersAsync(Guid knowledgePointId, Guid? tenantId = null) { diff --git a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs index f7f58376..ab1e8e3f 100644 --- a/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs +++ b/aspnet-core/src/SuperAbp.Exam.Domain/PaperManagement/Papers/PaperSection.cs @@ -174,7 +174,7 @@ private PaperQuestionRule GetPaperQuestionRule(Guid ruleId) private void RecalculateTotals() { - TotalScore = PaperQuestions.Sum(q => q.Score) + PaperQuestionRules.Sum(r => r.Score); - TotalCount = PaperQuestions.Count + PaperQuestionRules.Sum(r => r.Count); + TotalScore = (PaperQuestions?.Sum(q => q.Score) ?? 0) + (PaperQuestionRules?.Sum(r => r.Score) ?? 0); + TotalCount = (PaperQuestions?.Count ?? 0) + (PaperQuestionRules?.Sum(r => r.Count) ?? 0); } } \ No newline at end of file From 3fe6490946ec3cc6cdd74daf3f278443754d1680 Mon Sep 17 00:00:00 2001 From: snow Date: Mon, 2 Feb 2026 14:40:54 +0800 Subject: [PATCH 5/6] show edit --- .../admin/exam-management/exams/models.ts | 1 + .../exam/edit/edit.component.html | 351 +++++++++--------- .../exam/edit/edit.component.ts | 8 +- .../exam-management/exam/exam.component.ts | 3 - .../Exams/GetExamForEditorOutput.cs | 14 +- 5 files changed, 183 insertions(+), 194 deletions(-) diff --git a/angular-admin/src/app/proxy/admin/exam-management/exams/models.ts b/angular-admin/src/app/proxy/admin/exam-management/exams/models.ts index b2ce647e..a0a91cc7 100644 --- a/angular-admin/src/app/proxy/admin/exam-management/exams/models.ts +++ b/angular-admin/src/app/proxy/admin/exam-management/exams/models.ts @@ -56,6 +56,7 @@ export interface ExamUserExamDto { } export interface GetExamForEditorOutput extends ExamCreateOrUpdateDtoBase { + status?: number; } export interface GetExamsInput extends PagedAndSortedResultRequestDto { diff --git a/angular-admin/src/app/routes/exam-management/exam/edit/edit.component.html b/angular-admin/src/app/routes/exam-management/exam/edit/edit.component.html index 7295e2c5..9efe2b4a 100644 --- a/angular-admin/src/app/routes/exam-management/exam/edit/edit.component.html +++ b/angular-admin/src/app/routes/exam-management/exam/edit/edit.component.html @@ -1,189 +1,174 @@ @if (loading) { - + } @else { -