|
@@ -5,6 +5,8 @@ using TEAMModelOS.SDK;
|
|
|
using TEAMModelOS.SDK.DI;
|
|
|
using TEAMModelOS.SDK.Models;
|
|
|
using TEAMModelOS.SDK.Extension;
|
|
|
+using StackExchange.Redis;
|
|
|
+using System.Text.RegularExpressions;
|
|
|
|
|
|
namespace HTEX.Test.Controllers
|
|
|
{
|
|
@@ -16,48 +18,35 @@ namespace HTEX.Test.Controllers
|
|
|
private readonly AzureCosmosFactory _azureCosmos;
|
|
|
private readonly AzureStorageFactory _azureStorage;
|
|
|
|
|
|
- // 创建一个字典来存储状态编号和对应的分数
|
|
|
- private readonly Dictionary<int, double> states = new Dictionary<int, double>();
|
|
|
+
|
|
|
public LessonRecordController(ILogger<LessonRecordController> logger, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage)
|
|
|
{
|
|
|
_logger = logger;
|
|
|
_azureCosmos = azureCosmos;
|
|
|
_azureStorage = azureStorage;
|
|
|
- #region
|
|
|
- // 无二次作答的互动,且未设置正确答案
|
|
|
- states.Add(1, 0); // 未作答0
|
|
|
- states.Add(2, 1); // 已作答1
|
|
|
-
|
|
|
- // 无二次作答的互动,且设置了正确答案
|
|
|
- states.Add(3, 0); // 未作答0
|
|
|
- states.Add(4, 1); // 已作答1
|
|
|
- states.Add(5, 1.5); // 作答正确1.5
|
|
|
-
|
|
|
- // 有二次作答的互动,且未设置正确答案
|
|
|
- states.Add(6, 0); // 第一次未作答0,第二次未作答0
|
|
|
- states.Add(7, 1); // 第一次已作答1,第二次未作答0
|
|
|
- states.Add(8, 1); // 第一次未作答0,第二次已作答1
|
|
|
- states.Add(9, 2); // 第一次已作答1,第二次已作答1
|
|
|
-
|
|
|
- // 有二次作答的互动,且设置了正确答案
|
|
|
- states.Add(10, 0); // 第一次未作答0,第二次未作答0
|
|
|
- states.Add(11, 1.5); // 第一次已作答,作答正确1.5,第二次未作答0
|
|
|
- states.Add(12, 1); // 第一次已作答,作答错误1.5,第二次未作答0
|
|
|
- states.Add(13, 1.5); // 第一次未作答0,第二次已作答,作答正确1.5
|
|
|
- states.Add(14, 1); // 第一次未作答0,第二次已作答,作答错误1
|
|
|
- states.Add(15, 2); // 第一次已作答,作答错误1,第二次已作答,作答错误1
|
|
|
- states.Add(16, 2.5); // 第一次已作答,作答正确1.5,第二次已作答,作答错误1
|
|
|
- states.Add(17, 2.5); // 第一次已作答,作答错误1,第二次已作答,作答正确1.5
|
|
|
- states.Add(18, 3); // 第一次已作答,作答正确1.5,第二次已作答,作答正确1.5
|
|
|
-
|
|
|
- // 抢权模式
|
|
|
- states.Add(19, 0); // 未参与抢权0
|
|
|
- states.Add(20, 1); // 参与抢权1
|
|
|
- states.Add(21, 1.5); // 抢权成功1.5
|
|
|
- // 挑人时被挑到
|
|
|
- states.Add(22, 1.5); // 被挑到1.5
|
|
|
-
|
|
|
- #endregion
|
|
|
+ }
|
|
|
+ [HttpPost("read")]
|
|
|
+ public async Task<IActionResult> Read(JsonElement json)
|
|
|
+ {
|
|
|
+ string m = await System.IO.File.ReadAllTextAsync("C:\\Users\\CrazyIter\\Downloads\\m.json");
|
|
|
+ string p = await System.IO.File.ReadAllTextAsync("C:\\Users\\CrazyIter\\Downloads\\p.json");
|
|
|
+ List<ItemInfo> mlist=m.ToObject<List<ItemInfo>>();
|
|
|
+ List<ItemInfo> plist=p.ToObject<List<ItemInfo>>();
|
|
|
+ var km = mlist.Where(x=> x.knowledge.IsNotEmpty()).SelectMany(x => x.knowledge).Distinct();
|
|
|
+ var kp = plist.Where(x=> x.knowledge.IsNotEmpty()).SelectMany(x => x.knowledge).Distinct();
|
|
|
+ List<CodeLong> cp = new List<CodeLong>();
|
|
|
+ foreach (var item in kp)
|
|
|
+ {
|
|
|
+ var count = plist.Where(x => x.knowledge.Contains(item)).Count();
|
|
|
+ cp.Add(new CodeLong() { code = item, value = count });
|
|
|
+ }
|
|
|
+ List<CodeLong> cm = new List<CodeLong>();
|
|
|
+ foreach (var item in km)
|
|
|
+ {
|
|
|
+ var count = mlist.Where(x => x.knowledge.Contains(item)).Count();
|
|
|
+ cm.Add(new CodeLong() { code = item, value = count });
|
|
|
+ }
|
|
|
+ return Ok(new { cm,cp });
|
|
|
}
|
|
|
[HttpPost("process-history")]
|
|
|
public async Task<IActionResult> ProcessHistory(JsonElement json)
|
|
@@ -89,6 +78,7 @@ namespace HTEX.Test.Controllers
|
|
|
//base.json
|
|
|
LessonBase? lessonBase = null;
|
|
|
List<StudentLessonData> studentLessonDatas = new List<StudentLessonData>();
|
|
|
+ //名单出席率低于30%的 不纳入计算。
|
|
|
try
|
|
|
{
|
|
|
BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/base.json").DownloadContentAsync();
|
|
@@ -185,7 +175,7 @@ namespace HTEX.Test.Controllers
|
|
|
/// <param name="lessonRecord"></param>
|
|
|
/// <param name="lessonBase"></param>
|
|
|
/// <returns></returns>
|
|
|
- public (LessonBase lessonBase, List<StudentLessonData> studentLessonDatas) GetBaseData(LessonRecord lessonRecord, LessonBase lessonBase)
|
|
|
+ private (LessonBase lessonBase, List<StudentLessonData> studentLessonDatas) GetBaseData(LessonRecord lessonRecord, LessonBase lessonBase)
|
|
|
{
|
|
|
//处理学生定位数据
|
|
|
List<StudentLessonData> studentLessonDatas = new List<StudentLessonData>();
|
|
@@ -215,131 +205,39 @@ namespace HTEX.Test.Controllers
|
|
|
/// <param name="lessonBase"></param>
|
|
|
/// <param name="irsDatas"></param>
|
|
|
/// <returns></returns>
|
|
|
- public async Task<List<StudentLessonData>> GetIRSData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<IRSData> irsDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
+ private async Task<List<StudentLessonData>> GetIRSData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<IRSData> irsDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
{
|
|
|
List<string> interactTypes = new List<string>() { "PopQuesLoad", "ReAtmpAnsStrt", "BuzrAns", "BuzrLoad", "PickupResult" };
|
|
|
//去重页面
|
|
|
- var enventsInteract = timeLineData.events.Where(x => interactTypes.Contains(x.Event)).GroupBy(x => x.Pgid)
|
|
|
- .Select(x => new { key = x.Key, list = x.ToList() });
|
|
|
- foreach (var item in enventsInteract)
|
|
|
+ var enventsInteract = timeLineData.events.Where(x => interactTypes.Contains(x.Event)).GroupBy(x => x.Pgid) .Select(x => new { key = x.Key, list = x.ToList() });
|
|
|
+
|
|
|
+ if (enventsInteract!= null)
|
|
|
{
|
|
|
- var irsDataPages = irsDatas.Where(y => item.key.Equals(y.pageID));
|
|
|
- foreach (var irsDataPage in irsDataPages)
|
|
|
+ var keys = enventsInteract.Select(x => x.key).ToList();
|
|
|
+
|
|
|
+ foreach (var item in enventsInteract)
|
|
|
{
|
|
|
- //检查是否设置正确答案。
|
|
|
- var answers = irsDataPage.question?["exercise"]?["answer"]?.ToJsonString().ToObject<List<string>>();
|
|
|
- var scoreNode = irsDataPage.question?["exercise"]?["score"];
|
|
|
- double score = 0;
|
|
|
- if (scoreNode!=null)
|
|
|
+ ProcessIRSPageData(irsDatas, studentLessonDatas, item);
|
|
|
+ }
|
|
|
+ //处理其他,评测类型的互动,因为有可能不会记录在TimeLine.json中
|
|
|
+ var envents_other = timeLineData.events.Where(x => !keys.Contains(x.Pgid)).GroupBy(x => x.Pgid) .Select(x => new { key = x.Key, list = x.ToList() });
|
|
|
+ if (envents_other!=null)
|
|
|
+ {
|
|
|
+ foreach (var item in envents_other)
|
|
|
{
|
|
|
- double.TryParse(scoreNode.ToString(), out score);
|
|
|
+ ProcessIRSPageData(irsDatas, studentLessonDatas, item);
|
|
|
}
|
|
|
- string interactType = string.Empty;
|
|
|
-
|
|
|
- if (irsDataPage.clientAnswers.IsNotEmpty())
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //处理其他,评测类型的互动,因为有可能不会记录在TimeLine.json中
|
|
|
+ var envents_other = timeLineData.events.GroupBy(x => x.Pgid) .Select(x => new { key = x.Key, list = x.ToList() });
|
|
|
+ if (envents_other!=null)
|
|
|
+ {
|
|
|
+ foreach (var item in envents_other)
|
|
|
{
|
|
|
-
|
|
|
- //第一个list是几轮,一次作答,二次作答, 第二个list是学生的下标, 第三个list是 答案
|
|
|
- List<List<List<string>>> clientAnswers = new List<List<List<string>>>();
|
|
|
- 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)
|
|
|
- {
|
|
|
- //有设置答案
|
|
|
- if (answers.IsNotEmpty())
|
|
|
- {
|
|
|
- for (int index = 0; index< clientAnswers[0].Count; index++)
|
|
|
- {
|
|
|
- //index 代表学生下标
|
|
|
- List<InteractRecord> interactRecords = new List<InteractRecord>();
|
|
|
- if (clientAnswers.Count==1)
|
|
|
- {
|
|
|
- //即问即答
|
|
|
- interactType = "PopQuesLoad";
|
|
|
- var ans0 = clientAnswers[0][index];
|
|
|
- var IS0 = GetInteractResultHasAnswer(answers, ans0);
|
|
|
- interactRecords.Add(new InteractRecord()
|
|
|
- {
|
|
|
- status = IS0,
|
|
|
- interactType= interactType
|
|
|
- });
|
|
|
- }
|
|
|
- if (clientAnswers.Count==2)
|
|
|
- {
|
|
|
- //二次作答
|
|
|
- interactType="ReAtmpAnsStrt";
|
|
|
- var ans1 = clientAnswers[1][index];
|
|
|
- var IS1 = GetInteractResultHasAnswer(answers, ans1);
|
|
|
- interactRecords.Add(new InteractRecord()
|
|
|
- {
|
|
|
- status = IS1,
|
|
|
- interactType= interactType
|
|
|
- });
|
|
|
- }
|
|
|
- if (clientAnswers.Count>2)
|
|
|
- {
|
|
|
- //三次作答
|
|
|
- interactType="TeAtmpAnsStrt";
|
|
|
- var ans2 = clientAnswers[2][index];
|
|
|
- var IS2 = GetInteractResultHasAnswer(answers, ans2);
|
|
|
- interactRecords.Add(new InteractRecord()
|
|
|
- {
|
|
|
- status = IS2,
|
|
|
- interactType= interactType
|
|
|
- });
|
|
|
- }
|
|
|
- studentLessonDatas[index].interactRecords.AddRange(interactRecords);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- //是否抢权作答的模式
|
|
|
- if (irsDataPage.isBuzz)
|
|
|
- {
|
|
|
- interactType = "BuzrAns";
|
|
|
- //处理参与抢权的
|
|
|
- Dictionary<string, InteractRecord> buzzParticipants = new Dictionary<string, InteractRecord>();
|
|
|
- foreach (var buzzParticipant in irsDataPage.buzzParticipants)
|
|
|
- {
|
|
|
- var studentData = studentLessonDatas.Find(x => x.seatID!.Equals(buzzParticipant));
|
|
|
- if (studentData != null)
|
|
|
- {
|
|
|
- buzzParticipants[buzzParticipant]=new InteractRecord() { status = InteractStatus.T1, interactType= interactType };
|
|
|
- }
|
|
|
- }
|
|
|
- //处理抢权成功的
|
|
|
- foreach (var buzzClient in irsDataPage.buzzClients)
|
|
|
- {
|
|
|
- buzzParticipants[buzzClient]=new InteractRecord() { status = InteractStatus.TT, interactType= interactType };
|
|
|
- }
|
|
|
- foreach (var studentLessonData in studentLessonDatas)
|
|
|
- {
|
|
|
- if (buzzParticipants.ContainsKey(studentLessonData.seatID!))
|
|
|
- {
|
|
|
- //处理已经有抢权结果的数据
|
|
|
- studentLessonData.interactRecords.Add(buzzParticipants[studentLessonData.seatID!]);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- //处理未参与抢权的
|
|
|
- studentLessonData.interactRecords.Add(new InteractRecord() { status = InteractStatus.T0, interactType = interactType });
|
|
|
- }
|
|
|
- }
|
|
|
+ ProcessIRSPageData(irsDatas, studentLessonDatas, item);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -359,7 +257,12 @@ namespace HTEX.Test.Controllers
|
|
|
var studentLessonData = studentLessonDatas.Find(x => x.seatID!.Equals($"{mbr}"));
|
|
|
if (studentLessonData!=null)
|
|
|
{
|
|
|
- studentLessonData.interactRecords.Add(new InteractRecord() { status = InteractStatus.TT, interactType = string.IsNullOrWhiteSpace(item.PickupType) ? "PickupResult" : item.PickupType });
|
|
|
+ studentLessonData.interactRecords.Add(new InteractRecord()
|
|
|
+ {
|
|
|
+ resultWeight = InteractWeight.TT,
|
|
|
+ resultType="TT",
|
|
|
+ interactType = string.IsNullOrWhiteSpace(item.PickupType) ? "PickupResult" : item.PickupType
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -367,54 +270,372 @@ namespace HTEX.Test.Controllers
|
|
|
return studentLessonDatas;
|
|
|
}
|
|
|
|
|
|
- private static InteractStatus GetInteractResultHasAnswer(List<string>? answers, List<string> ans0)
|
|
|
+ private static void ProcessIRSPageData(List<IRSData> irsDatas, List<StudentLessonData> studentLessonDatas, dynamic item)
|
|
|
{
|
|
|
- InteractStatus status = InteractStatus.T0;
|
|
|
- if (ans0.IsNotEmpty())
|
|
|
+ var irsDataPages = irsDatas.Where(y => item.key.Equals(y.pageID));
|
|
|
+ foreach (var irsDataPage in irsDataPages)
|
|
|
{
|
|
|
- //标准答案等于作答的结果
|
|
|
- if (answers!.Count == ans0.Count)
|
|
|
+ //检查是否设置正确答案。
|
|
|
+ var answers_q = irsDataPage.question?["exercise"]?["answer"]?.ToJsonString().ToObject<List<string>>();
|
|
|
+ List<string> answers = new List<string>();
|
|
|
+ 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 score = 0;
|
|
|
+ bool objective = false;
|
|
|
+
|
|
|
+ if (_objective!=null) {
|
|
|
+ objective = _objective.GetValue<bool>();
|
|
|
+ }
|
|
|
+ //题型
|
|
|
+ string type= string.Empty;
|
|
|
+ if (_type!=null)
|
|
|
{
|
|
|
- if (answers.All(item => ans0.Contains(item)))
|
|
|
+ //题型
|
|
|
+ type = _type.GetValue<string>();
|
|
|
+ List<string> types = new List<string>() { "single", "multiple" , "judge" , "sortmultiple" };
|
|
|
+ if (types.Contains(type))
|
|
|
{
|
|
|
- //完全正确
|
|
|
- status= InteractStatus.TT;
|
|
|
+ objective = true;
|
|
|
}
|
|
|
- else
|
|
|
+ else {
|
|
|
+ objective = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_answerType!=null)
|
|
|
+ {
|
|
|
+ _answerType.GetValue<string>();
|
|
|
+
|
|
|
+ //暂不处理,可能存在依然传文字的情况
|
|
|
+ //不是文本作答的处理,题目不是客观题,答案不记录
|
|
|
+ //if (!_answerType.Equals("text"))
|
|
|
+ //{
|
|
|
+ // objective=false;
|
|
|
+ // answers=new List<string>();
|
|
|
+ //}
|
|
|
+ }
|
|
|
+ if (scoreNode!=null)
|
|
|
+ {
|
|
|
+ double.TryParse(scoreNode.ToString(), out score);
|
|
|
+ }
|
|
|
+ string interactType = string.Empty;
|
|
|
+
|
|
|
+ if (irsDataPage.clientAnswers.IsNotEmpty())
|
|
|
+ {
|
|
|
+
|
|
|
+ //第一个list是几轮,一次作答,二次作答, 第二个list是学生的下标, 第三个list是 答案
|
|
|
+ List<List<List<string>>> clientAnswers = new List<List<List<string>>>();
|
|
|
+ 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++)
|
|
|
+ {
|
|
|
+ //index 代表学生下标
|
|
|
+ List<InteractRecord> interactRecords = new List<InteractRecord>();
|
|
|
+ if (clientAnswers.Count==1)
|
|
|
+ {
|
|
|
+ //即问即答
|
|
|
+ interactType = "PopQuesLoad";
|
|
|
+ var ans0 = clientAnswers[0][index];
|
|
|
+ var IS0 = GetInteractResultHasAnswer(answers, ans0, objective,type);
|
|
|
+ interactRecords.Add(new InteractRecord()
|
|
|
+ {
|
|
|
+ resultWeight = IS0.weight,
|
|
|
+ resultType=IS0.reultType,
|
|
|
+ interactType= interactType
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (clientAnswers.Count==2)
|
|
|
+ {
|
|
|
+ //二次作答
|
|
|
+ interactType="ReAtmpAnsStrt";
|
|
|
+ var ans1 = clientAnswers[1][index];
|
|
|
+ var IS1 = GetInteractResultHasAnswer(answers, ans1, objective,type);
|
|
|
+ interactRecords.Add(new InteractRecord()
|
|
|
+ {
|
|
|
+ resultWeight = IS1.weight,
|
|
|
+ resultType=IS1.reultType,
|
|
|
+ interactType= interactType
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (clientAnswers.Count>2)
|
|
|
+ {
|
|
|
+ //三次作答
|
|
|
+ interactType="TeAtmpAnsStrt";
|
|
|
+ var ans2 = clientAnswers[2][index];
|
|
|
+ var IS2 = GetInteractResultHasAnswer(answers, ans2, objective,type);
|
|
|
+ interactRecords.Add(new InteractRecord()
|
|
|
+ {
|
|
|
+ resultWeight = IS2.weight,
|
|
|
+ resultType=IS2.reultType,
|
|
|
+ interactType= interactType
|
|
|
+ });
|
|
|
+ }
|
|
|
+ studentLessonDatas[index].interactRecords.AddRange(interactRecords);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //是否抢权作答的模式
|
|
|
+ if (irsDataPage.isBuzz)
|
|
|
+ {
|
|
|
+ interactType = "BuzrAns";
|
|
|
+ //处理参与抢权的
|
|
|
+ Dictionary<string, InteractRecord> buzzParticipants = new Dictionary<string, InteractRecord>();
|
|
|
+ foreach (var buzzParticipant in irsDataPage.buzzParticipants)
|
|
|
+ {
|
|
|
+ var studentData = studentLessonDatas.Find(x => x.seatID!.Equals(buzzParticipant));
|
|
|
+ if (studentData != null)
|
|
|
+ {
|
|
|
+ buzzParticipants[buzzParticipant]=new InteractRecord() { resultWeight = InteractWeight.T1, interactType= interactType };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //处理抢权成功的
|
|
|
+ foreach (var buzzClient in irsDataPage.buzzClients)
|
|
|
+ {
|
|
|
+ buzzParticipants[buzzClient]=new InteractRecord() { resultWeight = InteractWeight.TT, interactType= interactType };
|
|
|
+ }
|
|
|
+ foreach (var studentLessonData in studentLessonDatas)
|
|
|
{
|
|
|
- //作答错误
|
|
|
- status= InteractStatus.T1;
|
|
|
+ if (buzzParticipants.ContainsKey(studentLessonData.seatID!))
|
|
|
+ {
|
|
|
+ //处理已经有抢权结果的数据
|
|
|
+ studentLessonData.interactRecords.Add(buzzParticipants[studentLessonData.seatID!]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //处理未参与抢权的
|
|
|
+ studentLessonData.interactRecords.Add(new InteractRecord() { resultWeight = InteractWeight.T0, interactType = interactType });
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- //标准答案比作答的结果多
|
|
|
- else if (answers!.Count > ans0.Count)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static (double weight,string reultType) GetInteractResultHasAnswer(List<string>? answers, List<string> ans0 , bool objective,string type)
|
|
|
+ {
|
|
|
+ //List<string> ans0 = new List<string>();
|
|
|
+ //ans?.ForEach(x => {
|
|
|
+ // if (!string.IsNullOrWhiteSpace(x))
|
|
|
+ // {
|
|
|
+ // ans0.Add(x);
|
|
|
+ // }
|
|
|
+ // else { ans.Add("");}
|
|
|
+ //});
|
|
|
+ double weight = InteractWeight.T0;
|
|
|
+ string reultType = InteractReultType.T0;
|
|
|
+ if (answers.IsNotEmpty())
|
|
|
+ {
|
|
|
+ if (ans0.IsNotEmpty())
|
|
|
{
|
|
|
- if (ans0.All(item => answers.Contains(item)))
|
|
|
+ if (objective) //客观题
|
|
|
{
|
|
|
- //部分正确
|
|
|
- status= InteractStatus.TP;
|
|
|
+ //标准答案等于作答的结果
|
|
|
+ if (answers!.Count == ans0.Count)
|
|
|
+ {
|
|
|
+ if (answers.All(item => ans0.Contains(item)))
|
|
|
+ {
|
|
|
+ //完全正确
|
|
|
+ weight= InteractWeight.TT;
|
|
|
+ reultType= InteractReultType.TT;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //作答错误
|
|
|
+ weight= InteractWeight.T1;
|
|
|
+ reultType = InteractReultType.T1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //标准答案比作答的结果多
|
|
|
+ else if (answers!.Count > ans0.Count)
|
|
|
+ {
|
|
|
+ if (ans0.All(item => answers.Contains(item)))
|
|
|
+ {
|
|
|
+ //部分正确
|
|
|
+ weight= InteractWeight.TP;
|
|
|
+ reultType = InteractReultType.TP;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //作答错误
|
|
|
+ weight= InteractWeight.T1;
|
|
|
+ reultType = InteractReultType.T1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //标准答案比作答结果少
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //作答错误
|
|
|
+ weight= InteractWeight.T1;
|
|
|
+ reultType = InteractReultType.T1;
|
|
|
+ }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- //作答错误
|
|
|
- status= InteractStatus.T1;
|
|
|
+ //填空题
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ else if (hasT && hasF)
|
|
|
+ {
|
|
|
+ //部分正确
|
|
|
+ weight= InteractWeight.TP;
|
|
|
+ reultType = InteractReultType.TP;
|
|
|
+ }
|
|
|
+ else if (!hasT && hasF)
|
|
|
+ {
|
|
|
+ //没有正确的,但有错误的,代表参与了
|
|
|
+ weight= InteractWeight.T1;
|
|
|
+ reultType = InteractReultType.T1;
|
|
|
+ }
|
|
|
+ else if (!hasT && !hasF)
|
|
|
+ {
|
|
|
+ //没有正确的,也没有错误的,代表没有作答
|
|
|
+ weight= InteractWeight.T0;
|
|
|
+ reultType = InteractReultType.T0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //主观题,完全匹配的
|
|
|
+ if (answers!.All(item => ans0.Contains(item)))
|
|
|
+ {
|
|
|
+ //完全正确
|
|
|
+ weight= InteractWeight.TT;
|
|
|
+ reultType = InteractReultType.TT;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ { // 使用LINQ查询来判断是否有匹配的答案
|
|
|
+ bool hasMatchingAnswer = answers!.Intersect(ans0).Any();
|
|
|
+ if (hasMatchingAnswer)
|
|
|
+ {
|
|
|
+ //主观题回答正确即为完全正确
|
|
|
+ weight= InteractWeight.TT;
|
|
|
+ reultType = InteractReultType.TT;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //没有匹配上答案,则采用Levenshtein距离来评估两个字符串的相似度
|
|
|
+ var sc = CalculateSimilarity(answers![0], ans0[0]) * 1.0/100 *(InteractWeight.TT-InteractWeight.T1);
|
|
|
+ weight = sc;
|
|
|
+ reultType = InteractReultType.TP;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //没有作答
|
|
|
+ weight= InteractWeight.T0;
|
|
|
+ reultType = InteractReultType.T0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //没有答案的情况
|
|
|
+ if (ans0.IsNotEmpty())
|
|
|
+ {
|
|
|
+ bool hasAns = false;
|
|
|
+ ans0.ForEach(x => {
|
|
|
+ if (!string.IsNullOrWhiteSpace(x)) {
|
|
|
+ hasAns = true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (hasAns)
|
|
|
+ {
|
|
|
+ //作答了
|
|
|
+ weight= InteractWeight.T1;
|
|
|
+ reultType = InteractReultType.T1;
|
|
|
}
|
|
|
+ else {
|
|
|
+ //没有作答
|
|
|
+ weight= InteractWeight.T0;
|
|
|
+ reultType = InteractReultType.T0;
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
- //标准答案比作答结果少
|
|
|
else
|
|
|
{
|
|
|
- //作答错误
|
|
|
- status= InteractStatus.T1;
|
|
|
+ //没有作答
|
|
|
+ weight= InteractWeight.T0;
|
|
|
+ reultType = InteractReultType.T0;
|
|
|
}
|
|
|
}
|
|
|
- else
|
|
|
+ return (weight,reultType);
|
|
|
+ }
|
|
|
+ #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++)
|
|
|
{
|
|
|
- //没有作答
|
|
|
- status= InteractStatus.T0;
|
|
|
+ d[0, j] = j;
|
|
|
}
|
|
|
- return status;
|
|
|
+
|
|
|
+ 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))) * 100;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ #endregion
|
|
|
/// <summary>
|
|
|
/// 获取课中评测数据
|
|
|
/// </summary>
|
|
@@ -424,20 +645,79 @@ namespace HTEX.Test.Controllers
|
|
|
/// <param name="coworkDatas"></param>
|
|
|
/// <param name="studentLessonDatas"></param>
|
|
|
/// <returns></returns>
|
|
|
- public async Task<dynamic> GetExamData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<ExamData> examDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
+ private async Task<dynamic> GetExamData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<ExamData> examDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
{
|
|
|
+ foreach (var examData in examDatas)
|
|
|
+ {
|
|
|
+ var allocation= examData?.exam?.papers?.SelectMany(x => x.point).Sum();
|
|
|
+ var answersStd = examData?.exam?.papers?.FirstOrDefault()?.answers;
|
|
|
+ List<List<string>> answers= new List<List<string>>();
|
|
|
+ if (answersStd!=null)
|
|
|
+ {
|
|
|
+ answersStd.ForEach(x =>
|
|
|
+ {
|
|
|
+ List<string> ans = new List<string>();
|
|
|
+ x.ForEach(y =>
|
|
|
+ {
|
|
|
+ if (string.IsNullOrWhiteSpace(y))
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ answers.Add(ans);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ examData?.examClassResult?.ForEach(item =>{
|
|
|
+ int index = 0;
|
|
|
+ item.studentAnswersArray.ForEach(x => {
|
|
|
+ //是否要判断主观题或者客观题, 多套试卷,有主观题的
|
|
|
+ //主观题有回答的:608942756458532864\Clients\18782481024\Ans\27-4341670635487887360-examExchangeAnswerlist 27 从1开始的学生序号-4341670635487887360评测编号,内容qNo 是从1开始的题号。
|
|
|
+ if (x.IsNotEmpty())
|
|
|
+ {
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
return null;
|
|
|
}
|
|
|
-
|
|
|
- public async Task<dynamic> GetCoworkData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<CoworkData> coworkDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
+ /// <summary>
|
|
|
+ /// 协作参与率 态度计算
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="lessonRecord"></param>
|
|
|
+ /// <param name="lessonBase"></param>
|
|
|
+ /// <param name="timeLineData"></param>
|
|
|
+ /// <param name="coworkDatas"></param>
|
|
|
+ /// <param name="studentLessonDatas"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private async Task<dynamic> GetCoworkData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<CoworkData> coworkDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
{
|
|
|
return Ok(lessonRecord);
|
|
|
}
|
|
|
- public async Task<dynamic> GetTaskData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<TaskData> taskDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 处理学生回推数据,并将回推纳入学习态度计算。
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="lessonRecord"></param>
|
|
|
+ /// <param name="lessonBase"></param>
|
|
|
+ /// <param name="timeLineData"></param>
|
|
|
+ /// <param name="taskDatas"></param>
|
|
|
+ /// <param name="studentLessonDatas"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private async Task<dynamic> GetTaskData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<TaskData> taskDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
{
|
|
|
return Ok(lessonRecord);
|
|
|
}
|
|
|
- public async Task<dynamic> GetSmartRatingData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<SmartRatingData> smartRatingDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 评分参与率 态度计算
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="lessonRecord"></param>
|
|
|
+ /// <param name="lessonBase"></param>
|
|
|
+ /// <param name="timeLineData"></param>
|
|
|
+ /// <param name="smartRatingDatas"></param>
|
|
|
+ /// <param name="studentLessonDatas"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private async Task<dynamic> GetSmartRatingData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<SmartRatingData> smartRatingDatas, List<StudentLessonData> studentLessonDatas)
|
|
|
{
|
|
|
return Ok(lessonRecord);
|
|
|
}
|
|
@@ -492,46 +772,109 @@ namespace HTEX.Test.Controllers
|
|
|
/// 互动积分记录[-1,0,10]
|
|
|
/// </summary>
|
|
|
public List<InteractRecord> interactRecords { get; set; } = new List<InteractRecord>();
|
|
|
+ /// <summary>
|
|
|
+ /// 学生评测记录相关
|
|
|
+ /// </summary>
|
|
|
+ public List<StudentExamRecord> examRecords { get; set; } = new List<StudentExamRecord>();
|
|
|
}
|
|
|
+ /// <summary>
|
|
|
+ /// 学生课中评测记录
|
|
|
+ /// </summary>
|
|
|
public class StudentExamRecord
|
|
|
{
|
|
|
-
|
|
|
+ /// <summary>
|
|
|
+ /// 作答率0 未作答,1,所有题目作答,小数点则表示部分作答。 可纳入学习态度计算, 主观题需要确认 是否会在此写入答案。
|
|
|
+ /// </summary>
|
|
|
+ public int answerRate{ get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 评测得分
|
|
|
+ /// </summary>
|
|
|
+ public double score { get; set;}
|
|
|
+ /// <summary>
|
|
|
+ /// 评测id
|
|
|
+ /// </summary>
|
|
|
+ public string? examId { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 得分率
|
|
|
+ /// </summary>
|
|
|
+ public double scoreRate { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 配分
|
|
|
+ /// </summary>
|
|
|
+ // public double allocation { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 暂不计算
|
|
|
+ /// 每个题的得分情况
|
|
|
+ /// </summary>
|
|
|
+ // public List<double> itemScores { get; set; } = new List<double>();
|
|
|
}
|
|
|
|
|
|
public class InteractRecord
|
|
|
{
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// { "PopQuesLoad", "ReAtmpAnsStrt", "BuzrAns", "BuzrLoad", "PickupResult" };
|
|
|
+ /// </summary>
|
|
|
+ public string? interactType { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 互动结果权重,纳入学习状态计算
|
|
|
+ /// </summary>
|
|
|
+ public double resultWeight { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 互动结果类型,如:T0没有作答, 没有参与,T1作答错误,有参加,有抢权,TP部分正确,TT作答正确,抢权成功,被抽到
|
|
|
+ /// </summary>
|
|
|
+ public string? resultType { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 互动结果分值
|
|
|
+ /// </summary>
|
|
|
+ //public double resultScore { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 互动积分,试题评分
|
|
|
+ /// </summary>
|
|
|
+ public double interactScore { get; set; }
|
|
|
/// <summary>
|
|
|
/// 基准分值
|
|
|
/// </summary>
|
|
|
public double criterion { get; set; }
|
|
|
+ }
|
|
|
+ public static class InteractReultType
|
|
|
+ {
|
|
|
/// <summary>
|
|
|
- /// { "PopQuesLoad", "ReAtmpAnsStrt", "BuzrAns", "BuzrLoad", "PickupResult" };
|
|
|
+ /// 没有作答, 没有参与0
|
|
|
/// </summary>
|
|
|
- public string? interactType { get; set; }
|
|
|
-
|
|
|
+ public static readonly string T0 = "T0";
|
|
|
/// <summary>
|
|
|
- /// 互动结果状态
|
|
|
+ /// 作答错误,有参加,有抢权1
|
|
|
+ /// </summary>
|
|
|
+ public static readonly string T1 = "T1";
|
|
|
+ /// <summary>
|
|
|
+ /// 部分正确1.3
|
|
|
/// </summary>
|
|
|
- public InteractStatus status { get; set; }
|
|
|
+ public static readonly string TP = "TP";
|
|
|
+ /// <summary>
|
|
|
+ /// 作答正确,抢权成功,被抽到1.5
|
|
|
+ /// </summary>
|
|
|
+ public static readonly string TT ="TT";
|
|
|
+
|
|
|
}
|
|
|
- public enum InteractStatus
|
|
|
+ public static class InteractWeight
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 没有作答, 没有参与0
|
|
|
/// </summary>
|
|
|
- T0,
|
|
|
+ public static readonly double T0 = 0;
|
|
|
/// <summary>
|
|
|
/// 作答错误,有参加,有抢权1
|
|
|
/// </summary>
|
|
|
- T1,
|
|
|
+ public static readonly double T1 = 1;
|
|
|
/// <summary>
|
|
|
/// 部分正确1.3
|
|
|
/// </summary>
|
|
|
- TP,
|
|
|
+ public static readonly double TP =1.3;
|
|
|
/// <summary>
|
|
|
- /// 作答正确,抢权成功,被抽到
|
|
|
+ /// 作答正确,抢权成功,被抽到1.5
|
|
|
/// </summary>
|
|
|
- TT
|
|
|
+ public static readonly double TT = 1.5;
|
|
|
|
|
|
/// 互动参与指数(按倍数的权重设计)
|
|
|
/// 无二次作答的互动,且未设置正确答案:1.未作答0
|