浏览代码

增加树形结构关键字查询

guqiang 1 月之前
父节点
当前提交
6178b0f994

+ 9 - 0
src/Hotline.Application/Exam/Constants/Messages/BusinessErrorMessage.cs

@@ -0,0 +1,9 @@
+using Exam.Infrastructure.Validation.Validation;
+
+namespace Hotline.Application.Exam.Constants.Messages
+{
+    public class BusinessErrorMessage: ErrorMessage
+    {
+        public const string HasChild = "{0}拥有下级,不可删除";
+    }
+}

+ 0 - 7
src/Hotline.Application/Exam/Constants/Messages/ErrorMessage.cs

@@ -1,7 +0,0 @@
-namespace Hotline.Application.Exam.Constants.Messages
-{
-    public class ErrorMessage
-    {
-        public const string HasChild = "{0}拥有下级,不可删除";
-    }
-}

+ 9 - 0
src/Hotline.Application/Exam/QueryExtensions/Sourcewares/SourcewareCategoryQueryExtensions.cs

@@ -1,5 +1,8 @@
+using Exam.Infrastructure.Extensions;
 using Hotline.Exams.Sourcewares;
 using Hotline.Share.Requests.Sourceware;
+using JiebaNet.Segmenter.Common;
+using SqlSugar;
 using System.Linq.Expressions;
 
 namespace Exam.Application.QueryExtensions.Sourcewares
@@ -10,6 +13,12 @@ namespace Exam.Application.QueryExtensions.Sourcewares
         {
             Expression<Func<SourcewareCategory, bool>> expression = m => m.Id != null;
 
+            Expressionable<SourcewareCategory> expressionable = new Expressionable<SourcewareCategory>();
+
+            expressionable.AndIF(sourcewareCategoryPagedRequest.Name.IsNotNullOrEmpty(), x => x.Name.Contains(sourcewareCategoryPagedRequest.Name));
+
+            expression = expressionable.ToExpression();
+
             return expression;
         }
 

+ 1 - 1
src/Hotline.Application/Exam/Service/ExamManages/ExamTagService.cs

