Bläddra i källkod

Merge branch 'feature/exam' into test
合并冲突

guqiang 2 veckor sedan
förälder
incheckning
f29371fb76

+ 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>

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

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

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

@@ -117,5 +117,19 @@ 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<ViewExamQuestionDto> View(string id,string questionId);
+
+        /// <summary>
+        /// 查看考试
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        Task<List<ViewExamQuestionDto>> View(string id);
     }
 }

+ 12 - 1
src/Hotline.Application/Exam/QueryExtensions/ExamManages/ExamQuestionQueryExtensions.cs

@@ -30,7 +30,18 @@ namespace Hotline.Application.Exam.QueryExtensions.ExamManages
 
             expression = ExpressionableUtility.CreateExpression<ExamQuestionBak>()
                 .AndIF(examQuestionRequest.QuestionId.IsNotNullOrEmpty(), x => x.QuestionId == examQuestionRequest.QuestionId)
-                .AndIF(examQuestionRequest.ExamId.IsNotNullOrEmpty(), x => x.ExamId == examQuestionRequest.ExamId)
+                .ToExpression();
+
+            return expression;
+        }
+
+        public static Expression<Func<ExamUserExam, bool>> GetUserExamExpression(this ExamQuestionRequest examQuestionRequest)
+        {
+            Expression<Func<ExamUserExam, bool>> expression = m => m.Id != null;
+
+            expression = ExpressionableUtility.CreateExpression<ExamUserExam>()
+                .AndIF(examQuestionRequest.UserExamId.IsNotNullOrEmpty(), x => x.Id == examQuestionRequest.UserExamId
+                )
                 .ToExpression();
 
             return expression;

+ 188 - 5
src/Hotline.Application/Exam/Service/ExamManages/UserExamService.cs

@@ -43,6 +43,9 @@ 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
 {
@@ -91,13 +94,17 @@ namespace Hotline.Application.Exam.Service.ExamManages
         public async Task<ExamQuestionDto> GetExamQuestionDto(ExamQuestionRequest examQuestionRequest)
         {
             var expression = examQuestionRequest.GetExpression();
-            var question = await new ExamRepository<Exams.ExamManages.ExamQuestionBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(expression).FirstAsync();
-
+            var userUserExpression = examQuestionRequest.GetUserExamExpression();
+            //var question = await new ExamRepository<Exams.ExamManages.ExamQuestionBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(expression).FirstAsync();
+            var querable = new ExamRepository<Exams.ExamManages.ExamQuestionBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(expression);
+            var userExamTable = new ExamRepository<Exams.ExamManages.ExamUserExam>(_uow, _dataPermissionFilterBuilder, _serviceProvider).Queryable().Where(userUserExpression);
+            querable = querable.InnerJoin(userExamTable, (q, u) => q.ExamId == u.ExamId).Select((q, u) => q);
+            var question = await querable.FirstAsync();
             if (question != null)
             {
                 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);
+                var questionScore = await new ExamRepository<ExamQuestionScoreBak>(_uow, _dataPermissionFilterBuilder, _serviceProvider).GetAsync(x=>x.QuestionType == question.QuestionType && x.ExamManageId == question.ExamId);
 
                 if (questionScore != null)
                 {
@@ -151,7 +158,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
             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 && u.ExamId == examQuestionRequest.ExamId);
+            var userExamTable = _repository.Queryable().Where(u => u.UserId == _sessionContext.UserId && u.Id == examQuestionRequest.UserExamId);
             var examAnswerTable = examAnswerRepository.Queryable();
 
             var examAnswers = await examAnswerTable.InnerJoin(userExamItemTable, (e, i) => e.UserExamItemId == i.Id)
@@ -681,6 +688,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
         public async Task<UnExamUserPageViewResponse> GetUnExamUsers(UnExamUserReportPagedRequest unExamUserReportPagedRequest)
         {
+            if(unExamUserReportPagedRequest.EndTime == null)
             unExamUserReportPagedRequest.ResolveEndTime();
 
             var examManageRepository = new ExamRepository<ExamManage>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
@@ -714,6 +722,7 @@ namespace Hotline.Application.Exam.Service.ExamManages
 
         public async Task<UserExamResultPageViewResponse> GetUserExamResults(UserExamResultReportPagedRequest userExamResultReportPagedRequest)
         {
+            if(userExamResultReportPagedRequest.EndTime == null)
             userExamResultReportPagedRequest.ResolveEndTime();
 
             var examManageRepository = new ExamRepository<ExamManage>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
@@ -1306,10 +1315,184 @@ namespace Hotline.Application.Exam.Service.ExamManages
                 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,null);
+
+            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;
+
+        }
+
+
+
+        public async Task<ViewExamQuestionDto> View(string id, string questionId)
+        {
+            List<ViewExamQuestionDto> viewExamQuestionDtos = await GetViewExamQuestion(id, questionId);
+
+            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.FirstOrDefault();
+        }
+
+        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,
+                AttachmentId = s.AttachmentId
+            }).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))
+                .InnerJoin<ExamQuestionKnowladge>((kb,k)=>kb.KnowladgeId == k.Id).Select((kb, k) => new QuestionKnowladgeDto
+            {
+                Id = kb.Id,
+                QuestionId = kb.ExamQuestionId,
+                KnowladgeId = k.KnowladgeId,
+                Title = kb.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,string questionId)
+        {
+            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().WhereIF(!string.IsNullOrEmpty(questionId), x => x.QuestionId == questionId);
+            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
 
     }

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

@@ -68,7 +68,7 @@ namespace Hotline.Application.Exam.Service.Trains
         public async Task CompleteTrainRecordAsync(CompleteTrainRecordDto completeTrainRecordDto, CancellationToken cancellationToken)
         {
             var trainRecord = await _repository.GetAsync(x => x.Id == completeTrainRecordDto.Id);
-            trainRecord= _mapper.Map<CompleteTrainRecordDto,ExamTrainRecord>(completeTrainRecordDto, trainRecord);
+            trainRecord = _mapper.Map<CompleteTrainRecordDto, ExamTrainRecord>(completeTrainRecordDto, trainRecord);
             trainRecord.ToUpdate(_sessionContext);
 
             await _repository.UpdateWithValidateAsync(trainRecord, cancellationToken);
@@ -80,7 +80,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
             trainKnowladge.ToUpdate(_sessionContext);
 
-            await _trainKnowladgeRepository.UpdateWithValidateAsync(trainKnowladge,cancellationToken);
+            await _trainKnowladgeRepository.UpdateWithValidateAsync(trainKnowladge, cancellationToken);
 
         }
 
@@ -113,12 +113,12 @@ namespace Hotline.Application.Exam.Service.Trains
             SqlSugar.ISugarQueryable<TrainRecordViewResponse> queryResult = QueryResult(queryRequest);
 
             var total = await queryResult.CountAsync();
-            var items = await queryResult.ToPageListAsync(queryRequest.PageIndex,queryRequest.PageSize);
+            var items = await queryResult.ToPageListAsync(queryRequest.PageIndex, queryRequest.PageSize);
 
             return new TrainRecordPageViewResponse
             {
                 Items = items,
-                Pagination = new Pagination(queryRequest.PageIndex,queryRequest.PageSize,total)
+                Pagination = new Pagination(queryRequest.PageIndex, queryRequest.PageSize, total)
             };
 
         }
