浏览代码

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

qinchaoyue 3 天之前
父节点
当前提交
702465e2fa

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

@@ -117,9 +117,9 @@ namespace Hotline.Api.Controllers.Exam
         /// </summary>
         /// <returns></returns>
         [HttpPost(ExamManageApiRoute.ImportExcel)]
-        public async Task ImportExcel(IFormFile files)
+        public async Task ImportExcel(IFormFile file)
         {
-            await _questionService.ImportExcel(files, HttpContext.RequestAborted);
+            await _questionService.ImportExcel(file, HttpContext.RequestAborted);
         }
 
         /// <summary>

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

@@ -199,5 +199,16 @@ namespace Hotline.Api.Controllers.Exam
 
             return await _userExamService.GetUserExamResults(userExamResultReportPagedRequest); 
         }
+
+        /// <summary>
+        /// 查看考试试题
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet(UserExamApiRoute.View)]
+        public async Task<List<ViewExamQuestionDto>> View([FromQuery] string id)
+        {
+            return await _userExamService.View(id);
+        }
     }
 }

+ 7 - 0
src/Hotline.Application/Exam/Interface/ExamManages/IUserExamService.cs

@@ -117,5 +117,12 @@ namespace Hotline.Application.Exam.Interface.ExamManages
         /// <param name="examUserQueryRequest"></param>
         /// <returns></returns>
         Task<List<ExamUserViewResponse>> GetUserListAsync(ExamUserQueryRequest examUserQueryRequest);
+        
+        /// <summary>
+        /// 查看考试
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        Task<List<ViewExamQuestionDto>> View(string id);
     }
 }

+ 186 - 11
src/Hotline.Application/Exam/Service/ExamManages/UserExamService.cs

@@ -42,6 +42,10 @@ using DocumentFormat.OpenXml.Office2013.Excel;
 using Hotline.Share.Enums.Exams;
 using DocumentFormat.OpenXml.Wordprocessing;
 using Hotline.Repository.SqlSugar.Exam.Repositories.ExamManages;
+using Hotline.Exams.Questions;
+using Hotline.Exams.Sourcewares;
+using Hotline.Share.Dtos.Questions;
+using DocumentFormat.OpenXml.Office2010.Excel;
 
 namespace Hotline.Application.Exam.Service.ExamManages
 {
@@ -90,17 +94,24 @@ namespace Hotline.Application.Exam.Service.ExamManages
         public async Task<ExamQuestionDto> GetExamQuestionDto(ExamQuestionRequest examQuestionRequest)
         {
             var expression = examQuestionRequest.GetExpression();
-            var quesetion = await new ExamRepository<Exams.ExamManages.ExamQuestionBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(expression).FirstAsync();
+            var question = await new ExamRepository<Exams.ExamManages.ExamQuestionBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(expression).FirstAsync();
 
-            if (quesetion != null)
+            if (question != null)
             {
-                var examQuestionDto = _mapper.Map<ExamQuestionDto>(quesetion);
+                var examQuestionDto = _mapper.Map<ExamQuestionDto>(question);
+
+                var questionScore = await new ExamRepository<ExamQuestionScoreBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).GetAsync(x=>x.QuestionType == question.QuestionType && x.ExamManageId == examQuestionRequest.ExamId);
+
+                if (questionScore != null)
+                {
+                    examQuestionDto.Score = questionScore.Score;
+                }               
 
                 if (examQuestionDto.QuestionType.CheckSelectType())
                 {
-                    var questionOptions = await new ExamRepository<ExamQuestionOptionsBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(x => x.ExamQuestionId == quesetion.Id).ToListAsync();
+                    var questionOptions = await new ExamRepository<ExamQuestionOptionsBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(x => x.ExamQuestionId == question.Id).ToListAsync();
 
-                    List<ExamUserExamItemOptions> userItemItemOptions = await GetUserExteamItemOptios(quesetion);
+                    List<ExamUserExamItemOptions> userItemItemOptions = await GetUserExteamItemOptios(question);
 
                     if (questionOptions != null)
                     {
@@ -163,7 +174,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             var userItemItemOptions = await userExamItemOptionsTable
                 .InnerJoin(userExamItemTable, (o, u) => o.UserExamItemId == u.Id)
                 .InnerJoin(userExamTable, (o, u, e) => u.UserExamId == e.Id)
-                .Where((o, u, e) => u.QuestionId == quesetion.QuestionId && e.UserId == _sessionContext.UserId).
+                .Where((o, u, e) => u.QuestionId == quesetion.QuestionId && e.UserId == _sessionContext.UserId && e.ExamStatus == EExamStatus.Executing).
                 Select((o, u, e) => o).ToListAsync();
             return userItemItemOptions;
         }
@@ -320,7 +331,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             {
                 await UpdateExamAsync(_userExamItemRepository, updateUserExamItemDto, cancellationToken);
             }
-            
+
             await CalcuteExamItemScore(_userExamItemRepository, updateUserExamItemDto, cancellationToken);
 
             return startExamViewResponse;
@@ -344,7 +355,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 IsJoin = false
             };
 
-            if (userExam.StartTime == null)
+            if (userExam.StartTime == null || userExam.ExamStatus == EExamStatus.Complete)
                 userExam.StartTime = DateTime.Now;
 
             var startExamViewResponse = await CheckExamValid(userExam, cancellationToken);
@@ -365,6 +376,11 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 await _repository.UpdateWithValidateAsync(userExam, cancellationToken);
 
             }
+            // TODO: 删除之前选项和答案
+            else if(userExam.ExamStatus == EExamStatus.Complete)
+            {
+                await ReExam(userExam, cancellationToken);
+            }
             var examManage = await _examManageRepository.GetAsync(x => x.Id == userExam.ExamId);
 
             return new StartExamViewResponse
@@ -375,6 +391,29 @@ namespace Hotline.Application.Exam.Service.ExamManages
             };
         }
 
