using AgileObjects.AgileMapper.Extensions; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using MongoDB.Driver.Linq; using MySqlX.XDevAPI.Common; using System.Net; using System.Text; using System.Text.RegularExpressions; using static Tiobon.Core.Model.Consts; namespace Tiobon.Core.Services; /// /// 考试记录 (服务) /// public class Ghre_ExamRecordServices : BaseServices, IGhre_ExamRecordServices { private readonly IBaseRepository _dal; //private readonly IGhre_ExamPaperServices _ghre_ExamPaperServices; private readonly ILogger _logger; public Ghre_ExamRecordServices(ICaching caching, //IGhre_ExamPaperServices ghre_ExamPaperServices, IBaseRepository dal, ILogger logger) { this._dal = dal; base.BaseDal = dal; base._caching = caching; //_ghre_ExamPaperServices = ghre_ExamPaperServices; _logger = logger; } public override async Task> QueryFilterPage(QueryBody filter, string condition, bool? IsEnable = true) { if (string.IsNullOrWhiteSpace(filter.orderBy)) filter.orderBy = "CreateTime1 DESC"; if (filter.pageSize == 0) filter.pageSize = 10000; var countSql = @$" SELECT COUNT(1) FROM Ghre_ExamRecord_V A"; var sql = @$" SELECT * FROM Ghre_ExamRecord_V A"; string conditions = " WHERE IsEnable = 1"; conditions += $" AND dbo.FUserDataBelongPriv ({App.User.ID}, A.DataBelongID, NULL) = 1"; if (!string.IsNullOrEmpty(condition)) conditions += " AND " + condition; if (filter.jsonParam != null) foreach (JProperty jProperty in filter.jsonParam.Properties()) { var name = jProperty.Name; var value = jProperty.Value.ToString(); if (name == "page" || name == "pageSize") continue; if (name == "DueDate") { var jsonParam = JsonConvert.DeserializeObject(value); conditions += $" AND FORMAT(DueDate, 'yyyy-MM-dd') = '{jsonParam.columnValue}'"; continue; } if (!string.IsNullOrWhiteSpace(value)) { var jsonParam = JsonConvert.DeserializeObject(value); switch (jsonParam.operationKey) { case "Include": conditions += $" AND {name} LIKE '%{jsonParam.columnValue}%'"; break; case "NotInclude": conditions += $" AND {name} NOT LIKE '%{jsonParam.columnValue}%'"; break; case "IsNull": conditions += $" AND {name} IS NULL"; break; case "NotNull": conditions += $" AND {name} IS NOT NULL"; break; case "Equal": conditions += $" AND {name} ='{jsonParam.columnValue}'"; break; case "NotEqual": conditions += $" AND {name} !='{jsonParam.columnValue}'"; break; default: break; } } } sql += conditions; countSql += conditions; int total = await Db.Ado.GetIntAsync(countSql); sql = "SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY " + filter.orderBy + ") NUM FROM (SELECT * FROM (" + sql + " "; sql += ") A ) B ) C"; sql += " WHERE NUM <= " + filter.pageNum * filter.pageSize + " AND NUM >" + (filter.pageNum - 1) * filter.pageSize; var entitys = await Db.Ado.SqlQueryAsync(sql); var attachments = new List(); var ids = entitys.Select(x => x.Id.ToString()).ToList(); if (ids.Count > 0) attachments = await Db.Queryable().Where(x => ids.Contains(x.TableName)).ToListAsync(); attachments.ForEach(x => { x.PhysicsPath = "/Advanced" + x.PhysicsPath; x.RelativePath = "/Advanced" + x.RelativePath; x.ThumbnailPath = "/Advanced" + x.ThumbnailPath; x.FileURL = "/Advanced" + x.FileURL; }); entitys.ForEach(async x => { x.ScoreMethodLabel = await GetParaLabel("ScoreMethod", x.ScoreMethod); x.ScoreStatusLabel = await GetParaLabel("TrainingExamScoreStatus", x.ScoreStatus); //x.CourseStatusLabel = await GetParaLabel("TrainingCourseStatus", x.CourseStatus); //x.StudyStatusLabel = await GetParaLabel("TrainingStudyStatus", x.StudyStatus); if (x.IsPass != null) x.IsPassLabel = x.IsPass == true ? "合格" : "不合格"; if (x.FinallyIsPass != null) x.FinallyIsPassLabel = x.FinallyIsPass == true ? "合格" : "不合格"; x.Attachments = attachments.Where(o => o.TableName == x.Id.ToString()).ToList(); //x.InStatusLabel = x.InStatus == "1" ? "在职" : null; //x.InStatusLabel = x.InStatus == "2" ? "离职" : null; //x.InStatusLabel = x.InStatus == "0" ? "未入职" : null; if (!x.ExamDate.IsNull()) x.ExamDate1 = DateTimeHelper.ConvertToDayString(x.ExamDate); if (x.BeginTime != null) x.ExamDate1 = x.BeginTime.Value.ToString("yyyy-MM-dd"); x.TotalScore += x.Score ?? 0; x.TotalScore += x.AdjustScore ?? 0; x.TotalScore += x.ActualScore ?? 0; //if (x.DueDate != null) // x.DueDate1 = x.DueDate.Value.ToString("yyyy-MM-dd"); //if (x.ExamDate != null) // x.ExamDate1 = x.ExamDate.Value.ToString("yyyy-MM-dd"); x.DataBelongName = await GetDataBelongName(x.DataBelongID); }); return new ServicePageResult(filter.pageNum, total, filter.pageSize, entitys); } public async Task> Query(string examId, QueryBody body) { return await QueryFilterPage(body, $"ExamId='{examId}'"); } public async Task ModifyAdjustScore(string examRecordId, EditGhre_ExamRecordInput edit) { var entity = await QuerySingle(examRecordId); if (entity != null && entity.ExamId != null) if (await Db.Queryable().Where(x => x.Id == entity.ExamId.Value && x.Status == "Disabled").AnyAsync()) return ServiceResult.OprateFailed($"该考试已归档,不可进行调整分数!"); var paper = await Db.Queryable().FirstAsync(x => x.Id == entity.ExamPaperId); if (paper == null) return ServiceResult.OprateFailed("该考试管理的试卷已被删除,暂不可变更调整分!"); entity.AdjustScore = edit.AdjustScore ?? 0; //entity.Score += entity.AdjustScore; string score1 = Regex.Replace(entity.Score.ToString(), @"\.(0+)$", "") + "/" + Regex.Replace(entity.Score.ToString(), @"\.(0+)$", ""); if (entity.Score < 0) return ServiceResult.OprateFailed($"调整后得分为【{score1}】,得分不可小于0!"); if (entity.Score > paper.TotalScore) return ServiceResult.OprateFailed($"调整后得分为【{score1}】,不可大于卷面总分【{Regex.Replace(paper.TotalScore.ToString(), @"\.(0+)$", "") + "/" + Regex.Replace(paper.TotalScore.ToString(), @"\.(0+)$", "")}】!"); #region 处理最终得分 var exam = await Db.Queryable().Where(x => x.Id == entity.ExamId).FirstAsync(); if (exam != null) { if (exam.OnlineScorePercentage != null && exam.OfflineScorePercentage != null) if (exam.OnlineScorePercentage > 0 && exam.OfflineScorePercentage > 0) { decimal OnlineScorePercentage = exam.OnlineScorePercentage.Value / 100; decimal OfflineScorePercentage = exam.OfflineScorePercentage.Value / 100; entity.FinallyScore = (entity.Score + (entity.AdjustScore ?? 0)) * OnlineScorePercentage; if (entity.ActualScore != null && entity.ActualScore > 0) entity.FinallyScore += entity.ActualScore * OfflineScorePercentage; } } #endregion var paperId = entity.ExamPaperId; var examPaper = await Db.Queryable().Where(x => x.Id == paperId).FirstAsync(); if (examPaper != null) entity.IsPass = examPaper.PassScore > (entity.Score + entity.AdjustScore) ? false : true; await Update(entity, ["IsPass", "AdjustScore", "FinallyScore", "UpdateTime", "UpdateBy"]); return ServiceResult.OprateSuccess("修改成功!"); //return await QueryFilterPage(body, $"ExamId='{examId}'"); } public async Task ModifyActualScore(string examRecordId, EditGhre_ExamRecordInput edit) { var entity = await QuerySingle(examRecordId); if (entity != null && entity.ExamId != null) if (await Db.Queryable().Where(x => x.Id == entity.ExamId.Value && x.Status == "Disabled").AnyAsync()) return ServiceResult.OprateFailed($"该考试已归档,不可进行调整分数!"); if (edit.AdjustScore < 0) return ServiceResult.OprateFailed($"实操分为【{edit.AdjustScore}】,分数不可小于0!"); entity.ActualScore = edit.AdjustScore; //string score1 = Regex.Replace(entity.Score.ToString(), @"\.(0+)$", "") + "/" + Regex.Replace(entity.Score.ToString(), @"\.(0+)$", ""); #region 处理最终得分 var exam = await Db.Queryable().Where(x => x.Id == entity.ExamId).FirstAsync(); if (exam != null) { if (exam.OnlineScorePercentage != null && exam.OfflineScorePercentage != null) if (exam.OnlineScorePercentage > 0 && exam.OfflineScorePercentage > 0) { decimal OnlineScorePercentage = exam.OnlineScorePercentage.Value / 100; decimal OfflineScorePercentage = exam.OfflineScorePercentage.Value / 100; entity.FinallyScore = (entity.Score + (entity.AdjustScore ?? 0)) * OnlineScorePercentage; if (entity.ActualScore != null && entity.ActualScore > 0) entity.FinallyScore += entity.ActualScore * OfflineScorePercentage; } } #endregion await Update(entity, ["ActualScore", "FinallyScore", "UpdateTime", "UpdateBy"]); return ServiceResult.OprateSuccess("修改成功!"); } public async Task ModifyFinallyIsPass(string examRecordId, EditGhre_ExamRecordInput edit) { var entity = await QuerySingle(examRecordId); if (entity != null && entity.ExamId != null) if (await Db.Queryable().Where(x => x.Id == entity.ExamId.Value && x.Status == "Disabled").AnyAsync()) return ServiceResult.OprateFailed($"该考试已归档,不可进行调整!"); //if (entity.ActualScore is null && entity.AdjustScore is null) // return ServiceResult.OprateFailed($"请先变更调整分或实操分!"); entity.FinallyIsPass = edit.FinallyIsPass ?? false; //string score1 = Regex.Replace(entity.Score.ToString(), @"\.(0+)$", "") + "/" + Regex.Replace(entity.Score.ToString(), @"\.(0+)$", ""); await Update(entity, ["FinallyIsPass", "UpdateTime", "UpdateBy"]); return ServiceResult.OprateSuccess("修改成功!"); } public async Task> ExtendAsync(long examRecordId, long? groupId) { var extend = new Ghre_ExamRecordExtend(); var record = await QuerySingle(x => x.Id == examRecordId || x.StudyRecordId == examRecordId); examRecordId = record.Id; using var _context = ContextFactory.CreateContext(); var src = _context.Ghre_ExamRecordDetail.Where(x => x.ExamRecordId == record.Id); var src1 = _context.Ghre_ExamRecordAnswer .OrderBy(x => x.TaxisNo) .Where(x => x.ExamRecordDetailId != null && x.ExamRecordId == record.Id); if (groupId != null) src = src.Where(x => x.GroupId == groupId); else src = src.Where(x => x.IsEnable == 1); var details = await src .ToListAsync(); var detailIds = details.Select(x => x.Id).ToList(); src1 = src1.Where(x => detailIds.Contains(x.ExamRecordDetailId.Value)); var recordAnswers = await src1 .ToListAsync(); if (record.ScoreStatus == Consts.DIC_EXAM_RECORD_SCORE_STATUS.NO_SCORE) await ExamHelper.SystemMarkAsync(Db, record, details, recordAnswers); var exampaper = await Db.Queryable().FirstAsync(x => x.Id == record.ExamPaperId); var baseData = new DefaultGhre_ExamPaperBaseData(); baseData.PaperNo = exampaper.PaperNo; baseData.PaperName = exampaper.PaperName; baseData.AnswerTime = exampaper.AnswerTime; baseData.ScoreMethod = exampaper.ScoreMethod; baseData.TotalScore = exampaper.TotalScore; baseData.PassScore = exampaper.PassScore; baseData.RetakeTimes = exampaper.RetakeTimes; baseData.RemarkSz = exampaper.RemarkSz; baseData.LinkType = exampaper.LinkType; baseData.CourseId = exampaper.LinkType == "CourseId" ? exampaper.LinkId : null; baseData.CourseSceneId = exampaper.LinkType == "CourseSceneId" ? exampaper.LinkId : null; extend.baseData = baseData; extend.styleInfo.coverImage = exampaper.CoverUrl; extend.styleInfo.paperStyle = exampaper.Style; extend.styleInfo.coverBackGround = exampaper.CoverBackGround; var questions = await Db.Queryable() //.Where(x => x.ExamPaperId == exampaper.Id) .Where(x => (x.ExamPaperId == exampaper.Id && exampaper.SetMethod == DIC_EXAM_PAPER_SET_METHOD.MANUAL) || (x.ExamPaperId == examRecordId && exampaper.SetMethod == DIC_EXAM_PAPER_SET_METHOD.RANDOM)) .ToListAsync(); var previews = questions.Where(x => x.QuestionId != null).Select(x => new DefaultGhre_ExamPaperPreview() { Id = x.Id, ConfigId = x.ConfigId, parentId = x.ConfigId, QuestionId = x.QuestionId.Value, ExamPaperId = x.ExamPaperId, Score = x.Score, RealScore = details.Where(m => m.QuestionId == x.QuestionId).Sum(m => (m.Score ?? 0) + (m.AdjustScore ?? 0)), //ExamRecordDetailId = details.Where(m => m.QuestionId == x.QuestionId).First()?.Id }).ToList(); var questionIds = previews.Select(x => x.QuestionId).Distinct().ToList(); var questions1 = await Db.Queryable().Where(x => questionIds.Contains(x.Id)).ToListAsync(); var answers = await Db.Queryable().Where(x => x.QuestionId != null && questionIds.Contains(x.QuestionId.Value)).OrderBy(x => x.TaxisNo).ToListAsync(); ; previews.ForEach(x => { var answers1 = answers.Where(y => y.QuestionId == x.QuestionId).ToList(); x.QuestionType = questions1.FirstOrDefault(a => a.Id == x.QuestionId)?.QuestionType; x.QuestionContent = questions1.FirstOrDefault(a => a.Id == x.QuestionId)?.QuestionContent; if (!string.IsNullOrEmpty(x.QuestionContent)) x.QuestionContent = WebUtility.HtmlDecode(x.QuestionContent); var detail = new FromGhre_QuestionQuestionTypeDetail(); detail.content = x.QuestionContent; detail.difficulty = questions1.FirstOrDefault(a => a.Id == x.QuestionId)?.DifficultyLevel; detail.answer = answers1.Where(x => x.IsCorrect == true).FirstOrDefault()?.QuestionNo; detail.answer1 = answers1.Where(x => x.IsCorrect == true).Select(x => x.QuestionNo).ToList(); detail.answerList = answers1.Select(x => new FromGhre_QuestionQuestionAnswerList() { No = x.QuestionNo, label = x.AnswerContent, imageUrl = x.ImageUrl, imgWidthPc = x.ImageWidthPc, imgWidthApp = x.ImageWidthApp, }).ToList(); detail.RemarkSz = questions1.FirstOrDefault(a => a.Id == x.QuestionId)?.QuestionAnalysis; x.detail = detail; var recordDetail = details.FirstOrDefault(m => m.ExamPaperQuestionId == x.Id); if (recordDetail != null) x.ExamRecordDetailId = recordDetail.Id; switch (x.QuestionType) { case "Completion": case "ShortAnswer": var answerIds1 = recordAnswers.Where(m => m.ExamRecordDetailId == recordDetail?.Id && m.QuestionAnswerId == null).Select(m => m.AnswerContent).ToList(); answerIds1.ForEach(m => { x.value1.Add(m); }); if (x.value1.Any()) x.value = x.value1.First(); break; default: var answerIds = recordAnswers.Where(m => m.ExamRecordDetailId == recordDetail?.Id && m.QuestionAnswerId != null).Select(m => m.QuestionAnswerId).ToList(); answers1.Where(m => answerIds.Contains(m.Id)).ForEach(m => { x.value1.Add(m.QuestionNo); }); if (x.value1.Any()) x.value = x.value1.First(); break; } }); extend.questionList = previews; string sql = @$"SELECT StaffNo, StaffName, dbo.FO_DeptInfo (DeptID, getdate (), 1, 'DeptNo') DeptNo, dbo.FO_DeptInfo (DeptID, getdate (), 1, 'DeptFullPateName') DepteName FROM Ghra_Staff WHERE StaffID = {record.StaffId}"; extend.StaffInfo = await Db.Ado.SqlQuerySingleAsync(sql); extend.StaffInfo.StaffScore = details.Sum(x => x.Score) ?? 0; sql = @$"SELECT A.StaffNo, A.StaffName, dbo.FO_DeptInfo (A.DeptID, getdate (), 1, 'DeptNo') DeptNo, dbo.FO_DeptInfo (A.DeptID, getdate (), 1, 'DeptName') DepteName, A.PhotoUrl, B.TitleName FROM Ghra_Staff A LEFT JOIN Ghra_Title B ON B.TitleID = A.TitleID WHERE A.StaffID = {record.StaffId}"; extend.CommentData = await Db.Ado.SqlQuerySingleAsync(sql); if (record.ScoreStatus == Consts.DIC_EXAM_RECORD_SCORE_STATUS.NO_SCORE) extend.CommentData.IsFirstTime = true; extend.CommentData.Comment = record.Comment; var body = new QueryBody(); body.pageNum = 1; body.pageSize = 10000; var records = await QueryFilterPage(body, $"ExamId='{record.ExamId}'"); var records1 = records.result.DT_TableDataT1; int index = records1.FindIndex(x => x.Id == examRecordId); extend.PreviousRecordId = index - 1 >= 0 && records1.Count > 1 ? records1[index - 1].Id : null; extend.NextRecordId = records1.Count > index + 1 ? records1[index + 1].Id : null; return ServiceResult.OprateSuccess("查询成功!", extend); } public async Task CommentAsync(Ghre_ExamRecordExtend extend, long examRecordId) { var record = await QuerySingle(x => x.Id == examRecordId); record.Score = extend.StaffInfo.StaffScore; record.ScoreStatus = Consts.DIC_EXAM_RECORD_SCORE_STATUS.HAS_SCORE; record.Comment = extend.CommentData.Comment; var details = await Db.Queryable().Where(x => x.ExamRecordId == record.Id).ToListAsync(); extend.questionList.ForEach(x => { //var recordDetail = details.FirstOrDefault(m => m.ExamPaperQuestionId == x.Id); var recordDetail = details.FirstOrDefault(m => m.Id == x.ExamRecordDetailId); if (recordDetail != null) { recordDetail.Score = x.RealScore; recordDetail.IsCorrect = x.Score == x.RealScore ? true : false; } }); var paperId = record.ExamPaperId; var examPaper = await Db.Queryable().Where(x => x.Id == paperId).FirstAsync(); if (examPaper != null) record.IsPass = examPaper.PassScore > (record.Score + (record.AdjustScore ?? 0)) ? false : true; record.Score = details.Sum(x => x.Score); record.Score = extend.questionList.Sum(x => x.RealScore); await Db.Updateable(record).ExecuteCommandAsync(); await Db.Updateable(details).ExecuteCommandAsync(); var groupId = details.First()?.GroupId; var group = await Db.Queryable().Where(x => x.Id == groupId).FirstAsync(); if (group != null) { group.Score = record.Score; await Db.Updateable(group).UpdateColumns(it => new { it.Score }, true) .ExecuteCommandAsync(); } if (record.IsPass == true && record.StudyRecordId != null) { var studyRecord = await Db.Queryable().Where(x => x.Id == record.StudyRecordId).FirstAsync(); await ExamHelper.MarkCompleteStatusAsync(Db, studyRecord); } return ServiceResult.OprateSuccess("提交成功!"); } public async Task> QueryExamAsync(long id) { var extend = new QueryExam(); var body = new QueryBody(); body.pageNum = 1; body.pageSize = 10000; bool isOpenClass = false; long? examRecordId = 0; Ghre_Exam exam = null; var staffId = App.User.StaffId; var openClass = await Db.Queryable().Where(x => x.Id == id).FirstAsync(); if (openClass != null) { var id1 = await Db.Queryable().Where(x => x.OpenClassId == id && x.StaffId == staffId).Select(x => x.Id).FirstAsync(); if (id1 > 0) id = id1; else { id1 = await Db.Queryable().Where(x => x.OpenClassId == id && x.StaffId == staffId).Select(x => x.Id).FirstAsync(); if (id1 > 0) id = id1; } if (id1 == 0 && openClass.IsRequireStudy == false) { long? courseSnapId = null; if (openClass.LinkType == "Course") courseSnapId = await Db.Queryable().Where(x => x.CourseId == openClass.LinkId).Select(x => x.Id).FirstAsync(); var insrt = new InsertGhre_ExamRecordInput() { ExamId = openClass.ExamId, StudyRecordId = null, StaffId = staffId, CourseSnapId = courseSnapId, CourseSceneId = openClass.LinkType == "CourseScene" ? openClass.LinkId : null, CourseId = openClass.LinkType == "Course" ? openClass.LinkId : null, ExamPaperId = openClass.ExamPaperId, ExamDate = DateTime.Now.Date, RetakeTimes = 0, Status = DIC_EXAM_RECORD_STATUS.WAIT, ScoreStatus = DIC_EXAM_RECORD_SCORE_STATUS.NO_SCORE, BeginTime = openClass.ExamStartTime, EndTime = openClass.ExamEndTime, OpenClassId = openClass?.Id }; id = await base.Add(insrt); } exam = await Db.Queryable() .Where(x => x.Id == openClass.ExamId) .FirstAsync(x => x.Status == DIC_EXAM_STATUS.RELEASED); isOpenClass = true; } Ghre_StudyRecord studyRecord = null; if (await Db.Queryable().AnyAsync(x => x.Id == id)) { studyRecord = await Db.Queryable().FirstAsync(x => x.ExamId == id && x.StaffId == staffId); if (studyRecord != null) id = studyRecord.Id; } if (await Db.Queryable().AnyAsync(x => x.Id == id && x.StaffId == staffId)) { var examRecord = await Db.Queryable().FirstAsync(x => x.StudyRecordId == id && x.StaffId == staffId); if (!examRecord.IsNull()) examRecordId = examRecord.Id; else { studyRecord = await Db.Queryable().FirstAsync(x => x.Id == id && x.StaffId == staffId); exam = await Db.Queryable() .Where(x => x.Id == studyRecord.ExamId) .FirstAsync(x => x.Status == Consts.DIC_EXAM_STATUS.RELEASED); if (exam.IsNull()) exam = await Db.Queryable() .Where(x => x.Status == Consts.DIC_EXAM_STATUS.RELEASED && ((x.DateType == Consts.DicExamDateType.EXAM_DATE && x.BeginTime.Value.Date <= DateTime.Now.Date && x.EndTime.Value.Date >= DateTime.Now.Date) || x.DateType == Consts.DicExamDateType.AFTER_HOW_LONG)) .WhereIF(!studyRecord.CourseId.IsNull(), x => x.CourseId == studyRecord.CourseId) .WhereIF(!studyRecord.CourseSceneId.IsNull(), x => x.CourseSceneId == studyRecord.CourseSceneId) .FirstAsync(); if (exam.IsNull()) return ServiceResult.OprateFailed("该门课程尚未开启考试,请联系HR !"); var insrt = new InsertGhre_ExamRecordInput() { ExamId = exam.Id, StudyRecordId = studyRecord.Id, StaffId = studyRecord.StaffId, CourseSnapId = studyRecord.CourseSnapId, CourseSceneId = studyRecord.CourseSceneId, CourseId = studyRecord.CourseId, ExamPaperId = exam.ExamPaperId, ExamDate = DateTime.Now.Date, RetakeTimes = 0, Status = DIC_EXAM_RECORD_STATUS.WAIT, ScoreStatus = DIC_EXAM_RECORD_SCORE_STATUS.NO_SCORE, BeginTime = exam.BeginTime, EndTime = exam.EndTime, OpenClassId = openClass?.Id, }; examRecordId = await base.Add(insrt); if (studyRecord.ExamId.IsNull()) { string sql = $@"UPDATE Ghre_StudyRecord SET ExamId={exam.Id} WHERE Id='{studyRecord.Id}'; "; await Db.Ado.ExecuteCommandAsync(sql); } } } if (examRecordId == 0) examRecordId = id; var records = await QueryFilterPage(body, $"Id='{examRecordId}' AND StaffId='{staffId}'"); if (!records.result.DT_TableDataT1.Any()) return ServiceResult.OprateFailed("无效的考试链接!"); var record = records.result.DT_TableDataT1.FirstOrDefault(); extend.Status1 = record.Status; if (studyRecord.IsNull()) studyRecord = await Db.Queryable().FirstAsync(x => x.Id == record.StudyRecordId); if (exam.IsNull()) exam = await Db.Queryable() .Where(x => x.Id == studyRecord.ExamId) .FirstAsync(x => x.Status == Consts.DIC_EXAM_STATUS.RELEASED || x.Status == Consts.DIC_EXAM_STATUS.DISABLED); if (exam.StudyFinishedRule != DIC_EXAM_STUDY_FINISHED_RULE.NO_STUDY_EXAM_PASS) if ((isOpenClass == false && exam.IsRequireStudy == true) || (isOpenClass == true && openClass.IsRequireStudy == true)) if (studyRecord.StudyProgress.IsNull() || (!studyRecord.StudyProgress.IsNull() && studyRecord.StudyProgress < 100)) return ServiceResult.OprateFailed("学习尚未结束暂不可考试!"); if (exam.IsNull() && (record.Status == DIC_EXAM_RECORD_STATUS.WAIT || record.Status == DIC_EXAM_RECORD_STATUS.EXAMING)) return ServiceResult.OprateFailed("该门课程尚未开启考试,请联系HR !"); if (exam.Status == Consts.DIC_EXAM_STATUS.DISABLED && (record.Status == DIC_EXAM_RECORD_STATUS.WAIT || record.Status == DIC_EXAM_RECORD_STATUS.EXAMING)) return ServiceResult.OprateFailed("该考试已归档,暂不可考试 !"); var dt = Db.GetDate(); if (exam.DateType == Consts.DicExamDateType.AFTER_HOW_LONG) { record.BeginTime = studyRecord?.EndTime ?? DateTime.Now; if (!record.BeginTime.IsNull()) record.EndTime = record.BeginTime.Value.AddDays(exam.AfterHowLong ?? 7); } if (isOpenClass) { if (record.Status == DIC_EXAM_RECORD_STATUS.WAIT && (record.EndTime < dt.Date || record.BeginTime > dt)) extend.IsAllowExam = false; } else { if (!(record.BeginTime.Value.Date <= dt.Date && record.EndTime.Value.Date >= dt.Date) && (record.Status == DIC_EXAM_RECORD_STATUS.WAIT || record.Status == DIC_EXAM_RECORD_STATUS.EXAMING)) { extend.IsAllowExam = false; } } //return ServiceResult.OprateFailed("考试已结束!"); var details = await Db.Queryable().Where(x => x.ExamRecordId == record.Id).ToListAsync(); var detailIds = details.Select(x => x.Id).ToList(); var recordAnswers = await Db.Queryable() .OrderBy(x => x.TaxisNo) .Where(x => x.ExamRecordDetailId != null && detailIds.Contains(x.ExamRecordDetailId.Value)) .ToListAsync(); //if (record.ScoreStatus == "NoScore") // await ExamHelper.SystemMarkAsync(Db, record, details, recordAnswers); var exampaper = await Db.Queryable().FirstAsync(x => x.Id == record.ExamPaperId); var baseData = new DefaultGhre_ExamPaperBaseData(); baseData.PaperNo = exampaper.PaperNo; baseData.PaperName = exampaper.PaperName; baseData.AnswerTime = exampaper.AnswerTime; baseData.ScoreMethod = exampaper.ScoreMethod; baseData.TotalScore = exampaper.TotalScore; baseData.PassScore = exampaper.PassScore; baseData.RetakeTimes = exampaper.RetakeTimes; baseData.RemarkSz = exampaper.RemarkSz; baseData.LinkType = exampaper.LinkType; baseData.CourseId = exampaper.LinkType == "CourseId" ? exampaper.LinkId : null; baseData.CourseSceneId = exampaper.LinkType == "CourseSceneId" ? exampaper.LinkId : null; extend.baseData = baseData; extend.styleInfo.coverImage = exampaper.CoverUrl; extend.styleInfo.paperStyle = exampaper.Style; extend.styleInfo.coverBackGround = exampaper.CoverBackGround; if (exampaper.SetMethod == DIC_EXAM_PAPER_SET_METHOD.RANDOM && record.Status != DIC_EXAM_RECORD_STATUS.EXAM_END && record.Status != DIC_EXAM_RECORD_STATUS.SYSTEM_END) { await Db.Deleteable().Where(x => x.ExamPaperId == examRecordId).ExecuteCommandAsync(); var configs = await Db.Queryable().OrderBy(x => x.TaxisNo).Where(x => x.ExamPaperId == exampaper.Id).ToListAsync(); var examPaperQuestionIds = new List(); for (int i = 0; i < configs.Count; i++) { var config = configs[i]; string sql = $@"SELECT TOP {config.Quantity} *,NEWID() AS GuidValue FROM Ghre_Question WHERE IsEnable=1"; if (!string.IsNullOrWhiteSpace(config.DifficultyLevel)) sql += $" AND DifficultyLevel='{config.DifficultyLevel}'"; if (!string.IsNullOrWhiteSpace(config.QuestionType)) sql += $" AND QuestionType='{config.QuestionType}'"; if (config.CourseId != null) sql += $" AND (CourseId='{config.CourseId}' OR CourseIds like '%{config.CourseId}%')"; if (config.QuestionId != null) sql += $" AND Id='{config.QuestionId}'"; if (examPaperQuestionIds.Any()) sql += $" AND Id NOT IN ({string.Join(",", examPaperQuestionIds)})"; sql += $" ORDER BY GuidValue ASC"; var questions2 = await Db.Ado.SqlQueryAsync(sql); if (questions2.Any()) { examPaperQuestionIds.AddRange(questions2.Select(x => x.Id)); var insertExamPaperQuestions = questions2.Select(x => new Ghre_ExamPaperQuestion { Id = SnowFlakeSingle.instance.getID(), CreateTime = DateTime.Now, ExamPaperId = examRecordId, QuestionId = x.Id, ConfigId = x.Id, Score = config.Score }).ToList(); await Db.Insertable(insertExamPaperQuestions).ExecuteCommandAsync(); } } } var questions = await Db.Queryable() .Where(x => (x.ExamPaperId == exampaper.Id && exampaper.SetMethod == DIC_EXAM_PAPER_SET_METHOD.MANUAL) || (x.ExamPaperId == examRecordId && exampaper.SetMethod == DIC_EXAM_PAPER_SET_METHOD.RANDOM)) .ToListAsync(); var previews = questions.Where(x => x.QuestionId != null).Select(x => new DefaultGhre_ExamPaperPreview() { Id = x.Id, ConfigId = x.ConfigId, parentId = x.ConfigId, QuestionId = x.QuestionId.Value, ExamPaperId = x.ExamPaperId, Score = x.Score, RealScore = details.Where(m => m.QuestionId == x.QuestionId).Sum(m => (m.Score ?? 0) + (m.AdjustScore ?? 0)), //ExamRecordDetailId = details.Where(m => m.QuestionId == x.QuestionId).First()?.Id }).ToList(); var questionIds = previews.Select(x => x.QuestionId).Distinct().ToList(); var questions1 = await Db.Queryable().Where(x => questionIds.Contains(x.Id)).ToListAsync(); var answers = await Db.Queryable().Where(x => x.QuestionId != null && questionIds.Contains(x.QuestionId.Value)).OrderBy(x => x.TaxisNo).ToListAsync(); ; previews.ForEach(x => { var answers1 = answers.Where(y => y.QuestionId == x.QuestionId).ToList(); x.QuestionType = questions1.FirstOrDefault(a => a.Id == x.QuestionId)?.QuestionType; x.QuestionContent = questions1.FirstOrDefault(a => a.Id == x.QuestionId)?.QuestionContent; if (!string.IsNullOrEmpty(x.QuestionContent)) x.QuestionContent = WebUtility.HtmlDecode(x.QuestionContent); var detail = new FromGhre_QuestionQuestionTypeDetail(); detail.content = x.QuestionContent; detail.difficulty = questions1.FirstOrDefault(a => a.Id == x.QuestionId)?.DifficultyLevel; //detail.answer = answers1.Where(x => x.IsCorrect == true).FirstOrDefault()?.QuestionNo; //detail.answer1 = answers1.Where(x => x.IsCorrect == true).Select(x => x.QuestionNo).ToList(); if (x.QuestionType == "Completion") detail.answer1 = answers1.Where(x => x.IsCorrect == true).Select(x => "").ToList(); if (x.QuestionType != "Completion") detail.answerList = answers1.Select(x => new FromGhre_QuestionQuestionAnswerList() { No = x.QuestionNo, label = x.AnswerContent, imageUrl = x.ImageUrl, imgWidthPc = x.ImageWidthPc, imgWidthApp = x.ImageWidthApp, }).ToList(); x.detail = detail; var recordDetail = details.FirstOrDefault(m => m.ExamPaperQuestionId == x.Id); if (recordDetail != null) x.ExamRecordDetailId = recordDetail.Id; switch (x.QuestionType) { case "Completion": case "ShortAnswer": var answerIds1 = recordAnswers.Where(m => m.ExamRecordDetailId == recordDetail?.Id && m.QuestionAnswerId == null).Select(m => m.AnswerContent).ToList(); answerIds1.ForEach(m => { x.value1.Add(m); }); if (x.value1.Any()) x.value = x.value1.First(); break; default: var answerIds = recordAnswers.Where(m => m.ExamRecordDetailId == recordDetail?.Id && m.QuestionAnswerId != null).Select(m => m.QuestionAnswerId).ToList(); answers1.Where(m => answerIds.Contains(m.Id)).ForEach(m => { x.value1.Add(m.QuestionNo); }); if (x.value1.Any()) x.value = x.value1.First(); break; } }); extend.questionList = previews; extend.StaffNo = record.StaffNo; extend.StaffName = record.StaffName; extend.DeptNo = record.DeptNo; extend.DeptName = record.DeptName; extend.StaffPhoto = record.StaffPhotoUrl; extend.ExamName = record.ExamName + "(" + record.ExamNo + ")"; extend.ExamRemark = exam.RemarkSz; if (isOpenClass) { extend.ExamBeginDate = DateTimeHelper.ConvertToMiniuteString(record.BeginTime); extend.ExamEndDate = DateTimeHelper.ConvertToMiniuteString(record.EndTime); } else { extend.ExamBeginDate = DateTimeHelper.ConvertToDayString(record.BeginTime); extend.ExamEndDate = DateTimeHelper.ConvertToDayString(record.EndTime); } extend.ExamStatus = record.Status; extend.TotalScore = details.Where(x => x.Score != null).Sum(x => x.Score); extend.Id = record.Id; extend.CourseName = record.CourseName; extend.CanRetake = true; extend.ScoreOut = false; if ((record.RetakeTimes ?? 0) >= (exampaper.RetakeTimes ?? 0)) extend.CanRetake = false; //TimeSpan timeDifference = record.EndTime.Value - DateTime.Now; //extend.RemainingSecond = Convert.ToInt32(timeDifference.TotalSeconds); //if (extend.RemainingSecond < 0) extend.RemainingSecond = 0; extend.RemainingSecond = 3600; if (!exampaper.AnswerTime.IsNull()) extend.RemainingSecond = exampaper.AnswerTime.Value * 60; #region 更新实际开始时间 if (extend.ExamStatus != Consts.DIC_EXAM_RECORD_STATUS.EXAM_END) { string sql = $"UPDATE Ghre_ExamRecord SET ActualBeginTime = GETDATE(),ActualEndTime = NULL WHERE Id={examRecordId}"; await Db.Ado.ExecuteCommandAsync(sql); } #endregion if (!record.ActualEndTime.IsNull()) { TimeSpan timeDifference = record.ActualEndTime.Value - record.ActualBeginTime.Value; extend.UsageTime = $"{timeDifference.Minutes}分{timeDifference.Seconds}秒"; } if (record.IsView == true) extend.CanRetake = false; if (exampaper.ScoreMethod == DIC_EXAM_PAPER_SCORE_METHOD.MANUAL && record.ScoreStatus == DIC_EXAM_RECORD_SCORE_STATUS.NO_SCORE && record.Status == DIC_EXAM_RECORD_STATUS.EXAM_END) { extend.ScoreOut = true; extend.ScoreOutTime = "等待人工阅卷"; extend.IsAllowView = false; } if (record.Status == DIC_EXAM_RECORD_STATUS.SYSTEM_END) { extend.IsAllowView = false; extend.IsMissExam = true; } #region 根据参数判断 考完,是否允许查看答案和解析、考完,查看答案和解析后,是否允许重新考试 if (record.Status == DIC_EXAM_RECORD_STATUS.EXAM_END && exam.IsViewResult != true) extend.IsAllowView = false; if (record.Status == DIC_EXAM_RECORD_STATUS.EXAM_END && exam.IsViewResult == true && exam.IsAfterViewResultRetake == true) { if (exam.IsViewResult == true) { if (exam.IsAfterViewResultRetake == true && (record.RetakeTimes ?? 0) < (exampaper.RetakeTimes ?? 0)) extend.CanRetake = true; else extend.CanRetake = false; } else extend.IsAllowView = false; } extend.IsAfterViewResultRetake = exam.IsAfterViewResultRetake; #endregion var Groups = await Db.Queryable() .OrderByDescending(x => x.ExamTime) .Where(x => x.ExamRecordId == record.Id) .Select(x => new { GroupId = x.Id, x.ExamRecordId, x.ExamTime, x.Score }).ToListAsync(); extend.Groups = Groups .Select(x => new ExamGroup() { GroupId = x.GroupId, ExamRecordId = x.ExamRecordId, ExamTime = x.ExamTime.ObjToString() + (x.Score != null ? $"得分:{x.Score}" : ""), }).ToList(); return ServiceResult.OprateSuccess("查询成功!", extend); } public async Task StartExamAsync(long examRecordId) { var entity = await base.QuerySingle(examRecordId); if (entity is null) return ServiceResult.OprateFailed("无效的考试ID!"); var exam = await Db.Queryable() .Where(x => x.Id == entity.ExamId) .FirstAsync(x => x.Status == Consts.DIC_EXAM_STATUS.RELEASED); var studyRecord = await Db.Queryable().FirstAsync(x => x.Id == entity.StudyRecordId); if (exam.DateType == Consts.DicExamDateType.AFTER_HOW_LONG) { entity.BeginTime = studyRecord?.EndTime ?? DateTime.Now; if (!entity.BeginTime.IsNull()) entity.EndTime = entity.BeginTime.Value.AddDays(exam.AfterHowLong ?? 7); } var dt = Db.GetDate(); if (!(entity.BeginTime.Value.Date <= dt.Date && entity.EndTime.Value.Date >= dt.Date)) return ServiceResult.OprateFailed("考试已结束!"); #region 试卷 引用次数 if (entity.Status == Consts.DIC_EXAM_RECORD_STATUS.WAIT) { string sql = $"UPDATE Ghre_ExamPaper SET LinkTimes = ISNULL(LinkTimes, 0)+1 WHERE Id={entity.ExamPaperId}"; await Db.Ado.ExecuteCommandAsync(sql); } #endregion if (entity.ActualBeginTime is null) entity.ActualBeginTime = DateTime.Now; if (entity.Status == Consts.DIC_EXAM_RECORD_STATUS.WAIT) entity.Status = Consts.DIC_EXAM_RECORD_STATUS.EXAMING; await Update(entity, new List() { "ActualBeginTime", "Status" }); return ServiceResult.OprateSuccess("成功!"); } public async Task RetakeExamAsync(long examRecordId) { var entity = await base.QuerySingle(examRecordId); if (entity is null) return ServiceResult.OprateFailed("无效的考试ID!"); var exampaper = await Db.Queryable().FirstAsync(x => x.Id == entity.ExamPaperId); if ((entity.RetakeTimes ?? 0) >= (exampaper.RetakeTimes ?? 0)) return ServiceResult.OprateFailed($"重考次数已达上限,已重考次数【{entity.RetakeTimes ?? 0}】,允许重考次数【{exampaper.RetakeTimes ?? 0}】!"); if (entity.Status == DIC_EXAM_RECORD_STATUS.EXAM_END) entity.Status = DIC_EXAM_RECORD_STATUS.EXAMING; entity.RetakeTimes = entity.RetakeTimes is null ? 1 : entity.RetakeTimes + 1; entity.ScoreStatus = DIC_EXAM_RECORD_SCORE_STATUS.NO_SCORE; entity.Score = 0; entity.IsPass = false; entity.FinallyIsPass = false; var sql = $@"UPDATE Ghre_ExamRecordDetail SET IsEnable=0 WHERE ExamRecordId='{entity.Id}'; UPDATE Ghre_ExamRecordAnswer SET IsEnable=0 WHERE ExamRecordId='{entity.Id}';"; await Db.Ado.ExecuteCommandAsync(sql); await Update(entity, new List() { "Status","RetakeTimes","ScoreStatus" }); return ServiceResult.OprateSuccess("成功!"); } public async Task AnswerExamAsync(List answers, long studyRecordId) { var record = await base.QuerySingle(x => x.Id == studyRecordId); if (record is null) return ServiceResult.OprateFailed("无效的考试ID"); using var _context = ContextFactory.CreateContext(); var exampaper = await Db.Queryable().FirstAsync(x => x.Id == record.ExamPaperId); var dt = Db.GetDate(); var group = new Ghre_ExamRecordGroup() { StaffId = App.User.StaffId, ExamId = record.ExamId, ExamTime = DateTime.Now, ExamRecordId = record.Id, StudyRecordId = record.StudyRecordId }; var groupId = await Db.Insertable(group).ExecuteReturnSnowflakeIdAsync(); var exam = await Db.Queryable() .Where(x => x.Id == record.ExamId) .FirstAsync(x => x.Status == DIC_EXAM_STATUS.RELEASED); var studyRecord = await Db.Queryable().FirstAsync(x => x.Id == record.StudyRecordId); if (exam.DateType == DicExamDateType.AFTER_HOW_LONG) { record.BeginTime = studyRecord?.EndTime ?? DateTime.Now; if (!record.BeginTime.IsNull()) record.EndTime = record.BeginTime.Value.AddDays(exam.AfterHowLong ?? 7); } var endTime = record.EndTime.Value.AddDays(1).AddSeconds(9); if (!(record.BeginTime.Value.Date <= dt.Date && record.EndTime.Value.Date >= dt.Date)) return ServiceResult.OprateFailed("考试已结束!"); string sql = $@"UPDATE Ghre_ExamRecordDetail SET IsEnable=0 WHERE ExamRecordId='{record.Id}'; UPDATE Ghre_ExamRecordAnswer SET IsEnable=0 WHERE ExamRecordId='{record.Id}';"; //多次考试成绩认定,Latest,最新分数; Highest,最高分数; Lowest,最低分数 var ScoreRecognition = exam.ScoreRule ?? "Latest"; //if (exampaper.ScoreMethod == DIC_EXAM_PAPER_SCORE_METHOD.SYSTEM && ScoreRecognition != "Latest") //{ // sql = $@"UPDATE Ghre_ExamRecordDetail SET IsEnable=2 WHERE ExamRecordId='{record.Id}'; // UPDATE Ghre_ExamRecordAnswer SET IsEnable=2 WHERE ExamRecordId='{record.Id}';"; //} await Db.Ado.ExecuteCommandAsync(sql); var questionIds = answers.Select(x => x.QuestionId).ToList(); var questionAnswers = await Db.Queryable().Where(x => x.QuestionId != null && questionIds.Contains(x.QuestionId.Value)).OrderBy(x => x.TaxisNo).ToListAsync(); ; var staff = await Db.Queryable().Where(x => x.UserId == App.User.ID).FirstAsync(); var recordDetails = new List(); var recordDetailAnswers = new List(); answers.ForEach(answer => { long id = SnowFlakeSingle.instance.getID(); recordDetails.Add(new Ghre_ExamRecordDetail() { Id = id, CreateTime = DateTime.Now, ExamRecordId = record.Id, ExamPaperId = answer.ExamPaperId, ExamPaperQuestionId = answer.Id, QuestionId = answer.QuestionId, StaffId = staff?.UserStaffID, Score = 0, AdjustScore = 0, GroupId = groupId }); var questionAnswers1 = questionAnswers.Where(x => x.QuestionId == answer.QuestionId).ToList(); switch (answer.QuestionType) { case "TrueOrFalse": case "Single": recordDetailAnswers.Add(new Ghre_ExamRecordAnswer() { Id = SnowFlakeSingle.instance.getID(), CreateTime = DateTime.Now, ExamRecordDetailId = id, ExamRecordId = record.Id, QuestionAnswerId = answer.value.IsNull() ? null : questionAnswers1.First(x => x.QuestionNo == answer.value)?.Id, }); break; case "Multiple": var TaxisNo = 100; if (answer.value1.IsNull() || (!answer.value1.IsNull() && !answer.value1.Any())) recordDetailAnswers.Add(new Ghre_ExamRecordAnswer() { Id = SnowFlakeSingle.instance.getID(), CreateTime = DateTime.Now, ExamRecordDetailId = id, ExamRecordId = record.Id, AnswerContent = null, TaxisNo = TaxisNo }); else foreach (var value in answer.value1) { recordDetailAnswers.Add(new Ghre_ExamRecordAnswer() { Id = SnowFlakeSingle.instance.getID(), CreateTime = DateTime.Now, ExamRecordDetailId = id, ExamRecordId = record.Id, QuestionAnswerId = value.IsNull() ? null : questionAnswers1.First(x => x.QuestionNo == value)?.Id, TaxisNo = TaxisNo }); TaxisNo += 100; } break; case "Completion": var TaxisNo1 = 100; if (answer.value1.IsNull() || (!answer.value1.IsNull() && !answer.value1.Any())) recordDetailAnswers.Add(new Ghre_ExamRecordAnswer() { Id = SnowFlakeSingle.instance.getID(), CreateTime = DateTime.Now, ExamRecordDetailId = id, ExamRecordId = record.Id, AnswerContent = null, TaxisNo = TaxisNo1 }); else foreach (var value in answer.value1) { recordDetailAnswers.Add(new Ghre_ExamRecordAnswer() { Id = SnowFlakeSingle.instance.getID(), CreateTime = DateTime.Now, ExamRecordDetailId = id, ExamRecordId = record.Id, AnswerContent = value, TaxisNo = TaxisNo1 }); TaxisNo1 += 100; } break; case "ShortAnswer": recordDetailAnswers.Add(new Ghre_ExamRecordAnswer() { Id = SnowFlakeSingle.instance.getID(), CreateTime = DateTime.Now, ExamRecordId = record.Id, ExamRecordDetailId = id, AnswerContent = answer.value }); break; default: break; } }); await _context.Ghre_ExamRecordDetail.AddRangeAsync(recordDetails); await _context.Ghre_ExamRecordAnswer.AddRangeAsync(recordDetailAnswers); await _context.SaveChangesAsync(); record.Status = DIC_EXAM_RECORD_STATUS.EXAM_END; record.ActualEndTime = DateTime.Now; record.ExamDate = DateTime.Now.Date; if (record.AnswerCount.IsNullOrEmpty()) record.AnswerCount = 1; else record.AnswerCount = record.AnswerCount + 1; var lastScore = record.Score; #region 打分-系统评分 if (record.ScoreStatus == DIC_EXAM_RECORD_SCORE_STATUS.NO_SCORE && exampaper.ScoreMethod == DIC_EXAM_PAPER_SCORE_METHOD.SYSTEM) { await ExamHelper.SystemMarkAsync(Db, record, recordDetails, recordDetailAnswers); record.ScoreStatus = DIC_EXAM_RECORD_SCORE_STATUS.HAS_SCORE; record.AdjustScore = 0; _context.Ghre_ExamRecordDetail.UpdateRange(recordDetails); _context.Ghre_ExamRecordAnswer.UpdateRange(recordDetailAnswers); await _context.SaveChangesAsync(); } #endregion group.Score = record.Score; await Db.Updateable(group).UpdateColumns(it => new { it.Score }, true) .ExecuteCommandAsync(); #region 多次考试成绩认定 if (exampaper.ScoreMethod == DIC_EXAM_PAPER_SCORE_METHOD.SYSTEM && (ScoreRecognition == "Highest" || ScoreRecognition == "Lowest")) { if ((ScoreRecognition == "Highest" && record.Score < lastScore) || ScoreRecognition == "Lowest" && record.Score > lastScore) { record.Score = lastScore; //sql = $@"UPDATE Ghre_ExamRecordDetail SET IsEnable=0 WHERE ExamRecordId='{record.Id}'; // UPDATE Ghre_ExamRecordAnswer SET IsEnable=0 WHERE ExamRecordId='{record.Id}';"; //await Db.Ado.ExecuteCommandAsync(sql); //sql = $@"UPDATE Ghre_ExamRecordDetail SET IsEnable=1 WHERE IsEnable=2 AND ExamRecordId='{record.Id}'; // UPDATE Ghre_ExamRecordAnswer SET IsEnable=1 WHERE IsEnable=2 AND ExamRecordId='{record.Id}';"; //await Db.Ado.ExecuteCommandAsync(sql); } #region 处理最终得分 if (exam.OnlineScorePercentage != null && exam.OfflineScorePercentage != null) if (exam.OnlineScorePercentage > 0 && exam.OfflineScorePercentage > 0) { decimal OnlineScorePercentage = exam.OnlineScorePercentage.Value / 100; decimal OfflineScorePercentage = exam.OfflineScorePercentage.Value / 100; record.FinallyScore = (record.Score + (record.AdjustScore ?? 0)) * OnlineScorePercentage; if (record.ActualScore != null && record.ActualScore > 0) record.FinallyScore += record.ActualScore * OfflineScorePercentage; } #endregion } #endregion record.UpdateTime = DateTime.Now; await Update(record, new List { "Status", "Score", "FinallyScore", "AdjustScore", "ActualEndTime", "ScoreStatus", "UpdateTime", "ExamDate", "AnswerCount" }, null, $"Id='{record.Id}'"); if (exampaper.ScoreMethod == DIC_EXAM_PAPER_SCORE_METHOD.SYSTEM) await DealPass(Db, studyRecordId); return ServiceResult.OprateSuccess("提交成功!"); } public async Task DealPass(ISqlSugarClient Db, long studyRecordId) { try { var record = await Db.Queryable().FirstAsync(x => x.Id == studyRecordId); _logger.LogInformation($"【DealPass:{studyRecordId}】1"); var studyRecord = await Db.Queryable().FirstAsync(x => x.Id == record.StudyRecordId); studyRecord.ReverseI1 = 1; await Db.Updateable(studyRecord).UpdateColumns(it => new { it.ReverseI1 }, true)//true表示追加AOP赋值列 .ExecuteCommandAsync(); var examPaper = await Db.Queryable().FirstAsync(x => x.Id == record.ExamPaperId); _logger.LogInformation($"【DealPass:{studyRecordId}】PassScore:{examPaper.PassScore},Score:{record.Score},PassScore:{record.AdjustScore},"); record.IsPass = examPaper.PassScore > ((record.Score ?? 0) + (record.AdjustScore ?? 0)) ? false : true; _logger.LogInformation($"【DealPass:{studyRecordId}】IsPass:{record.IsPass}"); record.FinallyIsPass = record.IsPass; await Db.Updateable(record).UpdateColumns(it => new { it.IsPass, it.FinallyIsPass }, true)//true表示追加AOP赋值列 .ExecuteCommandAsync(); await Db.Deleteable().Where(x => x.ExamId == studyRecord.ExamId).ExecuteCommandAsync(); if (record.IsPass == true) { if (studyRecord.CourseSceneId.IsNull()) { var course = await Db.Queryable().FirstAsync(x => x.Id == studyRecord.CourseId); #region 学分发放 var creditPoint = new Ghre_CreditPoint() { CourseId = studyRecord.CourseId, CourseSnapId = studyRecord.CourseSnapId, StaffId = studyRecord.StaffId, ExamId = studyRecord.ExamId, Date = DateTime.Now.Date, CreditPoints = course.CreditPoints }; await Db.Insertable(creditPoint).ExecuteReturnSnowflakeIdListAsync(); #endregion #region 证书发放 #endregion } else { var courses = await Db.Queryable().Where(x => x.CourseSceneId == studyRecord.CourseSceneId).ToListAsync(); for (int i = 0; i < courses.Count; i++) { var snap = await Db.Queryable().FirstAsync(x => x.CourseId == courses[i].Id); #region 学分发放 var creditPoint = new Ghre_CreditPoint() { CourseId = courses[i].Id, CourseSnapId = snap?.Id, StaffId = studyRecord.StaffId, ExamId = studyRecord.ExamId, Date = DateTime.Now.Date, CreditPoints = courses[i].CreditPoints }; await Db.Insertable(creditPoint).ExecuteReturnSnowflakeIdListAsync(); #endregion } } } #region 处理培训记录有效时间 if (studyRecord.StudyRuleId != null) { var studyRule = await Db.Queryable().FirstAsync(x => x.Id == studyRecord.StudyRuleId); if (studyRule != null && studyRule.ResultValidPeriod != null) { studyRecord.ValidBeginTime = DateTime.Now; studyRecord.ValidEndTime = studyRecord.ValidBeginTime.Value.AddMonths(studyRule.ResultValidPeriod.Value); await Db.Updateable(studyRecord).UpdateColumns(it => new { it.ValidBeginTime, it.ValidEndTime }, true)//true表示追加AOP赋值列 .ExecuteCommandAsync(); record.ValidBeginTime = studyRecord.ValidBeginTime; record.ValidEndTime = studyRecord.ValidEndTime; await Db.Updateable(record).UpdateColumns(it => new { it.ValidBeginTime, it.ValidEndTime }) .ExecuteCommandAsync(); } } #endregion #region 处理学习完成状态 studyRecord.CompleteStatus = DIC_STUDY_RECORD_STUDY_COMPLETE_STATUS.NO_FINISH; await Db.Updateable(studyRecord) .UpdateColumns(it => new { it.CompleteStatus }, true) .ExecuteCommandAsync(); if (record.IsPass == true) await ExamHelper.MarkCompleteStatusAsync(Db, studyRecord); #endregion _logger.LogInformation($"【DealPass:{studyRecordId}】2"); } catch (Exception E) { _logger.LogInformation($"【DealPass:{studyRecordId}】Message:{E.Message}"); _logger.LogInformation($"【DealPass:{studyRecordId}】StackTrace:{E.StackTrace}"); } } public async Task ViewExamPaperCallBackAsync(long examRecordId) { var entity = await base.QuerySingle(examRecordId); if (entity is null) return ServiceResult.OprateFailed("无效的考试ID!"); entity.IsView = true; entity.ViewTime = DateTime.Now; await Update(entity, new List() { "IsView","ViewTime" }); return ServiceResult.OprateSuccess("成功!"); } #region Excel导入 public override async Task> DownloadExcel(string menuName) { var physicsPath = $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}wwwroot"; var path = $"{$"{Path.DirectorySeparatorChar}files{Path.DirectorySeparatorChar}ExcelTemplate{Path.DirectorySeparatorChar}"}"; if (!Directory.Exists(physicsPath + path)) Directory.CreateDirectory(physicsPath + path); Type entityType = typeof(Ghre_ExamRecord); var fileName = entityType.GetEntityTableName() + ".xlsx"; var physicsPath1 = physicsPath + path + fileName; //if (dataSourceLists.Any()) // physicsPath1 = physicsPath + path + newFileName; var result = ServiceResult.OprateSuccess("考试成绩_" + DateTimeHelper.ConvertToSecondString1(DateTime.Now) + ".xlsx", physicsPath1); return result; } public override async Task> ImportExcel(IFormFile file, string menuName = null, long? MasterId = null) { var data = new ExcelData(); long id = SnowFlakeSingle.instance.getID(); var physicsPath = $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}wwwroot"; var path = $"{$"{Path.DirectorySeparatorChar}files{Path.DirectorySeparatorChar}import{Path.DirectorySeparatorChar}{id}{Path.DirectorySeparatorChar}"}"; if (!Directory.Exists(physicsPath + path)) Directory.CreateDirectory(physicsPath + path); var filepath = physicsPath + path + file.FileName; using (var stream = File.Create(filepath)) { await file.CopyToAsync(stream); } string extension = Path.GetExtension(filepath); bool isExistError = false; var id1 = SnowFlakeSingle.instance.getID(); string errorFileName = path + SnowFlakeSingle.instance.getID() + extension; var dt = NPOIHelper.ImportExcel(filepath, "考试成绩"); if (dt.Columns["Comments"] == null) dt.Columns.Add("Comments", typeof(string)); var fields = new List { "工号", "姓名", "考试日期", "考试分数", "调整分", "实操分", "是否合格", "备注" }; for (int i = 0; i < dt.Rows.Count; i++) { var comments = new List(); bool isContinue = false; fields.ForEach(x => { if (!dt.Columns.Contains(x)) { comments.Add("未查询到【" + x + "】列!"); data.ErrorCount++; dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a)); isExistError = true; isContinue = true; } }); if (isContinue) continue; var StaffNo = dt.Rows[i]["工号"].ToString(); var StaffName = dt.Rows[i]["姓名"].ToString(); var ExamDate = dt.Rows[i]["考试日期"].ToString(); var Score = dt.Rows[i]["考试分数"].ToString(); var AdjustScore = dt.Rows[i]["调整分"].ToString(); var ActualScore = dt.Rows[i]["实操分"].ToString(); var IsPass = dt.Rows[i]["是否合格"].ToString(); if (StaffNo.IsNullOrEmpty() && StaffName.IsNullOrEmpty()) continue; var remarkSz = dt.Rows[i]["备注"].ToString(); var staff = await Db.Queryable().Where(x => x.StaffNo == StaffNo && x.StaffName == StaffName).FirstAsync(); if (staff == null) { comments.Add($"未查询到该员工,工号或姓名填写错误!"); data.ErrorCount++; dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a)); isExistError = true; continue; } var exam = await Db.Queryable().Where(x => x.Id == MasterId).FirstAsync(); if (ExamDate.IsNullOrEmpty()) ExamDate = DateTime.Now.ToString(); if (Score.IsNullOrEmpty()) Score = "0"; try { Convert.ToInt32(Score); } catch (Exception) { comments.Add($"考试分数填写有误!"); data.ErrorCount++; dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a)); isExistError = true; continue; } try { Convert.ToInt32(AdjustScore); } catch (Exception) { comments.Add($"调整分填写有误!"); data.ErrorCount++; dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a)); isExistError = true; continue; } try { Convert.ToInt32(ActualScore); } catch (Exception) { comments.Add($"实操分填写有误!"); data.ErrorCount++; dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a)); isExistError = true; continue; } try { Convert.ToDateTime(ExamDate); } catch (Exception) { comments.Add($"考试日期填写有误!"); data.ErrorCount++; dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a)); isExistError = true; continue; } //if (await base.AnyAsync(x => x.CertificateRuleId == rule.Id && x.StaffId == staff.StaffID && x.CourseId == course.Id)) //{ // comments.Add($"系统已存在相同证照数据!"); // data.ErrorCount++; // dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a)); // isExistError = true; // continue; //} var snap = await Db.Queryable().FirstAsync(x => x.CourseId == exam.CourseId); var ExamRecordId = SnowFlakeSingle.Instance.NextId(); var StudyRecordId = SnowFlakeSingle.Instance.NextId(); var dict1 = new Dictionary { { "Id", StudyRecordId }, { "CreateBy", App.User.ID }, { "CreateTime", DateTime.Now }, { "ExamId", MasterId }, { "StaffId", staff.StaffID }, { "CourseId", exam.CourseId }, { "CourseSnapId", snap?.Id }, { "CourseSceneId", exam.CourseSceneId }, { "JoinTime", DateTime.Now }, { "RemarkSz", "导入考试成绩生成" } }; var dict = new Dictionary { { "Id", ExamRecordId }, { "CreateBy", App.User.ID }, { "CreateTime", DateTime.Now }, { "ExamId", MasterId }, { "StudyRecordId", StudyRecordId }, { "StaffId", staff.StaffID }, //{ "CourseId", exam.CourseId }, { "CourseSnapId", snap?.Id }, { "Score", Score }, { "AdjustScore", Score }, { "ActualScore", ActualScore }, { "ExamDate", ExamDate }, { "IsPass", IsPass=="是"?true:false }, { "ScoreStatus", "HasScore" }, { "Source", "ExcelImport" }, { "ExamPaperId",exam.ExamPaperId }, { "RemarkSz", remarkSz } }; try { await Db.Insertable(dict1).AS("Ghre_StudyRecord").ExecuteCommandAsync(); await Db.Insertable(dict).AS("Ghre_ExamRecord").ExecuteCommandAsync(); data.SuccessCount++; //data.SuccessCount += list.Count; } catch (Exception E) { comments.Add(E.Message); data.ErrorCount++; dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a)); isExistError = true; continue; } } if (isExistError) { NPOIHelper.ExportExcel(dt, null, "考试成绩", physicsPath + errorFileName); data.filePath = "/Advanced" + errorFileName; } return ServiceResult.OprateSuccess("导入成功!", data); } #endregion #region 提交附件 public async Task SubmitAttachment(long examRecordId, List attachments) { var path = attachments.Select(x => x.RelativePath.Replace("/Advanced", null)).Distinct().ToList(); await Db.Updateable() .SetColumns(it => new Ghre_Attachment() { TableName = null }) .Where(it => it.TableName == examRecordId.ObjToString()) .ExecuteCommandAsync(); await Db.Updateable() .SetColumns(it => new Ghre_Attachment() { TableName = examRecordId.ObjToString() }) .Where(it => path.Contains(it.RelativePath)) .ExecuteCommandAsync(); return ServiceResult.OprateSuccess("保存成功!"); } #endregion #region 发放证书 /// /// 发放证书 /// /// public async Task IssueCertificate() { var now = DateTime.Now; //抓取当天提交考试的数据 var records = await Db.Queryable() .Where(x => x.ExamDate != null && x.ExamDate.Value.Date == now.Date && //x.IsPass == true && (x.IsIssueCertificate == null || x.IsIssueCertificate == false)) .ToListAsync(); _logger.LogInformation($"【发放证书】查询到{records.Count}条考试数据"); var rules = new List(); if (records.Any()) { for (int i = 0; i < records.Count; i++) { var record = records[i]; await IssueCourseCertificate(record.StaffId, null, record.Id, record.CourseId, record.CourseSceneId); if (record.CourseSceneId != null) { var courses = await Db.Queryable() .Where(x => x.CourseSceneIds != null && x.CourseSceneIds.Contains(record.CourseSceneId.ObjToString())) .ToListAsync(); if (courses.Any()) for (int j = 0; j < courses.Count; j++) { await IssueCourseCertificate(record.StaffId, null, record.Id, courses[j].Id, null); } } } } if (await Db.Queryable() .Where(x => x.StudyStatus == "HasFinish" && (x.IsIssueCertificate == null || x.IsIssueCertificate == false)) .AnyAsync()) { var studyRecords = await Db.Queryable() .Where(x => x.StudyStatus == "HasFinish" && (x.IsIssueCertificate == null || x.IsIssueCertificate == false)) .ToListAsync(); _logger.LogInformation($"【发放证书】查询到{studyRecords.Count}条待发放学习数据!"); for (int i = 0; i < studyRecords.Count; i++) { await IssueCourseCertificate(studyRecords[i].StaffId, studyRecords[i].Id, null, studyRecords[i].CourseId, studyRecords[i].CourseSceneId); if (studyRecords[i].CourseSceneId != null) { var courses = await Db.Queryable() .Where(x => x.CourseSceneIds != null && x.CourseSceneIds.Contains(studyRecords[i].CourseSceneId.ObjToString())) .ToListAsync(); if (courses.Any()) for (int j = 0; j < courses.Count; j++) { await IssueCourseCertificate(studyRecords[i].StaffId, studyRecords[i].Id, null, courses[j].Id, null); } } } _logger.LogInformation($"【发放证书】学习数据处理完成!"); } else _logger.LogInformation($"【发放证书】未查询到待发放学习数据!"); return ServiceResult.OprateSuccess("发放成功!"); } private static string CreateRandomNum(int num) { string str = "0123456789"; StringBuilder sb = new StringBuilder(); for (int i = 0; i < num; i++) { sb.Append(str[new Random(Guid.NewGuid().GetHashCode()).Next(0, str.Length - 1)]); } return sb.ToString(); } /// /// 处理证书数据 /// /// 员工ID /// 学习记录ID /// 考试记录ID /// 课程ID /// 课程场景ID /// private async Task IssueCourseCertificate(int? staffId, long? studyRecordId = null, long? examRecordId = null, long? courseId = null, long? courseSceneId = null) { var now = DateTime.Now; var rules = await Db.Queryable() .WhereIF(studyRecordId != null, x => x.SendRule == "CourseFinish") .WhereIF(examRecordId != null, x => (x.SendRule == "ExamPass" || x.SendRule == "ExamScore")) .WhereIF(courseId != null, x => x.CourseId1 != null && x.CourseId1.Contains(courseId.ObjToString())) .WhereIF(courseSceneId != null, x => x.CourseSceneId1 != null && x.CourseSceneId1.Contains(courseSceneId.ObjToString())) .WhereIF(courseId != null && courseSceneId != null, x => x.Id == 0) .WhereIF(studyRecordId != null && examRecordId != null, x => x.Id == 0) .ToListAsync(); for (int j = 0; j < rules.Count; j++) { var rule = rules[j]; var certificateNoItems = await Db.Queryable() .Where(x => x.CertificateRuleId == rule.Id && x.field == "CertificateNo") .FirstAsync(); if (examRecordId != null) { if (rule.SendRule == "ExamPass" && !await Db.Queryable() .Where(x => x.Id == examRecordId.Value && x.IsPass == true).AnyAsync()) continue; if (rule.SendRule == "ExamScore" && !await Db.Queryable() .Where(x => x.Id == examRecordId.Value && x.Score >= rule.ScoreMin && x.Score <= rule.ScoreMax ).AnyAsync()) continue; } string ValidityPeriod = string.Empty; DateTime? ValidityPeriodTime = null; if (rule.ValidityType == "StaticDuration" && rule.StaticNum != null) { if (rule.StaticType == "year") ValidityPeriodTime = now.AddYears(rule.StaticNum.Value); else if (rule.StaticType == "day") ValidityPeriodTime = now.AddDays(rule.StaticNum.Value); else if (rule.StaticType == "month") ValidityPeriodTime = now.AddMonths(rule.StaticNum.Value); ValidityPeriod = DateTimeHelper.ConvertToSecondString(ValidityPeriodTime); } else if (rule.ValidityType == "Option" && rule.ValidityTime != null) { ValidityPeriodTime = rule.ValidityTime; ValidityPeriod = DateTimeHelper.ConvertToSecondString(ValidityPeriodTime); } else if (rule.ValidityType == "Unlimited") { ValidityPeriodTime = DateTime.MaxValue; ValidityPeriod = "长期"; } var certificate = new Ghre_Certificate() { CertificateRuleId = rule.Id, StaffId = staffId, CourseId = courseId, AwardDate = now, ValidityPeriod = ValidityPeriod, ValidityPeriodTime = ValidityPeriodTime, AwardSource = studyRecordId != null ? $"学习完成" : $"考试完成", Reverse1 = studyRecordId != null ? $"{studyRecordId}" : $"{examRecordId}" }; certificate.CertificateNo = SnowFlakeSingle.Instance.NextId().ObjToString(); if (certificateNoItems != null) { if (certificateNoItems.certNoRule == "manual") certificate.CertificateNo = rule.Id.ObjToString(); else if (certificateNoItems.certNoRule == "fixed") { var certNoFixed = certificateNoItems.certNoFixed; int length = 22 - (certNoFixed.IsNotEmptyOrNull() ? certNoFixed.Length : 0); certificate.CertificateNo = certNoFixed + CreateRandomNum(length); } } await Db.Insertable(certificate).ExecuteReturnSnowflakeIdAsync(); } if (studyRecordId != null) await Db.Updateable() .SetColumns(it => new Ghre_StudyRecord() { IsIssueCertificate = true }, true) .Where(x => x.Id == studyRecordId) .ExecuteCommandAsync(); if (examRecordId != null) await Db.Updateable() .SetColumns(it => new Ghre_ExamRecord() { IsIssueCertificate = true }, true) .Where(x => x.Id == examRecordId) .ExecuteCommandAsync(); } #endregion #region 查询考试组 public async Task>> QueryGroups(long examRecordId) { var Groups = await Db.Queryable() .OrderByDescending(x => x.ExamTime) .Where(x => x.ExamRecordId == examRecordId) .Select(x => new { GroupId = x.Id, x.ExamRecordId, x.ExamTime, x.Score }).ToListAsync(); var groups = Groups .Select(x => new ExamGroup() { GroupId = x.GroupId, ExamRecordId = x.ExamRecordId, ExamTime = x.ExamTime.ObjToString() + (x.Score != null ? $"得分:{x.Score}" : ""), }).ToList(); return ServiceResult>.OprateSuccess("成功!", groups); } #endregion public async Task MarkCompleteStatus(long id) { var studyRecord = await Db.Queryable().Where(x => x.Id == id).FirstAsync(); await ExamHelper.MarkCompleteStatusAsync(Db, studyRecord); return ServiceResult.OprateSuccess(); } }