Bladeren bron

Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test

libin 2 weken geleden
bovenliggende
commit
0d1e43d915
25 gewijzigde bestanden met toevoegingen van 371 en 142 verwijderingen
  1. 11 0
      src/Hotline.Api/Controllers/Exam/ExamManageController.cs
  2. 2 0
      src/Hotline.Application/Exam/Constants/ApiRoutes/ExamManageApiRoute.cs
  3. 10 2
      src/Hotline.Application/Exam/Interface/ExamManages/IExamManageService.cs
  4. 5 1
      src/Hotline.Application/Exam/Interface/Strategy/IExamStrategy.cs
  5. 3 1
      src/Hotline.Application/Exam/QueryExtensions/ExamManages/UserExamQueryExtensions.cs
  6. 71 28
      src/Hotline.Application/Exam/Service/ExamManages/ExamManageService.cs
  7. 89 46
      src/Hotline.Application/Exam/Service/ExamManages/UserExamService.cs
  8. 17 16
      src/Hotline.Application/Exam/Service/Practices/PracticeService.cs
  9. 1 1
      src/Hotline.Application/Exam/Service/Questions/QuestionService.cs
  10. 22 2
      src/Hotline.Application/Exam/Service/Trains/TrainRecordService.cs
  11. 17 3
      src/Hotline.Application/Exam/Strategy/CheckEndTimeStrategy.cs
  12. 17 3
      src/Hotline.Application/Exam/Strategy/CheckStartTimeStrategy.cs
  13. 15 3
      src/Hotline.Application/Exam/Strategy/CheckValidateCountStrategy.cs
  14. 19 3
      src/Hotline.Application/Exam/Strategy/CheckValidateTimeStrategy.cs
  15. 12 8
      src/Hotline.Application/Exam/Strategy/ExamStrategyProxy.cs
  16. 1 1
      src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs
  17. 2 2
      src/Hotline.Repository.SqlSugar/Exam/Validators/ExamManages/ExamManageValidator.cs
  18. 0 6
      src/Hotline.Share/Dtos/ExamManages/GradingExamItemDto.cs
  19. 16 3
      src/Hotline.Share/Dtos/ExamManages/GradingExamQuestionDto.cs
  20. 6 3
      src/Hotline.Share/Dtos/Trains/TrainPracticeDto.cs
  21. 3 1
      src/Hotline.Share/Exams/Extensions/ReportPagedRequestExtensions.cs
  22. 2 2
      src/Hotline.Share/Requests/Exam/UserExamResultReportPagedRequest.cs
  23. 3 2
      src/TianQue.Sdk/TQHttpClient.cs
  24. 9 2
      test/Hotline.Tests/Application/RedPackApplicationTest.cs
  25. 18 3
      test/Hotline.Tests/Mock/OrderServiceMock.cs

+ 11 - 0
src/Hotline.Api/Controllers/Exam/ExamManageController.cs

@@ -101,5 +101,16 @@ namespace Hotline.Api.Controllers.Exam
         {
             await _examManageService.UpdateStatus(statusActionRequests, HttpContext.RequestAborted);
         }
+
+        /// <summary>
+        /// 更新考试状态
+        /// </summary>
+        /// <param name="entityQueryRequest"></param>
+        /// <returns></returns>
+        [HttpPost(ExamManageApiRoute.UpdateExamStatus)]
+        public async Task UpdateExamStatus([FromBody] EntityQueryRequest entityQueryRequest)
+        {
+            await _examManageService.UpdateExamStatus(entityQueryRequest, HttpContext.RequestAborted);
+        }
     }
 }

+ 2 - 0
src/Hotline.Application/Exam/Constants/ApiRoutes/ExamManageApiRoute.cs

@@ -5,5 +5,7 @@
         public const string ImportExcel = "ImportExcel";
 
         public const string Download = "Download";
+
+        public const string UpdateExamStatus = "UpdateExamStatus";
     }
 }

+ 10 - 2
src/Hotline.Application/Exam/Interface/ExamManages/IExamManageService.cs

@@ -1,4 +1,5 @@
-using Exam.Share;
+using Exam.Infrastructure.Data.Entity;
+using Exam.Share;
 using Exam.Share.ViewResponses.Exam;
 using Hotline.Exams.ExamManages;
 using Hotline.Repository.SqlSugar.Exam.Interface;
@@ -16,6 +17,13 @@ namespace Hotline.Application.Exam.Interface.ExamManages
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         public Task GenerateTestPaper(GenerateExamTestPaperRequest generateExamTestPaperRequest, CancellationToken cancellationToken);
-
+        
+        /// <summary>
+        /// 更新考试状态
+        /// </summary>
+        /// <param name="entityQueryRequest"></param>
+        /// <param name="requestAborted"></param>
+        /// <returns></returns>
+        public Task UpdateExamStatus(EntityQueryRequest entityQueryRequest, CancellationToken requestAborted);
     }
 }

+ 5 - 1
src/Hotline.Application/Exam/Interface/Strategy/IExamStrategy.cs

@@ -16,6 +16,10 @@ namespace Hotline.Application.Exam.Interface.Strategy
 
         public string ErroMessage { get; }
 
-        public Action CallBack { get; set; }
+        public Func<object> CallBack { get; set; }
+
+        public object GetResult();
+
+
     }
 }

+ 3 - 1
src/Hotline.Application/Exam/QueryExtensions/ExamManages/UserExamQueryExtensions.cs

@@ -103,7 +103,9 @@ namespace Hotline.Application.Exam.QueryExtensions.ExamManages
 
             expression = ExpressionableUtility.CreateExpression<ExamUserExam>()
             .AndIF(userExamResultReportPagedRequest.MinScore.IsNotNull(), x => x.Score >= userExamResultReportPagedRequest.MinScore)
-            .AndIF(userExamResultReportPagedRequest.MaxScore.IsNotNull(), x => x.Score <= userExamResultReportPagedRequest.MaxScore)
+            .AndIF(userExamResultReportPagedRequest.MaxScore.IsNotNull() && userExamResultReportPagedRequest.MinScore.IsNull(), x => x.Score <= userExamResultReportPagedRequest.MaxScore || x.Score== null)
+            .AndIF(userExamResultReportPagedRequest.MaxScore.IsNotNull() && userExamResultReportPagedRequest.MinScore.IsNotNull(), x => x.Score <= userExamResultReportPagedRequest.MaxScore)
+            .And(x=>x.ExamStatus == Share.Enums.Exams.EExamStatus.Complete)
             .ToExpression();
 
             return expression;

+ 71 - 28
src/Hotline.Application/Exam/Service/ExamManages/ExamManageService.cs

@@ -328,36 +328,11 @@ namespace Hotline.Application.Exam.Service.ExamManages
             }
         }
 