+        /// <summary>
+        /// 重考
+        /// </summary>
+        /// <param name="userExam"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        private async Task ReExam(ExamUserExam userExam, CancellationToken cancellationToken)
+        {
+            //新增重考记录
+            var reExamUserExam = _mapper.Map<ExamUserExam, ExamUserExam>(userExam);
+
+            reExamUserExam.IsCheck = false;
+            reExamUserExam.IsSubmit = false;
+            reExamUserExam.IsSuccess = false;
+            reExamUserExam.IsReExam = true;
+            reExamUserExam.Score = 0;
+            reExamUserExam.ExamStatus = EExamStatus.NoStart;
+
+            reExamUserExam.ToInsert(_sessionContext);
+
+            await _repository.AddWithValidateAsync(reExamUserExam, cancellationToken);
+        }
+
         private async Task<StartExamViewResponse> CheckExamValid(ExamUserExam examUserExam, CancellationToken cancellationToken)
         {
 
@@ -719,7 +758,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
         public async Task<GradingResultPageViewResponse> GetGradingResultPagedList(GradingPagedRequest gradingPagedRequest)
         {
             // 只要有阅卷记录就在已阅卷列表中,已阅卷和未阅卷会有重复数据,只有所有记录都已阅卷才会从未阅卷列表中排除
-            var userExamTable = _repository.Queryable().Where(x=>x.IsSubmit);
+            var userExamTable = _repository.Queryable().Where(x => x.IsSubmit);
 
             var examManageTable = new ExamRepository<ExamManage>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
 
@@ -1264,16 +1303,152 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 Status = u.Status,
                 SortIndex = u.SortIndex,
                 ExamStatus = u.ExamStatus,
-                IsSuccess = u.IsCheck? u.IsSuccess:null,
+                IsSuccess = u.IsCheck ? u.IsSuccess : null,
                 EndTime = e.EndTime,
                 StartTime = e.StartTime,
                 TimeSpan = e.TimeSpan,
                 ExamType = e.ExamType,
                 ExamId = e.Id,
-                IsCheck = u.IsCheck
+                IsCheck = u.IsCheck,
+                IsReExam = u.IsReExam,
+                CanReExam = SqlFunc.Subqueryable<ExamUserExamItem>().Where(x=>x.UserExamId == u.Id).Count()< e.Count
             });
             return queryable;
         }
