LessonRecordController.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  1. using Azure.Storage.Blobs.Models;
  2. using Microsoft.AspNetCore.Mvc;
  3. using System.Text.Json;
  4. using TEAMModelOS.SDK;
  5. using TEAMModelOS.SDK.DI;
  6. using TEAMModelOS.SDK.Models;
  7. using TEAMModelOS.SDK.Extension;
  8. namespace HTEX.Test.Controllers
  9. {
  10. [ApiController]
  11. [Route("lesson-record")]
  12. public class LessonRecordController : ControllerBase
  13. {
  14. private readonly ILogger<LessonRecordController> _logger;
  15. private readonly AzureCosmosFactory _azureCosmos;
  16. private readonly AzureStorageFactory _azureStorage;
  17. // 创建一个字典来存储状态编号和对应的分数
  18. private readonly Dictionary<int, double> states = new Dictionary<int, double>();
  19. public LessonRecordController(ILogger<LessonRecordController> logger, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage)
  20. {
  21. _logger = logger;
  22. _azureCosmos = azureCosmos;
  23. _azureStorage = azureStorage;
  24. #region
  25. // 无二次作答的互动,且未设置正确答案
  26. states.Add(1, 0); // 未作答0
  27. states.Add(2, 1); // 已作答1
  28. // 无二次作答的互动,且设置了正确答案
  29. states.Add(3, 0); // 未作答0
  30. states.Add(4, 1); // 已作答1
  31. states.Add(5, 1.5); // 作答正确1.5
  32. // 有二次作答的互动,且未设置正确答案
  33. states.Add(6, 0); // 第一次未作答0,第二次未作答0
  34. states.Add(7, 1); // 第一次已作答1,第二次未作答0
  35. states.Add(8, 1); // 第一次未作答0,第二次已作答1
  36. states.Add(9, 2); // 第一次已作答1,第二次已作答1
  37. // 有二次作答的互动,且设置了正确答案
  38. states.Add(10, 0); // 第一次未作答0,第二次未作答0
  39. states.Add(11, 1.5); // 第一次已作答,作答正确1.5,第二次未作答0
  40. states.Add(12, 1); // 第一次已作答,作答错误1.5,第二次未作答0
  41. states.Add(13, 1.5); // 第一次未作答0,第二次已作答,作答正确1.5
  42. states.Add(14, 1); // 第一次未作答0,第二次已作答,作答错误1
  43. states.Add(15, 2); // 第一次已作答,作答错误1,第二次已作答,作答错误1
  44. states.Add(16, 2.5); // 第一次已作答,作答正确1.5,第二次已作答,作答错误1
  45. states.Add(17, 2.5); // 第一次已作答,作答错误1,第二次已作答,作答正确1.5
  46. states.Add(18, 3); // 第一次已作答,作答正确1.5,第二次已作答,作答正确1.5
  47. // 抢权模式
  48. states.Add(19, 0); // 未参与抢权0
  49. states.Add(20, 1); // 参与抢权1
  50. states.Add(21, 1.5); // 抢权成功1.5
  51. // 挑人时被挑到
  52. states.Add(22, 1.5); // 被挑到1.5
  53. #endregion
  54. }
  55. [HttpPost("read")]
  56. public async Task<IActionResult> Read(JsonElement json)
  57. {
  58. string m = await System.IO.File.ReadAllTextAsync("C:\\Users\\CrazyIter\\Downloads\\m.json");
  59. string p = await System.IO.File.ReadAllTextAsync("C:\\Users\\CrazyIter\\Downloads\\p.json");
  60. List<ItemInfo> mlist=m.ToObject<List<ItemInfo>>();
  61. List<ItemInfo> plist=p.ToObject<List<ItemInfo>>();
  62. var km = mlist.Where(x=> x.knowledge.IsNotEmpty()).SelectMany(x => x.knowledge).Distinct();
  63. var kp = plist.Where(x=> x.knowledge.IsNotEmpty()).SelectMany(x => x.knowledge).Distinct();
  64. List<CodeLong> cp = new List<CodeLong>();
  65. foreach (var item in kp)
  66. {
  67. var count = plist.Where(x => x.knowledge.Contains(item)).Count();
  68. cp.Add(new CodeLong() { code = item, value = count });
  69. }
  70. List<CodeLong> cm = new List<CodeLong>();
  71. foreach (var item in km)
  72. {
  73. var count = mlist.Where(x => x.knowledge.Contains(item)).Count();
  74. cm.Add(new CodeLong() { code = item, value = count });
  75. }
  76. return Ok(new { cm,cp });
  77. }
  78. [HttpPost("process-history")]
  79. public async Task<IActionResult> ProcessHistory(JsonElement json)
  80. {
  81. //1709222400000 2024.3.1
  82. var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
  83. .GetList<LessonRecord>($"SELECT value c FROM School AS c where c.startTime>1709222400000 and c.expire<=0 and c.status<>404",
  84. $"LessonRecord-{json.GetProperty("schoolId")}", pageSize: 20);
  85. if (result.list.IsNotEmpty())
  86. {
  87. foreach (var item in result.list)
  88. {
  89. //读取TimeLine.json
  90. TimeLineData? timeLineData = null;
  91. try
  92. {
  93. BlobDownloadResult timeLineBlobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/TimeLine.json").DownloadContentAsync();
  94. timeLineData = timeLineBlobDownload.Content.ToObjectFromJson<TimeLineData>();
  95. }
  96. catch (Exception ex)
  97. {
  98. if (!ex.Message.Contains("The specified blob does not exist"))
  99. {
  100. _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/TimeLine.json");
  101. }
  102. }
  103. //读取基础Base信息
  104. //base.json
  105. LessonBase? lessonBase = null;
  106. List<StudentLessonData> studentLessonDatas = new List<StudentLessonData>();
  107. try
  108. {
  109. BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/base.json").DownloadContentAsync();
  110. string basejson = baseblobDownload.Content.ToString().Replace("\"Uncall\"", "0").Replace("Uncall", "0");
  111. lessonBase = basejson.ToObject<LessonBase>();
  112. var data = GetBaseData(item, lessonBase);
  113. studentLessonDatas=data.studentLessonDatas;
  114. }
  115. catch (Exception ex)
  116. {
  117. if (!ex.Message.Contains("The specified blob does not exist"))
  118. {
  119. _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/base.json");
  120. }
  121. }
  122. //读取Task.json
  123. ///Event 过滤类型 : 'WrkSpaceLoad'作品收集, 'WrkCmp' 作品贴上 文件:Task.json 根据clientWorks 中的seatID 匹配base.json 中的 student
  124. List<TaskData> taskDatas = new List<TaskData>();
  125. try
  126. {
  127. BlobDownloadResult taskBlobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/Task.json").DownloadContentAsync();
  128. taskDatas = taskBlobDownload.Content.ToObjectFromJson<List<TaskData>>();
  129. }
  130. catch (Exception ex)
  131. {
  132. if (!ex.Message.Contains("The specified blob does not exist"))
  133. {
  134. _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/Task.json");
  135. }
  136. }
  137. //读取互评信息
  138. //Event 过滤类型 'RatingStart'
  139. //smartRateSummary.mutualSummary.mutualType 互评【All(每人多件评分) Two(随机分配互评) Self(自评)】 smartRateSummary.meteor_VoteSummary 投票
  140. //读取SmartRating.json
  141. List<SmartRatingData> smartRatingDatas = new List<SmartRatingData>();
  142. try
  143. {
  144. BlobDownloadResult smartRatingBlobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/SmartRating.json").DownloadContentAsync();
  145. smartRatingDatas = smartRatingBlobDownload.Content.ToObjectFromJson<List<SmartRatingData>>();
  146. }
  147. catch (Exception ex)
  148. {
  149. if (!ex.Message.Contains("The specified blob does not exist"))
  150. {
  151. _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/SmartRating.json");
  152. }
  153. }
  154. //读取互动信息
  155. //Event 过滤类型 'PopQuesLoad', 'ReAtmpAnsStrt', 'BuzrAns','BuzrLoad'
  156. //TimeLine.json 中找到对应类型,根据Pgid 去 IRS.json 中找到对应数据,从clientAnswers 的下标对应 base.json 中的 student 找到对应学生信息 clientAnswers.length > 1 则表示有二次作答
  157. //读取IRS.json
  158. List<IRSData> irsDatas = new List<IRSData>();
  159. try
  160. {
  161. BlobDownloadResult irsBlobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/IRS.json").DownloadContentAsync();
  162. irsDatas = irsBlobDownload.Content.ToObjectFromJson<List<IRSData>>();
  163. }
  164. catch (Exception ex)
  165. {
  166. if (!ex.Message.Contains("The specified blob does not exist"))
  167. {
  168. _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/IRS.json");
  169. }
  170. }
  171. //读取协作信息
  172. ///Event 过滤类型 'CoworkLoad'
  173. //Cowork.json 中找到对应类型,根据Pgid 去 Cowork.json 中找到对应数据
  174. List<CoworkData> coworkDatas = new List<CoworkData>();
  175. try
  176. {
  177. BlobDownloadResult irsBlobDownload = await _azureStorage.GetBlobContainerClient(item.school).GetBlobClient($"/records/{item.id}/IES/Cowork.json").DownloadContentAsync();
  178. coworkDatas = irsBlobDownload.Content.ToObjectFromJson<List<CoworkData>>();
  179. }
  180. catch (Exception ex)
  181. {
  182. if (!ex.Message.Contains("The specified blob does not exist"))
  183. {
  184. _logger.LogError(ex, $"文件不存在:/records/{item.id}/IES/Cowork.json");
  185. }
  186. }
  187. }
  188. }
  189. return Ok("Lesson records");
  190. }
  191. /// <summary>
  192. /// 处理base.json的数据
  193. /// </summary>
  194. /// <param name="lessonRecord"></param>
  195. /// <param name="lessonBase"></param>
  196. /// <returns></returns>
  197. private (LessonBase lessonBase, List<StudentLessonData> studentLessonDatas) GetBaseData(LessonRecord lessonRecord, LessonBase lessonBase)
  198. {
  199. //处理学生定位数据
  200. List<StudentLessonData> studentLessonDatas = new List<StudentLessonData>();
  201. int index = 0;
  202. lessonBase.student.ForEach(x =>
  203. {
  204. studentLessonDatas.Add(new StudentLessonData()
  205. {
  206. id = x.id,
  207. index = index,
  208. seatID =$"{x.seatID}",
  209. groupId = x.groupId,
  210. });
  211. index++;
  212. });
  213. return (lessonBase, studentLessonDatas);
  214. }
  215. /// <summary>
  216. ///读取互动信息
  217. ///Event 过滤类型 'PopQuesLoad', 'ReAtmpAnsStrt', 'BuzrAns','BuzrLoad'
  218. /// 在IRS.json处理 'PopQuesLoad'互动问答 , 'ReAtmpAnsStrt' 二次作答 , 'BuzrAns' 抢权(新), 'BuzrLoad'抢权(旧), PickupResult 挑人算不算互动?? 读取PickupMemberId "[\r\n 35\r\n]"
  219. ///TimeLine.json 中找到对应类型,根据Pgid 去 IRS.json 中找到对应数据,从clientAnswers 的下标对应 base.json 中的 student 找到对应学生信息 clientAnswers.length > 1 则表示有二次作答
  220. ///读取IRS.json
  221. /// </summary>
  222. /// <param name="lessonRecord"></param>
  223. /// <param name="lessonBase"></param>
  224. /// <param name="irsDatas"></param>
  225. /// <returns></returns>
  226. private async Task<List<StudentLessonData>> GetIRSData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<IRSData> irsDatas, List<StudentLessonData> studentLessonDatas)
  227. {
  228. List<string> interactTypes = new List<string>() { "PopQuesLoad", "ReAtmpAnsStrt", "BuzrAns", "BuzrLoad", "PickupResult" };
  229. //去重页面
  230. var enventsInteract = timeLineData.events.Where(x => interactTypes.Contains(x.Event)).GroupBy(x => x.Pgid) .Select(x => new { key = x.Key, list = x.ToList() });
  231. if (enventsInteract!= null)
  232. {
  233. var keys = enventsInteract.Select(x => x.key).ToList();
  234. foreach (var item in enventsInteract)
  235. {
  236. ProcessIRSPageData(irsDatas, studentLessonDatas, item);
  237. }
  238. //处理其他,评测类型的互动,因为有可能不会记录在TimeLine.json中
  239. var envents_other = timeLineData.events.Where(x => !keys.Contains(x.Pgid)).GroupBy(x => x.Pgid) .Select(x => new { key = x.Key, list = x.ToList() });
  240. if (envents_other!=null)
  241. {
  242. foreach (var item in envents_other)
  243. {
  244. ProcessIRSPageData(irsDatas, studentLessonDatas, item);
  245. }
  246. }
  247. }
  248. else
  249. {
  250. //处理其他,评测类型的互动,因为有可能不会记录在TimeLine.json中
  251. var envents_other = timeLineData.events.GroupBy(x => x.Pgid) .Select(x => new { key = x.Key, list = x.ToList() });
  252. if (envents_other!=null)
  253. {
  254. foreach (var item in envents_other)
  255. {
  256. ProcessIRSPageData(irsDatas, studentLessonDatas, item);
  257. }
  258. }
  259. }
  260. //单独处理挑人的逻辑
  261. //是否从小组里面挑人。
  262. //不需要去重页面,直接获取挑人大类 PickupResult
  263. //小类处理:PickupRight , PickupOption , PickupNthGrp ,PickupEachGrp ,PickupDiff
  264. var enventsPickup = timeLineData.events.Where(x => x.Event.Equals("PickupResult"));
  265. if (enventsPickup.IsNotEmpty())
  266. {
  267. foreach (var item in enventsPickup)
  268. {
  269. List<int> mbrs = item.PickupMemberId.ToObject<List<int>>();
  270. foreach (var mbr in mbrs)
  271. {
  272. var studentLessonData = studentLessonDatas.Find(x => x.seatID!.Equals($"{mbr}"));
  273. if (studentLessonData!=null)
  274. {
  275. studentLessonData.interactRecords.Add(new InteractRecord() { status = InteractStatus.TT, interactType = string.IsNullOrWhiteSpace(item.PickupType) ? "PickupResult" : item.PickupType });
  276. }
  277. }
  278. }
  279. }
  280. return studentLessonDatas;
  281. }
  282. private static void ProcessIRSPageData(List<IRSData> irsDatas, List<StudentLessonData> studentLessonDatas, dynamic item)
  283. {
  284. var irsDataPages = irsDatas.Where(y => item.key.Equals(y.pageID));
  285. foreach (var irsDataPage in irsDataPages)
  286. {
  287. //检查是否设置正确答案。
  288. var answers = irsDataPage.question?["exercise"]?["answer"]?.ToJsonString().ToObject<List<string>>();
  289. var _objective = irsDataPage.question?["exercise"]?["objective"];
  290. var scoreNode = irsDataPage.question?["exercise"]?["score"];
  291. double score = 0;
  292. bool objective = false;
  293. if (_objective!=null) {
  294. objective = _objective.GetValue<bool>();
  295. }
  296. if (scoreNode!=null)
  297. {
  298. double.TryParse(scoreNode.ToString(), out score);
  299. }
  300. string interactType = string.Empty;
  301. if (irsDataPage.clientAnswers.IsNotEmpty())
  302. {
  303. //第一个list是几轮,一次作答,二次作答, 第二个list是学生的下标, 第三个list是 答案
  304. List<List<List<string>>> clientAnswers = new List<List<List<string>>>();
  305. foreach (var key in irsDataPage.clientAnswers.Keys)
  306. {
  307. clientAnswers.Add(irsDataPage.clientAnswers[key]);
  308. }
  309. // 获取第一个列表的长度作为比较基准
  310. int firstListLength = clientAnswers.First().Count;
  311. bool isSameLength = true;
  312. // 遍历剩余的列表并检查它们的长度是否与第一个列表相同
  313. foreach (var innerList in clientAnswers.Skip(1))
  314. {
  315. if (innerList.Count != firstListLength)
  316. {
  317. isSameLength = false;
  318. break;
  319. }
  320. }
  321. //并检查学生集合的长度是否与第一个列表相同
  322. if (!isSameLength && studentLessonDatas.Count()==firstListLength)
  323. {
  324. //有设置答案
  325. if (answers.IsNotEmpty())
  326. {
  327. for (int index = 0; index< clientAnswers[0].Count; index++)
  328. {
  329. //index 代表学生下标
  330. List<InteractRecord> interactRecords = new List<InteractRecord>();
  331. if (clientAnswers.Count==1)
  332. {
  333. //即问即答
  334. interactType = "PopQuesLoad";
  335. var ans0 = clientAnswers[0][index];
  336. var IS0 = GetInteractResultHasAnswer(answers, ans0);
  337. interactRecords.Add(new InteractRecord()
  338. {
  339. status = IS0,
  340. interactType= interactType
  341. });
  342. }
  343. if (clientAnswers.Count==2)
  344. {
  345. //二次作答
  346. interactType="ReAtmpAnsStrt";
  347. var ans1 = clientAnswers[1][index];
  348. var IS1 = GetInteractResultHasAnswer(answers, ans1);
  349. interactRecords.Add(new InteractRecord()
  350. {
  351. status = IS1,
  352. interactType= interactType
  353. });
  354. }
  355. if (clientAnswers.Count>2)
  356. {
  357. //三次作答
  358. interactType="TeAtmpAnsStrt";
  359. var ans2 = clientAnswers[2][index];
  360. var IS2 = GetInteractResultHasAnswer(answers, ans2);
  361. interactRecords.Add(new InteractRecord()
  362. {
  363. status = IS2,
  364. interactType= interactType
  365. });
  366. }
  367. studentLessonDatas[index].interactRecords.AddRange(interactRecords);
  368. }
  369. }
  370. }
  371. }
  372. //是否抢权作答的模式
  373. if (irsDataPage.isBuzz)
  374. {
  375. interactType = "BuzrAns";
  376. //处理参与抢权的
  377. Dictionary<string, InteractRecord> buzzParticipants = new Dictionary<string, InteractRecord>();
  378. foreach (var buzzParticipant in irsDataPage.buzzParticipants)
  379. {
  380. var studentData = studentLessonDatas.Find(x => x.seatID!.Equals(buzzParticipant));
  381. if (studentData != null)
  382. {
  383. buzzParticipants[buzzParticipant]=new InteractRecord() { status = InteractStatus.T1, interactType= interactType };
  384. }
  385. }
  386. //处理抢权成功的
  387. foreach (var buzzClient in irsDataPage.buzzClients)
  388. {
  389. buzzParticipants[buzzClient]=new InteractRecord() { status = InteractStatus.TT, interactType= interactType };
  390. }
  391. foreach (var studentLessonData in studentLessonDatas)
  392. {
  393. if (buzzParticipants.ContainsKey(studentLessonData.seatID!))
  394. {
  395. //处理已经有抢权结果的数据
  396. studentLessonData.interactRecords.Add(buzzParticipants[studentLessonData.seatID!]);
  397. }
  398. else
  399. {
  400. //处理未参与抢权的
  401. studentLessonData.interactRecords.Add(new InteractRecord() { status = InteractStatus.T0, interactType = interactType });
  402. }
  403. }
  404. }
  405. }
  406. }
  407. private static InteractStatus GetInteractResultHasAnswer(List<string>? answers, List<string> ans0)
  408. {
  409. InteractStatus status = InteractStatus.T0;
  410. if (ans0.IsNotEmpty())
  411. {
  412. //标准答案等于作答的结果
  413. if (answers!.Count == ans0.Count)
  414. {
  415. if (answers.All(item => ans0.Contains(item)))
  416. {
  417. //完全正确
  418. status= InteractStatus.TT;
  419. }
  420. else
  421. {
  422. //作答错误
  423. status= InteractStatus.T1;
  424. }
  425. }
  426. //标准答案比作答的结果多
  427. else if (answers!.Count > ans0.Count)
  428. {
  429. if (ans0.All(item => answers.Contains(item)))
  430. {
  431. //部分正确
  432. status= InteractStatus.TP;
  433. }
  434. else
  435. {
  436. //作答错误
  437. status= InteractStatus.T1;
  438. }
  439. }
  440. //标准答案比作答结果少
  441. else
  442. {
  443. //作答错误
  444. status= InteractStatus.T1;
  445. }
  446. }
  447. else
  448. {
  449. //没有作答
  450. status= InteractStatus.T0;
  451. }
  452. return status;
  453. }
  454. /// <summary>
  455. /// 获取课中评测数据
  456. /// </summary>
  457. /// <param name="lessonRecord"></param>
  458. /// <param name="lessonBase"></param>
  459. /// <param name="timeLineData"></param>
  460. /// <param name="coworkDatas"></param>
  461. /// <param name="studentLessonDatas"></param>
  462. /// <returns></returns>
  463. private async Task<dynamic> GetExamData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<ExamData> examDatas, List<StudentLessonData> studentLessonDatas)
  464. {
  465. foreach (var examData in examDatas)
  466. {
  467. var allocation= examData?.exam?.papers?.SelectMany(x => x.point).Sum();
  468. var answersStd = examData?.exam?.papers?.FirstOrDefault()?.answers;
  469. List<List<string>> answers= new List<List<string>>();
  470. if (answersStd!=null)
  471. {
  472. answersStd.ForEach(x =>
  473. {
  474. List<string> ans = new List<string>();
  475. x.ForEach(y =>
  476. {
  477. if (string.IsNullOrWhiteSpace(y))
  478. {
  479. }
  480. });
  481. answers.Add(ans);
  482. });
  483. }
  484. examData?.examClassResult?.ForEach(item =>{
  485. int index = 0;
  486. item.studentAnswersArray.ForEach(x => {
  487. //是否要判断主观题或者客观题, 多套试卷,有主观题的
  488. //主观题有回答的:608942756458532864\Clients\18782481024\Ans\27-4341670635487887360-examExchangeAnswerlist 27 从1开始的学生序号-4341670635487887360评测编号,内容qNo 是从1开始的题号。
  489. if (x.IsNotEmpty())
  490. {
  491. }
  492. });
  493. });
  494. }
  495. return null;
  496. }
  497. /// <summary>
  498. /// 协作参与率 态度计算
  499. /// </summary>
  500. /// <param name="lessonRecord"></param>
  501. /// <param name="lessonBase"></param>
  502. /// <param name="timeLineData"></param>
  503. /// <param name="coworkDatas"></param>
  504. /// <param name="studentLessonDatas"></param>
  505. /// <returns></returns>
  506. private async Task<dynamic> GetCoworkData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<CoworkData> coworkDatas, List<StudentLessonData> studentLessonDatas)
  507. {
  508. return Ok(lessonRecord);
  509. }
  510. /// <summary>
  511. /// 处理学生回推数据,并将回推纳入学习态度计算。
  512. /// </summary>
  513. /// <param name="lessonRecord"></param>
  514. /// <param name="lessonBase"></param>
  515. /// <param name="timeLineData"></param>
  516. /// <param name="taskDatas"></param>
  517. /// <param name="studentLessonDatas"></param>
  518. /// <returns></returns>
  519. private async Task<dynamic> GetTaskData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<TaskData> taskDatas, List<StudentLessonData> studentLessonDatas)
  520. {
  521. return Ok(lessonRecord);
  522. }
  523. /// <summary>
  524. /// 评分参与率 态度计算
  525. /// </summary>
  526. /// <param name="lessonRecord"></param>
  527. /// <param name="lessonBase"></param>
  528. /// <param name="timeLineData"></param>
  529. /// <param name="smartRatingDatas"></param>
  530. /// <param name="studentLessonDatas"></param>
  531. /// <returns></returns>
  532. private async Task<dynamic> GetSmartRatingData(LessonRecord lessonRecord, LessonBase lessonBase, TimeLineData timeLineData, List<SmartRatingData> smartRatingDatas, List<StudentLessonData> studentLessonDatas)
  533. {
  534. return Ok(lessonRecord);
  535. }
  536. }
  537. public class LessonRecordData
  538. {
  539. /// <summary>
  540. /// 互动次数
  541. /// </summary>
  542. public int interactCount;
  543. public List<StudentLessonData> data { get; set; } = new List<StudentLessonData>();
  544. }
  545. /// <summary>
  546. /// 学生课中数据
  547. /// </summary>
  548. public class StudentLessonData
  549. {
  550. /// <summary>
  551. /// 学生的学号
  552. /// </summary>
  553. public string? id { get; set; }
  554. /// <summary>
  555. /// 学生所在下标
  556. /// </summary>
  557. public int index { get; set; } = -1;
  558. /// <summary>
  559. /// 学生座位号
  560. /// </summary>
  561. public string? seatID { get; set; }
  562. /// <summary>
  563. /// 小组编号
  564. /// </summary>
  565. public string? groupId { get; set; }
  566. /// <summary>
  567. /// 小组下标 ,暂不使用
  568. /// </summary>
  569. //public int groupIndex { get; set; } = -1;
  570. /// <summary>
  571. /// 学生专属的互动次数,单独设置此字段,因为存在挑人的情况,需要单独设置
  572. /// </summary>
  573. public int interactCount { get; set; }
  574. /// <summary>
  575. /// 互动积分
  576. /// </summary>
  577. public double interactScore { get; set; }
  578. /// <summary>
  579. /// -1表示本次互动未统计分数,0表示本次互动答错为0,大于0 的分数表示本次互动打对为相应的分数。 该分数用于统计成果。
  580. /// 互动积分记录[-1,0,10]
  581. /// </summary>
  582. public List<InteractRecord> interactRecords { get; set; } = new List<InteractRecord>();
  583. /// <summary>
  584. /// 学生评测记录相关
  585. /// </summary>
  586. public List<StudentExamRecord> examRecords { get; set; } = new List<StudentExamRecord>();
  587. }
  588. /// <summary>
  589. /// 学生课中评测记录
  590. /// </summary>
  591. public class StudentExamRecord
  592. {
  593. /// <summary>
  594. /// 作答率0 未作答,1,所有题目作答,小数点则表示部分作答。 可纳入学习态度计算, 主观题需要确认 是否会在此写入答案。
  595. /// </summary>
  596. public int answerRate{ get; set; }
  597. /// <summary>
  598. /// 评测得分
  599. /// </summary>
  600. public double score { get; set;}
  601. /// <summary>
  602. /// 评测id
  603. /// </summary>
  604. public string? examId { get; set; }
  605. /// <summary>
  606. /// 得分率
  607. /// </summary>
  608. public double scoreRate { get; set; }
  609. /// <summary>
  610. /// 配分
  611. /// </summary>
  612. // public double allocation { get; set; }
  613. /// <summary>
  614. /// 暂不计算
  615. /// 每个题的得分情况
  616. /// </summary>
  617. // public List<double> itemScores { get; set; } = new List<double>();
  618. }
  619. public class InteractRecord
  620. {
  621. /// <summary>
  622. /// 基准分值
  623. /// </summary>
  624. public double criterion { get; set; }
  625. /// <summary>
  626. /// { "PopQuesLoad", "ReAtmpAnsStrt", "BuzrAns", "BuzrLoad", "PickupResult" };
  627. /// </summary>
  628. public string? interactType { get; set; }
  629. /// <summary>
  630. /// 互动结果状态,纳入学习状态计算
  631. /// </summary>
  632. public InteractStatus status { get; set; }
  633. }
  634. public enum InteractStatus
  635. {
  636. /// <summary>
  637. /// 没有作答, 没有参与0
  638. /// </summary>
  639. T0,
  640. /// <summary>
  641. /// 作答错误,有参加,有抢权1
  642. /// </summary>
  643. T1,
  644. /// <summary>
  645. /// 部分正确1.3
  646. /// </summary>
  647. TP,
  648. /// <summary>
  649. /// 作答正确,抢权成功,被抽到
  650. /// </summary>
  651. TT
  652. /// 互动参与指数(按倍数的权重设计)
  653. /// 无二次作答的互动,且未设置正确答案:1.未作答0
  654. /// 2.已作答1
  655. ///
  656. /// 无二次作答的互动,且设置了正确答案:3.未作答0
  657. /// 4.已作答1
  658. /// 5.不完全正确1.3
  659. /// 6.作答正确1.5
  660. ///
  661. ///
  662. /// 有二次作答的互动,且未设置正确答案:7.第一次未作答0,第二次未作答0=》0
  663. /// 8.第一次已作答1,第二次未作答0=》1
  664. /// 9.第一次未作答0,第二次已作答1=》1
  665. /// 10.第一次已作答1,第二次已作答1=》2
  666. ///
  667. /// 有二次作答的互动,且设置了正确答案:(16种可能)
  668. /// 11.第一次未作答0,第二次未作答0=》0
  669. /// 12.第一次已作答,不完全正确1.3,第二次未作答0=》1.3
  670. /// 13.第一次已作答,作答正确1.5,第二次未作答0=》1.5
  671. /// 14.第一次已作答,作答错误1,第二次未作答0=》1
  672. /// 15.第一次未作答0,第二次已作答,不完全正确1.3=》1.3
  673. /// 16.第一次未作答0,第二次已作答,作答正确1.5=》1.5
  674. /// 17.第一次未作答0,第二次已作答,作答错误1=》1
  675. /// 18.第一次已作答,作答错误1,第二次已作答,作答错误1=》2
  676. /// 19.第一次已作答,不完全正确1.3,第二次已作答,作答错误1=》2.3
  677. /// 20.第一次已作答,作答正确1.5,第二次已作答,作答错误1=》2.5
  678. /// 21.第一次已作答,作答错误1,第二次已作答,不完全正确1.3=》2.3
  679. /// 22.第一次已作答,作答错误1,第二次已作答,作答正确1.5=》2.5
  680. /// 23.第一次已作答,不完全正确1.3,第二次已作答,不完全正确1.3=》2.6
  681. /// 24.第一次已作答,不完全正确1.3,第二次已作答,作答正确1.5=》2.8
  682. /// 25.第一次已作答,作答正确1.5,第二次已作答,不完全正确1.3=》2.8
  683. /// 26.第一次已作答,作答正确1.5,第二次已作答,作答正确1.5=》3
  684. ///
  685. /// 抢权模式: 27.未参与抢权 0
  686. /// 28.参与抢权 1
  687. /// 29.抢权成功 1.5
  688. /// 挑人时被挑到 30.被挑到 1.5
  689. /// 有三次作答的互动,且设置了正确答案:(64种可能)
  690. /*
  691. 1 未作答0 未作答0 未作答0 0
  692. 2 未作答0 未作答0 不完全正确1.3 1.3
  693. 3 未作答0 未作答0 作答正确1.5 1.5
  694. 4 未作答0 未作答0 作答错误1 1
  695. 5 未作答0 不完全正确1.3 未作答0 1.3
  696. 6 未作答0 不完全正确1.3 不完全正确1.3 2.6
  697. 7 未作答0 不完全正确1.3 作答正确1.5 2.8
  698. 8 未作答0 不完全正确1.3 作答错误1 2.3
  699. 9 未作答0 作答正确1.5 未作答0 1.5
  700. 10 未作答0 作答正确1.5 不完全正确1.3 2.8
  701. 11 未作答0 作答正确1.5 作答正确1.5 3
  702. 12 未作答0 作答正确1.5 作答错误1 2.5
  703. 13 未作答0 作答错误1 未作答0 1
  704. 14 未作答0 作答错误1 不完全正确1.3 2.3
  705. 15 未作答0 作答错误1 作答正确1.5 2.5
  706. 16 未作答0 作答错误1 作答错误1 2
  707. 17 已作答错误1 未作答0 未作答0 1
  708. 18 已作答错误1 未作答0 不完全正确1.3 2.3
  709. 19 已作答错误1 未作答0 作答正确1.5 2.5
  710. 20 已作答错误1 未作答0 作答错误1 2
  711. 21 已作答错误1 不完全正确1.3 未作答0 2.3
  712. 22 已作答错误1 不完全正确1.3 不完全正确1.3 3.6
  713. 23 已作答错误1 不完全正确1.3 作答正确1.5 3.8
  714. 24 已作答错误1 不完全正确1.3 作答错误1 3.3
  715. 25 已作答错误1 作答正确1.5 未作答0 2.5
  716. 26 已作答错误1 作答正确1.5 不完全正确1.3 3.8
  717. 27 已作答错误1 作答正确1.5 作答正确1.5 4
  718. 28 已作答错误1 作答正确1.5 作答错误1 3.5
  719. 29 已作答错误1 作答错误1 未作答0 2
  720. 30 已作答错误1 作答错误1 不完全正确1.3 3.3
  721. 31 已作答错误1 作答错误1 作答正确1.5 3.5
  722. 32 已作答错误1 作答错误1 作答错误1 3
  723. 33 已作答不完全正确1.3 未作答0 未作答0 1.3
  724. 34 已作答不完全正确1.3 未作答0 不完全正确1.3 2.6
  725. 35 已作答不完全正确1.3 未作答0 作答正确1.5 2.8
  726. 36 已作答不完全正确1.3 未作答0 作答错误1 2.3
  727. 37 已作答不完全正确1.3 不完全正确1.3 未作答0 2.6
  728. 38 已作答不完全正确1.3 不完全正确1.3 不完全正确1.3 3.9
  729. 39 已作答不完全正确1.3 不完全正确1.3 作答正确1.5 4.1
  730. 40 已作答不完全正确1.3 不完全正确1.3 作答错误1 3.6
  731. 41 已作答不完全正确1.3 作答正确1.5 未作答0 2.8
  732. 42 已作答不完全正确1.3 作答正确1.5 不完全正确1.3 4.1
  733. 43 已作答不完全正确1.3 作答正确1.5 作答正确1.5 4.3
  734. 44 已作答不完全正确1.3 作答正确1.5 作答错误1 3.8
  735. 45 已作答不完全正确1.3 作答错误1 未作答0 2.3
  736. 46 已作答不完全正确1.3 作答错误1 不完全正确1.3 3.6
  737. 47 已作答不完全正确1.3 作答错误1 作答正确1.5 3.8
  738. 48 已作答不完全正确1.3 作答错误1 作答错误1 3.3
  739. 49 已作答正确1.5 未作答0 未作答0 1.5
  740. 50 已作答正确1.5 未作答0 不完全正确1.3 2.8
  741. 51 已作答正确1.5 未作答0 作答正确1.5 3
  742. 52 已作答正确1.5 未作答0 作答错误1 2.5
  743. 53 已作答正确1.5 不完全正确1.3 未作答0 2.8
  744. 54 已作答正确1.5 不完全正确1.3 不完全正确1.3 4.1
  745. 55 已作答正确1.5 不完全正确1.3 作答正确1.5 4.3
  746. 56 已作答正确1.5 不完全正确1.3 作答错误1 3.8
  747. 57 已作答正确1.5 作答正确1.5 未作答0 3
  748. 58 已作答正确1.5 作答正确1.5 不完全正确1.3 4.3
  749. 59 已作答正确1.5 作答正确1.5作答正确1.5 4.5
  750. 60 已作答正确1.5 作答正确1.5作答错误1 4
  751. 61 已作答正确1.5 作答错误1 未作答0 2.5
  752. 62 已作答正确1.5 作答错误1 不完全正确1.3 3.8
  753. 63 已作答正确1.5 作答错误1 作答正确1.54
  754. 64 已作答正确1.5 作答错误1 作答错误1 3.5
  755. */
  756. }
  757. /*
  758. *
  759. /// 事件
  760. /// 推送相关 在Push.json处理 DifObjPush 推送给学生 差异化推送 "PushMemberId":[1,4,8,12,17,18,19,23,24,27,32,36] ,FastPgPush 同一推送
  761. /// 互动相关 在IRS.json处理 'PopQuesLoad'互动问答 , 'ReAtmpAnsStrt' 二次作答 , 'BuzrAns' 抢权(新), 'BuzrLoad'抢权(旧), PickupResult 挑人算不算互动?? 读取PickupMemberId "[\r\n 35\r\n]"
  762. /// 测验相关 在IRS.json处理 SPQStrt 测验模式
  763. /// 任务相关 在Task.json处理 'WrkSpaceLoad' 作品收集, 'WrkCmp' 作品贴上 是什么操作
  764. /// 评分相关 在SmartRating.json 处理 'SmartRating' 评分模式,分 投票Voting 和 GrandRating 星光大评分(All每人多件评分,Two随机分配互评, Self自评)
  765. /// 协作相关 在Cowork.json 处理 CoworkLoad 协作类型 coworkType All: '全体协作', Group: '分组协作', 其他的为 : '差异化协作',
  766. 问题汇总:
  767. TimeLine.json
  768. 挑人大类 Event= PickupResult 里面 分小类
  769. PickupType=PickupRight , PickupOption , PickupNthGrp ,PickupEachGrp ,PickupDiff 五种类型分别是什么意思,是否还有其他类型的。
  770. ,"PickupCount":1,"PickupOption":2 ,"PickupGroup":2 这三个字段是什么意思。
  771. "PickupMemberId":"[\r\n 1\r\n]" 里面是学生的座号还是数组下标。
  772. "Event":"PressGood","TargetClass":0,"MemberId":"[\r\n 1\r\n]","Count":1},
  773. 是代表什么意思。 MemberId 是座号还说下标。
  774. 8月27日 17:581. Task.json的 clientWorks.isGroupItem bool 类型 false代表什么意思 true代表什么意思
  775. 2. Cowork.json 的 coworkType All: '全体协作', Group: '分组协作', : '差异化协作', 差异化协作的简码是什么?
  776. 3. TimeLine.json 的 类型 PickupResult 挑人算不算互动?? 读取PickupMemberId "[\r\n 35\r\n]"
  777. 4. 小组任务具体详细信息如何获取? 需要精确到 所有小组任务信息和 某一小组的参与情况 用于计算小组任务参与率
  778. */
  779. }