MockDataController.cs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. using Microsoft.AspNetCore.Mvc;
  2. using System.Text.Json;
  3. using static HTEX.Test.Controllers.LessonRecordController;
  4. using TEAMModelOS.SDK.Extension;
  5. using TEAMModelOS.SDK.Models;
  6. using System;
  7. using OfficeOpenXml;
  8. using System.Reflection;
  9. using System.Xml;
  10. using System.Text.RegularExpressions;
  11. namespace HTEX.Test.Controllers
  12. {
  13. [ApiController]
  14. [Route("mock-data")]
  15. public class MockDataController : ControllerBase
  16. {
  17. private readonly ILogger<MockDataController> _logger;
  18. public MockDataController(ILogger<MockDataController> logger)
  19. {
  20. _logger = logger;
  21. }
  22. [HttpPost("student-lesson")]
  23. public async Task<IActionResult> StudentLesson(JsonElement json)
  24. {
  25. #region 数据模拟
  26. //学生人数
  27. int scount = Random.Shared.Next(40, 45);
  28. //评测次数
  29. int ecount = Random.Shared.Next(0, 3);
  30. //题目个数
  31. int qcount = Random.Shared.Next(8, 15);
  32. //互动次数
  33. int icount = Random.Shared.Next(3, 12);
  34. //任务次数
  35. int tcount = Random.Shared.Next(1, 3);
  36. //评价次数
  37. int pcount = Random.Shared.Next(1, 4);
  38. //协作次数
  39. int xcount = Random.Shared.Next(1, 3);
  40. List<StudentLessonData> students = new List<StudentLessonData>();
  41. //个人计分,小组计分
  42. List<WeightedItem> gpitems = new List<WeightedItem>
  43. {
  44. new WeightedItem { Value = 0, Weight = 0.3 },
  45. new WeightedItem { Value = 2, Weight = 0.1 },
  46. new WeightedItem { Value = 5, Weight = 0.2 },
  47. new WeightedItem { Value = 8, Weight = 0.1 },
  48. new WeightedItem { Value = 3, Weight = 0.05 },
  49. new WeightedItem { Value = 4, Weight = 0.02 },
  50. new WeightedItem { Value = 6, Weight = 0.03 },
  51. new WeightedItem { Value = 7, Weight = 0.2 }
  52. };
  53. //个人计分,小组计分
  54. List<WeightedItem> titems = new List<WeightedItem>
  55. {
  56. new WeightedItem { Value = 0, Weight = 0.4 },
  57. new WeightedItem { Value = 25, Weight = 0.1 },
  58. new WeightedItem { Value = 15, Weight = 0.1 },
  59. new WeightedItem { Value = 10, Weight = 0.05 },
  60. new WeightedItem { Value = 30, Weight = 0.05 },
  61. new WeightedItem { Value = 20, Weight = 0.02 },
  62. new WeightedItem { Value = 40, Weight = 0.03 },
  63. new WeightedItem { Value = 50, Weight = 0.05 },
  64. new WeightedItem { Value = 5, Weight = 0.05 },
  65. new WeightedItem { Value = 35, Weight = 0.05 },
  66. new WeightedItem { Value = 45, Weight = 0.05 },
  67. new WeightedItem { Value = 55, Weight = 0.05 }
  68. };
  69. //for (var i = 0; i<100; i++)
  70. //{
  71. // int randomValue = GetRandomValueByWeight(items);
  72. // Console.WriteLine(randomValue);
  73. //}
  74. //被评价的目标索引
  75. List<List<int>> cworkDist = new List<List<int>>(xcount);
  76. //被评价目标的次数或分数
  77. // List<List<int>> cworkCount = new List<List<int>>(xcount);
  78. for (int i = 0; i < xcount; i++)
  79. {
  80. //乱序取10-20人作为评价目标
  81. var vt = Enumerable.Range(0, scount).OrderBy(x => Random.Shared.Next()).Take(Random.Shared.Next(10, 21));
  82. cworkDist.Add(vt.ToList());
  83. //var counts = new List<int>();
  84. //foreach (var v in vt)
  85. //{
  86. // counts.Add(0);
  87. //}
  88. //cworkCount.Add(counts);
  89. }
  90. //被评价的目标索引
  91. List<List<int>> rateDist = new List<List<int>>(pcount);
  92. //被评价目标的次数或分数
  93. //List<List<int>> rateCount = new List<List<int>>(pcount);
  94. List<string> types = new List<string>();
  95. for (int i = 0; i < pcount; i++)
  96. {
  97. //乱序取10-20人作为评价目标
  98. var vt = Enumerable.Range(0, scount).OrderBy(x => Random.Shared.Next()).Take(Random.Shared.Next(10, 21));
  99. rateDist.Add(vt.ToList());
  100. // var counts = new List<int>();
  101. //foreach (var v in vt)
  102. //{
  103. // counts.Add(0);
  104. //}
  105. //rateCount.Add(counts);
  106. var t = Random.Shared.Next(0, 1);
  107. switch (true)
  108. {
  109. case bool when i==0:
  110. types.Add("Voting");
  111. break;
  112. case bool when i==1:
  113. types.Add("GrandRating");
  114. break;
  115. case bool when i==2:
  116. types.Add("PeerAssessment");
  117. break;
  118. }
  119. }
  120. for (var s = 0; s<scount; s++)
  121. {
  122. StudentLessonData student = new StudentLessonData()
  123. {
  124. index=s,
  125. seatID=$"{s+1}",
  126. id=$"2024{(s+1).ToString("D3")}",
  127. groupId=$"{Random.Shared.Next(1, 5)}",
  128. attend=1,
  129. gscore= GetRandomValueByWeight(gpitems),
  130. pscore= GetRandomValueByWeight(gpitems),
  131. tscore= GetRandomValueByWeight(titems),
  132. };
  133. for (var p = 0; p<pcount; p++)
  134. {
  135. student.rateingRecord.itemRecords.Add(new ItemRecord());
  136. }
  137. students.Add(student);
  138. }
  139. for (var s = 0; s<scount; s++)
  140. {
  141. var student = students[s];
  142. //互动
  143. for (var i = 0; i<icount; i++)
  144. {
  145. int criterion = 10;
  146. var item = new ItemRecord { criterion=criterion };
  147. var w = Random.Shared.Next(0, 4);
  148. switch (true)
  149. {
  150. //未参与
  151. case bool when w==0:
  152. item.resultWeight= InteractWeight.T0;
  153. item.resultType= InteractReultType.T0;
  154. item.itemScore=0;
  155. break;
  156. //参与了
  157. case bool when w==1:
  158. item.resultWeight= InteractWeight.T1;
  159. item.resultType= InteractReultType.T1;
  160. item.itemScore=0;
  161. break;
  162. //部分正确
  163. case bool when w==2:
  164. var score = Random.Shared.Next(1, criterion);
  165. item.resultWeight= MinMaxNormalization(1, criterion, score, InteractWeight.T1, InteractWeight.TT);
  166. item.resultType= InteractReultType.TP;
  167. item.itemScore=0;
  168. break;
  169. //完全正确
  170. case bool when w==3:
  171. item.resultWeight= InteractWeight.TT;
  172. item.resultType= InteractReultType.TT;
  173. item.itemScore=criterion;
  174. break;
  175. }
  176. student.interactRecord.interactRecords.Add(item);
  177. }
  178. //任务
  179. for (var t = 0; t<tcount; t++)
  180. {
  181. var w = Random.Shared.Next(0, 2);
  182. var item = new ItemRecord { };
  183. switch (true)
  184. {
  185. //未参与
  186. case bool when w==0:
  187. item.resultWeight= InteractWeight.T0;
  188. item.resultType= InteractReultType.T0;
  189. item.itemScore=0;
  190. break;
  191. //参加
  192. case bool when w==1:
  193. item.resultWeight= InteractWeight.TT;
  194. item.resultType= InteractReultType.TT;
  195. item.itemScore=10;
  196. break;
  197. }
  198. student.taskRecord.taskRate= student.taskRecord.itemRecords.Where(x => x.resultWeight>0).Count()*1.0/tcount;
  199. student.taskRecord.itemRecords.Add(item);
  200. }
  201. //评价
  202. for (var p = 0; p<pcount; p++)
  203. {
  204. var item = student.rateingRecord.itemRecords[p];
  205. var subtype = string.Empty;
  206. item.itemType=types[p];
  207. if (types[p].Equals("PeerAssessment"))
  208. {
  209. var sub = Random.Shared.Next(0, 3);
  210. subtype= sub==0 ? "ALL" : sub==1 ? "Two" : "Self";
  211. }
  212. var w = Random.Shared.Next(0, 3);
  213. switch (true)
  214. {
  215. //未参与
  216. case bool when w==0:
  217. item.resultWeight= InteractWeight.T0;
  218. item.resultType= InteractReultType.T0;
  219. item.itemScore=0;
  220. break;
  221. //参与
  222. case bool when w==1||w==2:
  223. item.resultWeight= InteractWeight.T1;
  224. item.resultType= InteractReultType.T1;
  225. if (item.itemType!.Equals("Voting"))
  226. {
  227. var index = Random.Shared.Next(0, rateDist[p].Count);
  228. //rateCount[p][index]+=1;
  229. students[rateDist[p][index]].rateingRecord.itemRecords[p].itemScore+=1;
  230. }
  231. else
  232. {
  233. if (item.itemType.Equals("PeerAssessment"))
  234. {
  235. var index = Random.Shared.Next(0, rateDist[p].Count);
  236. //操作次数
  237. int opt_count = Random.Shared.Next(1, 2);
  238. for (var count = 0; count<opt_count; count++)
  239. {
  240. var score = Random.Shared.Next(3, 10);
  241. // rateCount[p][index]+=score;
  242. students[rateDist[p][index]].rateingRecord.itemRecords[p].itemScore+=score;
  243. item.optCount+= 1;
  244. }
  245. }
  246. else
  247. {
  248. var index = Random.Shared.Next(0, rateDist[p].Count);
  249. var score = Random.Shared.Next(3, 10);
  250. // rateCount[p][index]+=score;
  251. students[rateDist[p][index]].rateingRecord.itemRecords[p].itemScore+=score;
  252. }
  253. }
  254. break;
  255. }
  256. // student.rateingRecord.itemRecords.Add(item);
  257. }
  258. //协作
  259. for (var x = 0; x<xcount; x++)
  260. {
  261. int[] r = new int[] { 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1 };
  262. var w = r[Random.Shared.Next(0, r.Length)];
  263. var item = new ItemRecord { };
  264. switch (true)
  265. {
  266. //未参与
  267. case bool when w==0:
  268. item.resultWeight= InteractWeight.T0;
  269. item.resultType= InteractReultType.T0;
  270. item.itemScore=0;
  271. break;
  272. //
  273. case bool when w==1:
  274. item.resultWeight= InteractWeight.TP;
  275. item.resultType= InteractReultType.TP;
  276. int[] q = new int[] { 10, 5, 5, 20, 30, 10, 25, 10, 15, 15, 30, 5, 10, 20, 15, 25, 10, 5, 15, 20, 20, 25, 5, 5 };
  277. item.itemScore=q[Random.Shared.Next(0, q.Count())];
  278. break;
  279. }
  280. student.coworkRecord.itemRecords.Add(item);
  281. }
  282. //评测
  283. for (var e = 0; e<ecount; e++)
  284. {
  285. StudentExamRecord examRecord = new();
  286. double allocation = 0;
  287. for (var q = 0; q<qcount; q++)
  288. {
  289. var criterion = Random.Shared.Next(5, 10);
  290. allocation+=criterion;
  291. var item = new ItemRecord { criterion =criterion };
  292. var w = Random.Shared.Next(0, 4);
  293. switch (true)
  294. {
  295. //未作答
  296. case bool when w==0:
  297. item.resultWeight= InteractWeight.T0;
  298. item.resultType= InteractReultType.T0;
  299. item.itemScore=0;
  300. break;
  301. //作答错误
  302. case bool when w==1:
  303. item.resultWeight= InteractWeight.T1;
  304. item.resultType= InteractReultType.T1;
  305. item.itemScore=0;
  306. break;
  307. //部分正确
  308. case bool when w==2:
  309. var score = Random.Shared.Next(1, criterion);
  310. item.resultWeight= MinMaxNormalization(1, criterion, score, InteractWeight.T1, InteractWeight.TT); // score * 1.0 / criterion* (InteractWeight.TT-InteractWeight.T1);
  311. item.resultType= InteractReultType.TP;
  312. item.itemScore=score;
  313. break;
  314. //完全正确
  315. case bool when w==3:
  316. item.resultWeight= InteractWeight.TT;
  317. item.resultType= InteractReultType.TT;
  318. item.itemScore=criterion;
  319. break;
  320. }
  321. examRecord.itemRecords.Add(item);
  322. }
  323. examRecord.qcount=qcount;
  324. examRecord.workCount= examRecord.itemRecords.Where(x => x.resultWeight>0).Count();
  325. examRecord.allocation=allocation;
  326. examRecord.score= examRecord.itemRecords.Where(x => x.itemScore>=0).Select(x => x.itemScore).Sum();//得分
  327. examRecord.scoreRate = Math.Round(examRecord.score * 1.0 / allocation, 4);//得分率
  328. examRecord.answerRate= Math.Round(examRecord.itemRecords.Where(x => x.resultWeight>0).Count()*1.0/qcount, 4);//作答率
  329. student.examRecords.Add(examRecord);
  330. }
  331. }
  332. for (var p = 0; p<pcount; p++)
  333. {
  334. var order = students.OrderByDescending(x => x.rateingRecord.itemRecords[p].itemScore);
  335. var maxItems = students.FindAll(x => x.rateingRecord.itemRecords[p].itemScore==order.First().rateingRecord.itemRecords[p].itemScore);
  336. var max = students.FindAll(x => x.rateingRecord.itemRecords[p].itemScore==order.First().rateingRecord.itemRecords[p].itemScore).First().rateingRecord.itemRecords[p].itemScore;
  337. var min = students.FindAll(x => x.rateingRecord.itemRecords[p].itemScore==order.Last().rateingRecord.itemRecords[p].itemScore).First().rateingRecord.itemRecords[p].itemScore;
  338. var sum = students.Sum(x => x.rateingRecord.itemRecords[p].itemScore);
  339. foreach (var student in students)
  340. {
  341. if (student.rateingRecord.itemRecords[p].itemScore>0 && student.rateingRecord.itemRecords[p].optCount>0)
  342. {
  343. student.rateingRecord.itemRecords[p].resultType=InteractReultType.TP;
  344. var data = MinMaxNormalization(min, max, student.rateingRecord.itemRecords[p].itemScore);
  345. student.rateingRecord.itemRecords[p].resultWeight=Math.Round(InteractWeight.T1+ data * 1.0 / 100 * (InteractWeight.TT-InteractWeight.T1), 4);
  346. if (maxItems.Select(x => x.seatID).Contains(student.seatID))
  347. {
  348. student.rateingRecord.itemRecords[p].resultType= InteractReultType.TT;
  349. student.rateingRecord.itemRecords[p].resultWeight= InteractWeight.TT;
  350. }
  351. }
  352. }
  353. }
  354. for (var p = 0; p<xcount; p++)
  355. {
  356. var order = students.OrderByDescending(x => x.coworkRecord.itemRecords[p].itemScore);
  357. var maxItems = students.FindAll(x => x.coworkRecord.itemRecords[p].itemScore==order.First().coworkRecord.itemRecords[p].itemScore);
  358. var max = students.FindAll(x => x.coworkRecord.itemRecords[p].itemScore==order.First().coworkRecord.itemRecords[p].itemScore).First().coworkRecord.itemRecords[p].itemScore;
  359. var min = students.FindAll(x => x.coworkRecord.itemRecords[p].itemScore==order.Last().coworkRecord.itemRecords[p].itemScore).First().coworkRecord.itemRecords[p].itemScore;
  360. var sum = students.Sum(x => x.coworkRecord.itemRecords[p].itemScore);
  361. foreach (var student in students)
  362. {
  363. if (student.coworkRecord.itemRecords[p].itemScore>0)
  364. {
  365. student.coworkRecord.itemRecords[p].resultType=InteractReultType.TP;
  366. var data = MinMaxNormalization(min, max, student.coworkRecord.itemRecords[p].itemScore);
  367. student.coworkRecord.itemRecords[p].resultWeight=Math.Round(InteractWeight.T1+ data * 1.0 / 100 * (InteractWeight.TT-InteractWeight.T1), 4);
  368. if (maxItems.Select(x => x.seatID).Contains(student.seatID))
  369. {
  370. student.coworkRecord.itemRecords[p].resultType= InteractReultType.TT;
  371. student.coworkRecord.itemRecords[p].resultWeight= InteractWeight.TT;
  372. }
  373. }
  374. }
  375. }
  376. #endregion 数据模拟
  377. string jsons = await System.IO.File.ReadAllTextAsync("F:\\lesson-local\\analysis.json");
  378. long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
  379. LessonDataAnalysis lessonDataAnalysis = jsons.ToObject<LessonDataAnalysis>();
  380. ProcessStudentData(students, lessonDataAnalysis, scount, ecount, qcount, icount, tcount, pcount, xcount, time );
  381. try {
  382. await System.IO.File.WriteAllTextAsync($"F:\\mock-data\\{time}.json", new { scount, ecount, qcount, icount, tcount, pcount, xcount, students }.ToJsonString());
  383. } catch (Exception ex) {
  384. Console.WriteLine(scount);
  385. }
  386. return Ok(new { scount, ecount, qcount, icount, tcount, pcount, xcount, students });
  387. }
  388. private void ProcessStudentData(List<StudentLessonData> studentLessonDatas, LessonDataAnalysis lessonDataAnalysis, int scount, int ecount, int qcount, int icount, int tcount, int pcount, int xcount,long time )
  389. {
  390. //历史记录的个人计分集合,通过“2倍标准差规则”移除异常值后得到的集合
  391. var max_q = lessonDataAnalysis.pscore.Max();
  392. //历史记录的互动计分集合,通过“2倍标准差规则”移除异常值后得到的集合
  393. var max_t = lessonDataAnalysis.tscore.Max();
  394. //历史记录的小组计分集合,通过“2倍标准差规则”移除异常值后得到的集合
  395. var max_h = lessonDataAnalysis.gscore.Max();
  396. var j = InteractWeight.T1;
  397. double t = InteractWeight.TT;
  398. List<StudentLessonItem> lessonItems= new List<StudentLessonItem>();
  399. foreach (var studentLessonData in studentLessonDatas)
  400. {
  401. StudentLessonItem lessonItem = new StudentLessonItem() { studentId= studentLessonData.id! };
  402. double u = 0.0;
  403. if (studentLessonData.attend==1)
  404. {
  405. u=100.0;
  406. }
  407. //c个人计分指数,d互动计分指数,e小组计分指数
  408. double c = 0, d = 0, e = 0;
  409. {
  410. //互动相关的计分
  411. //课例互动次数
  412. double n = studentLessonData.interactRecord.interactRecords.Count()*1.0;
  413. if (n>0)
  414. {
  415. //是IES大陆正式站历史课例数据,自2024-03-01至2024-10-08日,互动指数或学法指数黄灯或绿灯,不包含醍摩豆学校及测试学校,课例时长超过5分钟的有效课例(10,680笔数据) 的IRS互动+抢权+挑人的次数集合,
  416. //通过“2倍标准差规则” 移除异常值后得到的集合,再通过K-Means聚类算法得到高低位阶互动频次两个集合,并根据当前课例互动次数位阶的集合的质心值,该值定为m值
  417. var m = n<=lessonDataAnalysis.clustersInteract.First().Value.Max() ? lessonDataAnalysis.clustersInteract.First().Key*1.0 : lessonDataAnalysis.clustersInteract.Last().Key *1.0;
  418. //学生作答次数
  419. var w = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>=InteractWeight.T1).Count()*1.0;
  420. //作答正确数(包括部分正确)
  421. var r = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>InteractWeight.T1).Count()*1.0;
  422. //有参与的权重集合60≤k(x)≤100
  423. var kw = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>=InteractWeight.T1).Sum(x => x.resultWeight*1.0);
  424. //有得分的权重集合60<e(x)≤100
  425. var er = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>InteractWeight.T1).Sum(x => x.resultWeight*1.0);
  426. //本节课的所有互动计分
  427. var i = studentLessonData.interactRecord.interactRecords.Sum(x => x.itemScore*1.0);
  428. //本节课教师手动给学生的个人计分
  429. var s = studentLessonData.pscore;
  430. //个人计分指数
  431. c = GetPersent(lessonDataAnalysis.pscore,s)/100;// s*1.0/max_q;
  432. //互动计分指数
  433. d = GetPersent(lessonDataAnalysis.tscore, i)/100; //i*1.0/max_t;
  434. //互动成效指数
  435. var a = (d+w*kw/(j*m)+r*er/(j*m))*1.0/n;
  436. //互动参与指数
  437. var b = ((w*w)/m+(r*r)/m)*1.0/n;
  438. //c+a= 个人计分指数+ 个人互动成效指数
  439. //学习成效
  440. var f1 = Math.Round(190*1.0/(1+Math.Exp(-(c+a)))-95, 4);
  441. lessonItem.hd_cx=f1;
  442. var f2 = Math.Round(200*1.0/(1+Math.Exp(-(b+u/100)))-100, 4);
  443. lessonItem.hd_cy=f2;
  444. lessonItem.hd_cyc=w;
  445. lessonItem.hd_fqc=n;
  446. lessonItem.hd_zqc=r;
  447. lessonItem.gr_jf=s;
  448. }
  449. //studentLessonData.achieve=f1;
  450. //studentLessonData.attitude=f2;
  451. // _logger.LogInformation($"{studentLessonData.id}=>学习成效:{f1}\t学习态度:{f2}\t互动次数:{n}\t参与次数:{w}\t正确次数:{r}\t个人计分:{s}\t{Math.Round(c, 2)}\t互动计分:{i}\t{Math.Round(d, 2)}");
  452. }
  453. {
  454. //评测相关指数
  455. double n = studentLessonData.examRecords.Count()*1.0;
  456. if (n>0)
  457. {
  458. //题目数量
  459. double nq = studentLessonData.examRecords.Sum(x => x.qcount)*1.0;
  460. // double max_e = lessonDataAnalysis.exam.Max();
  461. //得分率
  462. double sum_s = studentLessonData.examRecords.Sum(x => x.scoreRate);
  463. //作答率
  464. double sum_a = studentLessonData.examRecords.Sum(x => x.answerRate);
  465. double f8 = Math.Round(sum_s/n*100, 4);
  466. double f9 = Math.Round(sum_a/n*100, 4);
  467. lessonItem.pc_df=f8;
  468. lessonItem.pc_zd=f9;
  469. }
  470. // _logger.LogInformation($"{studentLessonData.id}=>评测指数:{f8}\t得分率:{Math.Round(sum_s/n,4)}\t参与指数:{f9}\t作答率:{Math.Round(sum_a/n,4)}");
  471. }
  472. {
  473. //小组相关指数
  474. }
  475. {
  476. //任务相关指数
  477. double n = studentLessonData.taskRecord.itemRecords.Count()*1.0;
  478. if (n>0)
  479. {
  480. double max_m = lessonDataAnalysis.task.Max();
  481. double w = studentLessonData.taskRecord.itemRecords.Where(x => x.resultWeight>0).Count()*1.0;
  482. double y = (10 *w/n+(j/t) *w)/max_m;
  483. double l = max_m*(w*w/n+(j/t) * w)/n;
  484. double f4 = Math.Round(190*1.0/(1+Math.Exp(-(y)))-95, 4);
  485. double f5 = Math.Round(200*1.0/(1+Math.Exp(-(l)))-100, 4);
  486. lessonItem.rw_fqc =n;
  487. lessonItem.rw_cyc =w;
  488. lessonItem.rw_cx =f4;
  489. lessonItem.rw_cy =f5;
  490. }
  491. // _logger.LogInformation($"{studentLessonData.id}=>任务指数:{f4}\t参与指数:{f5}\t任务次数:{n}\t参与次数:{w}\t");
  492. }
  493. {
  494. //评价相关指数
  495. double n = studentLessonData.rateingRecord.itemRecords.Count()*1.0;
  496. if (n>0)
  497. {
  498. var v = studentLessonData.rateingRecord.itemRecords.Where(x => x.itemType.Equals("Voting"));
  499. double vc = v.Count()*1.0;
  500. var g = studentLessonData.rateingRecord.itemRecords.Where(x => x.itemType.Equals("GrandRating"));
  501. double gc = g.Count()*1.0;
  502. var p = studentLessonData.rateingRecord.itemRecords.Where(x => x.itemType.Equals("PeerAssessment"));
  503. double pc = p.Count()*1.0;
  504. var vg = v.Sum(x => x.itemScore);
  505. var vo = v.Sum(x => x.optCount);
  506. double vs = vc/n* (vg+ vo);
  507. var gg = g.Sum(x => x.itemScore);
  508. var go = g.Sum(x => x.optCount);
  509. double gs = gc/n* (gg+ go);
  510. var pg = p.Sum(x => x.itemScore);
  511. var po = p.Sum(x => x.optCount);
  512. double ps = pc/n* (pg+ po);
  513. double h = vs+ps+gs;
  514. double f3 = Math.Round(190*1.0/(1+Math.Exp(-(h)))-95, 4);
  515. studentLessonData.appraise=f3;
  516. // _logger.LogInformation($"{studentLessonData.id}=>评价能力:{f3}\t评价次数:{n}\t投票次数:{vc}-{vg}-{vo}\t星光次数:{gc}-{gg}-{go}\t互评次数:{pc}-{pg}-{po}");
  517. lessonItem.pj_nl =f3;
  518. lessonItem.pj_cs =n;
  519. lessonItem.pj_vc =vc;
  520. lessonItem.pj_vg =vg;
  521. lessonItem.pj_vo =vo;
  522. lessonItem.pj_gc =gc;
  523. lessonItem.pj_gg =gg;
  524. lessonItem.pj_go =go;
  525. lessonItem.pj_pc =pc;
  526. lessonItem.pj_pg =pg;
  527. lessonItem.pj_po =po;
  528. }
  529. }
  530. {
  531. //协作相关指数
  532. var n= studentLessonData.coworkRecord.itemRecords.Count()*1.0;
  533. if (n>0 )
  534. {
  535. //总的协作成果数
  536. var w = studentLessonData.coworkRecord.itemRecords.Where(x => x.resultWeight>0);
  537. double ss = w.Sum(x => x.itemScore)*1.0;
  538. double sw = w.Sum(x => x.resultWeight)*1.0;
  539. double wc = w.Count()*1.0;
  540. double x= 0.0;
  541. if (wc>0) {
  542. x=sw/(j *wc);
  543. }
  544. double max_xzcg = 40;
  545. double k = (wc*wc/n+x)/n+ wc*(ss/max_xzcg)* (wc/n);
  546. double f6 = Math.Round(190*1.0/(1+Math.Exp(-(k)))-95, 4);
  547. double f7 = Math.Round(200*1.0/(1+Math.Exp(-(k)))-100, 4);
  548. lessonItem.xz_fqc =n;
  549. lessonItem.xz_cyc =wc;
  550. lessonItem.xz_cgf =ss;
  551. lessonItem.xz_cx =f6;
  552. lessonItem.xz_cy =f7;
  553. }
  554. //_logger.LogInformation($"{studentLessonData.id}=>协作指数:{f6}\t参与指数:{f7}\t协作次数:{n}\t参与次数:{wc}\t协作成果分数:{ss}\t{k}");
  555. }
  556. double xx_cx =0,xx_cy=0;
  557. int avg_cx = 0, avg_cy=0;
  558. if (lessonItem.xz_cx>0)
  559. {
  560. avg_cx+=1;
  561. }
  562. if (lessonItem.pj_nl>0)
  563. {
  564. avg_cx+=1;
  565. }
  566. if (lessonItem.rw_cx>0)
  567. {
  568. avg_cx+=1;
  569. }
  570. if (lessonItem.pc_df>0)
  571. {
  572. avg_cx+=1;
  573. }
  574. if (lessonItem.hd_cx>0)
  575. {
  576. avg_cx+=1;
  577. }
  578. xx_cx+=lessonItem.hd_cx * 1.0/avg_cx+ lessonItem.pc_df* 1.0/avg_cx+ lessonItem.rw_cx* 1.0/avg_cx+ lessonItem.pj_nl* 1.0/avg_cx+ lessonItem.xz_cx* 1.0/avg_cx;
  579. if (lessonItem.xz_cy>0)
  580. {
  581. avg_cy+=1;
  582. }
  583. if (lessonItem.pj_nl>0)
  584. {
  585. avg_cy+=1;
  586. }
  587. if (lessonItem.rw_cy>0)
  588. {
  589. avg_cy+=1;
  590. }
  591. if (lessonItem.pc_zd>0)
  592. {
  593. avg_cy+=1;
  594. }
  595. if (lessonItem.hd_cy>0)
  596. {
  597. avg_cy+=1;
  598. }
  599. xx_cy+=lessonItem.hd_cy * 1.0/avg_cy+ lessonItem.pc_zd* 1.0/avg_cy+ lessonItem.rw_cy* 1.0/avg_cy+ lessonItem.pj_nl* 1.0/avg_cy+ lessonItem.xz_cy* 1.0/avg_cy;
  600. lessonItem.xx_cx=xx_cx;
  601. lessonItem.xx_cy=xx_cy;
  602. lessonItems.Add(lessonItem);
  603. }
  604. ExportToExcel(lessonItems, $"F:\\mock-data\\{time}.xlsx");
  605. }
  606. private static void ExportToExcel(List<StudentLessonItem> items, string filePath)
  607. {
  608. ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
  609. using (ExcelPackage package = new ExcelPackage())
  610. {
  611. ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("学生课中数据");
  612. // 获取类的属性
  613. PropertyInfo[] properties = typeof(StudentLessonItem).GetProperties();
  614. // 添加表头
  615. int currentRow = 1;
  616. for (int i = 0; i < properties.Length; i++)
  617. {
  618. string summary = Regex.Replace(GetPropertySummary(properties[i]), @"\s+", "") ;
  619. worksheet.Cells[currentRow, i + 1].Value = summary;
  620. }
  621. // 填充数据
  622. currentRow = 2;
  623. foreach (var item in items)
  624. {
  625. for (int i = 0; i < properties.Length; i++)
  626. {
  627. worksheet.Cells[currentRow, i + 1].Value = properties[i].GetValue(item);
  628. }
  629. currentRow++;
  630. }
  631. // 设置表格样式
  632. worksheet.Cells[worksheet.Dimension.Address].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Left;
  633. worksheet.Cells[worksheet.Dimension.Address].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Top;
  634. // 保存到文件
  635. FileInfo fileInfo = new System.IO.FileInfo(filePath);
  636. package.SaveAs(fileInfo);
  637. }
  638. }
  639. private static string GetPropertySummary(PropertyInfo property)
  640. {
  641. var xmlDocumentationFile = "./x.xml"; // XML注释文件路径
  642. if (System.IO. File.Exists(xmlDocumentationFile))
  643. {
  644. XmlDocument xmlDocument = new XmlDocument();
  645. xmlDocument.Load(xmlDocumentationFile);
  646. XmlNodeList xmlNodeList = xmlDocument.DocumentElement.SelectNodes("//member[@name='P:" + property.DeclaringType.FullName + "." + property.Name + "']");
  647. if (xmlNodeList.Count > 0)
  648. {
  649. XmlNode xmlNode = xmlNodeList[0];
  650. if (xmlNode != null && xmlNode.FirstChild != null)
  651. {
  652. return xmlNode.FirstChild.InnerText;
  653. }
  654. }
  655. }
  656. return property.Name;
  657. }
  658. private static int GetRandomValueByWeight(List<WeightedItem> items)
  659. {
  660. Random random = new Random();
  661. double randomWeight = random.NextDouble();
  662. double cumulativeWeight = 0.0;
  663. foreach (var item in items)
  664. {
  665. cumulativeWeight += item.Weight;
  666. if (randomWeight <= cumulativeWeight)
  667. {
  668. return item.Value;
  669. }
  670. }
  671. // This should not happen if all weights sum up to 1
  672. return items[items.Count - 1].Value;
  673. }
  674. private static double MinMaxNormalization(double min, double max, double x, double minRank = 1, double maxRank = 100)
  675. {
  676. //排名指数计算=( 当前值分数- 298) / (9992 - 298) * (99 - 60) + 60
  677. //将每个人的积分转化为60-100
  678. //排名 = (积分 - 最低积分) / (最高积分 - 最低积分) * (最大排名 - 最小排名) + 最小排名
  679. return Math.Round(x==0 ? 0 : max-min!=0 ? (x - min)*1.0 / (max - min) * (maxRank - minRank) + minRank : (x)*1.0 / (max) * (maxRank - minRank) + minRank,4);
  680. }
  681. /// <summary>
  682. /// 计算当前元素在集合中超过了多少百分比的值
  683. /// </summary>
  684. /// <param name="nums"></param>
  685. /// <param name="curr"></param>
  686. /// <returns></returns>
  687. public static double GetPersent(IEnumerable<double> nums, double curr)
  688. {
  689. int count = 0;
  690. foreach (var op in nums.OrderBy(x => x))
  691. {
  692. if (op < curr)
  693. {
  694. count++;
  695. }
  696. else if (op == curr)
  697. {
  698. count++;
  699. }
  700. else
  701. {
  702. break;
  703. }
  704. }
  705. return count *1.0/ nums.Count() * 100;
  706. }
  707. }
  708. class WeightedItem
  709. {
  710. public int Value { get; set; }
  711. public double Weight { get; set; }
  712. }
  713. class StudentLessonItem
  714. {
  715. /// <summary>
  716. /// 学生id
  717. /// </summary>
  718. public string studentId { get; set; }
  719. /// <summary>
  720. /// 互动发起次数
  721. /// </summary>
  722. public double hd_fqc { get; set; } = 0;
  723. /// <summary>
  724. /// 互动参与次数
  725. /// </summary>
  726. public double hd_cyc { get; set; } = 0;
  727. /// <summary>
  728. /// 互动正确次数
  729. /// </summary>
  730. public double hd_zqc { get; set; } = 0;
  731. /// <summary>
  732. /// 个人计分
  733. /// </summary>
  734. public double gr_jf { get; set; } = 0;
  735. /// <summary>
  736. /// 互动成效指数
  737. /// </summary>
  738. public double hd_cx { get; set; } = 0;
  739. /// <summary>
  740. /// 互动参与指数
  741. /// </summary>
  742. public double hd_cy { get; set; } = 0;
  743. /// <summary>
  744. /// 评测得分率
  745. /// </summary>
  746. public double pc_df { get; set; } = 0;
  747. /// <summary>
  748. /// 评测作答率
  749. /// </summary>
  750. public double pc_zd { get; set; } = 0;
  751. /// <summary>
  752. /// 任务发起次数
  753. /// </summary>
  754. public double rw_fqc { get; set; } = 0;
  755. /// <summary>
  756. /// 任务参与次数
  757. /// </summary>
  758. public double rw_cyc { get; set; } = 0;
  759. /// <summary>
  760. /// 任务成效指数
  761. /// </summary>
  762. public double rw_cx { get; set; } = 0;
  763. /// <summary>
  764. /// 任务参与指数
  765. /// </summary>
  766. public double rw_cy { get; set; } = 0;
  767. /// <summary>
  768. /// 评价发起次数
  769. /// </summary>
  770. public double pj_cs { get; set; } = 0;
  771. /// <summary>
  772. /// 投票发起次数
  773. /// </summary>
  774. public double pj_vc { get; set; } = 0;
  775. /// <summary>
  776. /// 投票得票数
  777. /// </summary>
  778. public double pj_vg { get; set; } = 0;
  779. /// <summary>
  780. /// 投票次数
  781. /// </summary>
  782. public double pj_vo { get; set; } = 0;
  783. /// <summary>
  784. /// 星光发起次数
  785. /// </summary>
  786. public double pj_gc { get; set; } = 0;
  787. /// <summary>
  788. /// 星光得分数
  789. /// </summary>
  790. public double pj_gg { get; set; } = 0;
  791. /// <summary>
  792. /// 星光评分次数
  793. /// </summary>
  794. public double pj_go { get; set; } = 0;
  795. /// <summary>
  796. /// 互评发起次数
  797. /// </summary>
  798. public double pj_pc { get; set; } = 0;
  799. /// <summary>
  800. /// 互评得分数
  801. /// </summary>
  802. public double pj_pg { get; set; } = 0;
  803. /// <summary>
  804. /// 互评评分次数
  805. /// </summary>
  806. public double pj_po { get; set; } = 0;
  807. /// <summary>
  808. /// 评价能力
  809. /// </summary>
  810. public double pj_nl { get; set; } = 0;
  811. /// <summary>
  812. /// 协作发起次数
  813. /// </summary>
  814. public double xz_fqc { get; set; } = 0;
  815. /// <summary>
  816. /// 协作参与次数
  817. /// </summary>
  818. public double xz_cyc { get; set; } = 0;
  819. /// <summary>
  820. /// 协作成果分数
  821. /// </summary>
  822. public double xz_cgf { get; set; } = 0;
  823. /// <summary>
  824. /// 协作能力指数
  825. /// </summary>
  826. public double xz_cx { get; set; } = 0;
  827. /// <summary>
  828. /// 协作参与指数
  829. /// </summary>
  830. public double xz_cy { get; set; } = 0;
  831. /// <summary>
  832. /// 学习成效
  833. /// </summary>
  834. public double xx_cx { get; set; } = 0;
  835. /// <summary>
  836. /// 学习参与
  837. /// </summary>
  838. public double xx_cy { get; set; } = 0;
  839. }
  840. }