-        private async Task<List<ExamQuestion>> GetQuestions(ExamManage examManage)
-        {
-            var questionRepository = new ExamRepository<ExamQuestion>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
-
-            var questionTable = questionRepository.Queryable();
-            var testPaperItemTable = _testPaperItemRepository.Queryable().Where(x => x.TestPaperId == examManage.TestPaperId);
-
-            var questions = questionTable.InnerJoin(testPaperItemTable, (q, t) => q.Id == t.QuestionId)
-                .Select((q, t) => q);
-
-            return await questions.ToListAsync();
-        }
-
-        private async Task<List<ExamTagQuestion>> GetTagQuestions(ExamManage examManage)
+        public async Task UpdateExamStatus(EntityQueryRequest entityQueryRequest, CancellationToken requestAborted)
         {
-            var extractRuleRepository = new ExamRepository<ExamExtractRule>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
-            var ruleTagRepository = new ExamRepository<ExamRuleTag>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
-            var tagQuestionRepository = new ExamRepository<ExamTagQuestion>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
-
-          
-            var extractRuleTable = extractRuleRepository.Queryable().Where(x=>x.Id == examManage.ExtractRuleId && x.RuleType == examManage.ExamType);
-            var ruleTagTable = ruleTagRepository.Queryable();
-            var tagQuestionTable = tagQuestionRepository.Queryable();
-
-            var tagQuestions = await tagQuestionTable
-                .InnerJoin(ruleTagTable, (q, rt) => q.TagId == rt.TagId)
-                .InnerJoin(extractRuleTable, (q, rt, x) => rt.RuleId == x.Id)
-                .Select((q, rt, x) => q).ToListAsync();
+            List<ExamManage> examManages = await UpdateExamManageStatus(entityQueryRequest, requestAborted);
 
-            return tagQuestions;
+            //await UdpateUserExam(examManages, requestAborted);
 
         }
         #endregion
@@ -679,6 +654,74 @@ namespace Hotline.Application.Exam.Service.ExamManages
             }
 
         }
+
+        private async Task<List<ExamQuestion>> GetQuestions(ExamManage examManage)
+        {
+            var questionRepository = new ExamRepository<ExamQuestion>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
+
+            var questionTable = questionRepository.Queryable();
+            var testPaperItemTable = _testPaperItemRepository.Queryable().Where(x => x.TestPaperId == examManage.TestPaperId);
+
+            var questions = questionTable.InnerJoin(testPaperItemTable, (q, t) => q.Id == t.QuestionId)
+                .Select((q, t) => q);
+
+            return await questions.ToListAsync();
+        }
+
+        private async Task<List<ExamTagQuestion>> GetTagQuestions(ExamManage examManage)
+        {
+            var extractRuleRepository = new ExamRepository<ExamExtractRule>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
+            var ruleTagRepository = new ExamRepository<ExamRuleTag>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
+            var tagQuestionRepository = new ExamRepository<ExamTagQuestion>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
+
+
+            var extractRuleTable = extractRuleRepository.Queryable().Where(x => x.Id == examManage.ExtractRuleId && x.RuleType == examManage.ExamType);
+            var ruleTagTable = ruleTagRepository.Queryable();
+            var tagQuestionTable = tagQuestionRepository.Queryable();
+
+            var tagQuestions = await tagQuestionTable
+                .InnerJoin(ruleTagTable, (q, rt) => q.TagId == rt.TagId)
+                .InnerJoin(extractRuleTable, (q, rt, x) => rt.RuleId == x.Id)
+                .Select((q, rt, x) => q).ToListAsync();
+
+            return tagQuestions;
+
+        }
+
+
+        private async Task UdpateUserExam(List<ExamManage> examManages, CancellationToken requestAborted)
+        {
+            var examIds = examManages.Select(x => x.Id).ToList();
+            var userExams = await _userExamRepository.Queryable().Where(x => examIds.Contains(x.ExamId)).ToListAsync();
+
+            userExams.ForEach(item =>
+            {
+                item.ExamStatus = Share.Enums.Exams.EExamStatus.Complete;
+            });
+
+            userExams.ToUpdate(_sessionContext);
+
+            await _userExamRepository.UpdateWithValidateAsync(userExams, requestAborted);
+        }
+
+        private async Task<List<ExamManage>> UpdateExamManageStatus(EntityQueryRequest entityQueryRequest, CancellationToken requestAborted)
+        {
+            var queryable = _repository.Queryable()
+                .WhereIF(entityQueryRequest != null && entityQueryRequest.Ids != null, x => entityQueryRequest.Ids.Contains(x.Id))
+                .Where(x => x.EndTime < DateTime.Now);
+            var examManages = await queryable.ToListAsync();
+
+            examManages.ForEach(item =>
+            {
+                item.ExamStatus = Share.Enums.Exams.EExamStatus.Complete;
+            });
+
+            examManages.ToUpdate(_sessionContext);
+
+            await _repository.UpdateWithValidateAsync(examManages, requestAborted);
+
+            return examManages;
+        }
         #endregion
     }
 }

+ 89 - 46
src/Hotline.Application/Exam/Service/ExamManages/UserExamService.cs

@@ -142,8 +142,8 @@ namespace Hotline.Application.Exam.Service.ExamManages
             var examAnswerRepository = new ExamRepository<ExamAnswer>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var userExamItemRepository = new ExamRepository<ExamUserExamItem>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
 
-            var userExamItemTable = userExamItemRepository.Queryable().Where(i=> i.QuestionId == examQuestionRequest.QuestionId);
-            var userExamTable = _repository.Queryable().Where(u=> u.UserId == _sessionContext.UserId);
+            var userExamItemTable = userExamItemRepository.Queryable().Where(i => i.QuestionId == examQuestionRequest.QuestionId);
+            var userExamTable = _repository.Queryable().Where(u => u.UserId == _sessionContext.UserId);
             var examAnswerTable = examAnswerRepository.Queryable();
 
             var examAnswers = await examAnswerTable.InnerJoin(userExamItemTable, (e, i) => e.UserExamItemId == i.Id)