+
+        public async Task<List<ViewExamQuestionDto>> View(string id)
+        {
+           
+            List<ViewExamQuestionDto> viewExamQuestionDtos = await GetViewExamQuestion(id);
+
+            var questionIds = viewExamQuestionDtos.Select(x => x.QuestionId).ToList();
+
+            List<ViewQuestionAnswerDto> questionAnswers = await GetQuestionAnswers(id, questionIds);
+            List<ViewQuestionOptionDto> questionOptions = await GetQuestionOptions( questionIds);
+            List<QuestionKnowladgeDto> questionKnowladges = await GetQuestionKnowladges( questionIds);
+            List<QuestionSourcewareDto> sourcewares = await GetSourcewares(questionIds);
+
+            viewExamQuestionDtos.ForEach(item =>
+            {
+                item.QuestionKnowladgeDtos = questionKnowladges.Where(x => x.QuestionId == item.QuestionId).ToList();
+                item.QuestionSourcewareDtos = sourcewares.Where(x => x.QuestionId == item.QuestionId).ToList();
+                if (!item.QuestionType.CheckSelectType())
+                {
+                    var questionAnswer = questionAnswers.FirstOrDefault(x => x.QuestionId == item.QuestionId);
+                    item.Answer = questionAnswer?.Answer ?? string.Empty;
+                    item.CorrectAnswer = questionAnswer?.CorrectAnswer ?? string.Empty;
+                }
+                else
+                {
+                    item.QuestionOptions = questionOptions.Where(x => x.QuestionId == item.QuestionId).ToList();
+                    item.CorrectAnswer = string.Join(",", item.QuestionOptions.Where(x => x.IsAnswer).Select(x => x.Label));
+                }
+                
+            });
+
+
+            return viewExamQuestionDtos;
+
+        }
+
+        private  async Task<List<QuestionSourcewareDto>> GetSourcewares(List<string> questionIds)
+        {
+            var questionSourcewareTable = new ExamRepository<ExamQuestionSourcewareBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+            var sourcewareTable = new ExamRepository<ExamSourceware>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+
+            var querable = questionSourcewareTable.InnerJoin<ExamQuestionSourceware>((qsb,qs)=>qsb.SourcewareId == qs.Id).InnerJoin(sourcewareTable, (qsb,qs, s) => qs.SourcewareId == s.Id).Select((qsb, qs, s) => new QuestionSourcewareDto
+            {
+                Id = qs.Id,
+                Name = s.Name,
+                QuestionId = qsb.ExamQuestionId,
+                SourcewareId = s.Id
+            }).MergeTable().Where(x => questionIds.Contains(x.QuestionId));
+
+            return await querable.ToListAsync();
+        }
+
+        private  async Task<List<QuestionKnowladgeDto>> GetQuestionKnowladges(List<string> questionIds)
+        {
+            var questionKnowladgeTable = new ExamRepository<ExamQuestionKnowladgeBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+
+            return await questionKnowladgeTable.Where(x => questionIds.Contains(x.ExamQuestionId)).Select(x => new QuestionKnowladgeDto
+            {
+                Id = x.Id,
+                QuestionId = x.ExamQuestionId,
+                KnowladgeId = x.KnowladgeId,
+                Title = x.Title
+            }).ToListAsync();
+        }
+
+        private  async Task<List<ViewQuestionOptionDto>> GetQuestionOptions(List<string> questionIds)
+        {
+            var userExamItemOptionTable = _userExamItemOptionRepository.Queryable();
+            var questionOptionTable = new ExamRepository<ExamQuestionOptionsBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+
+            var querable = questionOptionTable.Where(x => questionIds.Contains(x.ExamQuestionId))
+                .LeftJoin(userExamItemOptionTable, (op, uio) => op.Id == uio.QuestionOptionId)
+                .Select((op, uio) => new ViewQuestionOptionDto
+                {
+                    Content = op.Content,
+                    Id = op.Id,
+                    IsAnswer = op.IsAnswer,
+                    Label = op.Label,
+                    QuestionId = op.ExamQuestionId,
+                    IsSelected = uio.Id != null
+                }).MergeTable().OrderBy(x=>x.Label);
+
+            return await querable.Distinct()
+                .ToListAsync();
+        }
+
+        private  async Task<List<ViewQuestionAnswerDto>> GetQuestionAnswers(string id, List<string> questionIds)
+        {
+            var userExamTable = _repository.Queryable().Where(x => x.Id == id);
+            var userExamItemTable = _userExamItemRepository.Queryable();
+            var examAnswerTable = _examAnswerRepository.Queryable();
+            var questionTable = new ExamRepository<ExamQuestionBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+            var questionAnswerTable = new ExamRepository<ExamQuestionAnswerBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+
+            var querable = examAnswerTable
+                .InnerJoin(userExamItemTable, (a, ui) => ui.Id == a.UserExamItemId &&  ui.UserExamId == id)
+                .LeftJoin(questionAnswerTable, (a, ui, qab) => qab.QuestionId == ui.QuestionId  )
+                .LeftJoin<ExamQuestionAnswer>((a, ui, qab ,qa) => qab.QuestionAnswerId == qa.Id )
+                .LeftJoin(questionTable, (a, ui, qab, qa,q)=>qab.QuestionId == q.QuestionId && questionIds.Contains(q.Id))
+                .Select((a, ui, qab, qa,q) => new ViewQuestionAnswerDto
+                {
+                    Answer = a.Answer,
+                    CorrectAnswer = qa.Answer != null ? qa.Answer : string.Empty,
+                    QuestionId = q.Id
+                }).MergeTable();
+
+            return await querable.ToListAsync();
+        }
+
+        private  async Task<List<ViewExamQuestionDto>> GetViewExamQuestion(string id)
+        {
+            var userExamTable = _repository.Queryable().Where(x => x.Id == id);
+            var userExamItemTable = _userExamItemRepository.Queryable();
+            var examManageTable = _examManageRepository.Queryable();
+            var questionTable = new ExamRepository<ExamQuestionBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+            var questionScoreTable = new ExamRepository<ExamQuestionScoreBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable();
+
+
+            var querable = userExamItemTable.InnerJoin(userExamTable, (ui, u) => ui.UserExamId == u.Id)
+                            .InnerJoin(questionTable, (ui, u, q) => ui.QuestionId == q.QuestionId && u.ExamId == q.ExamId)
+                            .InnerJoin(examManageTable, (ui, u, q, e) => u.ExamId == e.Id)
+                            .InnerJoin(questionScoreTable, (ui, u, q, e, s) => q.QuestionType == s.QuestionType && s.ExamManageId == e.Id)
+                            .Select((ui, u, q, e, s) => new ViewExamQuestionDto
+                            {
+                                Id = ui.Id,
+                                Score = s.Score,
+                                RealScore = ui.Score,
+                                Title = q.Title,
+                                QuestionType = q.QuestionType,
+                                QuestionId = q.Id,
+                            }).MergeTable().OrderBy(x=>x.QuestionType).OrderBy(x=>x.Id);
+
+            return await querable.Distinct().ToListAsync();
+        }
         #endregion
 
     }

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

