MockDataController.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. using Microsoft.AspNetCore.Mvc;
  2. using System.Text.Json;
  3. using TEAMModelOS.SDK.Extension;
  4. using TEAMModelOS.SDK.Models;
  5. using System;
  6. using OfficeOpenXml;
  7. using System.Reflection;
  8. using System.Xml;
  9. using System.Text.RegularExpressions;
  10. using HTEX.Lib.ETL.Lesson;
  11. using OfficeOpenXml.Style;
  12. using DocumentFormat.OpenXml.Spreadsheet;
  13. using OpenXmlPowerTools;
  14. namespace HTEX.Test.Controllers
  15. {
  16. public static class MockDataController
  17. {
  18. public static async Task MockData()
  19. {
  20. #region 数据模拟
  21. //学生人数
  22. int scount = Random.Shared.Next(40, 45);
  23. //互动次数
  24. int icount = Random.Shared.Next(21,22);
  25. //评测次数
  26. int ecount = Random.Shared.Next(0, 3);
  27. //题目个数
  28. int qcount = Random.Shared.Next(8, 15);
  29. //任务次数
  30. int tcount = Random.Shared.Next(1, 3);
  31. //评价次数
  32. int pcount = Random.Shared.Next(1, 4);
  33. //协作次数
  34. int xcount = Random.Shared.Next(1, 3);
  35. string type = "hd";
  36. int count = 0;
  37. switch (true)
  38. {
  39. case bool when type.Equals("hd"):
  40. count=icount;
  41. break;
  42. case bool when type.Equals("pc"):
  43. count=ecount;
  44. break;
  45. case bool when type.Equals("rw"):
  46. count=tcount;
  47. break;
  48. case bool when type.Equals("pj"):
  49. count=pcount;
  50. break;
  51. case bool when type.Equals("xz"):
  52. count=xcount;
  53. break;
  54. }
  55. for (var i = 1; i < count; i++)
  56. {
  57. await StudentLesson(scount,ecount,qcount,i,tcount,pcount,xcount);
  58. }
  59. }
  60. //[HttpPost("student-lesson")]
  61. public static async Task StudentLesson(int scount, int ecount, int qcount, int icount, int tcount, int pcount, int xcount)
  62. {
  63. List<StudentLessonData> students = new List<StudentLessonData>();
  64. //个人计分,小组计分
  65. List<WeightedItem> gpitems = new List<WeightedItem>
  66. {
  67. new WeightedItem { Value = 0, Weight = 0.3 },
  68. new WeightedItem { Value = 2, Weight = 0.1 },
  69. new WeightedItem { Value = 5, Weight = 0.2 },
  70. new WeightedItem { Value = 8, Weight = 0.1 },
  71. new WeightedItem { Value = 3, Weight = 0.05 },
  72. new WeightedItem { Value = 4, Weight = 0.02 },
  73. new WeightedItem { Value = 6, Weight = 0.03 },
  74. new WeightedItem { Value = 7, Weight = 0.2 }
  75. };
  76. //个人计分,小组计分
  77. List<WeightedItem> titems = new List<WeightedItem>
  78. {
  79. new WeightedItem { Value = 0, Weight = 0.4 },
  80. new WeightedItem { Value = 25, Weight = 0.1 },
  81. new WeightedItem { Value = 15, Weight = 0.1 },
  82. new WeightedItem { Value = 10, Weight = 0.05 },
  83. new WeightedItem { Value = 30, Weight = 0.05 },
  84. new WeightedItem { Value = 20, Weight = 0.02 },
  85. new WeightedItem { Value = 40, Weight = 0.03 },
  86. new WeightedItem { Value = 50, Weight = 0.05 },
  87. new WeightedItem { Value = 5, Weight = 0.05 },
  88. new WeightedItem { Value = 35, Weight = 0.05 },
  89. new WeightedItem { Value = 45, Weight = 0.05 },
  90. new WeightedItem { Value = 55, Weight = 0.05 }
  91. };
  92. //for (var i = 0; i<100; i++)
  93. //{
  94. // int randomValue = GetRandomValueByWeight(items);
  95. // Console.WriteLine(randomValue);
  96. //}
  97. //被评价的目标索引
  98. List<List<int>> cworkDist = new List<List<int>>(xcount);
  99. //被评价目标的次数或分数
  100. // List<List<int>> cworkCount = new List<List<int>>(xcount);
  101. for (int i = 0; i < xcount; i++)
  102. {
  103. //乱序取10-20人作为评价目标
  104. var vt = Enumerable.Range(0, scount).OrderBy(x => Random.Shared.Next()).Take(Random.Shared.Next(10, 21));
  105. cworkDist.Add(vt.ToList());
  106. //var counts = new List<int>();
  107. //foreach (var v in vt)
  108. //{
  109. // counts.Add(0);
  110. //}
  111. //cworkCount.Add(counts);
  112. }
  113. //被评价的目标索引
  114. List<List<int>> rateDist = new List<List<int>>(pcount);
  115. //被评价目标的次数或分数
  116. //List<List<int>> rateCount = new List<List<int>>(pcount);
  117. List<string> types = new List<string>();
  118. for (int i = 0; i < pcount; i++)
  119. {
  120. //乱序取10-20人作为评价目标
  121. var vt = Enumerable.Range(0, scount).OrderBy(x => Random.Shared.Next()).Take(Random.Shared.Next(10, 21));
  122. rateDist.Add(vt.ToList());
  123. // var counts = new List<int>();
  124. //foreach (var v in vt)
  125. //{
  126. // counts.Add(0);
  127. //}
  128. //rateCount.Add(counts);
  129. var t = Random.Shared.Next(0, 1);
  130. switch (true)
  131. {
  132. case bool when i==0:
  133. types.Add("Voting");
  134. break;
  135. case bool when i==1:
  136. types.Add("GrandRating");
  137. break;
  138. case bool when i==2:
  139. types.Add("PeerAssessment");
  140. break;
  141. }
  142. }
  143. for (var s = 0; s<scount; s++)
  144. {
  145. StudentLessonData student = new StudentLessonData()
  146. {
  147. index=s,
  148. seatID=$"{s+1}",
  149. id=$"2024{(s+1).ToString("D3")}",
  150. groupId=$"{Random.Shared.Next(1, 5)}",
  151. attend=1,
  152. gscore= GetRandomValueByWeight(gpitems),
  153. pscore= GetRandomValueByWeight(gpitems),
  154. tscore= GetRandomValueByWeight(titems),
  155. };
  156. for (var p = 0; p<pcount; p++)
  157. {
  158. student.rateingRecord.itemRecords.Add(new ItemRecord());
  159. }
  160. students.Add(student);
  161. }
  162. for (var s = 0; s<scount; s++)
  163. {
  164. var student = students[s];
  165. //互动
  166. for (var i = 0; i<icount; i++)
  167. {
  168. int criterion = 10;
  169. var item = new ItemRecord { criterion=criterion };
  170. var w = Random.Shared.Next(0, 4);
  171. switch (true)
  172. {
  173. //未参与
  174. case bool when w==0:
  175. item.resultWeight= InteractWeight.T0;
  176. item.resultType= InteractReultType.T0;
  177. item.itemScore=0;
  178. break;
  179. //参与了
  180. case bool when w==1:
  181. item.resultWeight= InteractWeight.T1;
  182. item.resultType= InteractReultType.T1;
  183. item.itemScore=0;
  184. break;
  185. //部分正确
  186. case bool when w==2:
  187. var score = Random.Shared.Next(1, criterion);
  188. item.resultWeight= MinMaxNormalization(1, criterion, score, InteractWeight.T1, InteractWeight.TT);
  189. item.resultType= InteractReultType.TP;
  190. item.itemScore=0;
  191. break;
  192. //完全正确
  193. case bool when w==3:
  194. item.resultWeight= InteractWeight.TT;
  195. item.resultType= InteractReultType.TT;
  196. item.itemScore=criterion;
  197. break;
  198. }
  199. student.interactRecord.interactRecords.Add(item);
  200. }
  201. //任务
  202. for (var t = 0; t<tcount; t++)
  203. {
  204. var w = Random.Shared.Next(0, 2);
  205. var item = new ItemRecord { };
  206. switch (true)
  207. {
  208. //未参与
  209. case bool when w==0:
  210. item.resultWeight= InteractWeight.T0;
  211. item.resultType= InteractReultType.T0;
  212. item.itemScore=0;
  213. break;
  214. //参加
  215. case bool when w==1:
  216. item.resultWeight= InteractWeight.TT;
  217. item.resultType= InteractReultType.TT;
  218. item.optCount= Random.Shared.Next(0, 4);
  219. item.itemScore=item.optCount*10;
  220. item.isGroup= Random.Shared.Next(0, 6)%2==3;
  221. break;
  222. }
  223. student.taskRecord.taskRate= student.taskRecord.itemRecords.Where(x => x.resultWeight>0).Count()*1.0/tcount;
  224. student.taskRecord.itemRecords.Add(item);
  225. }
  226. //评价
  227. for (var p = 0; p<pcount; p++)
  228. {
  229. var item = student.rateingRecord.itemRecords[p];
  230. var subtype = string.Empty;
  231. item.itemType=types[p];
  232. if (types[p].Equals("PeerAssessment"))
  233. {
  234. var sub = Random.Shared.Next(0, 3);
  235. subtype= sub==0 ? "ALL" : sub==1 ? "Two" : "Self";
  236. }
  237. var w = Random.Shared.Next(0, 3);
  238. switch (true)
  239. {
  240. //未参与
  241. case bool when w==0:
  242. item.resultWeight= InteractWeight.T0;
  243. item.resultType= InteractReultType.T0;
  244. item.itemScore=0;
  245. break;
  246. //参与
  247. case bool when w==1||w==2:
  248. item.resultWeight= InteractWeight.T1;
  249. item.resultType= InteractReultType.T1;
  250. if (item.itemType!.Equals("Voting"))
  251. {
  252. var index = Random.Shared.Next(0, rateDist[p].Count);
  253. //rateCount[p][index]+=1;
  254. students[rateDist[p][index]].rateingRecord.itemRecords[p].itemScore+=1;
  255. }
  256. else
  257. {
  258. if (item.itemType.Equals("PeerAssessment"))
  259. {
  260. var index = Random.Shared.Next(0, rateDist[p].Count);
  261. //操作次数
  262. int opt_count = Random.Shared.Next(1, 2);
  263. for (var count = 0; count<opt_count; count++)
  264. {
  265. var score = Random.Shared.Next(3, 10);
  266. // rateCount[p][index]+=score;
  267. students[rateDist[p][index]].rateingRecord.itemRecords[p].itemScore+=score;
  268. item.optCount+= 1;
  269. }
  270. }
  271. else
  272. {
  273. var index = Random.Shared.Next(0, rateDist[p].Count);
  274. var score = Random.Shared.Next(3, 10);
  275. // rateCount[p][index]+=score;
  276. students[rateDist[p][index]].rateingRecord.itemRecords[p].itemScore+=score;
  277. }
  278. }
  279. break;
  280. }
  281. // student.rateingRecord.itemRecords.Add(item);
  282. }
  283. //个人协作
  284. {
  285. for (var x = 0; x<xcount; x++)
  286. {
  287. int[] r = new int[] { 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1 };
  288. var w = r[Random.Shared.Next(0, r.Length)];
  289. var item = new ItemRecord { };
  290. switch (true)
  291. {
  292. //未参与
  293. case bool when w==0:
  294. item.resultWeight= InteractWeight.T0;
  295. item.resultType= InteractReultType.T0;
  296. item.itemScore=0;
  297. break;
  298. //
  299. case bool when w==1:
  300. item.resultWeight= InteractWeight.TP;
  301. item.resultType= InteractReultType.TP;
  302. 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 };
  303. item.itemScore=q[Random.Shared.Next(0, q.Count())];
  304. break;
  305. }
  306. student.coworkRecord.itemRecords.Add(item);
  307. }
  308. }
  309. //小组协作
  310. {
  311. int[] r = new int[] { 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1 };
  312. var w = r[Random.Shared.Next(0, r.Length)];
  313. var item = new ItemRecord { };
  314. double grpcoworkScore = 0;
  315. switch (true)
  316. {
  317. //未参与
  318. case bool when w==0:
  319. break;
  320. //
  321. case bool when w==1:
  322. 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 };
  323. grpcoworkScore= q[Random.Shared.Next(0, q.Count())]* Random.Shared.Next(0,3 );
  324. student.group_coworkScore.Add(grpcoworkScore);
  325. break;
  326. }
  327. }
  328. //评测
  329. for (var e = 0; e<ecount; e++)
  330. {
  331. StudentExamRecord examRecord = new();
  332. double allocation = 0;
  333. for (var q = 0; q<qcount; q++)
  334. {
  335. var criterion = Random.Shared.Next(5, 10);
  336. allocation+=criterion;
  337. var item = new ItemRecord { criterion =criterion };
  338. var w = Random.Shared.Next(0, 4);
  339. switch (true)
  340. {
  341. //未作答
  342. case bool when w==0:
  343. item.resultWeight= InteractWeight.T0;
  344. item.resultType= InteractReultType.T0;
  345. item.itemScore=0;
  346. break;
  347. //作答错误
  348. case bool when w==1:
  349. item.resultWeight= InteractWeight.T1;
  350. item.resultType= InteractReultType.T1;
  351. item.itemScore=0;
  352. break;
  353. //部分正确
  354. case bool when w==2:
  355. var score = Random.Shared.Next(1, criterion);
  356. item.resultWeight= MinMaxNormalization(1, criterion, score, InteractWeight.T1, InteractWeight.TT); // score * 1.0 / criterion* (InteractWeight.TT-InteractWeight.T1);
  357. item.resultType= InteractReultType.TP;
  358. item.itemScore=score;
  359. break;
  360. //完全正确
  361. case bool when w==3:
  362. item.resultWeight= InteractWeight.TT;
  363. item.resultType= InteractReultType.TT;
  364. item.itemScore=criterion;
  365. break;
  366. }
  367. examRecord.itemRecords.Add(item);
  368. }
  369. examRecord.qcount=qcount;
  370. examRecord.workCount= examRecord.itemRecords.Where(x => x.resultWeight>0).Count();
  371. examRecord.allocation=allocation;
  372. examRecord.score= examRecord.itemRecords.Where(x => x.itemScore>=0).Select(x => x.itemScore).Sum();//得分
  373. examRecord.scoreRate = Math.Round(examRecord.score * 1.0 / allocation, 4);//得分率
  374. examRecord.answerRate= Math.Round(examRecord.itemRecords.Where(x => x.resultWeight>0).Count()*1.0/qcount, 4);//作答率
  375. student.examRecords.Add(examRecord);
  376. }
  377. }
  378. for (var p = 0; p<pcount; p++)
  379. {
  380. var order = students.OrderByDescending(x => x.rateingRecord.itemRecords[p].itemScore);
  381. var maxItems = students.FindAll(x => x.rateingRecord.itemRecords[p].itemScore==order.First().rateingRecord.itemRecords[p].itemScore);
  382. var max = students.FindAll(x => x.rateingRecord.itemRecords[p].itemScore==order.First().rateingRecord.itemRecords[p].itemScore).First().rateingRecord.itemRecords[p].itemScore;
  383. var min = students.FindAll(x => x.rateingRecord.itemRecords[p].itemScore==order.Last().rateingRecord.itemRecords[p].itemScore).First().rateingRecord.itemRecords[p].itemScore;
  384. var sum = students.Sum(x => x.rateingRecord.itemRecords[p].itemScore);
  385. foreach (var student in students)
  386. {
  387. if (student.rateingRecord.itemRecords[p].itemScore>0 && student.rateingRecord.itemRecords[p].optCount>0)
  388. {
  389. student.rateingRecord.itemRecords[p].resultType=InteractReultType.TP;
  390. var data = MinMaxNormalization(min, max, student.rateingRecord.itemRecords[p].itemScore);
  391. student.rateingRecord.itemRecords[p].resultWeight=Math.Round(InteractWeight.T1+ data * 1.0 / 100 * (InteractWeight.TT-InteractWeight.T1), 4);
  392. if (maxItems.Select(x => x.seatID).Contains(student.seatID))
  393. {
  394. student.rateingRecord.itemRecords[p].resultType= InteractReultType.TT;
  395. student.rateingRecord.itemRecords[p].resultWeight= InteractWeight.TT;
  396. }
  397. }
  398. }
  399. }
  400. //个人协作
  401. for (var p = 0; p<xcount; p++)
  402. {
  403. var order = students.OrderByDescending(x => x.coworkRecord.itemRecords[p].itemScore);
  404. var maxItems = students.FindAll(x => x.coworkRecord.itemRecords[p].itemScore==order.First().coworkRecord.itemRecords[p].itemScore);
  405. var max = students.FindAll(x => x.coworkRecord.itemRecords[p].itemScore==order.First().coworkRecord.itemRecords[p].itemScore).First().coworkRecord.itemRecords[p].itemScore;
  406. var min = students.FindAll(x => x.coworkRecord.itemRecords[p].itemScore==order.Last().coworkRecord.itemRecords[p].itemScore).First().coworkRecord.itemRecords[p].itemScore;
  407. var sum = students.Sum(x => x.coworkRecord.itemRecords[p].itemScore);
  408. foreach (var student in students)
  409. {
  410. if (student.coworkRecord.itemRecords[p].itemScore>0)
  411. {
  412. student.coworkRecord.itemRecords[p].resultType=InteractReultType.TP;
  413. var data = MinMaxNormalization(min, max, student.coworkRecord.itemRecords[p].itemScore);
  414. student.coworkRecord.itemRecords[p].resultWeight=Math.Round(InteractWeight.T1+ data * 1.0 / 100 * (InteractWeight.TT-InteractWeight.T1), 4);
  415. if (maxItems.Select(x => x.seatID).Contains(student.seatID))
  416. {
  417. student.coworkRecord.itemRecords[p].resultType= InteractReultType.TT;
  418. student.coworkRecord.itemRecords[p].resultWeight= InteractWeight.TT;
  419. }
  420. }
  421. }
  422. }
  423. #endregion 数据模拟
  424. string jsons = await System.IO.File.ReadAllTextAsync("F:\\lesson-local\\analysis\\analysis.json");
  425. long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
  426. LessonDataAnalysisCluster lessonDataAnalysis = jsons.ToObject<LessonDataAnalysisCluster>();
  427. var lessonItems= LessonETLService. ProcessStudentDataV2(students, lessonDataAnalysis);
  428. var excleFile = $"F:\\mock-data\\{time}.xlsx";
  429. var runtimePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  430. XmlDocument xmlDocument = new XmlDocument();
  431. xmlDocument.Load($"{runtimePath}\\summary.xml");
  432. List<string> noStujson = new List<string>();
  433. await LessonETLService.ExportToExcel(lessonItems, excleFile, xmlDocument);
  434. try {
  435. await System.IO.File.WriteAllTextAsync($"F:\\mock-data\\{time}.json", new { scount, ecount, qcount, icount, tcount, pcount, xcount, students }.ToJsonString());
  436. } catch (Exception ex) {
  437. Console.WriteLine(scount);
  438. }
  439. //return Ok(new { scount, ecount, qcount, icount, tcount, pcount, xcount, students });
  440. }
  441. private static string GetPropertySummary(PropertyInfo property)
  442. {
  443. var xmlDocumentationFile = "./x.xml"; // XML注释文件路径
  444. if (System.IO. File.Exists(xmlDocumentationFile))
  445. {
  446. XmlDocument xmlDocument = new XmlDocument();
  447. xmlDocument.Load(xmlDocumentationFile);
  448. XmlNodeList xmlNodeList = xmlDocument.DocumentElement.SelectNodes("//member[@name='P:" + property.DeclaringType.FullName + "." + property.Name + "']");
  449. if (xmlNodeList.Count > 0)
  450. {
  451. XmlNode xmlNode = xmlNodeList[0];
  452. if (xmlNode != null && xmlNode.FirstChild != null)
  453. {
  454. return xmlNode.FirstChild.InnerText;
  455. }
  456. }
  457. }
  458. return property.Name;
  459. }
  460. private static int GetRandomValueByWeight(List<WeightedItem> items)
  461. {
  462. Random random = new Random();
  463. double randomWeight = random.NextDouble();
  464. double cumulativeWeight = 0.0;
  465. foreach (var item in items)
  466. {
  467. cumulativeWeight += item.Weight;
  468. if (randomWeight <= cumulativeWeight)
  469. {
  470. return item.Value;
  471. }
  472. }
  473. // This should not happen if all weights sum up to 1
  474. return items[items.Count - 1].Value;
  475. }
  476. private static double MinMaxNormalization(double min, double max, double x, double minRank = 1, double maxRank = 100)
  477. {
  478. //排名指数计算=( 当前值分数- 298) / (9992 - 298) * (99 - 60) + 60
  479. //将每个人的积分转化为60-100
  480. //排名 = (积分 - 最低积分) / (最高积分 - 最低积分) * (最大排名 - 最小排名) + 最小排名
  481. 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);
  482. }
  483. /// <summary>
  484. /// 计算当前元素在集合中超过了多少百分比的值
  485. /// </summary>
  486. /// <param name="nums"></param>
  487. /// <param name="curr"></param>
  488. /// <returns></returns>
  489. public static double GetPersent(IEnumerable<double> nums, double curr)
  490. {
  491. int count = 0;
  492. foreach (var op in nums.OrderBy(x => x))
  493. {
  494. if (op < curr)
  495. {
  496. count++;
  497. }
  498. else if (op == curr)
  499. {
  500. count++;
  501. }
  502. else
  503. {
  504. break;
  505. }
  506. }
  507. return count *1.0/ nums.Count() * 100;
  508. }
  509. }
  510. class WeightedItem
  511. {
  512. public int Value { get; set; }
  513. public double Weight { get; set; }
  514. }
  515. }