@@ -183,9 +183,9 @@ namespace Hotline.Application.Exam.Service.ExamManages
             var result = queryable.GroupBy(x => x.QuestionType).Select(m => new ExamQuestionViewResponse
             {
                 QuestionType = m.Key,
-                Questions = m.Select(n => new SimpleViewResponse
+                Questions = m.GroupBy(g => g.QuestionId).Select(n => new SimpleViewResponse
                 {
-                    Id = n.QuestionId
+                    Id = n.Key
                 }).ToList()
             }).ToList();
 
@@ -288,7 +288,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
             if (userExams.All(x => x.IsSubmit))
             {
-                var examManage = await _examManageRepository.GetAsync(x=>x.Id == examId);
+                var examManage = await _examManageRepository.GetAsync(x => x.Id == examId);
 
                 examManage.ExamStatus = EExamStatus.Complete;
 
@@ -304,6 +304,8 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
             if (!startExamViewResponse.CheckValidate())
             {
+                await SetExamStatus(userExam, startExamViewResponse, cancellationToken);
+
                 return startExamViewResponse;
             }
 
@@ -322,6 +324,16 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
             return startExamViewResponse;
         }
+
+        private async Task SetExamStatus(ExamUserExam userExam, StartExamViewResponse startExamViewResponse, CancellationToken cancellationToken)
+        {
+            userExam.ExamStatus = startExamViewResponse.IsCompleted ? EExamStatus.Complete : EExamStatus.NoStart;
+
+            userExam.ToUpdate(_sessionContext);
+
+            await _repository.UpdateWithValidateAsync(userExam, cancellationToken);
+        }
+
         public async Task<StartExamViewResponse> StartUserExamAsync(StartUserExamDto startUserExamDto, CancellationToken cancellationToken)
         {
             var userExam = await _repository.GetAsync(x => x.Id == startUserExamDto.Id);
@@ -338,6 +350,8 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
             if (!startExamViewResponse.CheckValidate())
             {
+                await SetExamStatus(userExam, startExamViewResponse, cancellationToken);
+
                 return startExamViewResponse;
             }
 
@@ -363,7 +377,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
         private async Task<StartExamViewResponse> CheckExamValid(ExamUserExam examUserExam, CancellationToken cancellationToken)
         {
 
-            var examManage = await _examManageRepository.Queryable().Where(x => x.Id == examUserExam.ExamId).FirstAsync();            
+            var examManage = await _examManageRepository.Queryable().Where(x => x.Id == examUserExam.ExamId).FirstAsync();
 
             var startExamViewResponse = new StartExamViewResponse
             {
@@ -382,15 +396,18 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 startExamViewResponse = AddCheckValidateTimeStrategy(examUserExam, examManage, startExamViewResponse, examStrategys);
                 startExamViewResponse = AddCheckValidateCountStrategy(examUserExam, examManage, startExamViewResponse, examStrategys);
 
+                examStrategyProxy.Initial(examStrategys);
+
                 if (!examStrategyProxy.Validate())
                 {
+                    startExamViewResponse = (StartExamViewResponse)examStrategyProxy.GetResult();
                     return startExamViewResponse;
                 }
             }
 
             startExamViewResponse.IsStart = true;
 
-            if (examManage.ExamStatus== EExamStatus.NoStart)
+            if (examManage.ExamStatus == EExamStatus.NoStart)
             {
                 await UpdateExamStatus(examManage, cancellationToken);
             }
@@ -417,12 +434,16 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 {
                     CallBack = () =>
                     {
-                        startExamViewResponse = new StartExamViewResponse
+                        var response = new StartExamViewResponse
                         {
                             IsJoin = false,
                             IsStart = false,
-                            IsCompleted = true
+                            IsCompleted = true,
+                            StartTime = examUserExam.StartTime,
+                            TimeSpan = examManage.TimeSpan
                         };
+
+                        return response;
                     }
                 };
                 examStrategys.Add(checkStartTime);
@@ -436,12 +457,16 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 {
                     CallBack = () =>
                     {
-                        startExamViewResponse = new StartExamViewResponse
+                        var response = new StartExamViewResponse
                         {
                             IsJoin = false,
                             IsStart = false,
-                            IsCompleted = true
+                            IsCompleted = true,
+                            StartTime = examUserExam.StartTime,
+                            TimeSpan = examManage.TimeSpan
                         };
+
+                        return response;
                     }
                 };
                 examStrategys.Add(checkStartTime);
@@ -458,12 +483,16 @@ namespace Hotline.Application.Exam.Service.ExamManages
             {
                 CallBack = () =>
                 {
-                    startExamViewResponse = new StartExamViewResponse
+                    var response = new StartExamViewResponse
                     {
                         IsJoin = false,
                         IsStart = false,
-                        IsCompleted = true
+                        IsCompleted = true,
+                        StartTime = examUserExam.StartTime,
+                        TimeSpan = examManage.TimeSpan
                     };
+
+                    return response;
                 }
             };
             examStrategys.Add(checkStartTime);
@@ -478,12 +507,16 @@ namespace Hotline.Application.Exam.Service.ExamManages
             {
                 CallBack = () =>
                 {
-                    startExamViewResponse = new StartExamViewResponse
+                    var response = new StartExamViewResponse
                     {
                         IsJoin = false,
                         IsStart = false,
-                        IsCompleted = true
+                        IsCompleted = true,
+                        StartTime = examUserExam.StartTime,
+                        TimeSpan = examManage.TimeSpan
                     };
+
+                    return response;
                 }
             };
             examStrategys.Add(checkStartTime);
@@ -498,12 +531,16 @@ namespace Hotline.Application.Exam.Service.ExamManages
             {
                 CallBack = () =>
                 {
-                    startExamViewResponse = new StartExamViewResponse
+                    var response = new StartExamViewResponse
                     {
                         IsJoin = false,
                         IsStart = false,
-                        IsCompleted = false
+                        IsCompleted = false,
+                        StartTime = examUserExam.StartTime,
+                        TimeSpan = examManage.TimeSpan
                     };
+
+                    return response;
                 }
             };
             examStrategys.Add(checkStartTime);
@@ -571,7 +608,8 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 Label = qo.Label,
                 IsAnswer = qo.IsAnswer,
                 IsSelected = o.Id != null,
-                Score = s.Score
+                QuestionScore = s.Score,
+                Score = i.Score
             }
                 );
 
@@ -586,6 +624,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 Answer = g.FirstOrDefault().Answer,
                 QuestionType = g.Key.QuestionType,
                 Id = g.Key.Id,
+                QuestionScore = g.FirstOrDefault().QuestionScore,
                 Score = g.FirstOrDefault().Score,
                 Title = g.FirstOrDefault().Title,
                 CorrectAnswer = g.Key.QuestionType.CheckSelectType() ? string.Join(",", g.Where(i => i.IsAnswer).Select(n => n.Label).Distinct()) : g.FirstOrDefault()?.CorrectAnswer
@@ -605,7 +644,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
         public async Task<UnExamUserPageViewResponse> GetUnExamUsers(UnExamUserReportPagedRequest unExamUserReportPagedRequest)
         {
-            unExamUserReportPagedRequest.ResoleEndTime();
+            unExamUserReportPagedRequest.ResolveEndTime();
 
             var examManageRepository = new ExamRepository<ExamManage>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var userRepository = new ExamRepository<User>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
@@ -638,7 +677,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
         public async Task<UserExamResultPageViewResponse> GetUserExamResults(UserExamResultReportPagedRequest userExamResultReportPagedRequest)
         {
-            userExamResultReportPagedRequest.ResoleEndTime();
+            userExamResultReportPagedRequest.ResolveEndTime();
 
             var examManageRepository = new ExamRepository<ExamManage>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var userRepository = new ExamRepository<User>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
@@ -660,7 +699,9 @@ namespace Hotline.Application.Exam.Service.ExamManages
                     CutoffScore = e.CutoffScore,
                     Score = ue.Score ?? 0,
 
-                });
+                })
+                .MergeTable()
+                .OrderByDescending(x => x.Score);
 
             var total = await queryResult.CountAsync();
             var items = await queryResult.ToPageListAsync(userExamResultReportPagedRequest.PageIndex, userExamResultReportPagedRequest.PageSize);
