LessonSticsController.cs 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364
  1. using Microsoft.AspNetCore.Http;
  2. using Microsoft.AspNetCore.Mvc;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7. using TEAMModelOS.Models;
  8. using TEAMModelOS.SDK.DI;
  9. using Microsoft.Extensions.Options;
  10. using Azure.Cosmos;
  11. using System.Text.Json;
  12. using TEAMModelOS.SDK.Models.Cosmos.Common;
  13. using TEAMModelOS.SDK.Models;
  14. using TEAMModelBI.Models;
  15. using TEAMModelOS.SDK.Extension;
  16. using System.Text;
  17. using TEAMModelBI.Tool;
  18. using MathNet.Numerics.LinearAlgebra.Double;
  19. using TEAMModelBI.Tool.CosmosBank;
  20. using TEAMModelOS.SDK.Context.BI;
  21. using TEAMModelOS.SDK.Models.Service.BI;
  22. using TEAMModelOS.SDK.Context.Constant;
  23. using TEAMModelOS.SDK.Models.Cosmos.BI.BISchool;
  24. using TEAMModelOS.SDK.Models.Cosmos.BI.BITable;
  25. using StackExchange.Redis;
  26. using System.Threading;
  27. namespace TEAMModelBI.Controllers.Census
  28. {
  29. [Route("lesson")]
  30. [ApiController]
  31. public class LessonSticsController : ControllerBase
  32. {
  33. private readonly AzureCosmosFactory _azureCosmos;
  34. private readonly AzureStorageFactory _azureStorage;
  35. private readonly AzureRedisFactory _azureRedis;
  36. private readonly DingDing _dingDing;
  37. private readonly Option _option;
  38. public LessonSticsController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureFactory, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option)
  39. {
  40. _azureCosmos = azureCosmos;
  41. _azureStorage = azureFactory;
  42. _azureRedis = azureRedis;
  43. _dingDing = dingDing;
  44. _option = option?.Value;
  45. }
  46. /// <summary>
  47. /// 依据区级ID分析该去所有学校课例 //已对接
  48. /// </summary>
  49. /// <param name="jsonElement"></param>
  50. /// <returns></returns>
  51. [ProducesDefaultResponseType]
  52. [HttpPost("get-schoolan")]
  53. public async Task<IActionResult> GetSchoolsAn(JsonElement jsonElement)
  54. {
  55. if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
  56. //jsonElement.TryGetProperty("site", out JsonElement site); //分开部署,就不需要,一站多用时,取消注释
  57. var (lWeekS, lWeekE) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "week");
  58. var (monthS, monthE) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "month");
  59. var cosmosClient = _azureCosmos.GetCosmosClient();
  60. ////分开部署,就不需要,一站多用时,取消注释
  61. //if ($"{site}".Equals(BIConst.Global))
  62. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  63. List<AreaSchools> areaSchools = new();
  64. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<AreaSchools>(queryText: $"select c.id,c.name,c.picture from c where c.areaId='{areaId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base")}))
  65. {
  66. areaSchools.Add(item);
  67. }
  68. if (areaSchools.Count > 0)
  69. {
  70. foreach (var item in areaSchools)
  71. {
  72. item.allCnt = await CommonFind.GetSqlValueCount(cosmosClient,"School",$"select value(count(c.id)) from c ",$"LessonRecord-{item.id}");
  73. item.weekCnt = await CommonFind.GetSqlValueCount(cosmosClient, "School", $"select value(count(c.id)) from c where c.startTime >= {lWeekS} and c.startTime <= {lWeekE}", $"LessonRecord-{item.id}");
  74. item.monthCnt = await CommonFind.GetSqlValueCount(cosmosClient, "School", $"select value(count(c.id)) from c where c.startTime >= {monthS} and c.startTime <= {monthE}", $"LessonRecord-{item.id}");
  75. }
  76. areaSchools = areaSchools.Where(w => (w.allCnt != 0 || w.weekCnt != 0 || w.monthCnt != 0)).ToList();
  77. }
  78. return Ok(new { state = RespondCode.Ok, areaSchools });
  79. }
  80. /// <summary>
  81. /// 统计区级一年每周的课例数据趋势 //已对接
  82. /// </summary>
  83. /// <param name="jsonElement"></param>
  84. /// <returns></returns>
  85. [ProducesDefaultResponseType]
  86. [HttpPost("get-weekcount")]
  87. public async Task<IActionResult> GetWeekCount(JsonElement jsonElement)
  88. {
  89. jsonElement.TryGetProperty("areaId", out JsonElement areaId);
  90. //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
  91. //Dictionary<int, double> weeks = new();
  92. List<double> weeks = new();
  93. var cosmosClient = _azureCosmos.GetCosmosClient();
  94. ////分开部署,就不需要,一站多用时,取消注释
  95. //if ($"{site}".Equals(BIConst.Global))
  96. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  97. int year = DateTimeOffset.UtcNow.Year;
  98. int dayOfweek = (int)DateTimeOffset.Parse($"{year}-1-1").DayOfWeek;
  99. int currentTime = DateTimeOffset.UtcNow.DayOfYear / 7 + 1;
  100. int currentTime1 = DateTimeOffset.UtcNow.DayOfYear / 7;
  101. var sqlTxts = "select value(c) from c";
  102. List<LessonCount> scount = new();
  103. List<LessonCount> tcount = new();
  104. StringBuilder sqlTxt = new("select c.id from c");
  105. if (!string.IsNullOrEmpty($"{areaId}"))
  106. {
  107. sqlTxt.Append($" where c.areaId='{areaId}'");
  108. }
  109. List<string> schools = await CommonFind.FindSchoolIds(cosmosClient, sqlTxt.ToString(), "Base");
  110. foreach (var sId in schools)
  111. {
  112. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<LessonCount>(queryText: sqlTxts, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{sId}-{year}") }))
  113. {
  114. scount.Add(item);
  115. }
  116. }
  117. List<string> teacIds = await CommonFind.FindRolesId(cosmosClient, schools);
  118. foreach (var tId in teacIds)
  119. {
  120. var sqlTxtt = $"select value(c) from c where c.id='{tId}'";
  121. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<LessonCount>(queryText: sqlTxtt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{year}") }))
  122. {
  123. tcount.Add(item);
  124. }
  125. }
  126. int days = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? days = 366 : days = 365;
  127. List<List<double>> lessons = new();
  128. if (scount.Count > 0)
  129. {
  130. foreach (LessonCount item in scount)
  131. {
  132. lessons.Add(item.beginCount);
  133. }
  134. }
  135. if (tcount.Count > 0)
  136. {
  137. foreach (LessonCount item in tcount)
  138. {
  139. lessons.Add(item.beginCount);
  140. }
  141. }
  142. if (lessons.Count > 0)
  143. {
  144. var bmatrix = DenseMatrix.OfColumns(lessons);
  145. //开学第一周周内开课
  146. if (dayOfweek == 0)
  147. {
  148. dayOfweek = 7;
  149. }
  150. //第一周多少天
  151. var dd = 7 - dayOfweek + 1;
  152. //一年有几周
  153. int sweeks = days / 7;
  154. //查询天数
  155. int dayYear = 0;
  156. if (currentTime > 0)
  157. {
  158. for (int i = 0; i <= currentTime; i++)
  159. {
  160. if (i == 0)
  161. {
  162. var bsum = bmatrix.SubMatrix(dayYear, dd, 0, bmatrix.ColumnCount).ColumnSums().Sum();
  163. dayYear += dd;
  164. //weeks.Add(i, bsum);
  165. weeks.Add(bsum);
  166. }
  167. else
  168. {
  169. var bsum = bmatrix.SubMatrix(dayYear, 7, 0, bmatrix.ColumnCount).ColumnSums().Sum();
  170. dayYear += 7;
  171. //weeks.Add(i, bsum);
  172. weeks.Add(bsum);
  173. }
  174. }
  175. }
  176. //最后一周是否有余
  177. int stary = days - dayYear;
  178. if (stary > 0 && stary < 7)
  179. {
  180. var bsum = bmatrix.SubMatrix(dayYear, stary - 1, 0, bmatrix.ColumnCount).ColumnSums().Sum();
  181. //weeks.Add((sweeks + 1), bsum);
  182. weeks.Add(bsum);
  183. }
  184. }
  185. return Ok(new { state = 200, weeks });
  186. }
  187. /// <summary>
  188. /// 统计所有区级的课例和活动 //已对接
  189. /// </summary>
  190. /// <returns></returns>
  191. [ProducesDefaultResponseType]
  192. [HttpPost("get-allarea")]
  193. public async Task<IActionResult> GetAllArea(JsonElement jsonElement)
  194. {
  195. //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
  196. var cosmosClient = _azureCosmos.GetCosmosClient();
  197. //if ($"{site}".Equals(BIConst.Global))
  198. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  199. List<AllAreaInfo> areaInfos = new();
  200. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Normal").GetItemQueryIterator<AllAreaInfo>(queryText: $"select c.id,c.name,c.standard,c.standardName from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base-Area") }))
  201. {
  202. areaInfos.Add(item);
  203. }
  204. foreach (var area in areaInfos)
  205. {
  206. string comSql = $"select value(c.id) from c where c.areaId='{area.id}'";
  207. List<string> scIds = await CommonFind.GetValueSingle(cosmosClient, "School", comSql, "Base");
  208. int tLessCnt = 0;
  209. int tActCnt = 0;
  210. string Sql = $"select value(c.id) from c where c.areaId='{area.id}'";
  211. if (scIds.Count > 0)
  212. {
  213. comSql = BICommonWay.ManyScSql("c.school", scIds);
  214. string lesSql = $"select value(count(c.id)) from c where c.pk='LessonRecord' and {comSql}";
  215. tLessCnt = await CommonFind.GetSqlValueCount(cosmosClient, new List<string>() { "School", "Teacher" }, lesSql);
  216. comSql = BICommonWay.ManyScSql(" and c.school", scIds);
  217. tActCnt = await ActivityWay.GetCnt(cosmosClient, condSql: comSql);
  218. }
  219. area.lessCnt = tLessCnt;
  220. area.actCnt = tActCnt;
  221. area.allCnt = tLessCnt + tActCnt;
  222. }
  223. areaInfos = areaInfos.Where(w => w.lessCnt != 0 && w.actCnt != 0).ToList();
  224. return Ok(new { state = 200, areaInfos });
  225. }
  226. /// <summary>
  227. /// 查询课例数量
  228. /// </summary>
  229. /// <param name="jsonElement"></param>
  230. /// <returns></returns>
  231. [ProducesDefaultResponseType]
  232. [HttpPost("get-count")]
  233. public async Task<IActionResult> GetCount(JsonElement jsonElement)
  234. {
  235. jsonElement.TryGetProperty("tmdId", out JsonElement tmdId);
  236. if (!jsonElement.TryGetProperty("term", out JsonElement term)) return BadRequest();
  237. //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
  238. var cosmosClient = _azureCosmos.GetCosmosClient();
  239. //if ($"{site}".Equals(BIConst.Global))
  240. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  241. var (start, end) = TimeHelper.GetTermStartOrEnd(DateTime.Now);
  242. object totals = new();
  243. StringBuilder sqlTxt = new($"select value(COUNT(c.id)) from c where c.pk='LessonRecord'");
  244. if (!string.IsNullOrEmpty($"{tmdId}"))
  245. {
  246. List<SchoolLen> schoolLens = new();
  247. List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
  248. foreach (var itemId in schoolIds)
  249. {
  250. School school = new();
  251. var response = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(itemId, new PartitionKey("Base"));
  252. if (response.Status == 200)
  253. {
  254. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  255. school = json.ToObject<School>();
  256. }
  257. SchoolLen schoolLen = new()
  258. {
  259. id = itemId,
  260. name =
  261. school.name != null ? school.name : itemId
  262. };
  263. //string sqlTxt = $"SELECT COUNT(c.id) AS totals FROM c WHERE c.code='LessonRecord-{itemId}'";
  264. sqlTxt.Append($" WHERE c.code='LessonRecord-{itemId}'");
  265. if (bool.Parse($"{term}") == true)
  266. {
  267. sqlTxt.Append($" and c.startTime >= {start} and c.startTime <= {end}");
  268. }
  269. schoolLen.totals = await CommonFind.GetSqlValueCount(cosmosClient, "School", sqlTxt.ToString());
  270. schoolLens.Add(schoolLen);
  271. }
  272. totals = schoolLens;
  273. }
  274. else
  275. {
  276. sqlTxt.Append($" where c.pk='LessonRecord'");
  277. if (bool.Parse($"{term}") == true)
  278. {
  279. sqlTxt.Append($" and c.startTime >= {start} and c.startTime <= {end}");
  280. }
  281. totals = await CommonFind.GetSqlValueCount(cosmosClient, new List<string>() { "School", "Teacher" }, sqlTxt.ToString());
  282. }
  283. return Ok(new { state = 200, totals });
  284. }
  285. /// <summary>
  286. /// 管家所关联的课例数据
  287. /// </summary>
  288. /// <param name="jsonElement"></param>
  289. /// <returns></returns>
  290. [ProducesDefaultResponseType]
  291. [HttpPost("get-assiist")]
  292. public async Task<IActionResult> GetAssiist(JsonElement jsonElement)
  293. {
  294. try
  295. {
  296. if (!jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) return BadRequest();
  297. //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
  298. var cosmosClient = _azureCosmos.GetCosmosClient();
  299. ////分开部署,就不需要,一站多用时,取消注释
  300. //if ($"{site}".Equals(BIConst.Global))
  301. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  302. List<SchoolLen> schoolLens = new();
  303. List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
  304. foreach (var itemId in schoolIds)
  305. {
  306. School school = new();
  307. var response = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(itemId, new PartitionKey("Base"));
  308. if (response.Status == 200)
  309. {
  310. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  311. school = json.ToObject<School>();
  312. }
  313. SchoolLen schoolLen = new() { id = itemId, name = school != null ? school.name : itemId };
  314. string sqlTxt = $"SELECT value(COUNT(c.id)) FROM c WHERE c.code='LessonRecord-{itemId}'";
  315. schoolLen.totals = await CommonFind.GetSqlValueCount(cosmosClient, "School", sqlTxt);
  316. schoolLens.Add(schoolLen);
  317. }
  318. return Ok(new { state = 200, schoolLens });
  319. }
  320. catch (Exception ex)
  321. {
  322. await _dingDing.SendBotMsg($"BI, {_option.Location} /lesson/get-assiist {ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  323. return BadRequest();
  324. }
  325. }
  326. /// <summary>
  327. /// 统计所有的课例数据
  328. /// </summary>
  329. /// <returns></returns>
  330. [ProducesDefaultResponseType]
  331. [HttpPost("get-diccount")]
  332. public async Task<IActionResult> GetDicCount(JsonElement jsonElement)
  333. {
  334. jsonElement.TryGetProperty("tmdId", out JsonElement tmdId);
  335. //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
  336. var cosmosClient = _azureCosmos.GetCosmosClient();
  337. ////分开部署,就不需要,一站多用时,取消注释
  338. //if ($"{site}".Equals(BIConst.Global))
  339. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  340. if (!string.IsNullOrEmpty($"{tmdId}"))
  341. {
  342. jsonElement.TryGetProperty("years", out JsonElement _years);
  343. int years = DateTime.UtcNow.Year;
  344. if (!string.IsNullOrEmpty($"{_years}"))
  345. {
  346. years = _years.GetInt32();
  347. }
  348. List<SchoolLen> schoolLens = new();
  349. List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
  350. foreach (string schoolId in schoolIds)
  351. {
  352. School school = new();
  353. var response = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(schoolId, new PartitionKey("Base"));
  354. if (response.Status == 200)
  355. {
  356. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  357. school = json.ToObject<School>();
  358. }
  359. SchoolLen schoolLen = new() { id = schoolId, name = school != null ? school.name : schoolId };
  360. List<List<double>> begin = new();
  361. await foreach (var lcount in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<LessonCount>(queryText: "select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{schoolId}-{years}") }))
  362. {
  363. begin.Add(lcount.beginCount);
  364. }
  365. schoolLen.totals = (long)DenseMatrix.OfColumns(begin).ColumnSums().Sum();
  366. schoolLens.Add(schoolLen);
  367. }
  368. return Ok(new { state = 200, schoolLens });
  369. }
  370. else
  371. {
  372. List<List<double>> begin = new();
  373. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<LessonCount>(queryText: "select value(c) from c where c.pk='LessonCount'", requestOptions: new QueryRequestOptions() { }))
  374. {
  375. begin.Add(item.beginCount);
  376. }
  377. var count = DenseMatrix.OfColumns(begin).ColumnSums().Sum();
  378. return Ok(new { state = 200, count });
  379. }
  380. }
  381. /// <summary>
  382. /// 顾问关联的学校统计本学期的课例
  383. /// </summary>
  384. /// <param name="jsonElement"></param>
  385. /// <returns></returns>
  386. [HttpPost("get-termcount")]
  387. public async Task<IActionResult> GetTermCount(JsonElement jsonElement)
  388. {
  389. if (jsonElement.TryGetProperty("tmdId", out JsonElement tmdId)) BadRequest();
  390. //jsonElement.TryGetProperty("site", out JsonElement site); //分开部署,就不需要,一站多用时,取消注释
  391. var cosmosClient = _azureCosmos.GetCosmosClient();
  392. ////分开部署,就不需要,一站多用时,取消注释
  393. //if ($"{site}".Equals(BIConst.Global))
  394. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  395. List<SchoolLen> schoolLens = new();
  396. List<string> schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"{tmdId}");
  397. foreach (var scid in schoolIds)
  398. {
  399. School school = new();
  400. var response = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(scid, new PartitionKey("Base"));
  401. if (response.Status == 200)
  402. {
  403. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  404. school = json.ToObject<School>();
  405. }
  406. SchoolLen schoolLen = new() { id = scid, name = !string.IsNullOrEmpty(school.name) ? school.name : scid };
  407. DateTimeOffset dateTime = DateTimeOffset.UtcNow;
  408. int year = (dateTime.Month <= 8 && dateTime.Month >= 3) ? dateTime.Year : dateTime.Year - 1;
  409. long stime = DateTimeOffset.Parse($"{year}-9-1").ToUnixTimeMilliseconds();
  410. //long etime = DateTimeOffset.Parse($"{year}-2-{((year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 29 : 28)}").ToUnixTimeMilliseconds();
  411. double totals = 0;
  412. var syear = DateTimeOffset.FromUnixTimeMilliseconds(stime).Year;
  413. var tyear = DateTimeOffset.UtcNow.Year;
  414. var tday = DateTimeOffset.UtcNow.DayOfYear;
  415. //今年多少天
  416. int tdays = (tyear % 4 == 0 && tyear % 100 != 0 || tyear % 400 == 0) ? 366 : 365;
  417. //去年多少天
  418. int pydays = (syear % 4 == 0 && syear % 100 != 0 || syear % 400 == 0) ? 366 : 365;
  419. List<LessonCount> scount = new();
  420. List<LessonCount> tcount = new();
  421. DenseMatrix dense = null;
  422. var queryClass = $"select value(c) from c ";
  423. await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonCount>(queryText: queryClass, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{scid}-{syear}") }))
  424. {
  425. scount.Add(item);
  426. }
  427. if (tyear > syear)
  428. {
  429. await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonCount>(queryText: queryClass, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonCount-{scid}-{tyear}") }))
  430. {
  431. tcount.Add(item);
  432. }
  433. if (tcount.Count > 0)
  434. {
  435. List<List<double>> be = new();
  436. foreach (var item in tcount)
  437. {
  438. be.Add(item.beginCount);
  439. }
  440. dense = DenseMatrix.OfColumns(be);
  441. }
  442. }
  443. if (scount.Count > 0)
  444. {
  445. List<List<double>> begin = new();
  446. foreach (LessonCount lesson in scount)
  447. {
  448. begin.Add(lesson.beginCount);
  449. }
  450. var matrix = DenseMatrix.OfColumns(begin);
  451. //求本学期
  452. var sdays = DateTimeOffset.FromUnixTimeMilliseconds(stime).DayOfYear;
  453. if (tday - sdays < 0)
  454. {
  455. //var tmatrix = DenseMatrix.OfColumns(scount.beginCount);
  456. //跨年后开始到本学期结束
  457. double endMonth = 0;
  458. if (null != dense)
  459. {
  460. endMonth = dense.SubMatrix(0, tday, 0, dense.ColumnCount).ColumnSums().Sum();
  461. }
  462. var startMonth = matrix.SubMatrix(sdays - 1, pydays - sdays, 0, matrix.ColumnCount).ColumnSums().Sum();
  463. totals = (endMonth + startMonth);
  464. }
  465. else
  466. {
  467. var allMonth = matrix.SubMatrix(sdays - 1, tday - sdays + 1, 0, matrix.ColumnCount).ColumnSums().Sum();
  468. totals = allMonth;
  469. }
  470. }
  471. schoolLen.totals = (long)totals;
  472. schoolLens.Add(schoolLen);
  473. }
  474. return Ok(new { state = 200, schoolLens });
  475. }
  476. /// <summary>
  477. /// 统计区级课例
  478. /// </summary>
  479. /// <param name="jsonElement"></param>
  480. /// <returns></returns>
  481. [ProducesDefaultResponseType]
  482. [HttpPost("get-areacount")]
  483. public async Task<IActionResult> GetAreaCount(JsonElement jsonElement)
  484. {
  485. if(!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
  486. //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
  487. List<string> schools = new();
  488. var cosmosClient = _azureCosmos.GetCosmosClient();
  489. ////分开部署,就不需要,一站多用时,取消注释
  490. //if ($"{site}".Equals(BIConst.Global))
  491. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  492. StringBuilder scSqlTxt = new("select c.id from c");
  493. if (!string.IsNullOrEmpty($"{areaId}"))
  494. {
  495. scSqlTxt.Append($" where c.areaId='{areaId}'");
  496. }
  497. schools = await CommonFind.FindSchoolIds(cosmosClient, scSqlTxt.ToString(), "Base");
  498. //所有的课程记录
  499. List<LessonRecord> records = new();
  500. List<string> tecIds = new();
  501. foreach (var school in schools)
  502. {
  503. string sqlTxt = $"select value(c) from c where c.code='LessonRecord-{school}'";
  504. await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonRecord>(queryText: sqlTxt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonRecord-{school}") }))
  505. {
  506. records.Add(item);
  507. }
  508. }
  509. tecIds = await CommonFind.FindRolesId(cosmosClient, schools);
  510. foreach (var tecId in tecIds)
  511. {
  512. string sqlTxt = $"select value(c) from c where c.id='{tecId}'";
  513. await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<LessonRecord>(queryText: sqlTxt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"LessonRecord") }))
  514. {
  515. records.Add(item);
  516. }
  517. }
  518. int dayCount = 0;
  519. var (dayStart, dayEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow);
  520. records.ForEach(x => { if (x.startTime >= dayStart && x.startTime <= dayEnd) dayCount += 1; });
  521. int weekCount = 0;
  522. var (weekStart, weekEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "week");
  523. records.ForEach(x => { if (x.startTime >= weekStart && x.startTime <= weekEnd) weekCount += 1; });
  524. int monthCount = 0;
  525. var (monthStart, monthEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "month");
  526. records.ForEach(x => { if (x.startTime >= monthStart && x.startTime <= monthEnd) monthCount += 1; });
  527. int termCount = 0;
  528. var (termStart, termEnd) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "term");
  529. records.ForEach(x => { if (x.startTime >= termStart && x.startTime <= termEnd) termCount += 1; });
  530. double teachCount = records.Where(r => r.tmdid != null).Where((x, i) => records.FindIndex(z => z.tmdid == x.tmdid) == i).ToList().Count;
  531. return Ok(new { state = 200, lessonCount = records.Count, teachCount, dayCount, weekCount, monthCount, termCount });
  532. }
  533. /// <summary>
  534. /// 依据课例Id获取课例详情 数据管理工具——查询工具
  535. /// </summary>
  536. /// <param name="jsonElement"></param>
  537. /// <returns></returns>
  538. [ProducesDefaultResponseType]
  539. [HttpPost("get-info")]
  540. public async Task<IActionResult> GetInfo(JsonElement jsonElement)
  541. {
  542. if (!jsonElement.TryGetProperty("lessonId", out JsonElement lessonId)) return BadRequest();
  543. //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
  544. var cosmosClient = _azureCosmos.GetCosmosClient();
  545. ////分开部署,就不需要,一站多用时,取消注释
  546. //if ($"{site}".Equals(BIConst.Global))
  547. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  548. List<object> lessons = new();
  549. string sqlTxt = $"select * from c where c.id='{lessonId}'";
  550. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: sqlTxt, requestOptions: new QueryRequestOptions() { }))
  551. {
  552. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  553. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  554. {
  555. lessons.Add(obj.ToObject<object>());
  556. }
  557. }
  558. return Ok(new { state = 200, lessons });
  559. }
  560. /// <summary>
  561. /// 获取课例统计数据
  562. /// </summary>
  563. /// <param name="jsonElement"></param>
  564. /// <returns></returns>
  565. [ProducesDefaultResponseType]
  566. [HttpPost("get-less")]
  567. public async Task<IActionResult> GetLess(JsonElement jsonElement)
  568. {
  569. if (!jsonElement.TryGetProperty("school", out JsonElement school)) return BadRequest();
  570. var table = _azureStorage.GetCloudTableClient().GetTableReference("BIStats");
  571. var tableSql = $" PartitionKey eq 'LessonHour' and school eq '{school}'";
  572. //lambda 表达式排序
  573. var lessStats = await table.QueryWhereString<LessStats>(tableSql.ToString());
  574. DenseMatrix openDense = null;
  575. DenseMatrix lessDense = null;
  576. List<List<double>> tempOpens = new();
  577. List<List<double>> tempLesss = new();
  578. foreach (var item in lessStats)
  579. {
  580. if (item.open != null)
  581. {
  582. List<double> opens = item.open.Split(',').ToList().ConvertAll(c => Convert.ToDouble(c));
  583. tempOpens.Add(opens);
  584. }
  585. if (item.lesson != null)
  586. {
  587. List<double> lesss = item.lesson.Split(',').ToList().ConvertAll(c => Convert.ToDouble(c));
  588. tempLesss.Add(lesss);
  589. }
  590. }
  591. openDense = DenseMatrix.OfColumns(tempOpens);
  592. lessDense = DenseMatrix.OfColumns(tempLesss);
  593. return Ok(new { state = 200, openDense, lessDense });
  594. }
  595. /// <summary>
  596. /// 测试 通过时间戳保存统计类型接口
  597. /// </summary>
  598. /// <param name="jsonElement"></param>
  599. /// <returns></returns>
  600. [ProducesDefaultResponseType]
  601. [HttpPost("set-bilessonstats")]
  602. public async Task<IActionResult> SetBILeesonStats(JsonElement jsonElement)
  603. {
  604. if (!jsonElement.TryGetProperty("unix", out JsonElement unix)) return BadRequest();
  605. if (!jsonElement.TryGetProperty("num", out JsonElement num)) return BadRequest();
  606. jsonElement.TryGetProperty("schoolId", out JsonElement schoolId);
  607. jsonElement.TryGetProperty("type", out JsonElement type);
  608. jsonElement.TryGetProperty("unixs", out JsonElement unixs);
  609. var cosmosClient = _azureCosmos.GetCosmosClient();
  610. DateTime expireYear = DateTime.UtcNow.AddYears(1); //一个月到期
  611. var UUID = Guid.NewGuid().ToString();
  612. List<long> unixsT = unixs.ToObject<List<long>>();
  613. RedisValue token = Environment.MachineName;
  614. foreach (var item in unixsT)
  615. {
  616. //await SetBILeesonStats(cosmosClient, item, num.GetInt32(), type: type.GetInt32(), schoolId: schoolId.GetString());
  617. //await BILeeson.SetCosmosDBStats(cosmosClient, _azureRedis, _dingDing, item, num.GetInt32(), type: type.GetInt32(), schoolId: schoolId.GetString());
  618. await BILeesonService.SetTableStats(_azureStorage, _azureRedis, _dingDing, item, num.GetInt32(), type: type.GetInt32(), "school", schoolId: schoolId.GetString());
  619. }
  620. //await BILeeson.SetBILeesonStats(cosmosClient, _azureRedis, unix.GetInt64(), num.GetInt32(), type: type.GetInt32(), schoolId: schoolId.GetString());
  621. //await SetBILeesonStats(cosmosClient, unix.GetInt64(), num.GetInt32(), type: -1, schoolId: schoolId.GetString());
  622. return Ok(new { state = 200 });
  623. }
  624. /// <summary>
  625. /// 通过时间戳保存统计类型
  626. /// </summary>
  627. /// <param name="cosmosClient">连接字符串</param>
  628. /// <param name="unix">时间戳</param>
  629. /// <param name="num">加减数量,可为负数</param>
  630. /// <param name="type">课例类型,0开课 1 课例</param>
  631. /// <param name="schoolId">学校ID,可不传</param>
  632. /// <returns></returns>
  633. public static async Task SetBILeesonStats(CosmosClient cosmosClient, long unix, int num, int type = 0, string schoolId = null)
  634. {
  635. //Monitor.TryEnter(unix); //锁对象
  636. SemaphoreSlim slimlock = new(1, 1); //对可同时访问资源或资源池的线程数加以限制
  637. await slimlock.WaitAsync();
  638. DateTimeOffset dateTime = DateTimeOffset.FromUnixTimeMilliseconds(unix);
  639. int year, month, day, hour, days;
  640. year = dateTime.Year;
  641. month = dateTime.Month;
  642. day = dateTime.Day;
  643. hour = dateTime.Hour;
  644. string hourId = $"{year}{month.ToString().PadLeft(2, '0')}{day.ToString().PadLeft(2, '0')}";
  645. var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  646. days = dateTime.DayOfYear;
  647. double[] daDays = new double[yearDays];
  648. daDays[days] = num;
  649. List<double> yDays = new(daDays);
  650. double[] daHours = new double[23];
  651. daHours[hour] = num;
  652. List<double> yHours = new(daHours);
  653. var openRes = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync($"{year}", new PartitionKey("LessonYear"));
  654. if (openRes.Status == 200)
  655. {
  656. using var json = await JsonDocument.ParseAsync(openRes.ContentStream);
  657. LessonStats lessonYear = json.ToObject<LessonStats>();
  658. if (type == 0)
  659. {
  660. if (lessonYear.open.Count == 0)
  661. lessonYear.open = yDays;
  662. else lessonYear.open[days] = lessonYear.open[days] + num;
  663. }
  664. else if (type == 1)
  665. {
  666. if (lessonYear.lesson.Count == 0)
  667. lessonYear.lesson = yDays;
  668. else lessonYear.lesson[days] = lessonYear.lesson[days] + num;
  669. }
  670. await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<LessonStats>(lessonYear, lessonYear.id, new PartitionKey($"{lessonYear.code}"));
  671. }
  672. else
  673. {
  674. LessonStats lessonYear = new();
  675. lessonYear.id = $"{year}";
  676. lessonYear.code = "LessonYear";
  677. lessonYear.pk = "LessonYear";
  678. if (type == 0)
  679. lessonYear.open = yDays;
  680. else if (type == 1)
  681. lessonYear.lesson = yDays;
  682. await cosmosClient.GetContainer("TEAMModelOS", "School").CreateItemAsync<LessonStats>(lessonYear, new PartitionKey($"{lessonYear.code}"));
  683. }
  684. var lessRes = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync($"{hourId}", new PartitionKey("LessonHour"));
  685. if (lessRes.Status == 200)
  686. {
  687. using var json = await JsonDocument.ParseAsync(lessRes.ContentStream);
  688. LessonStats lessonHour = json.ToObject<LessonStats>();
  689. if (type == 0)
  690. {
  691. if (lessonHour.open.Count == 0)
  692. lessonHour.open = yHours;
  693. else lessonHour.open[hour] = lessonHour.open[hour] + num;
  694. }
  695. else if (type == 1)
  696. {
  697. if (lessonHour.lesson.Count == 0)
  698. lessonHour.lesson = yHours;
  699. else lessonHour.lesson[hour] = lessonHour.lesson[hour] + num;
  700. }
  701. await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<LessonStats>(lessonHour, lessonHour.id, new PartitionKey($"LessonHour"));
  702. }
  703. else
  704. {
  705. LessonStats lessonHour = new();
  706. lessonHour.id = $"{hourId}";
  707. lessonHour.code = "LessonHour";
  708. lessonHour.pk = "LessonHour";
  709. if (type == 0)
  710. lessonHour.open = yDays;
  711. else if (type == 1)
  712. lessonHour.lesson = yDays;
  713. await cosmosClient.GetContainer("TEAMModelOS", "School").CreateItemAsync<LessonStats>(lessonHour, new PartitionKey("LessonHour"));
  714. }
  715. //学校统计
  716. if (!string.IsNullOrEmpty(schoolId))
  717. {
  718. var openResSc = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync($"{year}", new PartitionKey($"LessonYear-{schoolId}"));
  719. if (openResSc.Status == 200)
  720. {
  721. using var jsonSc = await JsonDocument.ParseAsync(openResSc.ContentStream);
  722. LessonStats lessonYearSc = jsonSc.ToObject<LessonStats>();
  723. if (type == 0)
  724. if (lessonYearSc.open.Count == 0)
  725. lessonYearSc.open = yDays;
  726. else lessonYearSc.open[days] = lessonYearSc.open[days] + num;
  727. else if (type == 1)
  728. {
  729. if (lessonYearSc.lesson.Count == 0)
  730. lessonYearSc.lesson = yDays;
  731. else lessonYearSc.lesson[days] = lessonYearSc.lesson[days] + num;
  732. }
  733. await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<LessonStats>(lessonYearSc, lessonYearSc.id, new PartitionKey($"LessonYear-{schoolId}"));
  734. }
  735. else
  736. {
  737. LessonStats lessonYearSc = new();
  738. lessonYearSc.id = $"{year}";
  739. lessonYearSc.code = $"LessonYear-{schoolId}";
  740. lessonYearSc.pk = "LessonYear";
  741. if (type == 0)
  742. lessonYearSc.open = yDays;
  743. else if (type == 1)
  744. lessonYearSc.lesson = yDays;
  745. await cosmosClient.GetContainer("TEAMModelOS", "School").CreateItemAsync<LessonStats>(lessonYearSc, new PartitionKey($"LessonYear-{schoolId}"));
  746. }
  747. var lessResSc = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync($"{hourId}", new PartitionKey($"LessonHour-{schoolId}"));
  748. if (lessResSc.Status == 200)
  749. {
  750. using var jsonSc = await JsonDocument.ParseAsync(lessResSc.ContentStream);
  751. LessonStats lessonHourSc = jsonSc.ToObject<LessonStats>();
  752. if (type == 0)
  753. if (lessonHourSc.open.Count == 0)
  754. lessonHourSc.open = yDays;
  755. else lessonHourSc.open[days] = lessonHourSc.open[days] + num;
  756. else if (type == 1)
  757. {
  758. if (lessonHourSc.lesson.Count == 0)
  759. lessonHourSc.lesson = yHours;
  760. else lessonHourSc.lesson[hour] = lessonHourSc.lesson[hour] + num;
  761. }
  762. await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<LessonStats>(lessonHourSc, lessonHourSc.id, new PartitionKey($"LessonHour-{schoolId}"));
  763. }
  764. else
  765. {
  766. LessonStats lessonYearSc = new();
  767. lessonYearSc.id = $"{hourId}";
  768. lessonYearSc.code = $"LessonHour-{schoolId}";
  769. lessonYearSc.pk = "LessonHour";
  770. if (type == 0)
  771. lessonYearSc.open = yHours;
  772. else if (type == 1)
  773. lessonYearSc.lesson = yHours;
  774. await cosmosClient.GetContainer("TEAMModelOS", "School").CreateItemAsync<LessonStats>(lessonYearSc, new PartitionKey($"LessonHour-{schoolId}"));
  775. }
  776. }
  777. slimlock.Release();
  778. //Monitor.Enter(unix);
  779. }
  780. /// <summary>
  781. /// 历史记录读取,并统计存储
  782. /// </summary>
  783. /// <param name="jsonElement"></param>
  784. /// <returns></returns>
  785. [ProducesDefaultResponseType]
  786. [HttpPost("get-alllesson")]
  787. public async Task<IActionResult> GetAllLessonRecords(JsonElement jsonElement)
  788. {
  789. //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
  790. var cosmosClient = _azureCosmos.GetCosmosClient();
  791. ////分开部署,就不需要,一站多用时,取消注释
  792. //if ($"{site}".Equals(BIConst.Global))
  793. // cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
  794. List<LessonRecord> allLesson = new();
  795. await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<LessonRecord>(queryText: $"select value(c) from c where c.pk='LessonRecord'", requestOptions: new QueryRequestOptions() { }))
  796. {
  797. allLesson.Add(item);
  798. }
  799. await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<LessonRecord>(queryText: $"select value(c) from c where c.pk='LessonRecord'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("LessonRecord") }))
  800. {
  801. allLesson.Add(item);
  802. }
  803. (List<LessonStats> lessYears, List<LessonStats> lessHours) = await AllLessonStats(allLesson, _azureRedis);
  804. foreach (var itemY in lessYears)
  805. {
  806. var response = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(itemY.id, new PartitionKey($"{itemY.code}"));
  807. if (response.Status == 200)
  808. {
  809. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  810. LessonStats lessonYear = json.ToObject<LessonStats>();
  811. lessonYear.open = itemY.open;
  812. lessonYear.lesson = itemY.lesson;
  813. await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<LessonStats>(lessonYear, lessonYear.id, new PartitionKey($"{lessonYear.code}"));
  814. }
  815. else
  816. await cosmosClient.GetContainer("TEAMModelOS", "School").CreateItemAsync<LessonStats>(itemY, new PartitionKey($"{itemY.code}"));
  817. }
  818. foreach (var itemH in lessHours)
  819. {
  820. var response = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(itemH.id, new PartitionKey($"{itemH.code}"));
  821. if (response.Status == 200)
  822. {
  823. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  824. LessonStats lessonHour = json.ToObject<LessonStats>();
  825. lessonHour.open = itemH.open;
  826. lessonHour.lesson = itemH.lesson;
  827. await cosmosClient.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<LessonStats>(lessonHour, lessonHour.id, new PartitionKey($"{lessonHour.code}"));
  828. }
  829. else
  830. await cosmosClient.GetContainer("TEAMModelOS", "School").CreateItemAsync<LessonStats>(itemH, new PartitionKey($"{itemH.code}"));
  831. }
  832. return Ok(new { state = 200, ycnt = lessYears.Count, hcnt = lessHours.Count, lessYears, lessHours });
  833. }
  834. #region 课例历史记录统计
  835. /// <summary>
  836. /// 统计所有课例
  837. /// </summary>
  838. /// <param name="lessRecs"></param>
  839. /// <returns></returns>
  840. public static async Task<(List<LessonStats> lessonYears, List<LessonStats> lessonHours)> AllLessonStats(List<LessonRecord> lessRecs, AzureRedisFactory azureRedis)
  841. {
  842. //统计所有
  843. List<LessCnt> allLess = lessRecs.Select(item => new LessCnt { hour = TimeHelper.GetDateTime(item.startTime).ToString("yyyyMMddHH"), cat = item.id, upload = item.upload, schoolId = item.school }).ToList();
  844. var openL = allLess.FindAll(f => f.upload == 0).GroupBy(g => g.hour).Select(s => new AllLess { key = s.Key, cnt = s.Count() }).ToList();
  845. var lessL = allLess.FindAll(s => s.upload == 1).GroupBy(g => g.hour).Select(s => new AllLess { key = s.Key, cnt = s.Count() }).ToList();
  846. List<LessonStats> lessYears = new();
  847. List<LessonStats> lessHours = new();
  848. //统计开课记录
  849. openL.ForEach(x =>
  850. {
  851. var (year, month, day, days, hour) = TimeHelper.GetDateTime(x.key);
  852. string id = $"{year}{month.ToString().PadLeft(2, '0')}{day.ToString().PadLeft(2, '0')}";
  853. LessonStats finHour = lessHours.Find(f => f.id.Equals(id));
  854. if (finHour != null)
  855. {
  856. if (finHour.open.Count == 0)
  857. {
  858. double[] da = new double[23];
  859. da[hour] = x.cnt;
  860. List<double> tempDays = new(da);
  861. finHour.open = tempDays;
  862. }
  863. else finHour.open[hour] = x.cnt;
  864. azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"BILesson:All:Open:{finHour.id}", $"{hour}", x.cnt);//一天24小时课例数 有上传 base.josn 小时为单位
  865. }
  866. else
  867. {
  868. //小时统计
  869. LessonStats lessonHour = new();
  870. lessonHour.id = id;
  871. lessonHour.code = "LessonHour";
  872. lessonHour.pk = "LessonHour";
  873. double[] daHours = new double[23];
  874. daHours[hour] = x.cnt;
  875. List<double> hourDays = new(daHours);
  876. lessonHour.open = hourDays;
  877. //lessonHour.ttl = 24 * 60 * 60 * 8; //设置过期时间 8天后自动删除
  878. lessHours.Add(lessonHour);
  879. }
  880. LessonStats findLess = lessYears.Find(f => f.id.Equals($"{year}"));
  881. if (findLess != null)
  882. {
  883. if (findLess.open.Count == 0)
  884. {
  885. var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  886. double[] da = new double[yearDays];
  887. da[days] = x.cnt;
  888. List<double> tempDays = new(da);
  889. findLess.open = tempDays;
  890. }
  891. else findLess.open[days] = x.cnt;
  892. }
  893. else
  894. {
  895. LessonStats lessonYear = new();
  896. lessonYear.id = $"{year}";
  897. lessonYear.code = "LessonYear";
  898. lessonYear.pk = "LessonYear";
  899. var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  900. double[] daDays = new double[yearDays];
  901. daDays[days] = x.cnt;
  902. List<double> yDays = new(daDays);
  903. lessonYear.open = yDays;
  904. lessYears.Add(lessonYear);
  905. }
  906. });
  907. //统计课例
  908. lessL.ForEach(x =>
  909. {
  910. var (year, month, day, days, hour) = TimeHelper.GetDateTime(x.key);
  911. string id = $"{year}{month.ToString().PadLeft(2, '0')}{day.ToString().PadLeft(2, '0')}";
  912. LessonStats finHour = lessHours.Find(f => f.id.Equals(id));
  913. if (finHour != null)
  914. {
  915. if (finHour.lesson.Count == 0)
  916. {
  917. double[] da = new double[23];
  918. da[hour] = x.cnt;
  919. List<double> tempDays = new(da);
  920. finHour.lesson = tempDays;
  921. }
  922. else finHour.lesson[hour] = x.cnt;
  923. }
  924. else
  925. {
  926. //小时统计
  927. LessonStats lessonHour = new();
  928. lessonHour.id = id;
  929. lessonHour.code = "LessonHour";
  930. lessonHour.pk = "LessonHour";
  931. double[] daHours = new double[23];
  932. daHours[hour] = x.cnt;
  933. List<double> hourDays = new(daHours);
  934. lessonHour.lesson = hourDays;
  935. lessHours.Add(lessonHour);
  936. }
  937. LessonStats findLess = lessYears.Find(f => f.id.Equals($"{year}"));
  938. if (findLess != null)
  939. {
  940. if (findLess.lesson.Count == 0)
  941. {
  942. var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  943. double[] da = new double[yearDays];
  944. da[days] = x.cnt;
  945. List<double> tempDays = new(da);
  946. findLess.lesson = tempDays;
  947. }
  948. else findLess.lesson[days] = x.cnt;
  949. }
  950. else
  951. {
  952. LessonStats lessonYear = new();
  953. lessonYear.id = $"{year}";
  954. lessonYear.code = "LessonYear";
  955. lessonYear.pk = "LessonYear";
  956. var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  957. double[] da = new double[yearDays];
  958. da[days] = x.cnt;
  959. List<double> tempDays = new(da);
  960. lessonYear.lesson = tempDays;
  961. lessYears.Add(lessonYear);
  962. }
  963. });
  964. //统计学校课例
  965. var scLess = lessRecs.Select(item => new LessCnt { hour = TimeHelper.GetDateTime(item.startTime).ToString("yyyyMMddHH"), cat = item.id, upload = item.upload, schoolId = item.school }).GroupBy(g => g.schoolId).Select(s => new ScLess { key = s.Key, lessCnt = s.ToList() }).ToList();
  966. foreach (var itemLess in scLess)
  967. {
  968. var openSCL = itemLess.lessCnt.FindAll(f => f.upload == 0).GroupBy(g => g.hour).Select(s => new ScLesson { key = s.Key, schoolId = itemLess.key, cnt = s.Count() }).ToList();
  969. var lessSCL = itemLess.lessCnt.FindAll(f => f.upload == 1).GroupBy(g => g.hour).Select(s => new ScLesson { key = s.Key, schoolId = itemLess.key, cnt = s.Count() }).ToList();
  970. openSCL.ForEach(f =>
  971. {
  972. if (!string.IsNullOrEmpty(f.schoolId))
  973. {
  974. var (year, month, day, days, hour) = TimeHelper.GetDateTime(f.key);
  975. string id = $"{year}{month.ToString().PadLeft(2, '0')}{day.ToString().PadLeft(2, '0')}";
  976. string codeHour = $"LessonHour-{f.schoolId}";
  977. LessonStats finHour = lessHours.Find(f => f.id.Equals(id) && f.code.Equals(codeHour));
  978. if (finHour != null)
  979. {
  980. if (finHour.open.Count == 0)
  981. {
  982. double[] da = new double[23];
  983. da[hour] = f.cnt;
  984. List<double> tempDays = new(da);
  985. finHour.open = tempDays;
  986. }
  987. else finHour.open[hour] = f.cnt;
  988. }
  989. else
  990. {
  991. //小时统计
  992. LessonStats lessonHour = new();
  993. lessonHour.id = id;
  994. lessonHour.code = codeHour;
  995. lessonHour.pk = "LessonHour";
  996. double[] daHours = new double[23];
  997. daHours[hour] = f.cnt;
  998. List<double> hourDays = new(daHours);
  999. lessonHour.open = hourDays;
  1000. //lessonHour.ttl = 24 * 60 * 60 * 8; //设置过期时间
  1001. lessHours.Add(lessonHour);
  1002. }
  1003. string codeYear = $"LessonYear-{f.schoolId}";
  1004. LessonStats findLess = lessYears.Find(f => f.id.Equals($"{year}") && f.code.Equals(codeYear));
  1005. if (findLess != null)
  1006. {
  1007. if (findLess.open.Count == 0)
  1008. {
  1009. var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  1010. double[] da = new double[yearDays];
  1011. da[days] = f.cnt;
  1012. List<double> tempDays = new(da);
  1013. findLess.open = tempDays;
  1014. }
  1015. else findLess.open[days] = f.cnt;
  1016. }
  1017. else
  1018. {
  1019. LessonStats lessonYear = new();
  1020. lessonYear.id = $"{year}";
  1021. lessonYear.code = codeYear;
  1022. lessonYear.code = "LessonYear";
  1023. var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  1024. double[] daDays = new double[yearDays];
  1025. daDays[days] = f.cnt;
  1026. List<double> yDays = new(daDays);
  1027. lessonYear.open = yDays;
  1028. lessYears.Add(lessonYear);
  1029. }
  1030. }
  1031. });
  1032. lessSCL.ForEach(x =>
  1033. {
  1034. if (!string.IsNullOrEmpty(x.schoolId))
  1035. {
  1036. if (!string.IsNullOrEmpty(x.schoolId))
  1037. {
  1038. var (year, month, day, days, hour) = TimeHelper.GetDateTime(x.key);
  1039. string id = $"{year}{month.ToString().PadLeft(2, '0')}{day.ToString().PadLeft(2, '0')}";
  1040. string codeHour = $"LessonHour-{x.schoolId}";
  1041. LessonStats finHour = lessHours.Find(f => f.id.Equals(id) && f.code.Equals(codeHour));
  1042. if (finHour != null)
  1043. {
  1044. if (finHour.lesson.Count == 0)
  1045. {
  1046. double[] da = new double[23];
  1047. da[hour] = x.cnt;
  1048. List<double> tempDays = new(da);
  1049. finHour.lesson = tempDays;
  1050. }
  1051. else finHour.lesson[hour] = x.cnt;
  1052. }
  1053. else
  1054. {
  1055. //小时统计
  1056. LessonStats lessonHour = new();
  1057. lessonHour.id = id;
  1058. lessonHour.code = codeHour;
  1059. lessonHour.pk = "LessonHour";
  1060. double[] daHours = new double[23];
  1061. daHours[hour] = x.cnt;
  1062. List<double> hourDays = new(daHours);
  1063. lessonHour.lesson = hourDays;
  1064. lessHours.Add(lessonHour);
  1065. }
  1066. string codeYear = $"LessonYear-{x.schoolId}";
  1067. LessonStats findLess = lessYears.Find(f => f.id.Equals($"{year}") && f.code.Equals(codeYear));
  1068. if (findLess != null)
  1069. {
  1070. if (findLess.lesson.Count == 0)
  1071. {
  1072. var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  1073. double[] da = new double[yearDays];
  1074. da[days] = x.cnt;
  1075. List<double> tempDays = new(da);
  1076. findLess.lesson = tempDays;
  1077. }
  1078. else findLess.lesson[days] = x.cnt;
  1079. }
  1080. else
  1081. {
  1082. LessonStats lessonYear = new();
  1083. lessonYear.id = $"{year}";
  1084. lessonYear.code = codeYear;
  1085. lessonYear.pk = "LessonYear";
  1086. var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  1087. double[] da = new double[yearDays];
  1088. da[days] = x.cnt;
  1089. List<double> tempDays = new(da);
  1090. lessonYear.lesson = tempDays;
  1091. lessYears.Add(lessonYear);
  1092. }
  1093. }
  1094. }
  1095. });
  1096. };
  1097. //openL.ForEach(x => {
  1098. // var (year, days, hour) = TimeHelper.GetDateTime(x.key);
  1099. // LessonYear findLess = lessYears.Find(f => f.id.Equals($"{year}"));
  1100. // if (findLess != null)
  1101. // {
  1102. // if (findLess.openYear.Count == 0)
  1103. // {
  1104. // var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  1105. // double[] da = new double[yearDays];
  1106. // da[days] = x.cnt;
  1107. // List<double> tempDays = new(da);
  1108. // findLess.openYear = tempDays;
  1109. // }
  1110. // else findLess.openYear[days] = x.cnt;
  1111. // }
  1112. // else
  1113. // {
  1114. // LessonYear lessonYear = new();
  1115. // lessonYear.id = $"{year}";
  1116. // lessonYear.code = "LessonYear";
  1117. // var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  1118. // double[] da = new double[yearDays];
  1119. // da[days] = x.cnt;
  1120. // List<double> tempDays = new(da);
  1121. // lessonYear.openYear = tempDays;
  1122. // lessYears.Add(lessonYear);
  1123. // }
  1124. //});
  1125. //lessL.ForEach(x => {
  1126. // var (year, days, hour) = TimeHelper.GetDateTime(x.key);
  1127. // LessonYear findLess = lessYears.Find(f => f.id.Equals($"{year}"));
  1128. // if (findLess != null)
  1129. // {
  1130. // if (findLess.lessonYear.Count == 0)
  1131. // {
  1132. // var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  1133. // double[] da = new double[yearDays];
  1134. // da[days] = x.cnt;
  1135. // List<double> tempDays = new(da);
  1136. // findLess.lessonYear = tempDays;
  1137. // }
  1138. // else findLess.lessonYear[days] = x.cnt;
  1139. // }
  1140. // else
  1141. // {
  1142. // LessonYear lessonYear = new();
  1143. // lessonYear.id = $"{year}";
  1144. // lessonYear.code = "LessonYear";
  1145. // var yearDays = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 366 : 365;
  1146. // double[] da = new double[yearDays];
  1147. // da[days] = x.cnt;
  1148. // List<double> tempDays = new(da);
  1149. // lessonYear.lessonYear = tempDays;
  1150. // lessYears.Add(lessonYear);
  1151. // }
  1152. //});
  1153. return (lessYears, lessHours);
  1154. }
  1155. /// <summary>
  1156. /// 统计学校课例
  1157. /// </summary>
  1158. public record ScLesson
  1159. {
  1160. public string key { get; set; }
  1161. public string schoolId { get; set; }
  1162. public int cnt { get; set; }
  1163. }
  1164. /// <summary>
  1165. /// 统计学校课例详细信息
  1166. /// </summary>
  1167. public record ScLess
  1168. {
  1169. public string key { get; set; }
  1170. public List<LessCnt> lessCnt { get; set; }
  1171. }
  1172. /// <summary>
  1173. /// 统计所有课例
  1174. /// </summary>
  1175. public record AllLess
  1176. {
  1177. public string key { get; set; }
  1178. public int cnt { get; set; }
  1179. }
  1180. /// <summary>
  1181. /// 统计所有课例详细
  1182. /// </summary>
  1183. public record LessCnt
  1184. {
  1185. public string hour { get; set; }
  1186. public string schoolId { get; set; }
  1187. public string cat { get; set; }
  1188. public int upload { get; set; }
  1189. }
  1190. #endregion
  1191. public record AreaSchools
  1192. {
  1193. public string id { get; set; }
  1194. public string name { get; set; }
  1195. public string picture { get; set; }
  1196. public int allCnt { get; set; }
  1197. public int weekCnt { get; set; }
  1198. public int monthCnt { get; set; }
  1199. }
  1200. public record AllAreaInfo
  1201. {
  1202. public string id { get; set; }
  1203. public string name { get; set; }
  1204. public string standard { get; set; }
  1205. public string standardName { get; set; }
  1206. public int lessCnt { get; set; }
  1207. public int actCnt { get; set; }
  1208. public int allCnt { get; set; }
  1209. }
  1210. public record SchoolLen
  1211. {
  1212. public string id { get; set; }
  1213. public string name { get; set;}
  1214. public long totals { get; set; }
  1215. }
  1216. }
  1217. }