using Azure.Storage.Blobs.Models; using Microsoft.AspNetCore.Mvc; using System.Text.Json; using TEAMModelOS.SDK; using TEAMModelOS.SDK.DI; using TEAMModelOS.SDK.Models; using TEAMModelOS.SDK.Extension; using StackExchange.Redis; using System.Text.RegularExpressions; using System.Linq; using static TEAMModelOS.SDK.Models.Cosmos.Student.StudentAnalysis; using static Microsoft.Azure.Amqp.Serialization.SerializableType; using Microsoft.AspNetCore.DataProtection.KeyManagement; using System.Drawing; using TEAMModelOS.SDK.Models.Cosmos.OpenEntity; using System.Diagnostics; using Microsoft.OData.UriParser; using HTEX.Test.Service; using System.IO; using static Pipelines.Sockets.Unofficial.SocketConnection; using static HTEX.Test.Controllers.LessonRecordController; namespace HTEX.Test.Controllers { [ApiController] [Route("lesson-record")] public class LessonRecordController : ControllerBase { private readonly ILogger _logger; private readonly AzureCosmosFactory _azureCosmos; private readonly AzureStorageFactory _azureStorage; private readonly List objectiveTypes=new List(){ "single", "multiple", "sortmultiple" , "judge" }; private readonly double minRank = 1; private readonly double maxRank = 100; public LessonRecordController(ILogger logger, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage) { _logger = logger; _azureCosmos = azureCosmos; _azureStorage = azureStorage; } [HttpPost("process-local")] public async Task ProcessLocal(JsonElement json) { string? id=json.GetProperty("id").GetString(); if (!string.IsNullOrWhiteSpace(id)) { string path = $"C:\\Users\\CrazyIter\\Downloads\\{id}"; var files = ListAllFiles(path); // var sampleJson =System.IO. File.ReadAllTextAsync(path); LessonBase? lessonBase = null; List studentLessonDatas = new List(); List taskDatas = new List(); List smartRatingDatas = new List(); List irsDatas = new List(); List coworkDatas = new List(); List examDatas = new List(); TimeLineData? timeLineData = null; foreach (var item in files) { if (item.Contains("IES\\base.json")) { string jsons = await System.IO.File.ReadAllTextAsync(item); jsons=jsons.Replace("\"Uncall\"", "0").Replace("Uncall", "0"); lessonBase = jsons.ToObject(); var data = GetBaseData( lessonBase); studentLessonDatas=data.studentLessonDatas; } if (item.Contains("IES\\TimeLine.json")) { string jsons = await System.IO.File.ReadAllTextAsync(item); timeLineData = jsons.ToObject(); } if (item.Contains("IES\\Task.json")) { string jsons = await System.IO.File.ReadAllTextAsync(item); taskDatas = jsons.ToObject>(); } if (item.Contains("IES\\SmartRating.json")) { string jsons = await System.IO.File.ReadAllTextAsync(item); smartRatingDatas = jsons.ToObject>(); } if (item.Contains("IES\\IRS.json")) { string jsons = await System.IO.File.ReadAllTextAsync(item); irsDatas = jsons.ToObject>(); } if (item.Contains("IES\\Cowork.json")) { string jsons = await System.IO.File.ReadAllTextAsync(item); coworkDatas = jsons.ToObject>(); } try { if (item.Contains($"\\{id}\\Exam\\") && item.EndsWith("Exam.json")) { string examsFile = item; if (examsFile.EndsWith("Exam.json")) { ExamData? examData = null; string jsons = await System.IO.File.ReadAllTextAsync(item); jsons= jsons.Replace("\"publish\": \"0\"", "\"publish\": 0").Replace("\"publish\": \"1\"", "\"publish\": 1"); examData = jsons.ToObject(); if (examData!=null && examData.exam.papers.IsNotEmpty()) { string paperId = examData.exam.papers.First().id; string paperPath = $"{path}\\ExamPaper\\{paperId}\\index.json"; string jsonp = await System.IO.File.ReadAllTextAsync(paperPath); LessonPaper lessonPaper = jsonp.ToObject(); examData.paper = lessonPaper; examDatas.Add(examData); } } } } catch (Exception ex) { _logger.LogError(ex, ex.Message); } } if (lessonBase!=null && timeLineData!=null) { studentLessonDatas = GetIRSData(lessonBase, timeLineData, irsDatas, studentLessonDatas, examDatas); studentLessonDatas = GetCoworkData(lessonBase, timeLineData, coworkDatas, studentLessonDatas); studentLessonDatas = GetExamData(lessonBase, timeLineData, examDatas, studentLessonDatas); studentLessonDatas = GetSmartRatingData(lessonBase, timeLineData, smartRatingDatas, studentLessonDatas); studentLessonDatas = GetTaskData(lessonBase, timeLineData, taskDatas, studentLessonDatas); } return Ok( new { studentLessonDatas }); }return Ok(); } [HttpPost("process-preview")] public async Task ProcessPreview(JsonElement json) { string path = $"F:\\lesson-local"; var files = ListAllFiles(path); List techCounts = new List(); //var files_count = files.Where(x => x.EndsWith("548724334458441728-count.json")).Take(100).ToList(); /* "examCount": 0, "taskCount": 0, "irsCount": 1, "coworkCount": 0, "smartRatingCount": 0, "timeCount": */ bool loadLocal = true; LessonDataAnalysis lessonDataAnalysis = new LessonDataAnalysis(); var files_anlysis = files.Where(x => x.EndsWith("analysis.json")).Take(1).FirstOrDefault(); if (files_anlysis!=null) { string jsons = await System.IO.File.ReadAllTextAsync(files_anlysis); lessonDataAnalysis= jsons.ToObject(); loadLocal=false; } if (loadLocal) { foreach (var item in files) { if (item.EndsWith("count.json")) { string jsons = await System.IO.File.ReadAllTextAsync(item); TechCount count = jsons.ToObject(); var pickupResult = count.timeCount.Where(x => x.code.Equals("PickupResult", StringComparison.OrdinalIgnoreCase)); int pickCount = 0; if (pickupResult!=null && pickupResult.Count()>0) { pickCount+=pickupResult.Sum(x => (int)x.value); } count.interactNormalCount=pickCount+ count.irsCount; count.lessonId=item.Replace("-count.json", "").Replace(path, "").Replace("\\", ""); string localjson = await System.IO.File.ReadAllTextAsync($"{path}\\{count.lessonId}-local.json"); var lessonLocal = localjson.ToObject(); if (lessonLocal?.lessonBase?.summary!=null) { count.smartRatingCountBase=lessonLocal.lessonBase.summary.smartRatingCount; count.irsCountBase=lessonLocal.lessonBase.summary.interactionCount; count.taskCountBase=lessonLocal.lessonBase.summary.collateTaskCount; count.coworkCountBase=lessonLocal.lessonBase.summary.coworkTaskCount; count.examCountBase=lessonLocal.lessonBase.summary.examCount; count.interactNormalCountBase= count.interactNormalCount; } if (lessonLocal?.lessonBase?.report?.clientSummaryList!=null) { count.pscore= lessonLocal.lessonBase.report.clientSummaryList.Where(x=>x.score>0).Select(x => x.score); count.gscore= lessonLocal.lessonBase.report.clientSummaryList.Where(x => x.groupScore>0).Select(x => x.groupScore); count.tscore= lessonLocal.lessonBase.report.clientSummaryList.Where(x => x.interactScore>0).Select(x => x.interactScore); } await System.IO.File.WriteAllTextAsync(item, count.ToJsonString()); techCounts.Add(count); } } Console.WriteLine($"techCounts:{techCounts.Count}"); //标准差偏差N倍,视为异常数据 int thresholdMultiplier = 2; lessonDataAnalysis.pscore = techCounts.SelectMany(x =>x.pscore); lessonDataAnalysis.pscore= CleanDataBySDThreshold(lessonDataAnalysis.pscore, thresholdMultiplier).OrderBy(x => x); List>> clustersDataPscore = new(); var clusterPscore = KMeansService.KMeans(lessonDataAnalysis.pscore.Select(x => x).OrderBy(x => x)); foreach (var item in clusterPscore) { Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()}"); } Console.WriteLine($"avg: {lessonDataAnalysis.pscore.Average()}"); foreach (var s in clusterPscore.OrderBy(x => x.Key)) { clustersDataPscore.Add(s); } lessonDataAnalysis.clustersPscore=clustersDataPscore; lessonDataAnalysis.gscore = techCounts.SelectMany(x => x.gscore); lessonDataAnalysis.gscore= CleanDataBySDThreshold(lessonDataAnalysis.gscore, thresholdMultiplier).OrderBy(x => x); List>> clustersDataGscore = new(); var clusterGscore = KMeansService.KMeans(lessonDataAnalysis.gscore.Select(x => x).OrderBy(x => x)); foreach (var item in clusterGscore) { Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()}"); } Console.WriteLine($"avg: {lessonDataAnalysis.gscore.Average()}"); foreach (var s in clusterGscore.OrderBy(x => x.Key)) { clustersDataGscore.Add(s); } lessonDataAnalysis.clustersGscore=clustersDataGscore; lessonDataAnalysis.tscore = techCounts.SelectMany(x => x.tscore); lessonDataAnalysis.tscore= CleanDataBySDThreshold(lessonDataAnalysis.tscore, thresholdMultiplier).OrderBy(x => x); List>> clustersDataTscore = new(); var clusterTscore = KMeansService.KMeans(lessonDataAnalysis.tscore.Select(x => x).OrderBy(x => x)); foreach (var item in clusterTscore) { Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()}"); } Console.WriteLine($"avg: {lessonDataAnalysis.tscore.Average()}"); foreach (var s in clusterTscore.OrderBy(x => x.Key)) { clustersDataTscore.Add(s); } lessonDataAnalysis.clustersTscore=clustersDataTscore; lessonDataAnalysis.cowork = techCounts.Where(x => x.coworkCount>0).Select(x => (double)x.coworkCount); lessonDataAnalysis.cowork= CleanDataBySDThreshold(lessonDataAnalysis.cowork, thresholdMultiplier); lessonDataAnalysis.coworkBase = techCounts.Where(x => x.coworkCountBase>0).Select(x => (double)x.coworkCountBase); lessonDataAnalysis.coworkBase= CleanDataBySDThreshold(lessonDataAnalysis.coworkBase, thresholdMultiplier); lessonDataAnalysis.task = techCounts.Where(x => x.taskCount > 0).Select(x => (double)x.taskCount); lessonDataAnalysis.task= CleanDataBySDThreshold(lessonDataAnalysis.task, thresholdMultiplier); lessonDataAnalysis.taskBase = techCounts.Where(x => x.taskCountBase > 0).Select(x => (double)x.taskCountBase); lessonDataAnalysis.taskBase = CleanDataBySDThreshold(lessonDataAnalysis.taskBase, thresholdMultiplier); lessonDataAnalysis.exam = techCounts.Where(x => x.examCount > 0).Select(x => (double)x.examCount); lessonDataAnalysis.exam = CleanDataBySDThreshold(lessonDataAnalysis.exam, thresholdMultiplier); lessonDataAnalysis.examBase = techCounts.Where(x => x.examCountBase > 0).Select(x => (double)x.examCountBase); lessonDataAnalysis.examBase = CleanDataBySDThreshold(lessonDataAnalysis.examBase, thresholdMultiplier); lessonDataAnalysis.smartRating = techCounts.Where(x => x.smartRatingCount > 0).Select(x => (double)x.smartRatingCount); lessonDataAnalysis.smartRating = CleanDataBySDThreshold(lessonDataAnalysis.smartRating, thresholdMultiplier); lessonDataAnalysis.smartRatingBase = techCounts.Where(x => x.smartRatingCountBase > 0).Select(x => (double)x.smartRatingCountBase); lessonDataAnalysis.smartRatingBase = CleanDataBySDThreshold(lessonDataAnalysis.smartRatingBase, thresholdMultiplier); lessonDataAnalysis.irs = techCounts.Where(x => x.irsCount > 0).Select(x => (double)x.irsCount); lessonDataAnalysis.irs = CleanDataBySDThreshold(lessonDataAnalysis.irs, thresholdMultiplier); lessonDataAnalysis.interactNormal = techCounts.Where(x => x.interactNormalCount > 0).Select(x => (double)x.interactNormalCount); Console.WriteLine($"interactNormal{lessonDataAnalysis.interactNormal.Count()}"); lessonDataAnalysis.interactNormal= CleanDataBySDThreshold(lessonDataAnalysis.interactNormal, thresholdMultiplier).OrderBy(x => x); Console.WriteLine($"interactNormal{lessonDataAnalysis.interactNormal.Count()}"); var tcount = techCounts.Where(x => x.coworkCount > 0 || x.taskCount>0 || x.interactNormalCount>0|| x.examCount>0 || x.smartRatingCount>0); double coworkWeight = lessonDataAnalysis.cowork.Count()*1.0/tcount.Count(); lessonDataAnalysis.coworkWeight=coworkWeight; double taskWeight = lessonDataAnalysis.task.Count()*1.0/tcount.Count(); lessonDataAnalysis.taskWeight=taskWeight; double interactWeight = lessonDataAnalysis.interactNormal.Count()*1.0/tcount.Count(); lessonDataAnalysis.interactWeight=interactWeight; double examWeight = lessonDataAnalysis. exam.Count()*1.0/tcount.Count(); lessonDataAnalysis.examWeight=examWeight; double smartRatingWeight = lessonDataAnalysis. smartRating.Count()*1.0/tcount.Count(); lessonDataAnalysis.smartRatingWeight=smartRatingWeight; List>> clustersDataInteract = new(); var clusterInteract = KMeansService.KMeans(lessonDataAnalysis.interactNormal.Select(x => (int)x).OrderBy(x => x)); foreach (var item in clusterInteract) { Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()}"); } foreach (var s in clusterInteract.OrderBy(x => x.Key)) { clustersDataInteract.Add(s); } lessonDataAnalysis.clustersInteract=clustersDataInteract; var groups = techCounts.SelectMany(x => x.timeCount).GroupBy(x => x.code).Select(x => new { key = x.Key, list = x.ToList() }); Dictionary> techDict = new Dictionary>(); foreach (var group in groups) { var array = group.list.Where(x => x.value>0).Select(x => (double)x.value); array = CleanDataBySDThreshold(array, thresholdMultiplier); techDict.Add(group.key, array); } System.IO. File.WriteAllText(Path.Combine(path, "analysis.json"), lessonDataAnalysis.ToJsonString()); } List lessons = new List(); var files_local = files.Where(x=>x.EndsWith("608942756458532864-local.json")).Take(100).ToList(); foreach (var item in files_local) { if (item.EndsWith("local.json")) { string jsons = await System.IO.File.ReadAllTextAsync(item); LessonLocal lesson = jsons.ToObject(); lessons.Add(lesson); lesson.studentLessonDatas = GetIRSData(lesson.lessonBase!, lesson.timeLineData!, lesson.irsDatas, lesson.studentLessonDatas, lesson.examDatas); lesson.studentLessonDatas = GetCoworkData(lesson.lessonBase!, lesson.timeLineData!, lesson.coworkDatas, lesson.studentLessonDatas); lesson.studentLessonDatas = GetExamData(lesson.lessonBase!, lesson.timeLineData!, lesson.examDatas, lesson.studentLessonDatas); lesson.studentLessonDatas = GetSmartRatingData(lesson.lessonBase!, lesson.timeLineData!, lesson.smartRatingDatas, lesson.studentLessonDatas); lesson.studentLessonDatas = GetTaskData(lesson.lessonBase!, lesson.timeLineData!, lesson.taskDatas, lesson.studentLessonDatas); var techCount = techCounts.Find(x => !string.IsNullOrWhiteSpace(x.lessonId) && !string.IsNullOrWhiteSpace(lesson?.lessonRecord?.id) && x.lessonId.Equals(lesson.lessonRecord.id)); if (techCount != null) { IEnumerable interact = lessonDataAnalysis.interactNormal; int interactCount = techCount.interactNormalCount; //当前课例的互动次数在互动总列表超过N%; //var persent = GetPersent(interact, interactCount); foreach (var studentLessonData in lesson.studentLessonDatas) { //互动的计分相关的 var x = 0.0; //互动参与度相关的 var y = 0.0; //i互动计分,s个人计分 double i = 0, s = 0; if (lesson?.lessonBase?.report?.clientSummaryList!=null) { var d = lesson?.lessonBase?.report?.clientSummaryList.Find(x => $"{x.seatID}".Equals(studentLessonData.seatID)); if (d!=null) { i=d.interactScore; s =d.score; } } //个人计分最大值 var q = lessonDataAnalysis.pscore.Max(); //互动计分最大值 var t = lessonDataAnalysis.tscore.Max(); if (studentLessonData.interactRecord.interactRecords.Count==interactCount && interactCount>0) { //互动次数 var n = studentLessonData.interactRecord.interactRecords.Count()*1.0; //聚类分数量大和数量小的类群。判断当前出题数在两个类群的最大范围内,再取其质心。 var m = n<=lessonDataAnalysis.clustersInteract.First().Value.Max() ? lessonDataAnalysis.clustersInteract.First().Key*1.0 : lessonDataAnalysis.clustersInteract.Last().Key *1.0; var w = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>=InteractWeight.T1).Count()*1.0; var r = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>InteractWeight.T1).Count()*1.0; var k = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>=InteractWeight.T1).Sum(x=> x.itemScore*1.0); var e = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>InteractWeight.T1).Sum(x => x.itemScore*1.0); var j = InteractWeight.T1; //学习成效算法 //x=((i/t) + ((n/m)*(w*(w/n)+(p/j)* (r/n) *r)))/n; x=((i/t) +(w*k)/(j*m) +(r*e)/(j*m) )/n; y=((n/m)*(w*(w/n)+ (r/n) *r))/n; // var rate = w*100.0/interactCount; // studentLessonData.interactRecord.interactScore=data; // studentLessonData.interactRecord.interactRate=rate; } else { if (studentLessonData.interactRecord.interactRecords.Count()!=0) { Console.WriteLine($"{studentLessonData.id}{lesson?.lessonRecord?.id}的互动次数不匹配。"); } } if (studentLessonData.taskRecord.itemRecords.Count>0) { } var attend = 0.0; if (studentLessonData.attend==1) { attend= 100/100; } var achieve = 190.0/(1+Math.Exp(-(s/q+x)))-95.0; var attitude= 200 / (1 + Math.Exp(-(s/q + y +attend))) - 100.0; studentLessonData.attitude=attitude; studentLessonData.achieve=achieve; } } } } return Ok(new { lessons, interactNormal = lessonDataAnalysis.interactNormal.OrderByDescending(x=>x), cowork = lessonDataAnalysis.cowork.OrderByDescending(x => x), exam = lessonDataAnalysis.exam.OrderByDescending(x => x), smartRating = lessonDataAnalysis.smartRating.OrderByDescending(x => x), }); } [HttpPost("process-history")] public async Task ProcessHistory(JsonElement json) { //1709222400000 2024.3.1 var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School) .GetList($"SELECT value c FROM School AS c where c.startTime>1706716800000 and c.expire<=0 and c.status<>404 and c.duration>300 and c.pk='LessonRecord' and c.school<>'hbcn' and c.school<>'habook' and (c.tLevel>0 or c.pLevel>0) ", null); if (result.list.IsNotEmpty()) { List ignore = new List() { "PgJump", "PgRcv", "PgAdd" }; Stopwatch stopwatch = Stopwatch.StartNew(); //stopwatch.Start(); //await GetLessData(result, ignore); //stopwatch.Stop(); //Console.WriteLine($"Elapsed Time: {stopwatch.ElapsedMilliseconds} ms"); //stopwatch.Reset(); stopwatch.Start(); string path = "F:\\lesson-local"; await foreach (var item in GetLessonLocal(result.list)) { if (item.lessonBase!=null && item.lessonBase.student!=null) { TechCount techCount = new TechCount { lessonId=item.lessonRecord?.id, examCount = item.examDatas.Count, taskCount = item.taskDatas.Count, irsCount = item.irsDatas.Count, coworkCount = item.coworkDatas.Count, smartRatingCount =item.smartRatingDatas.Count, timeCount=item.sokratesDatas.Where(x => !ignore.Contains(x.Event) && !x.Event.Contains("End", StringComparison.OrdinalIgnoreCase)).GroupBy(x => x.Event).Select(x => new CodeLong() { code=x.Key, value= x.ToList().Count }).ToList() }; await System.IO.File.WriteAllTextAsync($"{path}\\{item.lessonRecord!.id}-local.json", item.ToJsonString()); await System.IO.File.WriteAllTextAsync($"{path}\\{item.lessonRecord.id}-count.json", techCount.ToJsonString()); } else { Console.WriteLine($"没有课例id的数据:{item.lessonRecord?.id}"); System.IO.File.Delete($"{path}\\{item.lessonRecord!.id}-local.json"); System.IO.File.Delete($"{path}\\{item.lessonRecord!.id}-count.json"); } } stopwatch.Stop(); Console.WriteLine($"Elapsed Time: {stopwatch.ElapsedMilliseconds} ms"); } return Ok("Lesson records"); } public static List ListAllFiles(string directoryPath) { List filePaths = new List(); DirectoryInfo dirInfo = new DirectoryInfo(directoryPath); // 获取目录下的所有文件(包括子目录中的文件) FileInfo[] files = dirInfo.GetFiles("*", SearchOption.AllDirectories); foreach (FileInfo file in files) { filePaths.Add(file.FullName); // Console.WriteLine(file.FullName); } return filePaths; } public class LessonDataAnalysis { public long updateTime { get; set; } public IEnumerable cowork { get; set; } = new List(); public IEnumerable coworkBase { get; set; } = new List(); public IEnumerable task { get; set; } = new List(); public IEnumerable taskBase { get; set; } = new List(); public IEnumerable exam { get; set; } = new List(); public IEnumerable examBase { get; set; } = new List(); public IEnumerable smartRating { get; set; } = new List(); public IEnumerable smartRatingBase { get; set; } = new List(); public IEnumerable irs { get; set; } = new List(); public IEnumerable interactNormal { get; set; } = new List(); public List>> clustersInteract { get; set; } = new List>>(); public List>> clustersPscore { get; set; } = new List>>(); public List>> clustersTscore { get; set; } = new List>>(); public List>> clustersGscore { get; set; } = new List>>(); /// /// 个人计分 /// public IEnumerable pscore { get; set; } = new List(); /// /// 小组计分 /// public IEnumerable gscore { get; set; } = new List(); /// /// 互动计分 /// public IEnumerable tscore { get; set; } = new List(); public double coworkWeight { get; set; } public double taskWeight { get; set; } public double interactWeight { get; set; } public double examWeight { get; set; } public double smartRatingWeight { get; set; } } /// /// 计算当前元素在集合中超过了多少百分比的值 /// /// /// /// public static double GetPersent(IEnumerable nums, int curr) { int count = 0; foreach (var op in nums.OrderBy(x => x)) { if (op < curr) { count++; } else if (op == curr) { count++; } else { break; } } return count *1.0/ nums.Count() * 100; } /// /// 使用标准差定义异常值。如果一个数字与平均值的偏差超过某个标准差倍数(例如2倍或3倍),则可以认为它是异常的。 /// /// /// public static List CleanDataBySDThreshold(IEnumerable array, double thresholdMultiplier = 2) { if (array.Count() == 0) return new List(); double average = Math.Round(array.Sum()*1.0/array.Count(), 4); double variance = array.Select(x => Math.Round(Math.Pow(x - average, 2), 4)).Sum()*1.0/array.Count(); double standardDeviation = Math.Sqrt(Math.Round(variance, 4)); double threshold = Math.Round(thresholdMultiplier * standardDeviation); List datas = new List(); foreach (double value in array) { double deviation = Math.Round(Math.Abs(value - average), 4); if (deviation <= threshold) { datas.Add(value); } } return datas; } private async IAsyncEnumerable GetLessonLocal(List lessonRecords) { foreach (var lessonRecord in lessonRecords) { LessonLocal lessonLocal = new LessonLocal { lessonRecord=lessonRecord }; if (System.IO.File.Exists($"F:\\lesson-local\\{lessonRecord.id}-local.json")) { string jsonp = await System.IO.File.ReadAllTextAsync($"F:\\lesson-local\\{lessonRecord.id}-local.json"); lessonLocal = jsonp.ToObject(); } else { List files = new List() { $"/records/{lessonRecord.id}/IES/TimeLine.json", $"/records/{lessonRecord.id}/IES/base.json", $"/records/{lessonRecord.id}/IES/Task.json", $"/records/{lessonRecord.id}/IES/SmartRating.json", $"/records/{lessonRecord.id}/IES/IRS.json", $"/records/{lessonRecord.id}/IES/Cowork.json", $"/records/{lessonRecord.id}/Sokrates/SokratesRecords.json", }; lessonLocal = new LessonLocal { lessonRecord=lessonRecord }; lessonLocal = await GetLessonFiles(lessonLocal, files, lessonRecord.school); } if (lessonLocal.lessonBase!=null && lessonLocal.lessonBase.student!=null) { var baseData = GetBaseData(lessonLocal.lessonBase!); lessonLocal.studentLessonDatas= baseData.studentLessonDatas; List examDatas = await GetExamData(lessonRecord, lessonLocal.timeLineData); lessonLocal.examDatas = examDatas; lessonLocal.sokratesDatas= lessonLocal.sokratesDatas.IsNotEmpty() ? lessonLocal.sokratesDatas : lessonLocal.timeLineData!=null ? lessonLocal.timeLineData.events : new List(); } yield return lessonLocal; } } private async Task GetLessonFiles(LessonLocal lessonLocal, List files, string school) { await Parallel.ForEachAsync(files, async (file, _) => { try { BlobDownloadResult blobDownloadResult = await _azureStorage.GetBlobContainerClient(school).GetBlobClient(file).DownloadContentAsync(); switch (true) { case bool when file.Contains("IES/TimeLine.json"): lessonLocal.timeLineData= blobDownloadResult.Content.ToObjectFromJson(); break; case bool when file.Contains("IES/base.json"): lessonLocal.lessonBase= blobDownloadResult.Content.ToObjectFromJson(); break; case bool when file.Contains("IES/Task.json"): lessonLocal.taskDatas= blobDownloadResult.Content.ToObjectFromJson>(); break; case bool when file.Contains("IES/SmartRating.json"): lessonLocal.smartRatingDatas= blobDownloadResult.Content.ToObjectFromJson>(); break; case bool when file.Contains("IES/IRS.json"): lessonLocal.irsDatas= blobDownloadResult.Content.ToObjectFromJson>(); break; case bool when file.Contains("IES/Cowork.json"): lessonLocal.coworkDatas= blobDownloadResult.Content.ToObjectFromJson>(); break; case bool when file.Contains("Sokrates/SokratesRecords.json"): lessonLocal.sokratesDatas= blobDownloadResult.Content.ToObjectFromJson>(); break; } } catch (Exception ex) { //Console.WriteLine($"{file}"); } }); return lessonLocal; } private async Task GetLessData(CosmosDBResult result, List ignore) { foreach (var item in result.list) { //读取TimeLine.json TimeLineData? timeLineData = null; try { BlobDownloadResult timeLineBlobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/TimeLine.json").DownloadContentAsync(); timeLineData = timeLineBlobDownload.Content.ToObjectFromJson(); } catch (Exception ex) { if (!ex.Message.Contains("The specified blob does not exist")) { _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/TimeLine.json"); } } //读取基础Base信息 //base.json LessonBase? lessonBase = null; List studentLessonDatas = new List(); //名单出席率低于30%的 不纳入计算。,累计所有课例的科技使用次数及反馈情况,用于做科技分类比例的权重 try { BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/base.json").DownloadContentAsync(); string basejson = baseblobDownload.Content.ToString().Replace("\"Uncall\"", "0").Replace("Uncall", "0"); lessonBase = basejson.ToObject(); var data = GetBaseData(lessonBase); studentLessonDatas=data.studentLessonDatas; } catch (Exception ex) { if (!ex.Message.Contains("The specified blob does not exist")) { _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/base.json"); } } //读取Task.json ///Event 过滤类型 : 'WrkSpaceLoad'作品收集, 'WrkCmp' 作品贴上 文件:Task.json 根据clientWorks 中的seatID 匹配base.json 中的 student List taskDatas = new List(); try { BlobDownloadResult taskBlobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/Task.json").DownloadContentAsync(); taskDatas = taskBlobDownload.Content.ToObjectFromJson>(); } catch (Exception ex) { if (!ex.Message.Contains("The specified blob does not exist")) { _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/Task.json"); } } //读取互评信息 //Event 过滤类型 'RatingStart' //smartRateSummary.mutualSummary.mutualType 互评【All(每人多件评分) Two(随机分配互评) Self(自评)】 smartRateSummary.meteor_VoteSummary 投票 //读取SmartRating.json List smartRatingDatas = new List(); try { BlobDownloadResult smartRatingBlobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/SmartRating.json").DownloadContentAsync(); smartRatingDatas = smartRatingBlobDownload.Content.ToObjectFromJson>(); } catch (Exception ex) { if (!ex.Message.Contains("The specified blob does not exist")) { _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/SmartRating.json"); } } //读取互动信息 //Event 过滤类型 'PopQuesLoad', 'ReAtmpAnsStrt', 'BuzrAns','BuzrLoad' //TimeLine.json 中找到对应类型,根据Pgid 去 IRS.json 中找到对应数据,从clientAnswers 的下标对应 base.json 中的 student 找到对应学生信息 clientAnswers.length > 1 则表示有二次作答 //读取IRS.json List irsDatas = new List(); try { BlobDownloadResult irsBlobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/IRS.json").DownloadContentAsync(); irsDatas = irsBlobDownload.Content.ToObjectFromJson>(); } catch (Exception ex) { if (!ex.Message.Contains("The specified blob does not exist")) { _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/IRS.json"); } } //读取协作信息 ///Event 过滤类型 'CoworkLoad', "CoworkType":"CoworkGroup",类型 //Cowork.json 中找到对应类型,根据Pgid 去 Cowork.json 中找到对应数据 List coworkDatas = new List(); try { BlobDownloadResult blobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/Cowork.json").DownloadContentAsync(); coworkDatas = blobDownload.Content.ToObjectFromJson>(); } catch (Exception ex) { if (!ex.Message.Contains("The specified blob does not exist")) { _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/Cowork.json"); } } //苏格拉底SokratesRecords.json List sokrates = new List(); try { BlobDownloadResult blobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/Sokrates/SokratesRecords.json").DownloadContentAsync(); sokrates = blobDownload.Content.ToObjectFromJson>(); } catch (Exception ex) { if (!ex.Message.Contains("The specified blob does not exist")) { _logger.LogError(ex, $"文件不存在:/records/{item.id}/Sokrates/SokratesRecords.json"); } } List examDatas = await GetExamData(item, timeLineData); var lessonLocal = new LessonLocal { examDatas= examDatas, coworkDatas= coworkDatas, irsDatas = irsDatas, smartRatingDatas = smartRatingDatas, taskDatas = taskDatas, lessonBase = lessonBase, timeLineData = timeLineData, studentLessonDatas = studentLessonDatas, lessonRecord =item, sokratesDatas= sokrates.IsNotEmpty() ? sokrates : timeLineData!=null ? timeLineData.events : new List() }; TechCount techCount = new TechCount { examCount = examDatas.Count, taskCount = taskDatas.Count, irsCount = irsDatas.Count, coworkCount = coworkDatas.Count, smartRatingCount = smartRatingDatas.Count, timeCount= sokrates.Where(x => !ignore.Contains(x.Event) && !x.Event.Contains("End", StringComparison.OrdinalIgnoreCase)).GroupBy(x => x.Event).Select(x => new CodeLong() { code=x.Key, value= x.ToList().Count }).ToList() }; string path = "F:\\lesson-local"; await System.IO.File.WriteAllTextAsync($"{path}\\{item.id}-local.json", lessonLocal.ToJsonString()); await System.IO.File.WriteAllTextAsync($"{path}\\{item.id}-count.json", techCount.ToJsonString()); } } private async Task> GetExamData(LessonRecord item, TimeLineData? timeLineData) { //读取ExamData List examDatas = new List(); try { var examPages = timeLineData?.events.Where(x => !string.IsNullOrWhiteSpace(x.Pgid) && !string.IsNullOrWhiteSpace(x.ExamId)); if (examPages!=null && examPages.Count()>0) { var examsFiles = await _azureStorage.GetBlobContainerClient(item.school).List($"records/{item.id}/Exam"); var paperFiles = await _azureStorage.GetBlobContainerClient(item.school).List($"records/{item.id}/ExamPaper"); foreach (var examsFile in examsFiles) { if (examsFile.EndsWith("Exam.json")) { ExamData? examData = null; try { BlobDownloadResult examDataDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient(examsFile).DownloadContentAsync(); var str = examDataDownload.Content.ToString().Replace("\r\n","").Replace("\ufeff", "").Replace("\"publish\": \"0\"", "\"publish\": 0").Replace("\"publish\": \"1\"", "\"publish\": 1"); examData= str.ToObject(); // examData = examDataDownload.Content.ToObjectFromJson(); } catch (Exception ex) { if (!ex.Message.Contains("The specified blob does not exist")) { _logger.LogError(ex, $"文件不存在:{examsFile}"); } } if (examData!=null && examData.exam.papers.IsNotEmpty()) { string paperId = examData.exam.papers.First().id; if (_azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/ExamPaper/{paperId}/index.json").Exists()) { LessonPaper lessonPaper = null; try { BlobDownloadResult paperblobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/ExamPaper/{paperId}/index.json").DownloadContentAsync(); lessonPaper = paperblobDownload.Content.ToObjectFromJson(); examData.paper = lessonPaper; } catch (Exception ex) { if (!ex.Message.Contains("The specified blob does not exist")) { _logger.LogError(ex, $"文件不存在:/records/{item.id}/ExamPaper/{paperId}/index.json"); } } } examDatas.Add(examData); } } } } } catch (Exception ex) { _logger.LogError(ex, ex.Message); } return examDatas; } public class TechCount { public string? lessonId { get; set;} /// /// 评测数量 /// public int examCount { get; set;} /// /// 任务数量 /// public int taskCount { get; set;} /// /// IRS次数 /// public int irsCount { get; set; } /// /// 互动次数 /// //public int interactExamCount { get; set; } /// /// 互动次数 /// public int interactNormalCount { get; set; } /// /// 协作次数 /// public int coworkCount { get; set; } /// /// 智能评分次数 /// public int smartRatingCount { get; set; } public List timeCount { get; set; } = new List(); public IEnumerable pscore { get; set; } = new List(); public IEnumerable gscore { get; set; } = new List(); public IEnumerable tscore { get; set; } = new List(); /// /// 评测数量 /// public int examCountBase { get; set; } /// /// 任务数量 /// public int taskCountBase { get; set; } /// /// IRS次数 /// public int irsCountBase { get; set; } /// /// 互动次数 /// //public int interactExamCountBase { get; set; } /// /// 互动次数 /// public int interactNormalCountBase { get; set; } /// /// 协作次数 /// public int coworkCountBase { get; set; } /// /// 智能评分次数 /// public int smartRatingCountBase { get; set; } } /// /// 处理base.json的数据 /// /// /// /// private (LessonBase lessonBase, List studentLessonDatas) GetBaseData( LessonBase lessonBase) { //处理学生定位数据 List studentLessonDatas = new List(); int index = 0; try { if (lessonBase!=null) { lessonBase.student.ForEach(x => { int attend = 0; var client = lessonBase.report.clientSummaryList.Find(y => y.seatID == x.seatID); if (client!=null) { attend=client.attendState; } studentLessonDatas.Add(new StudentLessonData() { id = x.id, index = index, seatID =$"{x.seatID}", groupId = x.groupId, attend= attend }); index++; }); } } catch (Exception ex) { Console.WriteLine(lessonBase.ToJsonString()); } return (lessonBase, studentLessonDatas); } /// ///读取互动信息 ///Event 过滤类型 'PopQuesLoad', 'ReAtmpAnsStrt', 'BuzrAns','BuzrLoad' /// 在IRS.json处理 'PopQuesLoad'互动问答 , 'ReAtmpAnsStrt' 二次作答 , 'BuzrAns' 抢权(新), 'BuzrLoad'抢权(旧), PickupResult 挑人算不算互动?? 读取PickupMemberId "[\r\n 35\r\n]" ///TimeLine.json 中找到对应类型,根据Pgid 去 IRS.json 中找到对应数据,从clientAnswers 的下标对应 base.json 中的 student 找到对应学生信息 clientAnswers.length > 1 则表示有二次作答 ///读取IRS.json /// /// /// /// /// private List GetIRSData( LessonBase lessonBase, TimeLineData timeLineData, List irsDatas, List studentLessonDatas,List examDatas) { List interactTypes = new List() { "PopQuesLoad", "ReAtmpAnsStrt", "BuzrAns", "BuzrLoad", "PickupResult" }; //去重页面 var enventsInteract = timeLineData.events.Where(x => !string.IsNullOrWhiteSpace(x.Pgid) && interactTypes.Contains(x.Event)).GroupBy(x => x.Pgid) .Select(x => new { key = x.Key, list = x.ToList() }); if (enventsInteract!= null && enventsInteract.Count()>0) { var keys = enventsInteract.Select(x => x.key).ToList(); foreach (var item in enventsInteract) { ProcessIRSPageData(irsDatas, studentLessonDatas,examDatas, item); } //处理其他,评测类型的互动,因为有可能不会记录在TimeLine.json中 var envents_other = timeLineData.events.Where(x =>!string.IsNullOrWhiteSpace(x.Pgid) && !keys.Contains(x.Pgid)).GroupBy(x => x.Pgid) .Select(x => new { key = x.Key, list = x.ToList() }); if (envents_other!=null && envents_other.Count()>0) { foreach (var item in envents_other) { ProcessIRSPageData(irsDatas, studentLessonDatas,examDatas, item); } } } else { //处理其他,评测类型的互动,因为有可能不会记录在TimeLine.json中 var envents_other = timeLineData.events.Where(x=> !string.IsNullOrWhiteSpace(x.Pgid)).GroupBy(x => x.Pgid) .Select(x => new { key = x.Key, list = x.ToList() }); if (envents_other!=null && envents_other.Count()>0) { foreach (var item in envents_other) { ProcessIRSPageData(irsDatas, studentLessonDatas,examDatas, item); } } } //单独处理挑人的逻辑 //是否从小组里面挑人。 //不需要去重页面,直接获取挑人大类 PickupResult //小类处理:PickupRight , PickupOption , PickupNthGrp ,PickupEachGrp ,PickupDiff var enventsPickup = timeLineData.events.Where(x => !string.IsNullOrWhiteSpace(x.Pgid) && x.Event.Equals("PickupResult")); if (enventsPickup.IsNotEmpty()) { foreach (var item in enventsPickup) { List mbrs = item.PickupMemberId.ToObject>(); // 挑人挑中 TT ,没有挑中 T1 foreach (var studentLessonData in studentLessonDatas) { var mbr = mbrs.FindAll(x => studentLessonData.seatID!.Equals($"{x}")); if (mbr.IsNotEmpty()) { foreach (var m in mbr) { studentLessonData.attend=1; studentLessonData.interactRecord.interactRecords.Add(new ItemRecord() { resultWeight = InteractWeight.TT, resultType=InteractReultType.TT, itemType = string.IsNullOrWhiteSpace(item.PickupType) ? "PickupResult" : item.PickupType }); } } else { //处理未挑中的 if (studentLessonData.attend==1) { studentLessonData.interactRecord.interactRecords.Add(new ItemRecord() { resultWeight = InteractWeight.T1, resultType=InteractReultType.T1, itemType = string.IsNullOrWhiteSpace(item.PickupType) ? "PickupResult" : item.PickupType }); } } } } } return studentLessonDatas; } private static List ProcessIRSPageData(List irsDatas, List studentLessonDatas, List examDatas, dynamic item) { var irsDataPages = irsDatas.Where(y => item.key.Equals(y.pageID)); foreach (var irsDataPage in irsDataPages) { //检查是否设置正确答案。 var answers_q = irsDataPage.question?["exercise"]?["answer"]?.ToJsonString().ToObject>(); //根据题去找对应的试卷和评测信息 var question_id = $"{irsDataPage.question?["id"]}"; var examData = examDatas.Where(x =>x.paper!=null && x.paper.slides.Exists(x =>!string.IsNullOrWhiteSpace(x.url) && x.url.Equals($"{question_id}.json"))).FirstOrDefault(); List answers = new List(); answers_q?.ForEach(x => { if (!string.IsNullOrWhiteSpace(x)) { answers.Add(x); } }); var _objective = irsDataPage.question?["exercise"]?["objective"]; var scoreNode = irsDataPage.question?["exercise"]?["score"]; var _type = irsDataPage.question?["exercise"]?["type"]; var _answerType = irsDataPage.question?["exercise"]?["answerType"];//file,audio,text,image double questionScore = 0; bool objective = false; if (_objective!=null) { objective = _objective.GetValue(); } //题型 string type= string.Empty; if (_type!=null) { //题型 type = _type.GetValue(); List types = new List() { "single", "multiple" , "judge" , "sortmultiple" }; if (types.Contains(type)) { objective = true; } else { objective = false; } } if (_answerType!=null) { _answerType.GetValue(); //暂不处理,可能存在依然传文字的情况 //不是文本作答的处理,题目不是客观题,答案不记录 //if (!_answerType.Equals("text")) //{ // objective=false; // answers=new List(); //} } if (scoreNode!=null) { double.TryParse(scoreNode.ToString(), out questionScore); } string interactType = string.Empty; if (irsDataPage.clientAnswers.IsNotEmpty()) { //第一个list是几轮,一次作答,二次作答, 第二个list是学生的下标, 第三个list是 答案 List>> clientAnswers = new List>>(); foreach (var key in irsDataPage.clientAnswers.Keys) { clientAnswers.Add(irsDataPage.clientAnswers[key]); } // 获取第一个列表的长度作为比较基准 int firstListLength = clientAnswers.First().Count; bool isSameLength = true; // 遍历剩余的列表并检查它们的长度是否与第一个列表相同 foreach (var innerList in clientAnswers.Skip(1)) { if (innerList.Count != firstListLength) { isSameLength = false; break; } } //并检查学生集合的长度是否与第一个列表相同 if (isSameLength && studentLessonDatas.Count()==firstListLength) { for (int index = 0; index< clientAnswers[0].Count; index++) { var student = studentLessonDatas[index]; double studentScore = 0 ; if (examData!=null && examData.examClassResult.IsNotEmpty()) { var examResultIndex = examData.examClassResult.First().studentIds.IndexOf(student.id); var questionIndex = examData.paper.slides.Select(x => x.url).ToList().IndexOf($"{question_id}.json"); if (examResultIndex>=0 && examData.examClassResult.First().studentScores.Count>=(examResultIndex+1) //防止索引越界 && examData.examClassResult.First().studentScores[examResultIndex].Count>=(questionIndex+1)) //防止索引越界 { //获取index学生在questionIndex题的分数 studentScore = examData.examClassResult.First().studentScores[examResultIndex][questionIndex]; } } //index 代表学生下标 List interactRecords = new List(); if (clientAnswers.Count==1) { //即问即答 interactType = "PopQuesLoad"; var ans0 = clientAnswers[0][index]; var IS0 = GetInteractResultHasAnswer(answers, ans0, objective,type,questionScore, studentScore); interactRecords.Add(new ItemRecord() { resultWeight = IS0.weight, resultType=IS0.reultType, itemType= interactType, criterion= questionScore, itemScore= IS0.interactScore }); } if (clientAnswers.Count==2) { //二次作答 interactType="ReAtmpAnsStrt"; var ans1 = clientAnswers[1][index]; var IS1 = GetInteractResultHasAnswer(answers, ans1, objective,type,questionScore,studentScore); interactRecords.Add(new ItemRecord() { resultWeight = IS1.weight, resultType=IS1.reultType, itemType= interactType, criterion= questionScore, itemScore= IS1.interactScore }); } if (clientAnswers.Count>2) { //三次作答 interactType="TeAtmpAnsStrt"; var ans2 = clientAnswers[2][index]; var IS2 = GetInteractResultHasAnswer(answers, ans2, objective, type, questionScore, studentScore); interactRecords.Add(new ItemRecord() { resultWeight = IS2.weight, resultType=IS2.reultType, itemType= interactType, criterion= questionScore, itemScore= IS2.interactScore }); } if (studentLessonDatas[index].attend==1) { studentLessonDatas[index].interactRecord.interactRecords.AddRange(interactRecords); } } } } //是否抢权作答的模式 if (irsDataPage.isBuzz) { interactType = "BuzrAns"; //处理参与抢权的 Dictionary buzzParticipants = new Dictionary(); foreach (var buzzParticipant in irsDataPage.buzzParticipants) { var studentData = studentLessonDatas.Find(x => x.seatID!.Equals(buzzParticipant)); if (studentData != null) { buzzParticipants[buzzParticipant]=new ItemRecord() { resultWeight = InteractWeight.T1, itemType= interactType, resultType= InteractReultType.T1 }; } } //处理抢权成功的 foreach (var buzzClient in irsDataPage.buzzClients) { buzzParticipants[buzzClient]=new ItemRecord() { resultWeight = InteractWeight.TT, itemType= interactType, resultType= InteractReultType.TT }; } foreach (var studentLessonData in studentLessonDatas) { if (buzzParticipants.ContainsKey(studentLessonData.seatID!)) { //处理已经有抢权结果的数据 studentLessonData.attend=1; studentLessonData.interactRecord.interactRecords.Add(buzzParticipants[studentLessonData.seatID!]); } else { if (studentLessonData.attend==1) { //处理未参与抢权的 studentLessonData.interactRecord.interactRecords.Add(new ItemRecord() { resultWeight = InteractWeight.T0, itemType = interactType,resultType= InteractReultType.T0 }); } } } } } return studentLessonDatas; } private static (double weight,string reultType,double interactScore) GetInteractResultHasAnswer(List? answers, List ans0 , bool objective,string type, double questionScore, double studentScore) { //List ans0 = new List(); //ans?.ForEach(x => { // if (!string.IsNullOrWhiteSpace(x)) // { // ans0.Add(x); // } // else { ans.Add("");} //}); double weight = InteractWeight.T0; string reultType = InteractReultType.T0; double interactScore = 0; if (answers.IsNotEmpty()) { if (ans0.IsNotEmpty()) { if (objective) //客观题 { //标准答案等于作答的结果 if (answers!.Count == ans0.Count) { if (answers.All(item => ans0.Contains(item))) { //完全正确 weight= InteractWeight.TT; reultType= InteractReultType.TT; interactScore= studentScore==0 ? questionScore : studentScore; } else { //作答错误 weight= InteractWeight.T1; reultType = InteractReultType.T1; interactScore= studentScore; } } //标准答案比作答的结果多 else if (answers!.Count > ans0.Count) { if (ans0.All(item => answers.Contains(item))) { //部分正确 weight= InteractWeight.TP; reultType = InteractReultType.TP; // 2 * 0.3 * 10= 6 interactScore= studentScore==0 ? 1/(InteractWeight.TT-InteractWeight.T1) * (InteractWeight.TP-InteractWeight.T1) * questionScore : studentScore; } else { //作答错误 weight= InteractWeight.T1; reultType = InteractReultType.T1; interactScore= studentScore; } } //标准答案比作答结果少 else { //作答错误 weight= InteractWeight.T1; reultType = InteractReultType.T1; interactScore= studentScore; } } else { //填空题 if ("complete".Equals(type) && answers!.Count==ans0.Count) { bool hasT = false; bool hasF = false; for (int i = 0; i < answers!.Count; i++) { if (answers[i].Equals(ans0[i])) { hasT=true; } else { hasF=true; } } if (hasT && !hasF) { //完全正确 weight= InteractWeight.TT; reultType = InteractReultType.TT; interactScore= studentScore==0 ? questionScore : studentScore; } else if (hasT && hasF) { //部分正确 weight= InteractWeight.TP; reultType = InteractReultType.TP; // 2 * 0.3 * 10= 6 interactScore= studentScore==0 ? 1/(InteractWeight.TT-InteractWeight.T1) * (InteractWeight.TP-InteractWeight.T1) * questionScore : studentScore; } else if (!hasT && hasF) { //没有正确的,但有错误的,代表参与了 weight= InteractWeight.T1; reultType = InteractReultType.T1; interactScore= studentScore; } else if (!hasT && !hasF) { //没有正确的,也没有错误的,代表没有作答 weight= InteractWeight.T0; reultType = InteractReultType.T0; interactScore= studentScore; } } else { //主观题,完全匹配的 if (answers!.All(item => ans0.Contains(item))) { //完全正确 weight= InteractWeight.TT; reultType = InteractReultType.TT; interactScore= studentScore==0 ? questionScore : studentScore; } else { // 使用LINQ查询来判断是否有匹配的答案 bool hasMatchingAnswer = answers!.Intersect(ans0).Any(); if (hasMatchingAnswer) { //主观题回答正确即为完全正确 weight= InteractWeight.TT; reultType = InteractReultType.TT; interactScore= studentScore==0 ? questionScore : studentScore; } else { //优先根据得分与标准分的占比算出得分率,如果没有得分率,如果是直接从互动,不知道是评测的 需要先去评测找作答得分。,则采用Levenshtein距离来评估两个字符串的相似度 //没有匹配上答案,则采用Levenshtein距离来评估两个字符串的相似度 if (questionScore>0) { if (studentScore>0) { weight = studentScore * 1.0 / questionScore* (InteractWeight.TT-InteractWeight.T1); if (weight==InteractWeight.T1) { reultType = InteractReultType.T1; interactScore=studentScore; } else if (weight>InteractWeight.TT) { reultType = InteractReultType.TT; interactScore=studentScore==0? questionScore:studentScore; } else { reultType = InteractReultType.TP; // 2 * 0.3 * 10= 6 interactScore= studentScore==0 ? 1/(InteractWeight.TT-InteractWeight.T1) * (InteractWeight.TP-InteractWeight.T1) * questionScore : studentScore; } } else { weight=InteractWeight.T1+(CalculateSimilarity(answers![0], ans0[0]) *(InteractWeight.TT-InteractWeight.T1)); if (weight==InteractWeight.T1) { reultType = InteractReultType.T1; interactScore=studentScore; } else if (weight>InteractWeight.TT) { reultType = InteractReultType.TT; interactScore=studentScore==0? questionScore:studentScore; } else { reultType = InteractReultType.TP; // 2 * 0.3 * 10= 6 interactScore= studentScore==0 ? 1/(InteractWeight.TT-InteractWeight.T1) * (InteractWeight.TP-InteractWeight.T1) * questionScore : studentScore; } } } else { weight=InteractWeight.T1+(CalculateSimilarity(answers![0], ans0[0]) *(InteractWeight.TT-InteractWeight.T1)); if (weight==InteractWeight.T1) { reultType = InteractReultType.T1; interactScore=studentScore; } else if (weight>InteractWeight.TT) { reultType = InteractReultType.TT; interactScore=studentScore==0? questionScore:studentScore; } else { reultType = InteractReultType.TP; // 2 * 0.3 * 10= 6 interactScore= studentScore==0 ? 1/(InteractWeight.TT-InteractWeight.T1) * (InteractWeight.TP-InteractWeight.T1) * questionScore : studentScore; } } } } } } } else { //没有作答 weight= InteractWeight.T0; reultType = InteractReultType.T0; interactScore=studentScore; } } else { //没有标准答案的情况 if (ans0.IsNotEmpty()) { bool hasAns = false; ans0.ForEach(x => { if (!string.IsNullOrWhiteSpace(x)) { hasAns = true; } }); if (hasAns) { //作答了 weight= InteractWeight.T1; reultType = InteractReultType.T1; interactScore=studentScore; } else { //没有作答 weight= InteractWeight.T0; reultType = InteractReultType.T0; interactScore=studentScore; } } else { //没有作答 weight= InteractWeight.T0; reultType = InteractReultType.T0; interactScore=studentScore; } //如果教师手动给了分或AI评分 if (questionScore>0 && studentScore>0) { weight = studentScore * 1.0 / questionScore* (InteractWeight.TT-InteractWeight.T1); if (weight==InteractWeight.T1) { reultType = InteractReultType.T1; interactScore=studentScore; } else if (weight>InteractWeight.TT) { reultType = InteractReultType.TT; interactScore=studentScore==0 ? questionScore : studentScore; } else { reultType = InteractReultType.TP; // 2 * 0.3 * 10= 6 interactScore= studentScore==0 ? 1/(InteractWeight.TT-InteractWeight.T1) * (InteractWeight.TP-InteractWeight.T1) * questionScore : studentScore; } } } return (weight,reultType,interactScore); } #region C# 代码 如何判断两句话是否一个意思,非机器学习的算法。使用Levenshtein距离来评估两个字符串的相似度,但是不能判断它们是否表达了同一个意思,后续借助AI实现 public static double CalculateSimilarity(string s1, string s2) { int n = s1.Length; int m = s2.Length; int[,] d = new int[n + 1, m + 1]; for (int i = 0; i <= n; i++) { d[i, 0] = i; } for (int j = 0; j <= m; j++) { d[0, j] = j; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { int cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1; d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost); } } return (1.0 - ((double)d[n, m] / Math.Max(s1.Length, s2.Length))) ; } #endregion /// /// 获取课中评测数据 /// /// /// /// /// /// /// private List GetExamData( LessonBase lessonBase, TimeLineData timeLineData, List examDatas, List studentLessonDatas) { foreach (var examData in examDatas) { //直接取第一个元素的试卷,因为在HiTeach中,只会是一个试卷(一个科目),一个班参与。 var allocation= examData?.exam?.papers?.FirstOrDefault()?.point?.Sum(); var answersStd = examData?.exam?.papers?.FirstOrDefault()?.answers; List> answers= new List>(); if (answersStd!=null) { answersStd.ForEach(x => //去除[""]此种类型的标准答案,转为[] { List ans = new List(); if (x.Count!=0) { if (x.Count==1) { if (string.IsNullOrWhiteSpace(x[0])) { answers.Add(ans); } else { answers.Add(x); } } else { answers.Add(x); } } else { answers.Add(ans); } }); } examData?.examClassResult?.ForEach(item =>{ //学生下标 int index = 0; if (item.studentAnswersArray.Count()>0 && item.studentAnswersArray.Count() == item.studentIds.Count() //学生作答数量和学生id数量一致 && item.studentScores.Count()==item.studentIds.Count()) //学生分数和学生id数量一致 { item.studentAnswersArray.ForEach(stu => { var student = studentLessonDatas.Find(x => x.id!.Equals(item.studentIds[index])); if (student!=null && student.attend==1) { //是否要判断主观题或者客观题, 多套试卷,有主观题的 //,如果没获得结果, //主观题有回答的:608942756458532864\Clients\18782481024\Ans\27-4341670635487887360-examExchangeAnswerlist //27 从1开始的学生序号-4341670635487887360评测编号,内容qNo 是从1开始的题号。 if (stu.IsNotEmpty() && answers.Count()==stu.Count && examData.exam.papers[0].type.Count()==answers.Count ) { StudentExamRecord studentExam = new StudentExamRecord(); var studentScore = item.studentScores[index]; List answerRecords = new List(); //题目下标 int itemIndex = 0; stu.ForEach(ans => { bool objective = objectiveTypes.Contains(examData.exam.papers[0].type[itemIndex]); var questionScore = examData.exam.papers[0].point[itemIndex]; string type = examData.exam.papers[0].type[itemIndex]; var res= GetInteractResultHasAnswer(answers[itemIndex], ans, objective, type, questionScore, studentScore[itemIndex]); ItemRecord interactRecord = new ItemRecord() { itemType="SPQStrt",//类型 resultType=res.reultType,//作答结果类型 resultWeight=res.weight,//得分权重 criterion= questionScore,//标准分 itemScore= studentScore[itemIndex]//得分 }; answerRecords.Add(interactRecord); itemIndex++; }); studentExam.score= answerRecords.Where(x => x.itemScore>=0).Select(x => x.itemScore).Sum();//得分 studentExam.scoreRate= allocation.HasValue && allocation.Value>0 ? studentExam.score * 1.0/allocation.Value : 0;//得分率 studentExam.answerRate= answerRecords.Where(x => x.resultWeight>0).Count()*1.0/studentScore.Count();//作答率 studentExam.examId=examData.exam.id; studentExam.itemRecords=answerRecords; student.examRecords.Add(studentExam); } } index++; }); } }); } return studentLessonDatas; } /// /// 协作参与率 态度计算 /// /// /// /// /// /// /// private List GetCoworkData( LessonBase lessonBase, TimeLineData timeLineData, List coworkDatas, List studentLessonDatas) { int p = 0; foreach (var coworkData in coworkDatas) { var keys = coworkData.participateLevelList.Keys; foreach (var key in keys) { var student = studentLessonDatas.Find(x => x.seatID!.Equals(key)); if (student!=null && student.attend==1) { var score = coworkData.participateLevelList[key];//协作得分,是否是经过指数计算的 var itemRecord = new ItemRecord { criterion=-1, itemType= coworkData.coworkType, itemScore=score, isGroup= coworkData.coworkType.Equals("Group") ? true : false }; //不能完全依赖 if (score>0) { itemRecord.resultWeight = InteractWeight.TP; itemRecord.resultType = InteractReultType.TP; } else { itemRecord.resultWeight = InteractWeight.T0; itemRecord.resultType = InteractReultType.T0; } student.coworkRecord.itemRecords.Add(itemRecord); } } var order = studentLessonDatas.OrderByDescending(x => x.coworkRecord.itemRecords[p].itemScore); var maxItems = studentLessonDatas.FindAll(x => x.coworkRecord.itemRecords[p].itemScore==order.First().coworkRecord.itemRecords[p].itemScore); var max = studentLessonDatas.FindAll(x => x.coworkRecord.itemRecords[p].itemScore==order.First().coworkRecord.itemRecords[p].itemScore).First().coworkRecord.itemRecords[p].itemScore; var min = studentLessonDatas.FindAll(x => x.coworkRecord.itemRecords[p].itemScore==order.Last().coworkRecord.itemRecords[p].itemScore).First().coworkRecord.itemRecords[p].itemScore; var sum = studentLessonDatas.Sum(x => x.coworkRecord.itemRecords[p].itemScore); foreach (var student in studentLessonDatas) { if (student.attend==1 && student.coworkRecord.itemRecords.Count>=p+1 && student.coworkRecord.itemRecords[p].itemScore>0) { student.coworkRecord.itemRecords[p].resultType=InteractReultType.TP; var data = MinMaxNormalization(min, max, student.coworkRecord.itemRecords[p].itemScore); student.coworkRecord.itemRecords[p].resultWeight=InteractWeight.T1+ data * 1.0 / 100 * (InteractWeight.TT-InteractWeight.T1); if (maxItems.Select(x => x.seatID).Contains(student.seatID)) { student.coworkRecord.itemRecords[p].resultType= InteractReultType.TT; student.coworkRecord.itemRecords[p].resultWeight= InteractWeight.TT; } } } p++; } return studentLessonDatas; } /// /// 处理学生回推数据,并将回推纳入学习态度计算。 /// /// /// /// /// /// /// private List GetTaskData( LessonBase lessonBase, TimeLineData timeLineData, List taskDatas, List studentLessonDatas) { //协作也算任务的一种,'WrkSpaceLoad' 作品收集, "isGroupItem": false, int indexTask = 0; foreach (var taskData in taskDatas) { //作品收集是全部人员都要参加 foreach (var student in studentLessonDatas) { if (student.attend==1) { var work = taskData.clientWorks.Find(x =>$"{x.seatID}".Equals(student.seatID)); if (work!= null) { student.taskRecord.itemRecords.Add(new ItemRecord { itemType="WrkSpaceLoad", itemScore=10, resultWeight=InteractWeight.T1, resultType=InteractReultType.T1, isGroup= work.isGroupItem }); } else { student.taskRecord.itemRecords.Add(new ItemRecord { itemType="WrkSpaceLoad", itemScore=0, resultWeight=InteractWeight.T0, resultType=InteractReultType.T0, isGroup= false }); } } } //////// ///需要处理小组的情况,当前人员没有提交作品,但是有可能是小组其他人员提交了,需要判断一下。 /// var groupIdsA = studentLessonDatas.FindAll(x => x.attend==1 && x.taskRecord.itemRecords[indexTask].isGroup==true).GroupBy(x=>x.groupId).Select(x=>x.Key); foreach (var groupId in groupIdsA) { var groupStudents= studentLessonDatas.FindAll(x => x.attend==1 && !string.IsNullOrWhiteSpace(x.groupId) && x.groupId.Equals(groupId)); foreach (var student in groupStudents) { student.taskRecord.itemRecords[indexTask].isGroup=true; } } var groupIdsB = taskData.clientWorks.FindAll(x => x.seatID==0 && x.isGroupItem).Select(x => x.groupID).Distinct() ; foreach (var groupId in groupIdsB) { var groupStudents = studentLessonDatas.FindAll(x => x.attend==1 && !string.IsNullOrWhiteSpace(x.groupId) && x.groupId.Equals(groupId)); foreach (var student in groupStudents) { student.taskRecord.itemRecords[indexTask].isGroup=true; } } indexTask++; } return studentLessonDatas; } /// /// 评分参与率 态度计算 /// //读取互评信息 /// /// 评分相关 在SmartRating.json 处理 GrandRating 星光大评分, 投票Voting 和 PeerAssessment(All每人多件评分,Two随机分配互评, Self自评) //Event 过滤类型 'RatingStart' //smartRateSummary.mutualSummary.mutualType 互评【All(每人多件评分) Two(随机分配互评) Self(自评)】 smartRateSummary.meteor_VoteSummary 投票 //读取SmartRating.json /// /// /// /// /// /// /// private List GetSmartRatingData( LessonBase lessonBase, TimeLineData timeLineData, List smartRatingDatas, List studentLessonDatas) { int index = 0; foreach(var smartRatingData in smartRatingDatas) { string type = ""; //投票类型的 var keys_vote = smartRatingData.smartRateSummary?.meteor_VoteSummary?.Keys?.ToList(); if (keys_vote.IsNotEmpty()) { type="Voting"; bool addData=false; foreach (var key in keys_vote!) { var voteDetailResults = smartRatingData.smartRateSummary!.voteDetailResult[key]; foreach (var student in studentLessonDatas) { if (student.attend==1) { //投票是全员参与 var datasS = voteDetailResults.FindAll(x => x.id.Equals(student.seatID)); if (datasS.IsNotEmpty()) { //T1,只有评论别人,没被别人评论 或者是评论了别人,但是没有被别人评论, student.rateingRecord.itemRecords.Add(new ItemRecord { itemType=type, resultType=InteractReultType.T1, resultWeight = InteractWeight.T1 }); addData=true; } else { //T0 是没有评论别人,也没被别人评论, student.rateingRecord.itemRecords.Add(new ItemRecord { itemType=type, resultType=InteractReultType.T0, resultWeight = InteractWeight.T0 }); addData=true; } //T0 是没有评论别人,也没被别人评论, //T1,只有评论别人,没被别人评论 或者是评论了别人,但是没有被别人评论, //TP 有被别人评论,且评论了别人, //TT是评论了别人,且被别人评论次数最高,或者分值最高。 } } var meteor_VoteSummary = smartRatingData.smartRateSummary!.meteor_VoteSummary[key]; var order = meteor_VoteSummary.OrderByDescending(x => x.result); var maxItems = meteor_VoteSummary.FindAll(x => x.result==order.First().result); var max= meteor_VoteSummary.FindAll(x => x.result==order.First().result).First().result; var min = meteor_VoteSummary.FindAll(x => x.result==order.Last().result).First().result; var sum = meteor_VoteSummary.Sum(x=>x.result); //排名指数计算=( 当前值分数- 298) / (9992 - 298) * (99 - 60) + 60 //将每个人的积分转化为60-100 //排名 = (积分 - 最低积分) / (最高积分 - 最低积分) * (最大排名 - 最小排名) + 最小排名 foreach (var datasD in meteor_VoteSummary) { //有被人评论或投票 var student = studentLessonDatas.Find(x => x.seatID!.Equals(datasD.id)); if (student!=null) { if (index x.id).Contains(student.seatID)) { student.rateingRecord.itemRecords[index].resultType= InteractReultType.TT; student.rateingRecord.itemRecords[index].resultWeight= InteractWeight.TT; } } } } } if (addData) { index++; } } } //星光大评分,全员评分 var keys_GrandRating = smartRatingData.smartRateSummary?.scoreDetailResult?.Keys?.ToList(); if (keys_GrandRating.IsNotEmpty() && smartRatingData.smartRateSummary!=null && smartRatingData.smartRateSummary.meteor_ScoreSummary.IsNotEmpty()) { bool addData = false; type="GrandRating"; foreach (var student in studentLessonDatas) { if (student.attend==1) { if (keys_GrandRating!.Contains(student.seatID!)) { //T1,只有评论别人,没被别人评论 或者是评论了别人,但是没有被别人评论, student.rateingRecord.itemRecords.Add(new ItemRecord { itemType=type, resultType=InteractReultType.T1, resultWeight = InteractWeight.T1 }); addData = true; } else { //T0 是没有评论别人,也没被别人评论, student.rateingRecord.itemRecords.Add(new ItemRecord { itemType=type, resultType=InteractReultType.T0, resultWeight = InteractWeight.T0 }); addData = true; } } } var order = smartRatingData.smartRateSummary.meteor_ScoreSummary.Where(x => x.result>0).OrderByDescending(x => x.result); var maxItems = smartRatingData.smartRateSummary.meteor_ScoreSummary.FindAll(x => x.result==order.First().result); var max = smartRatingData.smartRateSummary.meteor_ScoreSummary.FindAll(x => x.result==order.First().result).First().result; var min = smartRatingData.smartRateSummary.meteor_ScoreSummary.FindAll(x => x.result==order.Last().result).First().result; var sum = smartRatingData.smartRateSummary.meteor_ScoreSummary.Sum(x => x.result); foreach (var meteor_ScoreSummary in smartRatingData.smartRateSummary.meteor_ScoreSummary) { var student= studentLessonDatas.Find(x => x.seatID!.Equals(meteor_ScoreSummary.id)); if (student!=null) { if (index x.id).Contains(student.seatID)) { student.rateingRecord.itemRecords[index].resultType= InteractReultType.TT; student.rateingRecord.itemRecords[index].resultWeight= InteractWeight.TT; } } } } } if (addData) { index++; } } // 互评 PeerAssessment(All每人多件评分,Two随机分配互评, Self自评) var keys_PeerAssessment = smartRatingData.smartRateSummary?.mutualDetailSummary?.Keys?.ToList(); if (keys_PeerAssessment.IsNotEmpty() && smartRatingData.smartRateSummary?.mutualSummary!=null && smartRatingData.smartRateSummary.mutualSummary.mutualResults.IsNotEmpty() && smartRatingData.smartRateSummary.mutualSummary.materialInfos.IsNotEmpty()) { bool addData = false; type="PeerAssessment"; foreach (var student in studentLessonDatas) { if (student.attend==1) { if (keys_PeerAssessment!.Contains(student.seatID!)) { //T1,只有评论别人,没被别人评论 或者是评论了别人,但是没有被别人评论, student.rateingRecord.itemRecords.Add(new ItemRecord { itemType=type, resultType=InteractReultType.T1, resultWeight = InteractWeight.T1 }); addData = true; } else { //T0 是没有评论别人,也没被别人评论, student.rateingRecord.itemRecords.Add(new ItemRecord { itemType=type, resultType=InteractReultType.T0, resultWeight = InteractWeight.T0 }); addData = true; } } } var order = smartRatingData.smartRateSummary.mutualSummary.mutualResults.Where(x => x.result>0).OrderByDescending(x => x.result); var maxItems = smartRatingData.smartRateSummary.mutualSummary.mutualResults.FindAll(x => x.result==order.First().result); var max = smartRatingData.smartRateSummary.mutualSummary.mutualResults.FindAll(x => x.result==order.First().result).First().result; var min = smartRatingData.smartRateSummary.mutualSummary.mutualResults.FindAll(x => x.result==order.Last().result).First().result; var sum = smartRatingData.smartRateSummary.mutualSummary.mutualResults.Sum(x => x.result); foreach (var mutualResult in smartRatingData.smartRateSummary.mutualSummary.mutualResults) { var student = studentLessonDatas.Find(x => x.seatID!.Equals(mutualResult.id)); if (student!=null) { if (index x.id).Contains(student.seatID)) { student.rateingRecord.itemRecords[index].resultType= InteractReultType.TT; student.rateingRecord.itemRecords[index].resultWeight= InteractWeight.TT; } } } } } if (addData) { index++; } } } return studentLessonDatas; } /// /// 最小-最大归一化(Min-Max Normalization)算法。这种算法通常用于将数据的特征值缩放到一个指定的范围内,通常是0到1之间,或者任何其他指定的范围。 /// /// public double MinMaxNormalization(double min ,double max,double x ) { //排名指数计算=( 当前值分数- 298) / (9992 - 298) * (99 - 60) + 60 //将每个人的积分转化为60-100 //排名 = (积分 - 最低积分) / (最高积分 - 最低积分) * (最大排名 - 最小排名) + 最小排名 return x==0 ? 0 : max-min!=0 ? (x - min)*1.0 / (max - min) * (maxRank - minRank) + minRank : (x)*1.0 / (max) * (maxRank - minRank) + minRank; } } public class LessonLocal { public LessonBase? lessonBase { get; set;} public TimeLineData? timeLineData { get; set; } public LessonRecord? lessonRecord { get; set; } public List studentLessonDatas { get; set; } = new List(); public List taskDatas { get; set; } = new List(); public List smartRatingDatas { get; set; } = new List(); public List irsDatas { get; set; } = new List(); public List coworkDatas { get; set; } = new List(); public List examDatas { get; set; } = new List(); public List sokratesDatas { get; set; } = new List(); } /// 互动参与指数(按倍数的权重设计) /// 无二次作答的互动,且未设置正确答案:1.未作答0 /// 2.已作答1 /// /// 无二次作答的互动,且设置了正确答案:3.未作答0 /// 4.已作答1 /// 5.不完全正确1.3 /// 6.作答正确1.5 /// /// /// 有二次作答的互动,且未设置正确答案:7.第一次未作答0,第二次未作答0=》0 /// 8.第一次已作答1,第二次未作答0=》1 /// 9.第一次未作答0,第二次已作答1=》1 /// 10.第一次已作答1,第二次已作答1=》2 /// /// 有二次作答的互动,且设置了正确答案:(16种可能) /// 11.第一次未作答0,第二次未作答0=》0 /// 12.第一次已作答,不完全正确1.3,第二次未作答0=》1.3 /// 13.第一次已作答,作答正确1.5,第二次未作答0=》1.5 /// 14.第一次已作答,作答错误1,第二次未作答0=》1 /// 15.第一次未作答0,第二次已作答,不完全正确1.3=》1.3 /// 16.第一次未作答0,第二次已作答,作答正确1.5=》1.5 /// 17.第一次未作答0,第二次已作答,作答错误1=》1 /// 18.第一次已作答,作答错误1,第二次已作答,作答错误1=》2 /// 19.第一次已作答,不完全正确1.3,第二次已作答,作答错误1=》2.3 /// 20.第一次已作答,作答正确1.5,第二次已作答,作答错误1=》2.5 /// 21.第一次已作答,作答错误1,第二次已作答,不完全正确1.3=》2.3 /// 22.第一次已作答,作答错误1,第二次已作答,作答正确1.5=》2.5 /// 23.第一次已作答,不完全正确1.3,第二次已作答,不完全正确1.3=》2.6 /// 24.第一次已作答,不完全正确1.3,第二次已作答,作答正确1.5=》2.8 /// 25.第一次已作答,作答正确1.5,第二次已作答,不完全正确1.3=》2.8 /// 26.第一次已作答,作答正确1.5,第二次已作答,作答正确1.5=》3 /// /// 抢权模式: 27.未参与抢权 0 /// 28.参与抢权 1 /// 29.抢权成功 1.5 /// 挑人时被挑到 30.被挑到 1.5 /// 有三次作答的互动,且设置了正确答案:(64种可能) /* 1 未作答0 未作答0 未作答0 0 2 未作答0 未作答0 不完全正确1.3 1.3 3 未作答0 未作答0 作答正确1.5 1.5 4 未作答0 未作答0 作答错误1 1 5 未作答0 不完全正确1.3 未作答0 1.3 6 未作答0 不完全正确1.3 不完全正确1.3 2.6 7 未作答0 不完全正确1.3 作答正确1.5 2.8 8 未作答0 不完全正确1.3 作答错误1 2.3 9 未作答0 作答正确1.5 未作答0 1.5 10 未作答0 作答正确1.5 不完全正确1.3 2.8 11 未作答0 作答正确1.5 作答正确1.5 3 12 未作答0 作答正确1.5 作答错误1 2.5 13 未作答0 作答错误1 未作答0 1 14 未作答0 作答错误1 不完全正确1.3 2.3 15 未作答0 作答错误1 作答正确1.5 2.5 16 未作答0 作答错误1 作答错误1 2 17 已作答错误1 未作答0 未作答0 1 18 已作答错误1 未作答0 不完全正确1.3 2.3 19 已作答错误1 未作答0 作答正确1.5 2.5 20 已作答错误1 未作答0 作答错误1 2 21 已作答错误1 不完全正确1.3 未作答0 2.3 22 已作答错误1 不完全正确1.3 不完全正确1.3 3.6 23 已作答错误1 不完全正确1.3 作答正确1.5 3.8 24 已作答错误1 不完全正确1.3 作答错误1 3.3 25 已作答错误1 作答正确1.5 未作答0 2.5 26 已作答错误1 作答正确1.5 不完全正确1.3 3.8 27 已作答错误1 作答正确1.5 作答正确1.5 4 28 已作答错误1 作答正确1.5 作答错误1 3.5 29 已作答错误1 作答错误1 未作答0 2 30 已作答错误1 作答错误1 不完全正确1.3 3.3 31 已作答错误1 作答错误1 作答正确1.5 3.5 32 已作答错误1 作答错误1 作答错误1 3 33 已作答不完全正确1.3 未作答0 未作答0 1.3 34 已作答不完全正确1.3 未作答0 不完全正确1.3 2.6 35 已作答不完全正确1.3 未作答0 作答正确1.5 2.8 36 已作答不完全正确1.3 未作答0 作答错误1 2.3 37 已作答不完全正确1.3 不完全正确1.3 未作答0 2.6 38 已作答不完全正确1.3 不完全正确1.3 不完全正确1.3 3.9 39 已作答不完全正确1.3 不完全正确1.3 作答正确1.5 4.1 40 已作答不完全正确1.3 不完全正确1.3 作答错误1 3.6 41 已作答不完全正确1.3 作答正确1.5 未作答0 2.8 42 已作答不完全正确1.3 作答正确1.5 不完全正确1.3 4.1 43 已作答不完全正确1.3 作答正确1.5 作答正确1.5 4.3 44 已作答不完全正确1.3 作答正确1.5 作答错误1 3.8 45 已作答不完全正确1.3 作答错误1 未作答0 2.3 46 已作答不完全正确1.3 作答错误1 不完全正确1.3 3.6 47 已作答不完全正确1.3 作答错误1 作答正确1.5 3.8 48 已作答不完全正确1.3 作答错误1 作答错误1 3.3 49 已作答正确1.5 未作答0 未作答0 1.5 50 已作答正确1.5 未作答0 不完全正确1.3 2.8 51 已作答正确1.5 未作答0 作答正确1.5 3 52 已作答正确1.5 未作答0 作答错误1 2.5 53 已作答正确1.5 不完全正确1.3 未作答0 2.8 54 已作答正确1.5 不完全正确1.3 不完全正确1.3 4.1 55 已作答正确1.5 不完全正确1.3 作答正确1.5 4.3 56 已作答正确1.5 不完全正确1.3 作答错误1 3.8 57 已作答正确1.5 作答正确1.5 未作答0 3 58 已作答正确1.5 作答正确1.5 不完全正确1.3 4.3 59 已作答正确1.5 作答正确1.5作答正确1.5 4.5 60 已作答正确1.5 作答正确1.5作答错误1 4 61 已作答正确1.5 作答错误1 未作答0 2.5 62 已作答正确1.5 作答错误1 不完全正确1.3 3.8 63 已作答正确1.5 作答错误1 作答正确1.54 64 已作答正确1.5 作答错误1 作答错误1 3.5 */ /* * /// 事件 /// 推送相关 在Push.json处理 DifObjPush 推送给学生 差异化推送 "PushMemberId":[1,4,8,12,17,18,19,23,24,27,32,36] ,FastPgPush 同一推送 /// 互动相关 在IRS.json处理 'PopQuesLoad'互动问答 , 'ReAtmpAnsStrt' 二次作答 , 'BuzrAns' 抢权(新), 'BuzrLoad'抢权(旧), PickupResult 挑人算不算互动?? 读取PickupMemberId "[\r\n 35\r\n]" /// 测验相关 在IRS.json处理 SPQStrt 测验模式 /// 任务相关 在Task.json处理 'WrkSpaceLoad' 作品收集, 'WrkCmp' 作品贴上 是什么操作 /// 评分相关 在SmartRating.json 处理 'SmartRating' 评分模式,分 投票Voting 和 GrandRating 星光大评分(All每人多件评分,Two随机分配互评, Self自评) /// 协作相关 在Cowork.json 处理 CoworkLoad 协作类型 coworkType All: '全体协作', Group: '分组协作', 其他的为 : '差异化协作', 问题汇总: TimeLine.json 挑人大类 Event= PickupResult 里面 分小类 PickupType=PickupRight , PickupOption , PickupNthGrp ,PickupEachGrp ,PickupDiff 五种类型分别是什么意思,是否还有其他类型的。 ,"PickupCount":1,"PickupOption":2 ,"PickupGroup":2 这三个字段是什么意思。 "PickupMemberId":"[\r\n 1\r\n]" 里面是学生的座号还是数组下标。 "Event":"PressGood","TargetClass":0,"MemberId":"[\r\n 1\r\n]","Count":1}, 是代表什么意思。 MemberId 是座号还说下标。 8月27日 17:581. Task.json的 clientWorks.isGroupItem bool 类型 false代表什么意思 true代表什么意思 2. Cowork.json 的 coworkType All: '全体协作', Group: '分组协作', : '差异化协作', 差异化协作的简码是什么? 3. TimeLine.json 的 类型 PickupResult 挑人算不算互动?? 读取PickupMemberId "[\r\n 35\r\n]" 4. 小组任务具体详细信息如何获取? 需要精确到 所有小组任务信息和 某一小组的参与情况 用于计算小组任务参与率 */ }