@@ -677,7 +718,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
         public async Task<GradingResultPageViewResponse> GetGradingResultPagedList(GradingPagedRequest gradingPagedRequest)
         {
             // 只要有阅卷记录就在已阅卷列表中,已阅卷和未阅卷会有重复数据,只有所有记录都已阅卷才会从未阅卷列表中排除
-            var userExamTable =  _repository.Queryable().WhereIF(gradingPagedRequest.IsCheck!=null, x => x.IsCheck == gradingPagedRequest.IsCheck && x.IsSubmit);
+            var userExamTable = _repository.Queryable().WhereIF(gradingPagedRequest.IsCheck != null, x => x.IsCheck == gradingPagedRequest.IsCheck && x.IsSubmit);
 
             var examManageTable = new ExamRepository<ExamManage>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
 
@@ -696,7 +737,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 TotalScore = e.TotalScore,
                 ExamName = e.Name,
                 ExamCode = e.Code,
-                IsCheck = SqlFunc.Subqueryable<ExamUserExam>().Where(x=>x.ExamId == e.Id && x.IsCheck).Any(),
+                IsCheck = SqlFunc.Subqueryable<ExamUserExam>().Where(x => x.ExamId == e.Id && x.IsCheck).Any(),
                 Id = e.Id,
                 Remark = e.Remark
             });
@@ -726,7 +767,9 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 {
                     var gradingExamItemDto = batchGradingExamItemDto.Items.Find(m => m.UserExamItemId == x.Id);
 
-                    var updateUserExamItem = _mapper.Map<GradingExamItemDto, ExamUserExamItem>(gradingExamItemDto,x);
+                    var updateUserExamItem = _mapper.Map<GradingExamItemDto, ExamUserExamItem>(gradingExamItemDto, x);
+
+                    updateUserExamItem.IsCheck = true;
 
                     updateUserExamItems.Add(updateUserExamItem);
                 });
@@ -737,27 +780,27 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
                 var userExamId = userExamItems.FirstOrDefault()?.UserExamId;
                 // 计算本次考试得分
-                var userExamItemsInCheck = await _userExamItemRepository.Queryable().Where(x => x.UserExamId == userExamId).ToListAsync();
-                var updateExamItemDTOs = new List<UpdateUserExamItemDto>();
-                userExamItemsInCheck.ForEach(x =>
-                {
-                    var updateUserExamItem = _mapper.Map<ExamUserExamItem, UpdateUserExamItemDto>(x);
-
-                    updateExamItemDTOs.Add(updateUserExamItem);
-                });
-                await CalcuteExamItemScore(_userExamItemRepository, updateExamItemDTOs,cancellationToken);
+                var userExamItemsInCheck = await _userExamItemRepository.Queryable()
+                    .InnerJoin<ExamQuestionBak>((u, q) => u.QuestionId == q.QuestionId)
+                    .Where((u, q) => u.UserExamId == userExamId && (q.QuestionType == EQuestionType.Single || q.QuestionType == EQuestionType.Multi || q.QuestionType == EQuestionType.Judge)).Select((u, q) => new UpdateUserExamItemDto
+                    {
+                        QuestionId = u.QuestionId,
+                        QuestionType = q.QuestionType,
+                        UserExamId = u.UserExamId,
+                    }).Distinct().ToListAsync();
+                await CalcuteExamItemScore(_userExamItemRepository, userExamItemsInCheck, cancellationToken);
 
                 await CalcuteTotalScore(_userExamItemRepository, userExamId, cancellationToken);
 
             }
 
-            
+
         }
 
         public async Task<List<ExamUserViewResponse>> GetUserListAsync(ExamUserQueryRequest examUserQueryRequest)
         {
-            var userExamTable =  _repository.Queryable().Where(x => x.ExamId == examUserQueryRequest.ExamId);
-            var queryable = await userExamTable.InnerJoin<User>((ux, u) => ux.UserId == u.Id).Select((ux,u) => new ExamUserViewResponse
+            var userExamTable = _repository.Queryable().Where(x => x.ExamId == examUserQueryRequest.ExamId);
+            var queryable = await userExamTable.InnerJoin<User>((ux, u) => ux.UserId == u.Id).Select((ux, u) => new ExamUserViewResponse
             {
                 ExamId = ux.ExamId,
                 UserId = ux.UserId,
@@ -813,8 +856,8 @@ namespace Hotline.Application.Exam.Service.ExamManages
             var examManageRepository = new ExamRepository<ExamManage>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var testPaperItemRepository = new ExamRepository<Exams.ExamManages.ExamQuestionBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var examQuestionScoreRepository = new ExamRepository<ExamQuestionScoreBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
-            var testPaperOptionsTable = testPaperItemOptionsRepository.Queryable().Where(x => questionIds.Contains( x.QuestionId ) && x.IsAnswer);
-            var testPaperItemTable = testPaperItemRepository.Queryable().Where(x => x.QuestionType== EQuestionType.Single || x.QuestionType == EQuestionType.Multi || x.QuestionType == EQuestionType.Judge);
+            var testPaperOptionsTable = testPaperItemOptionsRepository.Queryable().Where(x => questionIds.Contains(x.QuestionId) && x.IsAnswer);
+            var testPaperItemTable = testPaperItemRepository.Queryable().Where(x => x.QuestionType == EQuestionType.Single || x.QuestionType == EQuestionType.Multi || x.QuestionType == EQuestionType.Judge);
             var userExamTable = _repository.Queryable().Where(x => userExamIds.Contains(x.Id));
             var examManageTable = examManageRepository.Queryable();
             var testPaperOptionIds = await testPaperOptionsTable.InnerJoin(testPaperItemTable, (t, i) => t.ExamQuestionId == i.Id)
@@ -831,7 +874,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
 
             foreach (var addUserExamItemDto in addUserExamItemDtos)
-            {              
+            {
                 var isCorrect = userExamItemOptions.Select(x => x.QuestionOptionId).OrderBy(x => x).SequenceEqual(testPaperOptionIds.OrderBy(x => x));
                 var userExamItem = userExamItems.FirstOrDefault(x => x.QuestionId == addUserExamItemDto.QuestionId);
                 if (userExamItem != null)
@@ -839,10 +882,10 @@ namespace Hotline.Application.Exam.Service.ExamManages
                     userExamItem.IsCheck = true;
                     userExamItem.Score = isCorrect ? examQuesiontScores.FirstOrDefault(x => x.QuestionType == addUserExamItemDto.QuestionType)?.Score : 0;
                     userExamItem.ToUpdate(_sessionContext);
-                }               
+                }
             }
 
-          
+
             await userExamItemRepository.UpdateWithValidateAsync(userExamItems, cancellationToken);
         }
 
@@ -868,11 +911,11 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 if (examManage != null)
                 {
                     userExam.IsSuccess = userExam.Score > examManage.CutoffScore;
-                }               
+                }
 
                 userExam.ToUpdate(_sessionContext);
 
-                await _repository.UpdateWithValidateAsync(userExam,cancellationToken);
+                await _repository.UpdateWithValidateAsync(userExam, cancellationToken);
             }
         }
 
