OnLineController.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. using Azure.Cosmos;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.AspNetCore.Mvc;
  4. using StackExchange.Redis;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text.Json;
  9. using System.Threading.Tasks;
  10. using TEAMModelBI.Tool;
  11. using TEAMModelOS.SDK.DI;
  12. using TEAMModelOS.SDK.Extension;
  13. using TEAMModelOS.SDK.Models;
  14. using TEAMModelOS.SDK.Models.Table;
  15. namespace TEAMModelBI.Controllers.BIHome
  16. {
  17. [Route("online")]
  18. [ApiController]
  19. public class OnLineController : ControllerBase
  20. {
  21. private readonly AzureCosmosFactory _azureCosmos;
  22. private readonly AzureStorageFactory _azureStorage;
  23. private readonly AzureRedisFactory _azureRedis;
  24. public OnLineController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis)
  25. {
  26. _azureCosmos = azureCosmos;
  27. _azureStorage = azureStorage;
  28. _azureRedis = azureRedis;
  29. }
  30. /// <summary>
  31. /// 总数统计
  32. /// </summary>
  33. /// <returns></returns>
  34. [HttpPost("get-count")]
  35. public async Task<IActionResult> GetCount()
  36. {
  37. var cosmosClient = _azureCosmos.GetCosmosClient();
  38. var table = _azureStorage.GetCloudTableClient().GetTableReference("IESLogin");
  39. DateTimeOffset dateTime = DateTimeOffset.UtcNow;
  40. var (daySt, dayEt) = TimeHelper.GetStartOrEnd(dateTime); //今天开始时间 13位
  41. var (daySf, dayEf) = TimeHelper.GetStartOrEnd(dateTime, dateLenth: false); //今天开始时间 10位
  42. var (lastDayS, lastdayE) = TimeHelper.GetStartOrEnd(DateTimeOffset.Parse($"{dateTime.Year}-{dateTime.Month}-{dateTime.Day - 1}")); //昨天开始时间
  43. var near7S = dateTime.AddDays(-7).ToUnixTimeMilliseconds(); //前七天的开始时间
  44. var near7E = dateTime.ToUnixTimeMilliseconds(); //当前结束时间
  45. long hour1 = dateTime.AddHours(-1).ToUnixTimeMilliseconds(); //一小时前时间戳
  46. int areaCnt = 0; //学区总数
  47. int scCnt = 0; //学校总数
  48. int tchCnt = 0; //教师总数
  49. int stuCnt = 0; //学生总数
  50. int onStuCnt = 0; //学生在线人数
  51. int onTchCnt = 0; //教师在线人数
  52. int todayScCnt = 0; //今日新增学校数
  53. int todayTchCnt = 0; //今日新增教师
  54. int todayStuCnt = 0; //今日新增学生数
  55. string currentSql = "select value(count(c.id)) from c";
  56. areaCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Normal", currentSql, "Base-Area");
  57. scCnt = await CommonFind.GetSqlValueCount(cosmosClient, "School", currentSql, "Base");
  58. tchCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Teacher", currentSql, "Base");
  59. stuCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Student", "select value(count(c.id)) from c where c.pk='Base'");
  60. string addSql = $"select value(count(c.id)) from c where c.pk='Base' and c.createTime >={daySf} and c.createTime <= {dayEf}";
  61. todayScCnt = await CommonFind.GetSqlValueCount(cosmosClient, "School", addSql, "Base");
  62. todayTchCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Teacher", addSql, "Base");
  63. todayStuCnt = await CommonFind.GetSqlValueCount(cosmosClient, "Student", addSql, "Base");
  64. List<RecOnLine> recStuOnLines = new();
  65. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Student").GetItemQueryIterator<RecOnLine>(queryText: "select c.id,c.name,c.code,c.loginInfos from c where c.pk='Base' and array_length(c.loginInfos) > 0 ", requestOptions:new QueryRequestOptions() { }))
  66. {
  67. recStuOnLines.Add(item);
  68. }
  69. onStuCnt = (from rs in recStuOnLines from l in rs.loginInfos where l.expire >= hour1 select rs).ToList().Count(); //linq查询
  70. //onStuCnt = recStuOnLines.Select(rss => new RecOnLine { id = rss.id,code=rss.code, name =rss.name,loginInfos = new List<Teacher.LoginInfo> { rss.loginInfos.Find(f => f.expire >= hour1) } }).Where(w => w.loginInfos.FirstOrDefault() != null).ToList().Count(); //lambda 表达式查询
  71. List<RecOnLine> recTecOnLines = new();
  72. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<RecOnLine>(queryText: "select c.id,c.name,c.code,c.loginInfos from c where array_length(c.loginInfos) > 0 ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
  73. {
  74. recTecOnLines.Add(item);
  75. }
  76. onTchCnt = (from rs in recTecOnLines from l in rs.loginInfos where l.expire >= hour1 select rs).ToList().Count(); //linq查询
  77. //onStuCnt = recTecOnLines.Select(rss => new RecOnLine { id = rss.id,code=rss.code, name =rss.name,loginInfos = new List<Teacher.LoginInfo> { rss.loginInfos.Find(f => f.expire >= hour1) } }).Where(w => w.loginInfos.FirstOrDefault() != null).ToList().Count(); //lambda 表达式查询
  78. return Ok(new { state = 200, areaCnt, scCnt, tchCnt, stuCnt, todayScCnt, todayTchCnt, todayStuCnt, onStuCnt, onTchCnt});
  79. }
  80. /// <summary>
  81. /// 在线人数趋势图
  82. /// </summary>
  83. /// <returns></returns>
  84. [HttpPost("get-trend")]
  85. public async Task<IActionResult> GetTrend()
  86. {
  87. var table = _azureStorage.GetCloudTableClient().GetTableReference("IESLogin");
  88. DateTimeOffset dateTime = DateTimeOffset.UtcNow;
  89. var (daySt, dayEt) = TimeHelper.GetStartOrEnd(dateTime); //今天开始时间 13位
  90. var dateDay = dateTime.ToString("yyyyMMdd"); //获取当天的日期
  91. Dictionary<string, int> allDays = new(); //所有在线人数
  92. Dictionary<string, int> tchDays = new(); //教师在线人数
  93. Dictionary<string, int> stuDays = new(); //学生在线人数
  94. Dictionary<string, int> tmdDays = new(); //醍摩豆账户学生
  95. SortedSetEntry[] tchDay = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:IES:teacher:{dateDay}");
  96. if (tchDay.Length > 0)
  97. {
  98. foreach (var item in tchDay)
  99. {
  100. int val = ((int)item.Score);
  101. int key = ((int)item.Element);
  102. var hour = DateTime.SpecifyKind(Convert.ToDateTime($"{dateTime.Year}/{dateTime.Month}/{ dateTime.Day} {key}:00:00"), DateTimeKind.Utc).ToLocalTime().ToString("HH:mm");
  103. tchDays.Add(hour, val);
  104. if (allDays.ContainsKey(hour))
  105. allDays[hour] = (allDays[hour] + val);
  106. else
  107. allDays.Add(hour, val);
  108. }
  109. }
  110. else
  111. {
  112. string tableSqlTch = $"PartitionKey eq 'HourLogin' and RowKey ge '{daySt}' and RowKey le '{dayEt}' and Teacher ne 0";
  113. List<HourLogin> hourLoginsTch = await table.QueryWhereString<HourLogin>(tableSqlTch);
  114. var hourTchCnt = hourLoginsTch.GroupBy(x => x.Hour).Select(k => new { key = int.Parse(k.Key.ToString().Substring(8, 2)), value = k.Count() }).ToList();
  115. if (hourTchCnt.Count > 0)
  116. {
  117. foreach (var item in hourTchCnt)
  118. {
  119. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:IES:teacher:{dateDay}", $"{item.key}", item.value);//存一天24小时
  120. var hour = DateTime.SpecifyKind(Convert.ToDateTime($"{dateTime.Year}/{dateTime.Month}/{ dateTime.Day} {item.key}:00:00"), DateTimeKind.Utc).ToLocalTime().ToString("HH:mm");
  121. tchDays.Add(hour, item.value);
  122. if (allDays.ContainsKey(hour))
  123. allDays[hour] = (allDays[hour] + item.value);
  124. else
  125. allDays.Add(hour, item.value);
  126. }
  127. }
  128. }
  129. SortedSetEntry[] stuDay = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:IES:student:{dateDay}");
  130. if (stuDay.Length > 0)
  131. {
  132. foreach (var item in stuDay)
  133. {
  134. int val = (int)item.Score;
  135. int key = (int)item.Element;
  136. var hour = DateTime.SpecifyKind(Convert.ToDateTime($"{dateTime.Year}/{dateTime.Month}/{ dateTime.Day} {key}:00:00"), DateTimeKind.Utc).ToLocalTime().ToString("HH:mm");
  137. stuDays.Add(hour, val);
  138. if (allDays.ContainsKey(hour))
  139. allDays[hour] = (allDays[hour] + val);
  140. else
  141. allDays.Add(hour, val);
  142. }
  143. }
  144. else
  145. {
  146. string tableSqlStu = $"PartitionKey eq 'HourLogin' and RowKey ge '{daySt}' and RowKey le '{dayEt}' and Student ne 0";
  147. List<HourLogin> hourLoginsStu = await table.QueryWhereString<HourLogin>(tableSqlStu);
  148. var hourStuCnt = hourLoginsStu.GroupBy(x => x.Hour).Select(k => new { key = int.Parse(k.Key.ToString().Substring(8, 2)), value = k.Count() }).ToList();
  149. if (hourStuCnt.Count > 0)
  150. {
  151. foreach (var item in hourStuCnt)
  152. {
  153. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:IES:student:{dateDay}", $"{item.key}", item.value);//存一天24小时
  154. var hour = DateTime.SpecifyKind(Convert.ToDateTime($"{dateTime.Year}/{dateTime.Month}/{ dateTime.Day} {item.key}:00:00"), DateTimeKind.Utc).ToLocalTime().ToString("HH:mm");
  155. stuDays.Add(hour, item.value);
  156. if (allDays.ContainsKey(hour))
  157. allDays[hour] = (allDays[hour] + item.value);
  158. else
  159. allDays.Add(hour, item.value);
  160. }
  161. }
  162. }
  163. SortedSetEntry[] tmdDay = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:IES:tmduser:{dateDay}");
  164. if (tmdDay.Length > 0)
  165. {
  166. foreach (var item in stuDay)
  167. {
  168. int val = (int)item.Score;
  169. int key = (int)item.Element;
  170. var hour = DateTime.SpecifyKind(Convert.ToDateTime($"{dateTime.Year}/{dateTime.Month}/{ dateTime.Day} {key}:00:00"), DateTimeKind.Utc).ToLocalTime().ToString("HH:mm");
  171. tmdDays.Add(hour, val);
  172. if (allDays.ContainsKey(hour))
  173. allDays[hour] = (allDays[hour] + val);
  174. else
  175. allDays.Add(hour, val);
  176. }
  177. }
  178. else
  179. {
  180. string tableSqlTmd = $"PartitionKey eq 'HourLogin' and RowKey ge '{daySt}' and RowKey le '{dayEt}' and TmdUser ne 0";
  181. List<HourLogin> hourLoginsTmd = await table.QueryWhereString<HourLogin>(tableSqlTmd);
  182. var hourTmdCnt = hourLoginsTmd.GroupBy(x => x.Hour).Select(k => new { key = int.Parse(k.Key.ToString().Substring(8, 2)), value = k.Count() }).ToList();
  183. if (hourTmdCnt.Count > 0)
  184. {
  185. foreach (var item in hourTmdCnt)
  186. {
  187. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:IES:tmduser:{dateDay}", $"{item.key}", item.value);//存一天24小时
  188. var hour = DateTime.SpecifyKind(Convert.ToDateTime($"{dateTime.Year}/{dateTime.Month}/{ dateTime.Day} {item.key}:00:00"), DateTimeKind.Utc).ToLocalTime().ToString("HH:mm");
  189. tmdDays.Add(hour, item.value);
  190. if (allDays.ContainsKey(hour))
  191. allDays[hour] = (allDays[hour] + item.value);
  192. else
  193. allDays.Add(hour, item.value);
  194. }
  195. }
  196. }
  197. return Ok(new { state = 200,allDays = allDays.ToList(), tchDays=tchDays.ToList(), stuDays= stuDays.ToList(), tmdDays= tmdDays.ToList() });
  198. }
  199. /// <summary>
  200. /// 课例趋势图
  201. /// </summary>
  202. /// <returns></returns>
  203. [HttpPost("get-lessontrend")]
  204. public async Task<IActionResult> GetLessonTrend()
  205. {
  206. DateTimeOffset dateTime = DateTimeOffset.UtcNow;
  207. var cosmosClient = _azureCosmos.GetCosmosClient();
  208. int year = dateTime.Year; //当前年
  209. int month = dateTime.Month; //当前月
  210. int day = dateTime.Day; //当天
  211. int hour = dateTime.Hour; //当前小时
  212. Dictionary<int, int> scLessCnt = new(); //学校课例
  213. Dictionary<int, int> tecLessCnt = new(); //教师课例
  214. Dictionary<int, int> yasterdayCnt = new(); //昨天24小时课例
  215. for (int i = 0; i < 24; i++)
  216. {
  217. if (hour >= i)
  218. {
  219. DateTimeOffset timeHour = new DateTime(year, month, day, i, 0, 0);
  220. var (hourS, hourE) = TimeHelper.GetStartOrEnd(timeHour, type: "hour");
  221. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<int>(queryText: $"select value(count(c.id)) from c where c.pk='LessonRecord' and c.startTime >={hourS} and c.startTime <= {hourE}", requestOptions: new QueryRequestOptions() { }))
  222. {
  223. scLessCnt.Add(i, item);
  224. }
  225. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<int>(queryText: $"select value(count(c.id)) from c where c.startTime >={hourS} and c.startTime <= {hourE}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("LessonRecord") }))
  226. {
  227. tecLessCnt.Add(i, item);
  228. }
  229. }
  230. DateTimeOffset yesterday = new DateTime(year, month, day - 1, i, 0, 0);
  231. var (yHourS, yHourE) = TimeHelper.GetStartOrEnd(yesterday, type: "hour");
  232. string sql = $"select value(count(c.id)) from c where c.pk='LessonRecord' and c.startTime >= {yHourS} and c.startTime <= {yHourE}";
  233. int hourLessCnt = await CommonFind.GetSqlValueCount(cosmosClient, new List<string> { "School", "Teacher" }, sql);
  234. yasterdayCnt.Add(i, hourLessCnt);
  235. }
  236. return Ok(new { state = 200, scLessCnt = scLessCnt.ToList(), tecLessCnt = tecLessCnt.ToList(), yasterdayCnt = yasterdayCnt.ToList() });
  237. }
  238. /// <summary>
  239. /// 版本数量占比
  240. /// </summary>
  241. /// <returns></returns>
  242. [HttpPost("get-edition")]
  243. public async Task<IActionResult> GetEdition()
  244. {
  245. var cosmosClient = _azureCosmos.GetCosmosClient();
  246. List<RecScEd> scEdCnt = new();
  247. var ScSql = $"select c.id,c.name,c.size,c.scale from c";
  248. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<RecScEd>(queryText: ScSql, requestOptions:new QueryRequestOptions() { PartitionKey= new PartitionKey("Base")}))
  249. {
  250. scEdCnt.Add(item);
  251. }
  252. scEdCnt.ForEach(async scProductCnt =>
  253. {
  254. var response = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(scProductCnt.id, new PartitionKey("ProductSum"));
  255. if (response.Status == 200)
  256. {
  257. using var json = await JsonDocument.ParseAsync(response.ContentStream);
  258. SchoolProductSum ScProductSum = json.ToObject<SchoolProductSum>();
  259. scProductCnt.serial = ScProductSum.serial.Count();
  260. scProductCnt.service = ScProductSum.service.Count();
  261. scProductCnt.hard = ScProductSum.hard.Count();
  262. }
  263. });
  264. return Ok(new { state = 200, scEdCnt });
  265. }
  266. public record RecOnLine
  267. {
  268. public string id { get; set; }
  269. public string name { get; set; }
  270. public string code { get; set; }
  271. public List<Teacher.LoginInfo> loginInfos { get; set; }
  272. }
  273. public class RecScEd
  274. {
  275. public string id { get; set; }
  276. public string name { get; set; }
  277. public int size { get; set; }
  278. public int scale { get; set; }
  279. public int serial { get; set; } = 0;//软体
  280. public int service { get; set; } = 0; //服务
  281. public int hard { get; set; } = 0; //硬体
  282. }
  283. }
  284. }