@@ -99,7 +99,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
         {
             if (_repository.CheckHasChild(entityQueryRequest))
             {
-                throw new UserFriendlyException(string.Format(ErrorMessage.HasChild, typeof(ExamTag).GetDescription()));
+                throw new UserFriendlyException(BusinessErrorMessage.ServiceError,string.Format(BusinessErrorMessage.HasChild, typeof(ExamTag).GetDescription()));
             }
 
             return base.DeleteAsync(entityQueryRequest, cancellationToken);

+ 65 - 6
src/Hotline.Application/Exam/Service/Questions/QuestionService.cs

@@ -2,8 +2,10 @@
 using Exam.Application.Interface.Questions;
 using Exam.ExamManages;
 using Exam.Infrastructure.Data.Entity;
+using Exam.Infrastructure.Enums;
 using Exam.Insfrastructure.Service.Service;
 using Exam.Questions;
+using Exam.Repository.Sqlsugar;
 using Exam.Repository.Sqlsugar.Repositories;
 using Exam.Share.ViewResponses.Question;
 using Hotline.Application.Exam.QueryExtensions.Questions;
@@ -18,23 +20,32 @@ using XF.Domain.Dependency;
 
 namespace Hotline.Application.Exam.Service.Questions
 {
-    public class QuestionService : ApiService<Question, QuestionDto,HotlineDbContext>, IQuestionService, IScopeDependency
+    public class QuestionService : ApiService<Question, QuestionDto, HotlineDbContext>, IQuestionService, IScopeDependency
     {
         #region ctor
         private readonly IQuestionRepository _repository;
         private readonly IQuestionTagRepository _questionTagRepository;
         private readonly IQuestionOptionsRepository _questionOptionRepository;
+        private readonly IQuestionAnswerRepository _questionAnswerRepository;
+        private readonly IQuestionSourcewareRepository _questionSourcewareRepository;
+        private readonly IQuestionKnowladgeRepository _questionKnowladgeRepository;
         private readonly IDataPermissionFilterBuilder _dataPermissionFilterBuilder;
         private readonly IServiceProvider _serviceProvider;
         public QuestionService(IQuestionRepository repository,
             IQuestionTagRepository questionTagRepository,
             IQuestionOptionsRepository questionOptionsRepository,
+            IQuestionAnswerRepository questionAnswerRepository,
+            IQuestionSourcewareRepository questionSourcewareRepository,
+            IQuestionKnowladgeRepository questionKnowladgeRepository,
             IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider
             ) : base(repository)
         {
             _repository = repository;
             _questionTagRepository = questionTagRepository;
+            _questionAnswerRepository = questionAnswerRepository;
             _questionOptionRepository = questionOptionsRepository;
+            _questionSourcewareRepository = questionSourcewareRepository;
+            _questionKnowladgeRepository = questionKnowladgeRepository;
             _dataPermissionFilterBuilder = dataPermissionFilterBuilder;
             _serviceProvider = serviceProvider;
         }
@@ -56,7 +67,7 @@ namespace Hotline.Application.Exam.Service.Questions
             var questionTable = _repository.Queryable().Where(expression);
 
             var questionTagExpression = queryRequest.GetQuestionTagExpression();
-            var questionTagTable = new ExamRepository<QuestionTag>(_repository.UOW,_dataPermissionFilterBuilder,_serviceProvider).Queryable().Where(questionTagExpression);
+            var questionTagTable = new ExamRepository<QuestionTag>(_repository.UOW, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(questionTagExpression);
 
             var examTagExpression = queryRequest.GetExamTagExpression();
             var examTagTable = new ExamRepository<ExamTag>(_repository.UOW, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(examTagExpression);
@@ -111,7 +122,7 @@ namespace Hotline.Application.Exam.Service.Questions
             };
 
             return result;
-        } 
+        }
 
         public override async Task AddAsync(QuestionDto actionRequest, CancellationToken cancellationToken)
         {
@@ -120,6 +131,12 @@ namespace Hotline.Application.Exam.Service.Questions
             await AddQuestionTags(actionRequest, cancellationToken);
 
             await AddQuestionOptions(actionRequest, cancellationToken);
+
+            await AddQuestionAnswer(actionRequest, cancellationToken);
+
+            await AddKnowladges(actionRequest, cancellationToken);
+
+            await AddSourcewares(actionRequest, cancellationToken);
         }
         #endregion
 
@@ -128,23 +145,65 @@ namespace Hotline.Application.Exam.Service.Questions
         {
             if (actionRequest.QuestionTagDtos == null) return;
 
-            var questionTags = actionRequest.QuestionTagDtos.Adapt<QuestionTag>();
+            var questionTags = actionRequest.QuestionTagDtos.Where(x => x.OperationStatus == OperationStatus.Add).Adapt<QuestionTag>();
 
             questionTags.ToInsert(actionRequest);
 
-            await _questionTagRepository.AddWithValidateAsync(questionTags,cancellationToken);           
+            await _questionTagRepository.AddWithValidateAsync(questionTags, cancellationToken);
         }
 
         private async Task AddQuestionOptions(QuestionDto actionRequest, CancellationToken cancellationToken)
         {
             if (actionRequest.QuestionOptionsDtos == null) return;
 
-            var questionOptionses = actionRequest.QuestionOptionsDtos.Adapt<QuestionOptions>();
+            // 简单和填空没有选项
+            if (actionRequest.QuestionType == Share.Enums.Exams.EQuestionType.Essay || actionRequest.QuestionType == Share.Enums.Exams.EQuestionType.Blank)
+                return;
+
+            var questionOptionses = actionRequest.QuestionOptionsDtos.Where(x => x.OperationStatus == OperationStatus.Add).Adapt<QuestionOptions>();
 
             questionOptionses.ToInsert(actionRequest);
 
             await _questionOptionRepository.AddWithValidateAsync(questionOptionses, cancellationToken);
         }
+
+        private async Task AddQuestionAnswer(QuestionDto actionRequest, CancellationToken cancellationToken)
+        {
+            if (actionRequest.QuestionAnswerDto == null) return;
+
+            // 简单和填空没有选项
+            if (actionRequest.QuestionType == Share.Enums.Exams.EQuestionType.Multi
+                || actionRequest.QuestionType == Share.Enums.Exams.EQuestionType.Single
+                || actionRequest.QuestionType == Share.Enums.Exams.EQuestionType.Judge) return;
+
+            var questionAnswer = actionRequest.QuestionAnswerDto.Adapt<QuestionAnswer>();
+
+            questionAnswer.ToInsert(actionRequest);
+
+            await _questionAnswerRepository.AddWithValidateAsync(questionAnswer, cancellationToken);
+
+        }
+        private async Task AddSourcewares(QuestionDto actionRequest, CancellationToken cancellationToken)
+        {
+            if (actionRequest.QuestionSourcewareDtos == null) return;
+
+            var questionSourcewares = actionRequest.QuestionSourcewareDtos.Where(x=>x.OperationStatus == OperationStatus.Add).Adapt<QuestionSourceware>();
+
+            questionSourcewares.ToInsert(actionRequest);
+
+            await _questionSourcewareRepository.AddWithValidateAsync(questionSourcewares,cancellationToken);
+        }
+
+        private async Task AddKnowladges(QuestionDto actionRequest, CancellationToken cancellationToken)
+        {
+            if (actionRequest.QuestionKnowladgeDtos == null) return;
+
+            var questionKnowladges = actionRequest.QuestionKnowladgeDtos.Where(x => x.OperationStatus == OperationStatus.Add).Adapt<QuestionKnowladge>();
+
+            questionKnowladges.ToInsert(actionRequest);
+
+            await _questionKnowladgeRepository.AddWithValidateAsync(questionKnowladges, cancellationToken);
+        }
         #endregion
     }
 }

