guqiang пре 1 месец
родитељ
комит
2d0015ad78
20 измењених фајлова са 686 додато и 20 уклоњено
  1. 2 2
      src/Hotline.Api/Controllers/Exam/ExamTagController.cs
  2. 108 0
      src/Hotline.Api/Controllers/Exam/ExtractRuleController.cs
  3. 2 2
      src/Hotline.Api/Controllers/Exam/SourcewareCategoryController.cs
  4. 2 2
      src/Hotline.Api/Controllers/Exam/SourcewaresController.cs
  5. 9 0
      src/Hotline.Application/Exam/Constants/ApiRoutes/ExtractRuleApiRoute.cs
  6. 2 0
      src/Hotline.Application/Exam/Interface/ExamManages/IExtractRuleService.cs
  7. 25 0
      src/Hotline.Application/Exam/QueryExtensions/ExamManages/ExtractRuleQueryExtensions.cs
  8. 21 0
      src/Hotline.Application/Exam/QueryExtensions/ExamManages/TagQuestionQueryExtensions.cs
  9. 427 0
      src/Hotline.Application/Exam/Service/ExamManages/ExtractRuleService.cs
  10. 8 5
      src/Hotline.Application/Exam/Service/Questions/QuestionService.cs
  11. 3 1
      src/Hotline.Application/Exam/Service/Sourcewares/SourcewareService.cs
  12. 0 1
      src/Hotline.Application/Hotline.Application.csproj
  13. 1 1
      src/Hotline.Repository.SqlSugar/Service/ApiService.cs
  14. 2 1
      src/Hotline.Share/Dtos/TestPapers/ExtractRuleDto.cs
  15. 21 1
      src/Hotline.Share/Dtos/TestPapers/TagQuestionDto.cs
  16. 3 2
      src/Hotline.Share/Requests/Exam/ExtractRulePagedRequest.cs
  17. 14 0
      src/Hotline.Share/Requests/Exam/TagQuestionRequest.cs
  18. 2 1
      src/Hotline.Share/ViewResponses/Exam/ExtractRuleViewResponse.cs
  19. 33 0
      src/Hotline.Share/ViewResponses/Exam/TagQuestionViewResponse.cs
  20. 1 1
      src/Hotline/Exams/ExamManages/ExtractRule.cs

+ 2 - 2
src/Hotline.Api/Controllers/Exam/ExamTagController.cs