@@ -883,7 +926,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             userExamItem.UserExamItemOptionses = await AddUserExamItemOptions(addUserExamItemDto, cancellationToken);
 
             userExamItem.ExamAnswers = await AddExamAnswer(addUserExamItemDto, userExamItem.Id, cancellationToken);
-            
+
 
             await userExamItemRepository.AddNav(userExamItem)
                 .Include(x => x.UserExamItemOptionses)
@@ -938,7 +981,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             return null;
         }
 
-        private async Task<List<ExamAnswer>> AddExamAnswer(AddUserExamItemDto addUserExamItemDto,string id, CancellationToken cancellationToken)
+        private async Task<List<ExamAnswer>> AddExamAnswer(AddUserExamItemDto addUserExamItemDto, string id, CancellationToken cancellationToken)
         {
             if (addUserExamItemDto.QuestionType.CheckSelectType()) return null;
 
@@ -1054,7 +1097,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
                     await _examAnswerRepository.ValidateAddAsync(examAnswer, cancellationToken);
 
                     examAnswers.Add(examAnswer);
-                }                
+                }
 
                 return examAnswers;
             }

+ 17 - 16
src/Hotline.Application/Exam/Service/Practices/PracticeService.cs

@@ -39,6 +39,7 @@ using XF.Domain.Dependency;
 using Hotline.Repository.SqlSugar.Exam.Service;
 using Hotline.Repository.SqlSugar.Exam.Extensions;
 using Exam.Infrastructure.Extensions;
+using Consul;
 
 namespace Hotline.Application.Exam.Service.Practices
 {
@@ -593,44 +594,44 @@ namespace Hotline.Application.Exam.Service.Practices
             var tagIds = actionRequest.PracticeTagDtos.Select(x => x.TagId).ToList();
 
             var questionTagRepostiory = new ExamRepository<ExamQuestionTag>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
+
             var questionRepository = new ExamRepository<ExamQuestion>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
 
-            var questionTagTable = questionTagRepostiory.Queryable();
-            var questionTable = questionRepository.Queryable().Where(x=>!(x.QuestionType == Share.Enums.Exams.EQuestionType.Single && x.QuestionType == Share.Enums.Exams.EQuestionType.Multi || x.QuestionType == Share.Enums.Exams.EQuestionType.Judge));
+            ISugarQueryable<ExamQuestionTag, ExamQuestion> questionTable = GetCheckQuestions(questionTagRepostiory);
 
             // 按照标签获取试题,至少取一道
             if (actionRequest.Count < actionRequest.PracticeTagDtos.Count)
             {
-                questionTagTable = questionTagTable.Where(x => tagIds.Contains(x.TagId)).Take(actionRequest.Count);
+                var queryResult = questionTable.Where((qt, q) => tagIds.Contains(qt.TagId)).Take(actionRequest.Count).Select((qt, q) => q);
+
+                return await queryResult.ToListAsync();
             }
             else
             {
-                var unionQuestions = new List<ISugarQueryable<ExamQuestionTag>>();
+                var unionQuestions = new List<ISugarQueryable<ExamQuestion>>();
                 var ids = new List<string>();
                 // 保证每个标签至少获取一道题
                 tagIds.ForEach(v =>
                 {
-                    var unionQuestion = questionTagTable;
-                    unionQuestion= unionQuestion.Where(x => x.TagId == v).Take(1);
-                    ids.Add(questionTagRepostiory.Queryable().Where(x => x.TagId == v).Select(x => x.Id).First());
+                    var unionQuestion = GetCheckQuestions(questionTagRepostiory).Where((qt, q) => qt.TagId == v).Take(1).Select((qt, q) => q);
+                    ids.Add(GetCheckQuestions(questionTagRepostiory).Where((qt, q) => qt.TagId == v).Select(qt => qt.Id).First());
                     unionQuestions.Add(unionQuestion);
-                    questionTagTable = questionTagRepostiory.Queryable();
                 });
 
-                var mainQuesiton = questionTagTable;
-                mainQuesiton = mainQuesiton.Where(x => tagIds.Contains(x.TagId) && !ids.Contains(x.Id)).Take(actionRequest.Count - tagIds.Count);
+                var mainQuesiton = GetCheckQuestions(questionTagRepostiory).Where((qt, q) => tagIds.Contains(qt.TagId) && !ids.Contains(qt.Id)).Take(actionRequest.Count - tagIds.Count).Select((qt, q) => q);
 
                 unionQuestions.Add(mainQuesiton);
 
-                questionTagTable = questionTagRepostiory.Queryable();
-                questionTagTable = questionTagRepostiory.UnionAll(unionQuestions.ToArray());
-            }
+                var queryResult = questionRepository.UnionAll(unionQuestions.ToArray());
 
-            var queryResult = questionTagTable.InnerJoin(questionTable, (t, q) => t.QuestionId == q.Id)
-                              .Select((t, q) => q);
+                return await queryResult.ToListAsync();
+            }
 
-            return await queryResult.ToListAsync();
+        }
 
+        private static ISugarQueryable<ExamQuestionTag, ExamQuestion> GetCheckQuestions(ExamRepository<ExamQuestionTag> questionTagRepostiory)
+        {
+            return questionTagRepostiory.Queryable().InnerJoin<ExamQuestion>((qt, q) => qt.QuestionId == q.Id).Where((qt, q) => q.QuestionType == Share.Enums.Exams.EQuestionType.Single || q.QuestionType == Share.Enums.Exams.EQuestionType.Multi || q.QuestionType == Share.Enums.Exams.EQuestionType.Judge);
         }
 
         private async Task<string> GenerateCode(string codePrefix, int length)

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

@@ -980,7 +980,7 @@ namespace Hotline.Application.Exam.Service.Questions
 
             var questionAnswerDto = _mapper.Map<QuestionAnswerDto>(questionAnswer);
 