@@ -127,7 +127,7 @@ namespace Hotline.Application.Exam.Service.Trains
         {
             await GetTrainPracticeKnowladge(addTrainDto, cancellationToken);
 
-            await AddTrainRecordItem(addTrainDto,cancellationToken);
+            await AddTrainRecordItem(addTrainDto, cancellationToken);
 
             await AddTrainRecordAnswer(addTrainDto, cancellationToken);
 
@@ -138,7 +138,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
         private async Task GetTrainPracticeKnowladge(AddTrainDto addTrainDto, CancellationToken cancellationToken)
         {
-            var trainPracticeKnowladeRepository = new TrainPracticeKnowladgeRepository(_uow,_dataPermissionFilterBuilder,_serviceProvider);
+            var trainPracticeKnowladeRepository = new TrainPracticeKnowladgeRepository(_uow, _dataPermissionFilterBuilder, _serviceProvider);
             var trainPracticeKnowladge = await trainPracticeKnowladeRepository.GetAsync(x => x.TrainPracticeId == addTrainDto.TrainPracticeId);
 
             if (trainPracticeKnowladge != null)
@@ -208,6 +208,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
         public async Task<TrainResultPagedViewResponse> AnalysisTrainResult(TrainResultReportPagedRequest trainResultReportPagedRequest)
         {
+            if(trainResultReportPagedRequest.EndTime == null)
             trainResultReportPagedRequest.ResolveEndTime();
 
             var expression = trainResultReportPagedRequest.GetExpression();
@@ -227,7 +228,7 @@ namespace Hotline.Application.Exam.Service.Trains
             var queryResult = trainRecordTable.InnerJoin(trainPlanTable, (r, p) => r.TrainPlanId == p.Id)
                 .InnerJoin(trainPlanTemplateTable, (r, p, pt) => p.Id == pt.TrainPlanId)
                 .InnerJoin(trainTemplateTable, (r, p, pt, t) => pt.TrainTemplateId == t.Id)
-                .InnerJoin(userTable,(r,p,pt,t,u)=>r.UserId == u.Id)
+                .InnerJoin(userTable, (r, p, pt, t, u) => r.UserId == u.Id)
                 .Select((r, p, pt, t, u) => new TrainResultViewResponse
                 {
                     TrainName = t.Name,
@@ -250,7 +251,8 @@ namespace Hotline.Application.Exam.Service.Trains
 
         public async Task<TrainResultRateViewResponse> CalcuteAnalysisRate(TrainResultReportPagedRequest trainResultReportPagedRequest)
         {
-            trainResultReportPagedRequest.ResolveEndTime();
+            if (trainResultReportPagedRequest.EndTime == null)
+                trainResultReportPagedRequest.ResolveEndTime();
 
             var expression = trainResultReportPagedRequest.GetExpression();
             var templateExpression = trainResultReportPagedRequest.GetTemplateExpression();
@@ -278,7 +280,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
             var calcuteRateResult = new TrainResultRateViewResponse
             {
-                Complete = await queryResult.CountAsync(x=>x.IsComplete),
+                Complete = await queryResult.CountAsync(x => x.IsComplete),
                 Trainning = await queryResult.CountAsync(x => !x.IsComplete && x.TrainTime > DateTime.Now),
                 UnComplete = await queryResult.CountAsync(x => !x.IsComplete && x.TrainTime <= DateTime.Now),
             };
@@ -369,8 +371,9 @@ namespace Hotline.Application.Exam.Service.Trains
             var knowledgeTable = knowledgeRepository.Queryable();
 
             var queryable = questionTable.InnerJoin(questionKnowladgeTable, (r, p, tpt, tp, ExamPracticeQuestionKnowledge) => tp.QuestionId == ExamPracticeQuestionKnowledge.QuestionId)
-                .InnerJoin(knowledgeTable, (r, p, tpt, tp, ExamPracticeQuestionKnowledge,kl) => ExamPracticeQuestionKnowledge.KnowladgeId == kl.Id)
-                .GroupBy((r, p, tpt, tp, ExamPracticeQuestionKnowledge, kl) => new {
+                .InnerJoin(knowledgeTable, (r, p, tpt, tp, ExamPracticeQuestionKnowledge, kl) => ExamPracticeQuestionKnowledge.KnowladgeId == kl.Id)
+                .GroupBy((r, p, tpt, tp, ExamPracticeQuestionKnowledge, kl) => new
+                {
                     Title = kl.Title,
                     Id = kl.Id
                 })
@@ -382,7 +385,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
             return await queryable.ToListAsync();
         }
-       
+
 
         private async Task AddTrainRecordAnswer(AddTrainDto addTrainDto, CancellationToken cancellationToken)
         {
@@ -407,7 +410,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
             trainRecordAnswers.ToInsert(_sessionContext);
 
-            await _trainRecordAnswerRepository.AddWithValidateAsync(trainRecordAnswers,cancellationToken);
+            await _trainRecordAnswerRepository.AddWithValidateAsync(trainRecordAnswers, cancellationToken);
         }
 
         //private async Task<TrainPracticeDto> GetTrainQuestionOptions(AddTrainDto addTrainDto)
@@ -442,7 +445,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
             var trainRecordTable = _repository.Queryable().Where(x => x.Id == trainPracticeRequest.Id);
             var trainPlanTable = trainPlanRepository.Queryable();
-            var trainPracticeTable = trainPracticeRepostitory.Queryable().WhereIF(!string.IsNullOrEmpty(trainPracticeRequest.TrainPracticeId),x=>x.Id == trainPracticeRequest.TrainPracticeId);
+            var trainPracticeTable = trainPracticeRepostitory.Queryable().WhereIF(!string.IsNullOrEmpty(trainPracticeRequest.TrainPracticeId), x => x.Id == trainPracticeRequest.TrainPracticeId);
             var tranPlanTemplateTable = trainPlanTemplateRepository.Queryable();
 
             var trainPractices = trainPracticeTable.InnerJoin(tranPlanTemplateTable, (tp, tpt) => tp.TrainTemplateId == tpt.TrainTemplateId)
@@ -462,7 +465,7 @@ namespace Hotline.Application.Exam.Service.Trains
 
             var trainPracticeOptions = await trainPracticeOptionsRepository.Queryable()
                 .InnerJoin(trainPractices, (tpo, tp) => tpo.TrainPracticeId == tp.Id)
-                .Where((tpo, tp)=> tp.Id == trainPracticeRequest.TrainPracticeId)
+                .Where((tpo, tp) => tp.Id == trainPracticeRequest.TrainPracticeId)
                 .Select((tpo, tp) => tpo).ToListAsync();
 
             var queryable = trainRecordAnswerRepository.Queryable()
@@ -478,7 +481,7 @@ namespace Hotline.Application.Exam.Service.Trains
             var trainPracticeOptionsDtos = new List<SimpleTrainPracticeOptionsDto>();
 
             trainPracticeOptions.ForEach(x =>
-            {              
+            {
                 var trainPracticeOptionsDto = _mapper.Map<SimpleTrainPracticeOptionsDto>(x);
 
                 trainPracticeOptionsDto.IsSelected = trainRecordOptions.Any(m => m.QuestionOptionId == x.QuestionOptionId);

+ 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>

+ 1 - 1
src/Hotline.Share/Dtos/Questions/QuestionSourcewareDto.cs

@@ -12,7 +12,7 @@ namespace Hotline.Share.Dtos.Questions
     [Description("关联课件")]
     public class QuestionSourcewareDto:UpdateQuestionSourcewareDto
     {
-
+        public string AttachmentId { get; set; }
     }
 
     /// <summary>

+ 3 - 3
src/Hotline.Share/Requests/Exam/ExamQuestionRequest.cs

@@ -13,9 +13,9 @@ namespace Hotline.Share.Requests.Exam
         public string QuestionId { get; set; }
 
         /// <summary>
-        /// 考试Id
+        /// 用户考试Id
         /// </summary>
-        [Description("考试Id")]
-        public string ExamId { get; set; }
+        [Description("用户考试Id")]
+        public string UserExamId { get; set; }
     }
 }

+ 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