@@ -16,8 +16,8 @@ namespace Hotline.Api.Controllers.Exam
 {
     public class ExamTagController : BaseController
     {
-        private IExamTagService _examTagService;
-        private ISessionContext _sessionContext;
+        private readonly IExamTagService _examTagService;
+        private readonly ISessionContext _sessionContext;
         public ExamTagController(IExamTagService examTagService,ISessionContext sessionContext)
         {
             _examTagService = examTagService;

+ 108 - 0
src/Hotline.Api/Controllers/Exam/ExtractRuleController.cs

@@ -0,0 +1,108 @@
+using Exam.Application.Interface.Exam;
+using Exam.Infrastructure.Data.Entity;
+using Exam.Infrastructure.Data.Extensions;
+using Exam.Share.ViewResponses.Exam;
+using Hotline.Application.Exam.Constants.ApiRoutes;
+using Hotline.Application.Exam.Service.ExamManages;
+using Hotline.Share.Dtos.ExamManages;
+using Hotline.Share.Dtos.TestPapers;
+using Hotline.Share.Requests.Exam;
+using Hotline.Share.Requests.Sourceware;
+using Hotline.Share.ViewResponses.Exam;
+using Hotline.Share.ViewResponses.Sourcewares;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using XF.Domain.Authentications;
+
+namespace Hotline.Api.Controllers.Exam
+{
+    public class ExtractRuleController : BaseController
+    {
+        private readonly IExtractRuleService _extractRuleService;
+        private readonly ISessionContext _sessionContext;
+        public ExtractRuleController(IExtractRuleService extractRuleService,ISessionContext sessionContext)
+        {
+            _extractRuleService = extractRuleService;
+            _sessionContext = sessionContext;
+        }
+
+        /// <summary>
+        /// 新增考试标签
+        /// </summary>
+        /// <param name="extractRuleDto"></param>
+        /// <returns></returns>
+        [HttpPost(ExtractRuleApiRoute.Add)]
+        public async Task Add([FromBody] ExtractRuleDto extractRuleDto)
+        {
+            extractRuleDto.InitRequest(_sessionContext);
+            await _extractRuleService.AddAsync(extractRuleDto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 修改考试标签
+        /// </summary>
+        /// <param name="extractRuleDto"></param>
+        /// <returns></returns>
+        [HttpPut(ExtractRuleApiRoute.Update)]
+        public async Task Update([FromBody] ExtractRuleDto extractRuleDto)
+        {
+            extractRuleDto.InitRequest(_sessionContext);
+            await _extractRuleService.UpdateAsync(extractRuleDto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 删除考试标签
+        /// </summary>
+        /// <param name="entityQueryRequest"></param>
+        /// <returns></returns>
+        [HttpDelete(ExtractRuleApiRoute.Delete)]
+
+        public async Task Delete(EntityQueryRequest entityQueryRequest)
+        {
+            await _extractRuleService.DeleteAsync(entityQueryRequest, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 获取课件分页列表
+        /// </summary>
+        /// <param name="sourcewarePagedRequest"></param>
+        /// <returns></returns>
+        [HttpPost(ExtractRuleApiRoute.GetPagedList)]
+        public async Task<ExtractRulePageViewResponse> GetPagedList([FromBody] ExtractRulePagedRequest sourcewarePagedRequest)
+        {
+            var sourcewarePageViewResponse = await _extractRuleService.GetPagedListAsync(sourcewarePagedRequest);
+
+            return sourcewarePageViewResponse as ExtractRulePageViewResponse;
+        }
+
+
+        /// <summary>
+        /// 获取课件分类
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet(ExtractRuleApiRoute.Get)]
+        public async Task<ExtractRuleDto> Get(string id)
+        {
+            var extractRuleDto = await _extractRuleService.GetAsync(new EntityQueryRequest
+            {
+                Id = id
+            });
+
+            return extractRuleDto;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="tagQuestionRequest"></param>
+        /// <returns></returns>
+        [HttpPost(ExtractRuleApiRoute.GetTagQuestionCount)]
+        public async Task<List<TagQuestionViewResponse>> GetTagQuestionCount([FromBody]TagQuestionRequest tagQuestionRequest)
+        {
+            var tagQuestionViewResponses = await _extractRuleService.GetTagQuestionCount(tagQuestionRequest);
+
+            return tagQuestionViewResponses;
+        }
+    }
+}

+ 2 - 2
src/Hotline.Api/Controllers/Exam/SourcewareCategoryController.cs

@@ -13,8 +13,8 @@ namespace Hotline.Api.Controllers.Exam
 {
     public class SourcewareCategoryController : BaseController
     {
-        private ISourcewareCategoryService _sourcewareCategoryService;
-        private ISessionContext _sessionContext;
+        private readonly ISourcewareCategoryService _sourcewareCategoryService;
+        private readonly ISessionContext _sessionContext;
         public SourcewareCategoryController(ISourcewareCategoryService sourcewareCategoryService,ISessionContext sessionContext)
         {
             _sourcewareCategoryService = sourcewareCategoryService;

+ 2 - 2
src/Hotline.Api/Controllers/Exam/SourcewaresController.cs

@@ -12,8 +12,8 @@ namespace Hotline.Api.Controllers.Exam
 {
     public class SourcewaresController : BaseController
     {
-        private ISourcewareService _sourcewareService;
-        private ISessionContext _sessionContext;
+        private readonly ISourcewareService _sourcewareService;
+        private readonly ISessionContext _sessionContext;
 
         public SourcewaresController(ISourcewareService sourcewareService,ISessionContext sessionContext)
         {

+ 9 - 0
src/Hotline.Application/Exam/Constants/ApiRoutes/ExtractRuleApiRoute.cs

@@ -0,0 +1,9 @@
+using Exam.Infrastructure.Web.Constants;
+
+namespace Hotline.Application.Exam.Constants.ApiRoutes
+{
+    public class ExtractRuleApiRoute:ApiRoute
+    {
+        public const string GetTagQuestionCount = "GetTagQuestionCount";
+    }
+}

+ 2 - 0
src/Hotline.Application/Exam/Interface/ExamManages/IExtractRuleService.cs

@@ -4,10 +4,12 @@ using Exam.Share.ViewResponses.Exam;
 using Hotline.Repository.SqlSugar.Interface;
 using Hotline.Share.Dtos.TestPapers;
 using Hotline.Share.Requests.Exam;
+using Hotline.Share.ViewResponses.Exam;
 
 namespace Exam.Application.Interface.Exam
 {
     public interface IExtractRuleService:IQueryService<ExtractRuleViewResponse,ExtractRuleDto,ExtractRulePagedRequest>,IApiService<ExtractRuleDto,ExtractRule>
     {
+        public Task<List<TagQuestionViewResponse>> GetTagQuestionCount(TagQuestionRequest tagQuestionRequest);
     }
 }

+ 25 - 0
src/Hotline.Application/Exam/QueryExtensions/ExamManages/ExtractRuleQueryExtensions.cs

@@ -0,0 +1,25 @@
+using Exam.ExamManages;
+using Exam.Infrastructure.Extensions;
+using Exam.Infrastructure.Web.Utilities;
+using Hotline.Share.Requests.Exam;
+using JiebaNet.Segmenter.Common;
+using System.Linq.Expressions;
+
+namespace Hotline.Application.Exam.QueryExtensions.ExamManages
+{
+    public static class ExtractRuleQueryExtensions
+    {
+        public static Expression<Func<ExtractRule, bool>> GetExpression(this ExtractRulePagedRequest extractRulePagedRequest)
+        {
+            Expression<Func<ExtractRule, bool>> expression = m => m.Id != null;
+
+            expression = ExpressionableUtility.CreateExpression<ExtractRule>()
+                         .AndIF(extractRulePagedRequest.Code.IsNotNullOrEmpty(), x => x.Code.Contains(extractRulePagedRequest.Code))
+                         .AndIF(extractRulePagedRequest.Name.IsNotNullOrEmpty(), x => x.Name.Contains(extractRulePagedRequest.Name))
+                         .AndIF(extractRulePagedRequest.ExamType.IsNotNull(), x => x.RuleType == extractRulePagedRequest.ExamType)
+                         .AndIF(extractRulePagedRequest.Status.IsNotNull(), x => x.Status == extractRulePagedRequest.Status).ToExpression();
+
+            return expression;
+        }
+    }
+}

+ 21 - 0
src/Hotline.Application/Exam/QueryExtensions/ExamManages/TagQuestionQueryExtensions.cs

@@ -0,0 +1,21 @@
+using Exam.Infrastructure.Web.Utilities;
+using Exam.Questions;
+using Hotline.Share.Requests.Exam;
+using JiebaNet.Segmenter.Common;
+using System.Linq.Expressions;
+
+namespace Hotline.Application.Exam.QueryExtensions.ExamManages
+{
+    public static class TagQuestionQueryExtensions
+    {
+        public static Expression<Func<QuestionTag, bool>> GetExpression(this TagQuestionRequest tagQuestionRequest)
+        {
+            Expression<Func<QuestionTag, bool>> expression = m => m.Id != null;
+
+            expression = ExpressionableUtility.CreateExpression<QuestionTag>()
+                .AndIF(tagQuestionRequest.TagIds.IsNotNull(), x => tagQuestionRequest.TagIds.Contains(x.TagId)).ToExpression();
+
+            return expression;
+        }
+    }
+}

+ 427 - 0
src/Hotline.Application/Exam/Service/ExamManages/ExtractRuleService.cs

@@ -0,0 +1,427 @@
+using Exam.Application.Interface.Exam;
+using Exam.ExamManages;
+using Exam.Infrastructure.Data.Entity;
+using Exam.Infrastructure.Data.Extensions;
+using Exam.Infrastructure.Enums;
+using Exam.Infrastructure.Extensions;
+using Exam.Infrastructure.Web.Extensions;
+using Exam.Infrastructure.Web.Utilities;
+using Exam.Insfrastructure.Service.Service;
+using Exam.Questions;
+using Exam.Repository.Sqlsugar.Repositories;
+using Exam.Share.ViewResponses.Exam;
+using Hotline.Application.Exam.QueryExtensions.ExamManages;
+using Hotline.Repository.SqlSugar;
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Repository.SqlSugar.Exam.Interfaces.ExamManages;
+using Hotline.Repository.SqlSugar.Exam.Interfaces.Questions;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Share.Dtos.TestPapers;
+using Hotline.Share.Requests.Exam;
+using Hotline.Share.Tools;
+using Hotline.Share.ViewResponses.Exam;
+using JiebaNet.Segmenter.Common;
+using MapsterMapper;
+using SqlSugar;
+using XF.Domain.Dependency;
+
+namespace Hotline.Application.Exam.Service.ExamManages
+{
+    public class ExtractRuleService : ApiService<ExtractRule, ExtractRuleDto, HotlineDbContext>,IExtractRuleService, IScopeDependency
+    {
+        private readonly IExtractRuleRepository _repository;
+        private readonly ITagQuestionRepository _tagQuestionRepository;
+        private readonly IRuleTagRepository _ruleTagRepository;
+        private readonly IDataPermissionFilterBuilder _dataPermissionFilterBuilder;
+        private readonly IServiceProvider _serviceProvider;
+        private readonly IMapper _mapper;
+        public ExtractRuleService(IExtractRuleRepository repository,
+            ITagQuestionRepository tagQuestionRepository,
+            IRuleTagRepository ruleTagRepository,
+             IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider,
+            IMapper mapper) : base(repository, mapper)
+        {
+            _repository = repository;
+            _tagQuestionRepository = tagQuestionRepository;
+            _ruleTagRepository = ruleTagRepository;
+            _dataPermissionFilterBuilder = dataPermissionFilterBuilder;
+            _serviceProvider = serviceProvider;
+            _mapper = mapper;
+        }
+
+        #region public method
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="entityQueryRequest"></param>
+        /// <returns></returns>
+        public async Task<ExtractRuleDto> GetAsync(EntityQueryRequest entityQueryRequest)
+        {
+            var entity = await _repository.GetAsync(entityQueryRequest.Id);
+
+            var extractRuleDto = _mapper.Map<ExtractRuleDto>(entity);
+
+            if (extractRuleDto != null)
+            {
+                extractRuleDto.RuleTagDtos = await GetRuleTagDtos(entityQueryRequest);
+
+                extractRuleDto.TagQuestionDtos = await GetTagQuestions(entityQueryRequest);
+            }
+
+
+            return extractRuleDto;
+        }
+
+        public async Task<(int, List<ExtractRuleViewResponse>)> GetListAsync(ExtractRulePagedRequest queryRequest)
+        {
+            ISugarQueryable<ExtractRuleViewResponse> queryable = QueryResult(queryRequest);
+
+            var result = await queryable.ToListAsync();
+
+            var total = await queryable.CountAsync();
+
+            return (total, result);
+        }
+
+        public async Task<PageViewResponse<ExtractRuleViewResponse>> GetPagedListAsync(ExtractRulePagedRequest queryRequest)
+        {
+            ISugarQueryable<ExtractRuleViewResponse> queryable = QueryResult(queryRequest);
+
+            var list = await queryable.ToPageListAsync(queryRequest.PageIndex, queryRequest.PageSize);
+            var total = await queryable.CountAsync();
+
+            var result = new ExtractRulePageViewResponse
+            {
+                Items = list,
+                Pagination = new Pagination(queryRequest.PageIndex, queryRequest.PageSize, total)
+            };
+
+            return result;
+        }
+
+        /// <summary>
+        /// 新增抽题规则
+        /// </summary>
+        /// <param name="actionRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public override async Task AddAsync(ExtractRuleDto actionRequest, CancellationToken cancellationToken)
+        {
+            await base.AddAsync(actionRequest, cancellationToken);
+
+            await AddRuleTags(actionRequest,cancellationToken);
+
+            await AddTagQuestions(actionRequest, cancellationToken);
+        }
+
+        /// <summary>
+        /// 修改抽题规则
+        /// </summary>
+        /// <param name="actionRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public override async Task UpdateAsync(ExtractRuleDto actionRequest, CancellationToken cancellationToken)
+        {
+            await base.UpdateAsync(actionRequest, cancellationToken);
+
+            await ModifyRuleTags(actionRequest, cancellationToken);
+
+            await ModifyTagQuestions(actionRequest, cancellationToken);
+        }
+
+        /// <summary>
+        /// 删除抽题规则
+        /// </summary>
+        /// <param name="entityQueryRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public override async Task DeleteAsync(EntityQueryRequest entityQueryRequest, CancellationToken cancellationToken)
+        {
+            await base.DeleteAsync(entityQueryRequest, cancellationToken);
+
+            var tempEntityQueryRequest = ExpressionableUtility.CreateExpression<TagQuestion>()
+                .AndIF(entityQueryRequest.Id.IsNotNullOrEmpty(), x => x.RuleId == entityQueryRequest.Id)
+                .AndIF(entityQueryRequest.Ids.IsNotNull(), x => entityQueryRequest.Ids.Contains(x.RuleId)).ToEntityQueryRequest<TagQuestion>();
+
+            await DeleteTagQuestions(tempEntityQueryRequest, cancellationToken);
+
+            tempEntityQueryRequest = ExpressionableUtility.CreateExpression<RuleTag>()
+                .AndIF(entityQueryRequest.Id.IsNotNullOrEmpty(), x => x.RuleId == entityQueryRequest.Id)
+                .AndIF(entityQueryRequest.Ids.IsNotNull(), x => entityQueryRequest.Ids.Contains(x.RuleId)).ToEntityQueryRequest<RuleTag>();
+
+
+            await DeleteRuleTags(tempEntityQueryRequest, cancellationToken);
+        }
+
+        /// <summary>
+        /// 获取标题试题数
+        /// </summary>
+        /// <param name="tagQuestionRequest"></param>
+        /// <returns></returns>
+        public async Task<List<TagQuestionViewResponse>> GetTagQuestionCount(TagQuestionRequest tagQuestionRequest)
+        {
+            if (tagQuestionRequest.TagIds.IsNullOrEmpty()) return new List<TagQuestionViewResponse>();
+
+            var expression = tagQuestionRequest.GetExpression();
+            var questionTagTable = new ExamRepository<QuestionTag>(_repository.UOW, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(expression);
+            var questionTable = new ExamRepository<Question>(_repository.UOW, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+
+            var queryable = questionTagTable.LeftJoin(questionTable, (t, q) => t.QuestionId == q.Id)
+                .GroupBy((t,q)=> new { t.TagId, q.QuestionType }).Select((t, q) => new TagQuestionViewResponse
+            {
+                TagId = t.TagId,
+                QuestionType = q.QuestionType,
+                TotalCount = SqlFunc.AggregateCount(new
+                {
+                    TagId = t.TagId,
+                    QuestionType = q.QuestionType,
+                })
+            });
+
+            return await queryable.ToListAsync();
+        }
+        #endregion
+
+        #region private method
+        /// <summary>
+        /// 获取查询结果
+        /// </summary>
+        /// <param name="queryRequest"></param>
+        /// <returns></returns>
+        private ISugarQueryable<ExtractRuleViewResponse> QueryResult(ExtractRulePagedRequest queryRequest)
+        {
+            var expression = queryRequest.GetExpression();
+            var query = _repository.Queryable().Where(expression);
+            var querable = query.OrderBy(o => o.SortIndex).Select(m => new ExtractRuleViewResponse
+            {
+                Name = m.Name,
+                Id = m.Id,
+                Status = m.Status,
+                Code = m.Code,
+                SortIndex = m.SortIndex,
+                Remark = m.Remark
+            });
+            return querable;
+        }
+
+        /// <summary>
+        /// 新增标签试题
+        /// </summary>
+        /// <param name="actionRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        private async Task AddTagQuestions(ExtractRuleDto actionRequest, CancellationToken cancellationToken)
+        {
+            if (actionRequest.TagQuestionDtos == null) return;
+
+            var tagQuestionDtos = actionRequest.TagQuestionDtos.Where(x => x.OperationStatus == OperationStatus.Add).ToList();
+
+            var tagQuestions = _mapper.Map<List<TagQuestion>>(tagQuestionDtos);
+
+            tagQuestionDtos.InitRequest(actionRequest);
+
+            tagQuestions.ForEach(x => x.RuleId = actionRequest.Id);
+
+            tagQuestions.ToInsert(tagQuestionDtos);
+
+            await _tagQuestionRepository.AddWithValidateAsync(tagQuestions, cancellationToken);
+        }
+
+        /// <summary>
+        /// 新增规则标签
+        /// </summary>
+        /// <param name="actionRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        private async Task AddRuleTags(ExtractRuleDto actionRequest, CancellationToken cancellationToken)
+        {
+            if (actionRequest.RuleTagDtos == null) return;
+
+            var ruleTagDtos = actionRequest.RuleTagDtos.Where(x => x.OperationStatus == OperationStatus.Add).ToList();
+
+            var ruleTags = _mapper.Map<List<RuleTag>>(ruleTagDtos);
+
+            ruleTagDtos.InitRequest(actionRequest);
+
+            ruleTags.ForEach(x => x.RuleId = actionRequest.Id);
+
+            ruleTags.ToInsert(ruleTagDtos);
+
+            await _ruleTagRepository.AddWithValidateAsync(ruleTags, cancellationToken);
+
+        }
+
+        /// <summary>
+        /// 修改标签试题数
+        /// </summary>
+        /// <param name="actionRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        /// <exception cref="NotImplementedException"></exception>
+        private async Task ModifyTagQuestions(ExtractRuleDto actionRequest, CancellationToken cancellationToken)
+        {
+            if (actionRequest.TagQuestionDtos == null) return;
+
+            await AddTagQuestions(actionRequest, cancellationToken);
+
+            await UpdateTagQuestions(actionRequest ,cancellationToken);
+
+            var ruleTagDtos = actionRequest.TagQuestionDtos.Where(x => x.OperationStatus == OperationStatus.Delete).ToList();
+            var ids = ruleTagDtos.Select(x => x.Id).ToList();
+            var entityQueyRequest = ExpressionableUtility.CreateExpression<TagQuestion>()
+                .AndIF(ids.IsNotNull(), x => ids.Contains(x.Id)).ToEntityQueryRequest<TagQuestion>();
+
+            await DeleteTagQuestions(entityQueyRequest, cancellationToken);
+        }
+
+        /// <summary>
+        /// 修改标签试题数
+        /// </summary>
+        /// <param name="actionRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        /// <exception cref="NotImplementedException"></exception>
+        private async Task UpdateTagQuestions(ExtractRuleDto actionRequest, CancellationToken cancellationToken)
+        {
+            if (actionRequest.TagQuestionDtos == null) return;
+
+            var tagQuestionDtos = actionRequest.TagQuestionDtos.Where(x => x.OperationStatus == OperationStatus.Update).ToList();
+            var ids = tagQuestionDtos.Select(x => x.Id).ToList();
+            var tagQuestions = await _tagQuestionRepository.Queryable().Where(x => ids.Contains(x.Id)).ToListAsync();
+
+            var entitys = new List<TagQuestion>();
+            tagQuestionDtos.ForEach(x =>
+            {
+                var entity = tagQuestions.FirstOrDefault(x => x.Id == x.Id);
+                entity = _mapper.Map(x, entity);
+                entity.RuleId = actionRequest.Id;
+                entitys.Add(entity);
+            });
+            tagQuestionDtos.InitRequest(actionRequest);
+
+            entitys.ToUpdate(tagQuestionDtos);
+
+            await _tagQuestionRepository.UpdateWithValidateAsync(entitys, cancellationToken);
+        }
+
+        /// <summary>
+        /// 修改规则标签
+        /// </summary>
+        /// <param name="actionRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        /// <exception cref="NotImplementedException"></exception>
+        private async Task ModifyRuleTags(ExtractRuleDto actionRequest, CancellationToken cancellationToken)
+        {
+            if (actionRequest.RuleTagDtos == null) return;
+
+            await AddRuleTags(actionRequest, cancellationToken);
+
+            await UpdateRuleTags(actionRequest, cancellationToken);
+
+            var ruleTagDtos = actionRequest.RuleTagDtos.Where(x => x.OperationStatus == OperationStatus.Delete).ToList();
+            var ids = ruleTagDtos.Select(x => x.Id).ToList();
+            var entityQueyRequest = ExpressionableUtility.CreateExpression<RuleTag>()
+                .AndIF(ids.IsNotNull(), x => ids.Contains(x.Id)).ToEntityQueryRequest<RuleTag>();
+
+            await DeleteRuleTags(entityQueyRequest, cancellationToken);
+        }
+
+        private async Task UpdateRuleTags(ExtractRuleDto actionRequest, CancellationToken cancellationToken)
+        {
+            if (actionRequest.RuleTagDtos == null) return;
+
+            var ruleTagDtos = actionRequest.RuleTagDtos.Where(x => x.OperationStatus == OperationStatus.Update).ToList();
+            var ids = ruleTagDtos.Select(x => x.Id).ToList();
+            var ruleTags = await _ruleTagRepository.Queryable().Where(x=>ids.Contains(x.Id)).ToListAsync();
+
+            var entitys = new List<RuleTag>();
+            ruleTagDtos.ForEach(x =>
+            {
+                var entity = ruleTags.FirstOrDefault(x=>x.Id == x.Id);
+                entity = _mapper.Map(x, entity);
+                entity.RuleId = actionRequest.Id;
+                entitys.Add(entity);
+            });
+            ruleTagDtos.InitRequest(actionRequest);
+
+            entitys.ToUpdate(ruleTagDtos);
+
+            await _ruleTagRepository.UpdateWithValidateAsync(entitys,cancellationToken);
+
+        }
+
+
+        /// <summary>
+        /// 删除规则标签
+        /// </summary>
+        /// <param name="tempEntityQueryRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        private async Task DeleteRuleTags(EntityQueryRequest tempEntityQueryRequest, CancellationToken cancellationToken)
+        {
+            await _ruleTagRepository.DeleteWithValidateAsync(tempEntityQueryRequest, cancellationToken);
+        }
+
+        /// <summary>
+        /// 删除标签试题数
+        /// </summary>
+        /// <param name="tempEntityQueryRequest"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        private async Task DeleteTagQuestions(EntityQueryRequest tempEntityQueryRequest, CancellationToken cancellationToken)
+        {
+            await _tagQuestionRepository.DeleteWithValidateAsync(tempEntityQueryRequest, cancellationToken);
+        }
+
+        /// <summary>
+        /// 获取规则标签
+        /// </summary>
+        /// <param name="entityQueryRequest"></param>
+        /// <returns></returns>
+        /// <exception cref="NotImplementedException"></exception>
+        private async Task<List<RuleTagDto>> GetRuleTagDtos(EntityQueryRequest entityQueryRequest)
+        {
+            var ruleTagTable = _ruleTagRepository.Queryable().Where(x=>x.RuleId == entityQueryRequest.Id);
+
+            var examTagTable = new ExamRepository<ExamTag>(_repository.UOW, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+
+
+            var queryable = ruleTagTable.LeftJoin(examTagTable, (r, e) => r.TagId == e.Id).Select((r, e) => new RuleTagDto
+            {
+                Id = r.Id,
+                TagId = r.TagId,
+                Tag = e.Name
+            });
+
+            return await queryable.ToListAsync();
+
+        }
+
+        /// <summary>
+        /// 获取标签试题数
+        /// </summary>
+        /// <param name="entityQueryRequest"></param>
+        /// <returns></returns>
+        /// <exception cref="NotImplementedException"></exception>
+        private async Task<List<TagQuestionDto>> GetTagQuestions(EntityQueryRequest entityQueryRequest)
+        {
+            var tagQuestionTable = _tagQuestionRepository.Queryable().Where(x => x.RuleId == entityQueryRequest.Id);
+
+            var examTagTable = new ExamRepository<ExamTag>(_repository.UOW, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+
+
+            var tagQuestionDtos = tagQuestionTable.LeftJoin(examTagTable, (t, e) => t.TagId == e.Id).Select((t,e)=>new TagQuestionDto
+            {
+                Id = t.Id,
+                TagId =t.TagId,
+                QuestionType = t.QuestionType,
+                Count = t.Count,
+                Tag = e.Name
+            });
+
+            return await tagQuestionDtos.ToListAsync();
+        }
+        #endregion
+    }
+}

+ 8 - 5
src/Hotline.Application/Exam/Service/Questions/QuestionService.cs

@@ -74,15 +74,18 @@ namespace Hotline.Application.Exam.Service.Questions
 
             var questionDto = _mapper.Map<QuestionDto>(entity);
 
-            questionDto.QuestionTagDtos = await GetQuestionTags(entityQueryRequest);
+            if (questionDto != null)
+            {
+                questionDto.QuestionTagDtos = await GetQuestionTags(entityQueryRequest);
 
-            questionDto.QuestionAnswerDto = await GetQuestionAnswer(entityQueryRequest);
+                questionDto.QuestionAnswerDto = await GetQuestionAnswer(entityQueryRequest);
 
-            questionDto.QuestionKnowladgeDtos = await GetKnowladges(entityQueryRequest);
+                questionDto.QuestionKnowladgeDtos = await GetKnowladges(entityQueryRequest);
 
-            questionDto.QuestionOptionsDtos = await GetQuestionOptions(entityQueryRequest);
+                questionDto.QuestionOptionsDtos = await GetQuestionOptions(entityQueryRequest);
 
-            questionDto.QuestionSourcewareDtos = await GetQuestionSourcewares(entityQueryRequest);
+                questionDto.QuestionSourcewareDtos = await GetQuestionSourcewares(entityQueryRequest);
+            }            
 
             return questionDto;
         }

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

@@ -27,11 +27,13 @@ namespace Hotline.Application.Exam.Service.Sourcewares
         private readonly ISourcewareRepository _repository;
         private readonly IDataPermissionFilterBuilder _datePermissionFilterBuilder;
         private readonly IServiceProvider _serviceProvider;
+        private readonly IMapper _mapper;
         public SourcewareService(ISourcewareRepository repository, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider,IMapper mapper) : base(repository, mapper)
         {
             _repository = repository;
             _datePermissionFilterBuilder = dataPermissionFilterBuilder;
             _serviceProvider = serviceProvider;
+            _mapper = mapper;
         }
 
         #region public method
@@ -39,7 +41,7 @@ namespace Hotline.Application.Exam.Service.Sourcewares
         {
             var entity = await _repository.GetAsync(entityQueryRequest.Id);
 
-            return entity.Adapt<SourcewareDto>();
+            return _mapper.Map<SourcewareDto>(entity);
         }
 
         public async Task<(int, List<SourcewareViewResponse>)> GetListAsync(SourcewarePagedRequest queryRequest)

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

@@ -29,7 +29,6 @@
     <ProjectReference Include="..\XingTang.Sdk\XingTang.Sdk.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <Folder Include="Exam\Service\ExamManages\" />
     <Folder Include="Exam\Service\Practices\" />
     <Folder Include="Exam\Service\TestPapers\" />
     <Folder Include="Exam\Service\Trains\" />

+ 1 - 1
src/Hotline.Repository.SqlSugar/Service/ApiService.cs

@@ -37,7 +37,7 @@ namespace Exam.Insfrastructure.Service.Service
         /// <returns></returns>
         public virtual async Task AddAsync(TActionRequest actionRequest, CancellationToken cancellationToken)
         {
-            var entity = actionRequest.Adapt<T>();
+            var entity = _mapper.Map<T>(actionRequest);
 
             entity.ToInsert(actionRequest);
 

+ 2 - 1
src/Hotline.Share/Dtos/TestPapers/ExtractRuleDto.cs

@@ -1,4 +1,5 @@
 using Exam.Infrastructure.Data.Entity;
+using Hotline.Share.Enums.Exams;
 using System.ComponentModel;
 
 namespace Hotline.Share.Dtos.TestPapers
@@ -25,7 +26,7 @@ namespace Hotline.Share.Dtos.TestPapers
         /// 规则类型
         /// </summary>
         [Description("规则类型")]
-        public int Type { get; set; }
+        public EExamType RuleType { get; set; }
 
         /// <summary>
         /// 备注

+ 21 - 1
src/Hotline.Share/Dtos/TestPapers/TagQuestionDto.cs

@@ -1,4 +1,6 @@
 using Exam.Infrastructure.Data.Entity;
+using Exam.Infrastructure.Extensions;
+using Hotline.Share.Enums.Exams;
 using System.ComponentModel;
 
 namespace Hotline.Share.Dtos.TestPapers
@@ -15,6 +17,12 @@ namespace Hotline.Share.Dtos.TestPapers
         [Description("标签Id")]
         public string TagId { get; set; }
 
+        /// <summary>
+        /// 标签
+        /// </summary>
+        [Description("标签")]
+        public string Tag { get; set; }
+
         /// <summary>
         /// 规则Id
         /// </summary>
@@ -25,7 +33,19 @@ namespace Hotline.Share.Dtos.TestPapers
         /// 试题类型
         /// </summary>
         [Description("试题类型")]
-        public int Type { get; set; }
+        public EQuestionType QuestionType { get; set; }
+
+        /// <summary>
+        /// 试题类型
+        /// </summary>
+        [Description("试题类型")]
+        public string QuestionTypeDes
+        {
+            get
+            {
+                return QuestionType.GetDescription();
+            }
+        }
 
         /// <summary>
         /// 试题数量

+ 3 - 2
src/Hotline.Share/Requests/Exam/ExtractRulePagedRequest.cs

@@ -1,4 +1,5 @@
 using Exam.Infrastructure.Data.Interface;
+using Hotline.Share.Enums.Exams;
 
 namespace Hotline.Share.Requests.Exam
 {
@@ -8,8 +9,8 @@ namespace Hotline.Share.Requests.Exam
 
         public string Name { get; set; }
 
-        public int Type { get; set; }
+        public EExamType? ExamType { get; set; }
 
-        public int Status { get; set; }
+        public EPublicStatus? Status { get; set; }
     }
 }

+ 14 - 0
src/Hotline.Share/Requests/Exam/TagQuestionRequest.cs

@@ -0,0 +1,14 @@
+using Exam.Infrastructure.Data.Interface;
+using System.ComponentModel;
+
+namespace Hotline.Share.Requests.Exam
+{
+    public class TagQuestionRequest : IQueryRequest
+    {
+        /// <summary>
+        /// 标签Id
+        /// </summary>
+        [Description("标签Id")]
+        public List<string> TagIds { get; set; }
+    }
+}

+ 2 - 1
src/Hotline.Share/ViewResponses/Exam/ExtractRuleViewResponse.cs

@@ -1,4 +1,5 @@
 using Exam.Infrastructure.Data.Interface;
+using Hotline.Share.Enums.Exams;
 using System.ComponentModel;
 
 namespace Exam.Share.ViewResponses.Exam
@@ -27,7 +28,7 @@ namespace Exam.Share.ViewResponses.Exam
         /// 状态
         /// </summary>
         [Description("状态")]
-        public int Status { get; set; }
+        public EPublicStatus Status { get; set; }
 
         /// <summary>
         /// 排序

+ 33 - 0
src/Hotline.Share/ViewResponses/Exam/TagQuestionViewResponse.cs

@@ -0,0 +1,33 @@
+using Exam.Infrastructure.Data.Interface;
+using Hotline.Share.Enums.Exams;
+using System.ComponentModel;
+
+namespace Hotline.Share.ViewResponses.Exam
+{
+    public class TagQuestionViewResponse : IViewResponse
+    {
+        /// <summary>
+        /// 标签Id
+        /// </summary>
+        [Description("标签Id")]
+        public string TagId { get; set; }
+
+        /// <summary>
+        /// 试题类型
+        /// </summary>
+        [Description("试题类型")]
+        public EQuestionType QuestionType { get; set; }
+
+        /// <summary>
+        /// 总数
+        /// </summary>
+        [Description("总数")]
+        public int TotalCount { get; set; }
+
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Description("主键")]
+        public string Id { get; set; }
+    }
+}

+ 1 - 1
src/Hotline/Exams/ExamManages/ExtractRule.cs

@@ -30,7 +30,7 @@ namespace Exam.ExamManages
         /// </summary>
         [SugarColumn(ColumnDescription ="规则类型")]
         [Description("规则类型")]
-        public EExamMode RuleType { get; set; }
+        public EExamType RuleType { get; set; }
 
         /// <summary>
         /// 备注