@@ -274,7 +274,7 @@ namespace Hotline.Application.Exam.Service.Trains
                     SortIndex = r.SortIndex,
                     Status = r.Status,
                     TrainTime = p.TrainEndTime
-                });
+                }).MergeTable();
 
             var calcuteRateResult = new TrainResultRateViewResponse
             {

+ 1 - 1
src/Hotline.Application/Exam/Strategy/CheckValidateCountStrategy.cs

@@ -35,7 +35,7 @@ namespace Hotline.Application.Exam.Strategy
 
         public bool Validate()
         {
-            if (_count>=_validateCount)
+            if (_count>_validateCount)
             {
                 ErroMessage = "已超过可考次数,考试结束";
                 _current = this;

+ 1 - 1
src/Hotline.Application/Exam/Strategy/ExamStrategyProxy.cs

@@ -50,7 +50,7 @@ namespace Hotline.Application.Exam.Strategy
             var current = examStrategys.FirstOrDefault();
             if (current != null)
             {
-                for (var i = 1; i < examStrategys.Count - 1; i++)
+                for (var i = 1; i <= examStrategys.Count - 1; i++)
                 {
                     current.SetNext(examStrategys[i]);
                     current = examStrategys[i];

+ 45 - 0
src/Hotline.Share/Dtos/ExamManages/ExamQuestionDto.cs

@@ -1,6 +1,8 @@
 using Exam.Infrastructure.Data.Entity;
+using Hotline.Share.Dtos.Questions;
 using Hotline.Share.Enums.Exams;
 using System.ComponentModel;
+using System.Runtime.CompilerServices;
 
 namespace Hotline.Share.Dtos.ExamManages
 {
@@ -40,4 +42,47 @@ namespace Hotline.Share.Dtos.ExamManages
         [Description("答案")]
         public string Answer { get; set; }
     }
+
+    /// <summary>
+    /// 查看考试试题
+    /// </summary>
+    [Description("查看考试试题")]
+    public class ViewExamQuestionDto : ExamQuestionDto
+    {
+        /// <summary>
+        /// 实际得分
+        /// </summary>
+        [Description("实际得分")]
+        public int? RealScore { get; set; }
+
+        /// <summary>
+        /// 试题Id
+        /// </summary>
+        [Description("试题Id")]
+        public string QuestionId { get; set; }
+
+        /// <summary>
+        /// 试题关联知识
+        /// </summary>
+        [Description("试题关联知识")]
+        public List<QuestionKnowladgeDto> QuestionKnowladgeDtos { get; set; }
+
+        /// <summary>
+        /// 试题课件
+        /// </summary>
+        [Description("试题课件")]
+        public List<QuestionSourcewareDto> QuestionSourcewareDtos { get; set; }
+
+        /// <summary>
+        /// 查看试题选项
+        /// </summary>
+        [Description("查看试题选项")]
+        public new List<ViewQuestionOptionDto> QuestionOptions { get; set; }
+
+        /// <summary>
+        /// 参考答案
+        /// </summary>
+        [Description("参考答案")]
+        public string CorrectAnswer { get; set; }
+    }
 }

+ 13 - 0
src/Hotline.Share/Dtos/Questions/QuestionAnswerDto.cs

@@ -15,6 +15,19 @@ namespace Hotline.Share.Dtos.Questions
 
     }
 
+    /// <summary>
+    /// 查看试题参考答案
+    /// </summary>
+    [Description("查看试题参考答案")]
+    public class ViewQuestionAnswerDto : QuestionAnswerDto
+    {
+        /// <summary>
+        /// 正确答案
+        /// </summary>
+        [Description("正确答案")]
+        public string CorrectAnswer { get; set; }
+    }
+
     /// <summary>
     /// 试题参考答案
     /// </summary>

+ 9 - 0
src/Hotline.Share/Dtos/Questions/QuestionOptionsDto.cs

@@ -22,6 +22,15 @@ namespace Hotline.Share.Dtos.Questions
         }
     }
 
+    /// <summary>
+    /// 查看试题选项
+    /// </summary>
+    [Description("查看试题选项")]
+    public class ViewQuestionOptionDto : QuestionOptionsDto
+    {
+        public bool IsSelected { get; set; }
+    }
+
     /// <summary>
     /// 试题选项
     /// </summary>

+ 12 - 0
src/Hotline.Share/ViewResponses/Exam/UserExamResultViewResponse.cs

@@ -121,6 +121,18 @@ namespace Exam.Share.ViewResponses.Exam
         /// </summary>
         [Description("是否阅卷")]
         public bool IsCheck { get; set; }
+
+        /// <summary>
+        /// 是否重考
+        /// </summary>
+        [Description("是否重考")]
+        public bool? IsReExam { get; set; }
+
+        /// <summary>
+        /// 能否重考
+        /// </summary>
+        [Description("能否重考")]
+        public bool CanReExam { get; set; }
     }
 
     public class GradingResultViewResponse : IViewResponse