-            return questionAnswerDto;
+            return questionAnswerDto ?? new QuestionAnswerDto();
         }
 
         private async Task<List<QuestionTagDto>> GetQuestionTags(EntityQueryRequest entityQueryRequest)

+ 22 - 2
src/Hotline.Application/Exam/Service/Trains/TrainRecordService.cs

@@ -166,9 +166,29 @@ namespace Hotline.Application.Exam.Service.Trains
 
             trainPracticeDto.TrainPracticeKnowladgeDtos = await GetTrainPracticeKnowladges(trainPracticeRequest);
 
+            trainPracticeDto.AddTrainRecordAnswerDto = await GetTrainRecordAnswer(trainPracticeRequest);
+
             return trainPracticeDto;
         }
 
+        private async Task<AddTrainRecordAnswerDto?> GetTrainRecordAnswer(TrainPracticeRequest trainPracticeRequest)
+        {
+            var trainRecordAnswerRepository = new ExamRepository<ExamTrainRecordAnswer>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
+            var queryable = trainRecordAnswerRepository.Queryable()
+               .InnerJoin<ExamTrainRecord>((t, x) => t.TrainRecordId == x.Id)
+               .InnerJoin<ExamTrainPlanTemplate>((t, x, p) => x.TrainPlanId == p.TrainPlanId)
+               .InnerJoin<ExamTrainPractice>((t, x, p, tp) => p.TrainTemplateId == tp.TrainTemplateId)
+               .Where((t, x, p, tp) => tp.Id == trainPracticeRequest.TrainPracticeId)
+               .Select((t, x, p, tp) => t);
+
+            var examTrainRecordAnswer = await queryable
+                .FirstAsync();
+
+            var addTrainRecordAnswerDto = _mapper.Map<ExamTrainRecordAnswer, AddTrainRecordAnswerDto>(examTrainRecordAnswer);
+
+            return addTrainRecordAnswerDto;
+        }
+
         public async Task<SimpleTrainPracticeDto> GetSimpleTrainPracticeAsync(TrainPracticeRequest trainPracticeRequest)
         {
             SqlSugar.ISugarQueryable<ExamTrainPractice> trainPractices = GetTrainPractices(trainPracticeRequest);
@@ -188,7 +208,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
         public async Task<TrainResultPagedViewResponse> AnalysisTrainResult(TrainResultReportPagedRequest trainResultReportPagedRequest)
         {
-            trainResultReportPagedRequest.ResoleEndTime();
+            trainResultReportPagedRequest.ResolveEndTime();
 
             var expression = trainResultReportPagedRequest.GetExpression();
             var templateExpression = trainResultReportPagedRequest.GetTemplateExpression();
@@ -230,7 +250,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
         public async Task<TrainResultRateViewResponse> CalcuteAnalysisRate(TrainResultReportPagedRequest trainResultReportPagedRequest)
         {
-            trainResultReportPagedRequest.ResoleEndTime();
+            trainResultReportPagedRequest.ResolveEndTime();
 
             var expression = trainResultReportPagedRequest.GetExpression();
             var templateExpression = trainResultReportPagedRequest.GetTemplateExpression();

+ 17 - 3
src/Hotline.Application/Exam/Strategy/CheckEndTimeStrategy.cs

@@ -11,7 +11,7 @@ namespace Hotline.Application.Exam.Strategy
     {
         public string ErroMessage { get; private set; }
 
-        public Action CallBack { get; set; }
+        public Func<object> CallBack { get; set; }
 
         private IExamStrategy _next;
 
@@ -19,6 +19,9 @@ namespace Hotline.Application.Exam.Strategy
 
         private DateTime? _startTime;
 
+        private IExamStrategy _current;
+
+
         public CheckEndTimeStrategy(DateTime examEndTime, DateTime? startTime)
         {
             _examEndTime = examEndTime;
@@ -35,12 +38,23 @@ namespace Hotline.Application.Exam.Strategy
         {
             if (_examEndTime < _startTime)
             {
-                if (CallBack != null)
-                    CallBack();
                 ErroMessage = "考试结束";
+                _current = this;
                 return false;
             }
+            _current = _next;
+
+            if (_next == null) return true;
+
             return _next.Validate();
         }
+
+        public object GetResult()
+        {
+            if (_current != null && _current.CallBack != null)
+                return _current.CallBack();
+
+            return null;
+        }
     }
 }

+ 17 - 3
src/Hotline.Application/Exam/Strategy/CheckStartTimeStrategy.cs

@@ -6,7 +6,7 @@ namespace Hotline.Application.Exam.Strategy
     {
         public string ErroMessage { get; private set; }
 
-        public Action CallBack { get; set; }
+        public Func<object> CallBack { get; set; }
 
         private IExamStrategy _next;
 
@@ -14,6 +14,9 @@ namespace Hotline.Application.Exam.Strategy
 
         private DateTime? _startTime;
 
+        private IExamStrategy _current;
+
+
         public CheckStartTimeStrategy(DateTime examStartTime,DateTime? startTime)
         {
             _examStartTime = examStartTime;
@@ -30,12 +33,23 @@ namespace Hotline.Application.Exam.Strategy
         {
             if (_examStartTime > _startTime)
             {
-                if (CallBack != null)
-                    CallBack();
                 ErroMessage = "考试未开始";
+                _current = this;
                 return false;
             }
+            _current = _next;
+
+            if (_next == null) return true;
+
             return _next.Validate();
         }
+
+        public object GetResult()
+        {
+            if (_current != null && _current.CallBack != null)
+                return _current.CallBack();
+
+            return null;
+        }
     }
 }

+ 15 - 3
src/Hotline.Application/Exam/Strategy/CheckValidateCountStrategy.cs

@@ -11,7 +11,7 @@ namespace Hotline.Application.Exam.Strategy
     {
         public string ErroMessage { get; private set; }
 
-        public Action CallBack { get; set; }
+        public Func<object> CallBack { get; set; }
 
         private IExamStrategy _next;
 
@@ -19,6 +19,8 @@ namespace Hotline.Application.Exam.Strategy
 
         private int _count;
 
+        private IExamStrategy _current;
+
         public CheckValidateCountStrategy(int validateCount, int count)
         {
             _validateCount = validateCount;
@@ -35,12 +37,22 @@ namespace Hotline.Application.Exam.Strategy
         {
             if (_count>=_validateCount)
             {
-                if (CallBack != null)
-                    CallBack();
                 ErroMessage = "已超过可考次数,考试结束";
+                _current = this;
                 return false;
             }
+            _current = _next;
+
+            if (_next == null) return true;
+
             return _next.Validate();
         }
+        public object GetResult()
+        {
+            if (_current!=null && _current.CallBack != null)
+                return _current.CallBack();
+
+            return null;
+        }
     }
 }

+ 19 - 3
src/Hotline.Application/Exam/Strategy/CheckValidateTimeStrategy.cs

@@ -11,7 +11,7 @@ namespace Hotline.Application.Exam.Strategy
     {
         public string ErroMessage { get; private set; }
 
-        public Action CallBack { get; set; }
+        public Func<object> CallBack { get; set; }
 
         private IExamStrategy _next;
 
@@ -19,6 +19,9 @@ namespace Hotline.Application.Exam.Strategy
 
         private int _timeSpan;
 
+        private IExamStrategy _current;
+
+
         public CheckValidateTimeStrategy(int timeSpan, DateTime? startTime)
         {
             _startTime = startTime;
@@ -35,12 +38,25 @@ namespace Hotline.Application.Exam.Strategy
         {
             if (_startTime.Value.AddMinutes(_timeSpan) < DateTime.Now)
             {
-                if (CallBack != null)
-                    CallBack();
                 ErroMessage = "考试已超时,考试结束";
+                _current = this;
                 return false;
             }
+            _current = _next;
+
+            if (_next == null) return true;
+
             return _next.Validate();
         }
+
+
+
+        public object GetResult()
+        {
+            if (_current != null && _current.CallBack != null)
+                return _current.CallBack();
+
+            return null;
+        }
     }
 }

+ 12 - 8
src/Hotline.Application/Exam/Strategy/ExamStrategyProxy.cs

@@ -14,6 +14,10 @@ namespace Hotline.Application.Exam.Strategy
         /// </summary>
         public string ErrorMessage { get; private set; }
 
+        public ExamStrategyProxy()
+        {
+        }
+
 
         public bool Validate()
         {
@@ -26,19 +30,19 @@ namespace Hotline.Application.Exam.Strategy
                 }
                 else
                 {
-                    ErrorMessage = _current.ErroMessage;
-                    if (_current.CallBack != null)
-                    {
-                        _current.CallBack();
-                    }
-                    return false;
-                }
+                    ErrorMessage = _current.ErroMessage;                  
 
-                
+                    return false;
+                }                
             }
             return true;
         }
 