+ 1 - 1
src/Hotline.Application/Exam/Service/Sourcewares/SourcewareCategoryService.cs

@@ -94,7 +94,7 @@ namespace Exam.Application.Service.Sourcewares
 
             if (_repository.CheckHasChild(entityQueryRequest))
             {
-                throw new UserFriendlyException(string.Format(ErrorMessage.HasChild,typeof(SourcewareCategory).GetDescription()));
+                throw new UserFriendlyException(BusinessErrorMessage.ServiceError, string.Format(BusinessErrorMessage.HasChild,typeof(SourcewareCategory).GetDescription()));
             }
 
             return base.DeleteAsync(entityQueryRequest, cancellationToken);

+ 1 - 0
src/Hotline.Application/Hotline.Application.csproj

@@ -13,6 +13,7 @@
     <PackageReference Include="Quartz.Jobs" Version="3.13.1" />
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\Exam.Infrastructure.Validation\Exam.Infrastructure.Validation.csproj" />
     <ProjectReference Include="..\Exam.Infrastructure.Web\Exam.Infrastructure.Web.csproj" />
     <ProjectReference Include="..\Hotline.Ai.Jths\Hotline.Ai.Jths.csproj" />
     <ProjectReference Include="..\Hotline.Ai.XingTang\Hotline.Ai.XingTang.csproj" />

+ 34 - 0
src/Hotline.Repository.SqlSugar/Exam/Extensions/TreeExtensions.cs

@@ -0,0 +1,34 @@
+using Hotline.Exams.Base;
+using IdentityModel;
+using SqlSugar;
+using System.Linq.Expressions;
+using XF.Domain.Entities;
+using XF.Domain.Repository;
+
+namespace Hotline.Repository.SqlSugar.Exam.Extensions
+{
+    public static class TreeExtensions
+    {
+        /// <summary>
+        /// 获取树形结构
+        /// </summary>
+        /// <typeparam name="TEntity"></typeparam>
+        /// <param name="repository"></param>
+        /// <param name="expression"></param>
+        /// <returns></returns>
+        public static ISugarQueryable<TEntity> GetTree<TEntity>(this IRepository<TEntity> repository, Expression<Func<TEntity, bool>> expression) where TEntity : class, IEntity<string>, IParentEntity, new()
+        {
+            var queryResult = repository.Queryable().Where(expression).Select(m => m);
+
+            var parentQuery = repository.Queryable().InnerJoin(queryResult, (p, c) => p.Id == c.ParentId).Select(p => p);
+
+            var childQuery = repository.Queryable().InnerJoin(queryResult, (c, p) => p.Id == c.ParentId).Select(c => c);
+
+            var queryUnion = repository.UnionAll(queryResult, parentQuery, childQuery);
+
+            queryUnion = queryUnion.Distinct();
+
+            return queryUnion;
+        }
+    }
+}

+ 2 - 1
src/Hotline.Repository.SqlSugar/Exam/Repositories/ExamManages/ExamTagRepository.cs

@@ -3,6 +3,7 @@ using Exam.Repository.Sqlsugar.Repositories;
 using Exam.Repository.Sqlsugar.Validators.ExamManages;
 using Hotline.Repository.SqlSugar;
 using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Repository.SqlSugar.Exam.Extensions;
 using Hotline.Repository.SqlSugar.Exam.Interfaces.ExamManages;
 using SqlSugar;
 using System.ComponentModel;