+        public object GetResult()
+        {
+            return _current.GetResult();
+        }
+
         public void Initial(List<IExamStrategy> examStrategys)
         {
             if (examStrategys == null || examStrategys.Count <= 0) return;

+ 1 - 1
src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs

@@ -1122,7 +1122,7 @@ public abstract class SnapshotApplicationBase
             Items = await _notificationReceiverRepository.Queryable()
                 .LeftJoin<Notification>((receiver, notify) => notify.Id == receiver.NotificationId)
                 .LeftJoin<SnapshotBulletin>((receiver, notify, bulletin) => bulletin.Id == notify.ExternalId)
-                .Where((receiver, notify, bulletin) => bulletin.Shape == EBulletinShape.Message)
+                .Where((receiver, notify, bulletin) => bulletin.Shape == EBulletinShape.Message && receiver.ReceiverId == _sessionContext.UserId)
                 .GroupBy((receiver, notify, bulletin) => new { notify.Id, notify.ExternalId, notify.Title})
                 .Select((receiver, notify, bulletin) => new PointsBulletinItemsOutDto
                 {

+ 2 - 2
src/Hotline.Repository.SqlSugar/Exam/Validators/ExamManages/ExamManageValidator.cs

@@ -45,7 +45,7 @@ namespace Exam.Application
 
             RuleFor(m => m.Name).NotEmpty().WithMessage(x=>string.Format(ExamErrorMessage.IsRequired,x.GetType().GetDescription(nameof(ExamManage.Name))));
             RuleFor(m => m.Code).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamManage.Code))));
-            RuleFor(m => m.CutoffScore).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamManage.CutoffScore))));
+            RuleFor(m => m.CutoffScore).NotNull().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamManage.CutoffScore))));
             RuleFor(m => m.ExamType).NotNull().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamManage.ExamType))));
             RuleFor(m => m.Method).NotNull().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamManage.Method))));
             //RuleFor(m => m.TestPaperId).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, typeof(ExamTestPaper).GetDescription()));
@@ -55,7 +55,7 @@ namespace Exam.Application
             RuleFor(m => m.EndTime).NotNull().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamManage.EndTime))));
             RuleFor(m => m.EndTime).Must((e, v) => e.ExamType == EExamType.Simulate || e.StartTime < v).WithMessage(x => string.Format(ExamErrorMessage.Greater, x.GetType().GetDescription(nameof(ExamManage.EndTime)), x.GetType().GetDescription(nameof(ExamManage.StartTime))));
             RuleFor(m => m.TotalScore).NotNull().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamManage.TotalScore))));
-            RuleFor(m => m.CutoffScore).Must((e, v)=> e.TotalScore > v).WithMessage(x => string.Format(ExamErrorMessage.Greater, x.GetType().GetDescription(nameof(ExamManage.CutoffScore)), x.GetType().GetDescription(nameof(ExamManage.TotalScore))));
+            RuleFor(m => m.CutoffScore).Must((e, v)=> e.TotalScore >= v).WithMessage(x => string.Format(ExamErrorMessage.Greater, x.GetType().GetDescription(nameof(ExamManage.CutoffScore)), x.GetType().GetDescription(nameof(ExamManage.TotalScore))));
         }
 
         protected override void ValidateRuleWithAdd()

+ 0 - 6
src/Hotline.Share/Dtos/ExamManages/GradingExamItemDto.cs

@@ -16,12 +16,6 @@ namespace Exam.Share.Dtos.ExamManage
         /// </summary>
         [Description("得分")]
         public int Score { get; set; }
-
-        /// <summary>
-        /// 是否已阅卷
-        /// </summary>
-        [Description("是否已阅卷")]
-        public bool IsCheck { get; set; }
     }
 
     public class BatchGradingExamItemDto : IAddRequest

+ 16 - 3
src/Hotline.Share/Dtos/ExamManages/GradingExamQuestionDto.cs

@@ -3,6 +3,7 @@ using Exam.Share;
 using Hotline.Share.Dtos.ExamManages;
 using Hotline.Share.Enums.Exams;
 using System.ComponentModel;
+using System.Runtime.CompilerServices;
 
 namespace Exam.Application.Interface.Exam
 {
@@ -21,6 +22,12 @@ namespace Exam.Application.Interface.Exam
 
         public string CorrectAnswer { get; set; }
 
+        /// <summary>
+        /// 试题分数
+        /// </summary>
+        [Description("试题分数")]
+        public int QuestionScore { set; get; }
+
     }
 
     public class GradingExamQuestionTempDto
@@ -92,13 +99,19 @@ namespace Exam.Application.Interface.Exam
         public bool IsSelected { get; set; }
 
         /// <summary>
-        /// 分数
+        /// 试题分数
+        /// </summary>
+        [Description("试题分数")]
+        public int QuestionScore { get; set; }
+
+        /// <summary>
+        /// 实际分数
         /// </summary>
-        [Description("分数")]
+        [Description("实际分数")]
         public int? Score { get; set; }
     }
 
-    public class UserExamQuestionDto:IActionRequest
+    public class UserExamQuestionDto : IActionRequest
     {
         /// <summary>
         /// 主键

+ 6 - 3
src/Hotline.Share/Dtos/Trains/TrainPracticeDto.cs

@@ -27,9 +27,6 @@ namespace Hotline.Share.Dtos.Trains
         /// </summary>
         [Description("关联知识")]
         public new List<TrainPracticeKnowladgeDto> TrainPracticeKnowladgeDtos { get; set; }
-
-
-        
     }
 
     /// <summary>
@@ -68,6 +65,12 @@ namespace Hotline.Share.Dtos.Trains
         /// </summary>
         [Description("培训习题选项")]
         public List<SimpleTrainPracticeOptionsDto> TrainPracticeOptionsDtos { get; set; }
+
+
+        /// <summary>
+        /// 答案
+        /// </summary>
+        public AddTrainRecordAnswerDto? AddTrainRecordAnswerDto { get; set; }
     }
 
     public class AddTrainPracticeDto : IAddRequest, IOperationStatus

+ 3 - 1
src/Hotline.Share/Exams/Extensions/ReportPagedRequestExtensions.cs

@@ -4,8 +4,10 @@ namespace Hotline.Share.Exams.Extensions
 {
     public static class ReportPagedRequestExtensions
     {
-        public static void ResoleEndTime<T>(this T analysisReportRequest)where T :AnalysisReportRequest
+        public static void ResolveEndTime<T>(this T analysisReportRequest)where T :AnalysisReportRequest
         {
+            if (analysisReportRequest.StartTime == null) return;
+
             switch (analysisReportRequest.AnlysisType)
             {
                 case Share.Enums.Exams.EAnlysisType.Day:

+ 2 - 2
src/Hotline.Share/Requests/Exam/UserExamResultReportPagedRequest.cs

@@ -9,13 +9,13 @@ namespace Hotline.Share.Requests.Exam
         /// 最小分数
         /// </summary>
         [Description("最小分数")]
-        public int MinScore { get; set; }
+        public int? MinScore { get; set; }
 
         /// <summary>
         /// 最大分数
         /// </summary>
 
         [Description("最大分数")]
-        public int MaxScore { get; set; }
+        public int? MaxScore { get; set; }
     }
 }

+ 3 - 2
src/TianQue.Sdk/TQHttpClient.cs

@@ -78,11 +78,12 @@ public class TQHttpClient
 
             if (SSHHost.NotNullOrEmpty() && SSHPort != 0 && SSHUserName.NotNullOrEmpty() && SSHPassword.NotNullOrEmpty())
             {
+                var port = new Random().Next(8089, 8099);
                 _sshClient.Connect();
-                var forwardedPort = new ForwardedPortLocal("127.0.0.1", 8090, uri.Host, (uint)uri.Port);
+                var forwardedPort = new ForwardedPortLocal("127.0.0.1", (uint)port, uri.Host, (uint)uri.Port);
                 _sshClient.AddForwardedPort(forwardedPort);
                 forwardedPort.Start();
-                uri = new Uri("http://127.0.0.1:8090" + uri.AbsolutePath);
+                uri = new Uri("http://127.0.0.1:" + port + uri.AbsolutePath);
             }
 
             var content = new StringContent(body, Encoding.GetEncoding("UTF-8"));

+ 9 - 2
test/Hotline.Tests/Application/RedPackApplicationTest.cs

@@ -58,12 +58,19 @@ public class RedPackApplicationTest : TestBase
         var dhzy = _systemDicDataCacheManager.OrderTag.Where(m => m.DicDataName == "动火作业").FirstOrDefault();
         dhzy.ShouldNotBeNull("SysDicTypeConsts.OrderTag 缺少动作火作业基础信息");
         SetZuoXi();
-        SetSettingCache(SettingConstants.OvertimeBack, "0.00027778");
         var industryItems = await _industryRepository.Queryable().Where(m => m.Name == "安全隐患").Select(d => new { d.Id, d.Name, }).ToListAsync();
         var industry = industryItems.First();
         var order = _orderServiceMock.CreateOrder(industryId: industry.Id, industryName: industry.Name, tags: [dhzy.Id])
+            .StepHandle(async order => 
+            {
+                SetSettingCache(SettingConstants.OvertimeBack, "0.00027778");
+            })
             .办理到网格员(SetZuoXi)
-            .StepHandle(async order => Thread.Sleep(5 * 1000))
+            .StepHandle(async order =>
+            {
+                Thread.Sleep(5 * 1000);
+                SetSettingCache(SettingConstants.OvertimeBack, "4");
+            })
             .办理到派单员(Set班长)
             .办理到一级部门(SetPaiDanYuan)
             .办理到归档(Set一级部门)

+ 18 - 3
test/Hotline.Tests/Mock/OrderServiceMock.cs

@@ -30,6 +30,7 @@ using System;
 using DocumentFormat.OpenXml.Bibliography;
 using Hotline.Snapshot;
 using Hotline.Share.Enums.Settings;
+using Npgsql;
 
 namespace Hotline.Tests.Mock;
 public class OrderServiceMock
@@ -130,7 +131,21 @@ public class OrderServiceMock
         AddOrderDto.Title = "单元测试" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
         if (tags.NotNullOrEmpty())
             AddOrderDto.Tags = tags;
-        CreateOrderOutDto = _orderController.Add(AddOrderDto).GetAwaiter().GetResult().ToJson().FromJson<CreateOrderOutDto>();
+        RetryHelper.Retry(() =>
+            {
+                try
+                {
+                    CreateOrderOutDto = _orderController.Add(AddOrderDto).GetAwaiter().GetResult().ToJson().FromJson<CreateOrderOutDto>();
+                }
+                catch (PostgresException e)
+                {
+                    if (e.Message.Contains("unique_order_no"))
+                    {
+                        return false;
+                    }
+                }
+                return true;
+            }, 10);
         _orderServiceStartWorkflow.orderServiceMock = this;
         return _orderServiceStartWorkflow;
     }
@@ -657,7 +672,7 @@ public class OrderServiceMock
         return this;
 
     }
-    
+
     public string 申请延期(Action action = null)
     {
         action?.Invoke();
@@ -669,7 +684,7 @@ public class OrderServiceMock
             {
                 NextStepCode = step.Key,
                 NextStepName = step.Value,
-                NextHandlers = new List<StepAssignInfo>{step.Items.First()},
+                NextHandlers = new List<StepAssignInfo> { step.Items.First() },
                 Opinion = "单元测试延期申请",
                 FlowDirection = step.FlowDirection,
                 BackToCountersignEnd = step.BackToCountersignEnd,