@@ -24,7 +25,7 @@ namespace Exam.Repository.Sqlsugar
 
         public async Task<List<ExamTag>> GetTreeAsync(Expression<Func<ExamTag, bool>> expression)
         {
-            var examTagList = await base.Queryable().Where(expression).OrderBy(o => o.SortIndex).ToTreeAsync(m => m.Children, p => p.ParentId, "");
+            var examTagList = await this.GetTree(expression).OrderBy(o => o.SortIndex).ToTreeAsync(m => m.Children, p => p.ParentId, "");
 
             return examTagList;
         }

+ 3 - 2
src/Hotline.Repository.SqlSugar/Exam/Repositories/Sourcewares/SourcewareCategoryRepository.cs

@@ -2,6 +2,7 @@ using Exam.Repository.Sqlsugar.Validators.Sourcewares;
 using Hotline.Exams.Sourcewares;
 using Hotline.Repository.SqlSugar;
 using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Repository.SqlSugar.Exam.Extensions;
 using Hotline.Repository.SqlSugar.Exam.Interfaces.Sourcewares;
 using Hotline.Share.Requests.Sourceware;
 using SqlSugar;
@@ -15,7 +16,7 @@ namespace Exam.Repository.Sqlsugar.Repositories.Sourcewares
     /// 课件类型仓储
     /// </summary>
     [Description("课件类型仓储")]
-    public class SourcewareCategoryRepository : ExamRepository<SourcewareCategory>, ISourcewareCategoryRepository,IScopeDependency
+    public class SourcewareCategoryRepository : ExamRepository<SourcewareCategory>, ISourcewareCategoryRepository, IScopeDependency
     {
         public SourcewareCategoryRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider) : base(uow, dataPermissionFilterBuilder, serviceProvider)
         {
@@ -29,7 +30,7 @@ namespace Exam.Repository.Sqlsugar.Repositories.Sourcewares
         /// <returns></returns>
         public async Task<List<SourcewareCategory>> GetTreeAsync(Expression<Func<SourcewareCategory, bool>> expression)
         {
-            var sourcewareCategoryList = await base.Queryable().Where(expression).OrderBy(o=>o.SortIndex).ToTreeAsync(m=>m.Children,p=>p.ParentId,"");
+            var sourcewareCategoryList = await this.GetTree(expression).OrderBy(o => o.SortIndex).ToTreeAsync(m => m.Children, p => p.ParentId, "");
 
             return sourcewareCategoryList;
         }

+ 3 - 2
src/Hotline.Share/Dtos/Questions/QuestionDto.cs

@@ -1,4 +1,5 @@
 using Exam.Infrastructure.Data.Entity;
+using Hotline.Share.Enums.Exams;
 using System.ComponentModel;
 
 namespace Hotline.Share.Dtos.Questions
@@ -19,13 +20,13 @@ namespace Hotline.Share.Dtos.Questions
         /// 试题类型
         /// </summary>
         [Description("试题类型")]
-        public int Type { get; set; }
+        public EQuestionType QuestionType { get; set; }
 
         /// <summary>
         /// 难易程度
         /// </summary>
         [Description("难易程度")]
-        public int DifficultyLevel { get; set; }
+        public EDifficultyLevel DifficultyLevel { get; set; }
 
         /// <summary>
         /// 正式可用

+ 1 - 0
src/Hotline.Share/Requests/Sourceware/SourcewareCategoryRequest.cs

@@ -4,5 +4,6 @@ namespace Hotline.Share.Requests.Sourceware
 {
     public class SourcewareCategoryRequest : IQueryRequest
     {
+        public string Name { get; set; }
     }
 }

+ 6 - 1
src/Hotline/Exams/Sourcewares/SourcewareCategory.cs

@@ -24,12 +24,17 @@ namespace Hotline.Exams.Sourcewares
         [SugarColumn(ColumnDescription = "父级ID")]
         public string? ParentId { get; set; }
 
+        /// <summary>
+        /// 父级
+        /// </summary>
+        [Navigate(NavigateType.OneToOne,nameof(ParentId))]
+        public SourcewareCategory Parent { get; set; }
+
         /// <summary>
         /// 子分类
         /// </summary>
         [Description("子分类")]
         [SugarColumn(IsIgnore = true)]
         public List<SourcewareCategory> Children { get; set; }
-
     }
 }