ProductAnalysisController.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. using Microsoft.Azure.Cosmos;
  2. using DingTalk.Api.Request;
  3. using Microsoft.AspNetCore.Authorization;
  4. using Microsoft.AspNetCore.Http;
  5. using Microsoft.AspNetCore.Mvc;
  6. using Microsoft.Extensions.Configuration;
  7. using Microsoft.Extensions.Options;
  8. using StackExchange.Redis;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Dynamic;
  12. using System.Linq;
  13. using System.Reflection;
  14. using System.Text;
  15. using System.Text.Json;
  16. using System.Threading.Tasks;
  17. using TEAMModelBI.Filter;
  18. using TEAMModelBI.Tool;
  19. using TEAMModelBI.Tool.Extension;
  20. using TEAMModelOS.Models;
  21. using TEAMModelOS.SDK.Context.BI;
  22. using TEAMModelOS.SDK.DI;
  23. using TEAMModelOS.SDK.Extension;
  24. using TEAMModelOS.SDK.Models;
  25. using TEAMModelOS.SDK.Models.Service.BI;
  26. using PartitionKey = PartitionKey;
  27. using QueryRequestOptions = QueryRequestOptions;
  28. namespace TEAMModelBI.Controllers.ProductAnalysis
  29. {
  30. [Route("prodanalysis")]
  31. [ApiController]
  32. public class ProductAnalysisController : ControllerBase
  33. {
  34. //数据容器
  35. private readonly AzureCosmosFactory _azureCosmos;
  36. private readonly AzureStorageFactory _azureStorage;
  37. private readonly AzureRedisFactory _azureRedis;
  38. //钉钉提示信息
  39. private readonly DingDing _dingDing;
  40. private readonly Option _option;
  41. private readonly IConfiguration _configuration;
  42. public ProductAnalysisController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration)
  43. {
  44. _azureCosmos= azureCosmos;
  45. _azureStorage= azureStorage;
  46. _azureRedis = azureRedis;
  47. _dingDing = dingDing;
  48. _option= option?.Value;
  49. _configuration= configuration;
  50. }
  51. /// <summary>
  52. /// 取得產品分析IOT統計資料(redis)
  53. /// </summary>
  54. /// <param name="jsonElement"></param>
  55. /// <returns></returns>
  56. [ProducesDefaultResponseType]
  57. [Authorize(Roles = "IES")]
  58. [HttpPost("get-iotstics")]
  59. public async Task<IActionResult> GetIotStics(JsonElement jsonElement)
  60. {
  61. try
  62. {
  63. var cosmosClient = _azureCosmos.GetCosmosClient();
  64. var redisClinet8 = _azureRedis.GetRedisClient(8);
  65. if (!jsonElement.TryGetProperty("dateFrom", out JsonElement dateFromJobj)) return BadRequest();//查詢日期:起始(string)[例]2023-03-05
  66. if (!jsonElement.TryGetProperty("dateTo", out JsonElement dateToJobj)) return BadRequest();//查詢日期:結束(string)[例]2023-03-27
  67. if (!jsonElement.TryGetProperty("prod", out JsonElement prodJobj)) return BadRequest();//產品 HiTeach, HiTeachCC, HiTA
  68. string prod = (prodJobj.ToString().Equals("HiTeach") || prodJobj.ToString().Equals("HiTeachCC") || prodJobj.ToString().Equals("HiTA")) ? prodJobj.ToString() : string.Empty;
  69. if(string.IsNullOrWhiteSpace(prod)) return BadRequest();
  70. if (!jsonElement.TryGetProperty("schoolIds", out JsonElement schoolIdsJobj)) return BadRequest();//學校ID(array)
  71. List<string> schoolIds = schoolIdsJobj.ToObject<List<string>>();
  72. string dateUnit = (jsonElement.TryGetProperty("dateUnit", out JsonElement dateUnitJobj)) ? (!string.IsNullOrWhiteSpace(Convert.ToString(dateUnitJobj))) ? Convert.ToString(dateUnitJobj).ToLower() : "day" : "day"; //時間統計單位 ※以每年(Year)、每月(Month)、每日(Day) 為統計單位 預設值:每日
  73. string geoUnit = (jsonElement.TryGetProperty("geoUnit", out JsonElement geoUnitJobj)) ? (!string.IsNullOrWhiteSpace(Convert.ToString(geoUnitJobj))) ? Convert.ToString(geoUnitJobj).ToLower() : "city" : "city"; //地理統計單位 region:國 province:省 city:市 dist:區 預設值:市
  74. //起始終止日期換算
  75. List<string> dateFromList = dateFromJobj.ToString().Split('-').ToList();
  76. int dateFromYear = Convert.ToInt32(dateFromList[0], 10);
  77. int dateFromMonth = (dateUnit.Equals("day") || dateUnit.Equals("month")) ? Convert.ToInt32(dateFromList[1], 10) : 1;
  78. int dateFromDay = (dateUnit.Equals("day")) ? Convert.ToInt32(dateFromList[2], 10) : 1;
  79. List<string> dateToList = dateToJobj.ToString().Split('-').ToList();
  80. int dateToYear = Convert.ToInt32(dateToList[0], 10);
  81. int dateToMonth = (dateUnit.Equals("day") || dateUnit.Equals("month")) ? Convert.ToInt32(dateToList[1], 10) : 1;
  82. int dateToDay = (dateUnit.Equals("day")) ? Convert.ToInt32(dateToList[2], 10) : 1;
  83. DateTimeOffset dateTimeFrom = new DateTimeOffset(dateFromYear, dateFromMonth, dateFromDay, 0, 0, 0, TimeSpan.Zero);
  84. DateTimeOffset dateTimeTo = new DateTimeOffset(dateToYear, dateToMonth, dateToDay, 23, 59, 59, TimeSpan.Zero);
  85. long dateTimeFromSec = dateTimeFrom.ToUnixTimeSeconds();
  86. long dateTimeToSec = dateTimeTo.ToUnixTimeSeconds();
  87. //CosmosDB資料取得
  88. ////取得學校基本資訊 => 記入Dictionary
  89. Dictionary<string, Dictionary<string, string>> schDic = new();
  90. string SqlSch = $"SELECT c.id, c.name, c.code, c.region, c.province, c.city, c.areaId, c.dist FROM c WHERE (c.code = 'Base' OR c.code = 'VirtualBase')";
  91. //ARRAY_CONTAINS({schIdListStr}, c.id, true) AND
  92. if(schoolIds.Count > 0)
  93. {
  94. string schIdListStr = JsonSerializer.Serialize(schoolIds);
  95. SqlSch += $" AND ARRAY_CONTAINS({schIdListStr}, c.id, true)";
  96. }
  97. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIteratorSql(queryText: SqlSch, requestOptions: null))
  98. {
  99. var json = await JsonDocument.ParseAsync(item.Content);
  100. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  101. {
  102. string schId = obj.GetProperty("id").GetString();
  103. string name = Convert.ToString(obj.GetProperty("name"));
  104. string region = Convert.ToString(obj.GetProperty("region"));
  105. string province = Convert.ToString(obj.GetProperty("province"));
  106. string city = Convert.ToString(obj.GetProperty("city"));
  107. string dist = (obj.TryGetProperty("dist", out JsonElement distJ)) ? Convert.ToString(distJ) : string.Empty;
  108. string areaId = (obj.TryGetProperty("areaId", out JsonElement areaIdJ)) ? Convert.ToString(areaIdJ) : string.Empty;
  109. string type = Convert.ToString(obj.GetProperty("code"));
  110. if (!schDic.ContainsKey(schId))
  111. {
  112. Dictionary<string, string> schDicRow = new() { { "name", name }, { "region", region }, { "province", province }, { "city", city }, { "dist", dist }, { "areaId", areaId }, { "type", type } };
  113. schDic.Add(schId, schDicRow);
  114. }
  115. }
  116. }
  117. //取得學校產品授權資訊
  118. Dictionary<string, List<SchoolProductSumDataService>> serviceResultDic = new Dictionary<string, List<SchoolProductSumDataService>>(); //key:學校ID
  119. Dictionary<string, List<SchProdSerial>> serialResultDic = new Dictionary<string, List<SchProdSerial>>();
  120. if (schoolIds.Count > 0)
  121. {
  122. try
  123. {
  124. //服務
  125. string schoolIdsStr = JsonSerializer.Serialize(schoolIds);
  126. string SqlSchProdSoervice = $"SELECT * FROM c WHERE ARRAY_CONTAINS({schoolIdsStr}, c.id)";
  127. await foreach (SchoolProductSum schProductSum in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIteratorSql<SchoolProductSum>(queryText: SqlSchProdSoervice, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ProductSum") }))
  128. {
  129. if (schProductSum != null && schProductSum.service != null && schProductSum.service.Count > 0)
  130. {
  131. string schId = schProductSum.id;
  132. if (!serviceResultDic.ContainsKey(schId)) serviceResultDic.Add(schId, new List<SchoolProductSumDataService>());
  133. serviceResultDic[schId] = schProductSum.service;
  134. }
  135. }
  136. }
  137. catch (Exception ex)
  138. {
  139. }
  140. //軟體
  141. if (schoolIds.Count > 0)
  142. {
  143. List<string> schoolCodes = new List<string>();
  144. foreach (string schId in schoolIds)
  145. {
  146. schoolCodes.Add($"Product-{schId}");
  147. }
  148. string schoolCodesStr = JsonSerializer.Serialize(schoolCodes);
  149. string SqlSchProdSoft = $"SELECT * FROM c WHERE c.dataType = 'serial' AND c.expireStatus = 'A' AND ARRAY_CONTAINS({schoolCodesStr}, c.code, true)";
  150. try
  151. {
  152. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIteratorSql(queryText: SqlSchProdSoft, requestOptions: null ))
  153. {
  154. var json = await JsonDocument.ParseAsync(item.Content);
  155. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  156. {
  157. SchoolProductSerial serialRow = obj.ToObject<SchoolProductSerial>();
  158. SchAuthDataSerial schAuthDataSerial = new SchAuthDataSerial();
  159. schAuthDataSerial.prodCode = serialRow.prodCode;
  160. schAuthDataSerial.serial = serialRow.serial;
  161. schAuthDataSerial.deviceBoundCnt = (serialRow.deviceBound != null) ? serialRow.deviceBound.Count : 0;
  162. schAuthDataSerial.clientQty = serialRow.clientQty;
  163. schAuthDataSerial.regDate = serialRow.regDate;
  164. schAuthDataSerial.startDate = serialRow.startDate;
  165. schAuthDataSerial.endDate = serialRow.endDate;
  166. schAuthDataSerial.deviceMax = serialRow.deviceMax;
  167. schAuthDataSerial.aprule = serialRow.aprule;
  168. string schId = serialRow.code.Replace("Product-", "");
  169. if (!serialResultDic.ContainsKey(schId)) serialResultDic.Add(schId, new List<SchProdSerial>());
  170. SchProdSerial schProdSerialNow = serialResultDic[schId].Where(s => s.prodCode.Equals(serialRow.prodCode) && s.endDate.Equals(serialRow.endDate) && s.deviceMax.Equals(serialRow.deviceMax)).FirstOrDefault();
  171. if (schProdSerialNow == null)
  172. {
  173. SchProdSerial schProdSerialNew = new SchProdSerial();
  174. schProdSerialNew.prodCode = serialRow.prodCode;
  175. schProdSerialNew.endDate = serialRow.endDate;
  176. schProdSerialNew.deviceMax = serialRow.deviceMax;
  177. schProdSerialNew.serials.Add(schAuthDataSerial);
  178. serialResultDic[schId].Add(schProdSerialNew);
  179. }
  180. else
  181. {
  182. schProdSerialNow.serials.Add(schAuthDataSerial);
  183. }
  184. }
  185. }
  186. }
  187. catch (Exception ex)
  188. {
  189. }
  190. }
  191. }
  192. ////取得IOT產品分析資訊、回傳結果製作
  193. List<string> calProperty = new List<string>() {"lessonRecord", "useIES", "useIES5Resource", "useWebIrs", "useDeviceIrs", "useHaboard", "useHita", "lessonLengMin", "lessonLeng0","stuShow", "stuLessonLengMin", "tGreen", "tLesson", "lTypeCoop", "lTypeIact", "lTypeMis", "lTypeTst", "lTypeDif", "lTypeNone", "lessonCnt928","lessonCntId","lessonCntDevice","lessonCntIdDevice","mission","missionFin","item","interact","sendSok","learnPeer","learnCoop","useWordCloud","useClouDAS","useGPT","useIes5Test","usePaperTest","useExcelTest","useScoreBoard","learnParticipationCnt","learnParticipationT","coopMission","coopWork","coopContributionT","peerAct","peerStuParticipationT","useTransMode","useMiniMode"}; //要加算統計的欄位名
  194. List<ProdAnalysisApiResult> result = new List<ProdAnalysisApiResult>(); //各校統計資料
  195. Dictionary<string, ProdAnalysisApiResult> geoDic = new Dictionary<string, ProdAnalysisApiResult>(); //各地理資訊統計資料
  196. string Sql = $"SELECT * FROM c WHERE c.toolType = '{prod}' AND c.dateUnit = '{dateUnit}' AND c.dateTime >= {dateTimeFromSec} AND c.dateTime <= {dateTimeToSec}";
  197. if(schoolIds.Count > 0)
  198. {
  199. schoolIds.Add("noschoolid");
  200. schoolIds.Add("allschool");
  201. string schIdListStr = JsonSerializer.Serialize(schoolIds);
  202. Sql += $" AND ARRAY_CONTAINS({schIdListStr}, c.schoolId, true)";
  203. }
  204. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIteratorSql(queryText: Sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ProdAnalysis") }))
  205. {
  206. var json = await JsonDocument.ParseAsync(item.Content);
  207. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  208. {
  209. ProdAnalysisApiResult resultRow = obj.ToObject<ProdAnalysisApiResult>();
  210. resultRow.lTypeNone = ((resultRow.lTypeNone - resultRow.lessonLeng0) < 0) ? 0 : resultRow.lTypeNone - resultRow.lessonLeng0; //無學習型態數值須扣除未上課
  211. //各校IOT統計
  212. if (schDic.ContainsKey(resultRow.schoolId))
  213. {
  214. resultRow.school.name = schDic[resultRow.schoolId]["name"];
  215. resultRow.school.region = schDic[resultRow.schoolId]["region"];
  216. resultRow.school.province = schDic[resultRow.schoolId]["province"];
  217. resultRow.school.city = schDic[resultRow.schoolId]["city"];
  218. resultRow.school.dist = schDic[resultRow.schoolId]["dist"];
  219. resultRow.school.areaId = schDic[resultRow.schoolId]["areaId"];
  220. resultRow.school.type = schDic[resultRow.schoolId]["type"];
  221. }
  222. //各校產品授權資訊
  223. result.Add(resultRow);
  224. //地理位置統計
  225. string geoKey = string.Empty;
  226. switch (geoUnit)
  227. {
  228. case "region":
  229. geoKey = resultRow.school.region;
  230. break;
  231. case "province":
  232. geoKey = resultRow.school.region + resultRow.school.province;
  233. break;
  234. case "city":
  235. geoKey = resultRow.school.region + resultRow.school.province + resultRow.school.city;
  236. break;
  237. case "dist":
  238. geoKey = resultRow.school.region + resultRow.school.province + resultRow.school.city + resultRow.school.dist;
  239. break;
  240. }
  241. if (!string.IsNullOrWhiteSpace(geoKey))
  242. {
  243. geoKey = $"{geoKey}-{resultRow.date}";
  244. if (!geoDic.ContainsKey(geoKey)) geoDic.Add(geoKey, new ProdAnalysisApiResult());
  245. foreach (PropertyInfo propertyInfo in resultRow.GetType().GetProperties())
  246. {
  247. if (calProperty.Contains(propertyInfo.Name))
  248. {
  249. var propType = propertyInfo.PropertyType;
  250. var valNow = propertyInfo.GetValue(geoDic[geoKey]);
  251. var valTodo = resultRow.GetType().GetProperty(propertyInfo.Name).GetValue(resultRow);
  252. if (propType.Equals(typeof(long))) propertyInfo.SetValue(geoDic[geoKey], Convert.ToInt64(valNow.ToString(), 10) + Convert.ToInt64(valTodo.ToString(), 10));
  253. else propertyInfo.SetValue(geoDic[geoKey], Convert.ToInt32(valNow.ToString(), 10) + Convert.ToInt32(valTodo.ToString(), 10));
  254. }
  255. }
  256. decimal learnParticipationTmp = (resultRow.learnParticipationCnt > 0) ? (decimal)resultRow.learnParticipationT / (decimal)resultRow.learnParticipationCnt : 0;
  257. geoDic[geoKey].date = resultRow.date;
  258. geoDic[geoKey].learnParticipation = Math.Round(learnParticipationTmp, 2); //學習參與度指數(平均)
  259. geoDic[geoKey].deviceList = geoDic[geoKey].deviceList.Union(resultRow.deviceList).ToList();
  260. geoDic[geoKey].deviceCnt = geoDic[geoKey].deviceList.Count;
  261. geoDic[geoKey].deviceAuthList = geoDic[geoKey].deviceAuthList.Union(resultRow.deviceAuthList).ToList();
  262. geoDic[geoKey].deviceAuth = geoDic[geoKey].deviceAuthList.Count;
  263. geoDic[geoKey].deviceNoAuthList = geoDic[geoKey].deviceNoAuthList.Union(resultRow.deviceNoAuthList).ToList();
  264. geoDic[geoKey].deviceNoAuth = geoDic[geoKey].deviceNoAuthList.Count;
  265. geoDic[geoKey].tmidList = geoDic[geoKey].tmidList.Union(resultRow.tmidList).ToList();
  266. geoDic[geoKey].tmidCnt = geoDic[geoKey].tmidList.Count;
  267. }
  268. }
  269. }
  270. //地理資訊統計資料整理
  271. List<ProdAnalysisApiResultGeoExtend> geoResult = new List<ProdAnalysisApiResultGeoExtend>();
  272. foreach(KeyValuePair<string, ProdAnalysisApiResult> geoDicRow in geoDic)
  273. {
  274. ProdAnalysisApiResultGeoExtend geoResultRow = new ProdAnalysisApiResultGeoExtend();
  275. foreach (PropertyInfo propertyInfo in geoDicRow.Value.GetType().GetProperties())
  276. {
  277. var valNow = propertyInfo.GetValue(geoDicRow.Value);
  278. propertyInfo.SetValue(geoResultRow, valNow);
  279. }
  280. geoResultRow.geoInfo = geoDicRow.Key.Split("-").First();
  281. geoResult.Add(geoResultRow);
  282. }
  283. //學校產品授權資料整理
  284. List<SchAuthData> auth = new List<SchAuthData>();
  285. ////服務
  286. foreach(KeyValuePair<string, List<SchoolProductSumDataService>> op in serviceResultDic)
  287. {
  288. string schIdNow = op.Key;
  289. SchAuthData schAuthDataNow = auth.Where(a => a.schId.Equals(schIdNow)).FirstOrDefault();
  290. if(schAuthDataNow != null)
  291. {
  292. schAuthDataNow.authService = op.Value;
  293. }
  294. else
  295. {
  296. SchAuthData schAuthDataNew = new SchAuthData();
  297. schAuthDataNew.schId = schIdNow;
  298. schAuthDataNew.authService = op.Value;
  299. auth.Add(schAuthDataNew);
  300. }
  301. }
  302. ////序號
  303. foreach (KeyValuePair<string, List<SchProdSerial>> op in serialResultDic)
  304. {
  305. string schIdNow = op.Key;
  306. SchAuthData schAuthDataNow = auth.Where(a => a.schId.Equals(schIdNow)).FirstOrDefault();
  307. if (schAuthDataNow != null)
  308. {
  309. schAuthDataNow.authSerial = op.Value;
  310. }
  311. else
  312. {
  313. SchAuthData schAuthDataNew = new SchAuthData();
  314. schAuthDataNew.schId = schIdNow;
  315. schAuthDataNew.authSerial = op.Value;
  316. auth.Add(schAuthDataNew);
  317. }
  318. }
  319. return Ok(new { state = 200, data = result, geo = geoResult, auth });
  320. }
  321. catch (Exception ex)
  322. {
  323. await _dingDing.SendBotMsg($"BI,{_option.Location} /prodanalysis/get-iotstics \n {ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  324. return BadRequest();
  325. }
  326. }
  327. /// <summary>
  328. /// 取得學校資訊
  329. /// </summary>
  330. /// <param name="jsonElement"></param>
  331. /// <returns></returns>
  332. [ProducesDefaultResponseType]
  333. [Authorize(Roles = "IES")]
  334. [HttpPost("get-school")]
  335. public async Task<IActionResult> GetSchoolInfo(JsonElement jsonElement)
  336. {
  337. try
  338. {
  339. var cosmosClient = _azureCosmos.GetCosmosClient();
  340. List<string> schoolIds = (jsonElement.TryGetProperty("schoolIds", out JsonElement schoolIdsJobj)) ? schoolIdsJobj.ToObject<List<string>>() : new List<string>(); //學校ID(array)
  341. string region = (jsonElement.TryGetProperty("region", out JsonElement regionJobj)) ? regionJobj.GetString() : string.Empty; //地區
  342. string province = (jsonElement.TryGetProperty("province", out JsonElement provinceJobj)) ? provinceJobj.GetString() : string.Empty; //省
  343. string city = (jsonElement.TryGetProperty("city", out JsonElement cityJobj)) ? cityJobj.GetString() : string.Empty; //市
  344. string dist = (jsonElement.TryGetProperty("dist", out JsonElement distJobj)) ? distJobj.GetString() : string.Empty; //區
  345. List<string> areaIds = (jsonElement.TryGetProperty("areaIds", out JsonElement areaIdsJobj)) ? areaIdsJobj.ToObject<List<string>>() : new List<string>(); //學區ID(array)
  346. bool hasVirtual = (jsonElement.TryGetProperty("virtual", out JsonElement virtualJobj)) ? virtualJobj.GetBoolean() : true; //是否取得虛擬學校
  347. //國際站欄位調整
  348. if(_option.Location.Contains("Global"))
  349. {
  350. if(string.IsNullOrWhiteSpace(region) && !string.IsNullOrWhiteSpace(province))
  351. {
  352. region = province;
  353. province = string.Empty;
  354. dist = string.Empty;
  355. }
  356. }
  357. //地區特殊字去除
  358. comeRemoveStr.ForEach(c => { region = region.Replace(c, ""); });
  359. comeRemoveStr.ForEach(c => { province = province.Replace(c, ""); });
  360. if (!_option.Location.Contains("Global")) comeRemoveStr.ForEach(c => { city = city.Replace(c, ""); }); //國際站不去除「市」的特殊字元,以區分縣市
  361. comeRemoveStr.ForEach(c => { dist = dist.Replace(c, ""); });
  362. //CosmosDB資料取得
  363. List<SimpleSchoolInfo> result = new List<SimpleSchoolInfo>();
  364. ///檢索條件全無對策
  365. if(schoolIds.Count.Equals(0) && string.IsNullOrWhiteSpace(region) && string.IsNullOrWhiteSpace(province) && string.IsNullOrWhiteSpace(city) && string.IsNullOrWhiteSpace(dist) && areaIds.Count.Equals(0))
  366. {
  367. return Ok(new { state = 200, data = result });
  368. }
  369. string schIdListStr = JsonSerializer.Serialize(schoolIds);
  370. string areaIdsListStr = JsonSerializer.Serialize(areaIds);
  371. string Sql = $"SELECT c.id, c.name, c.region, c.province, c.city, c.dist, c.areaId FROM c WHERE (c.pk = 'Base' OR c.pk = 'School')";
  372. if (schoolIds.Count > 0) Sql += $" AND ARRAY_CONTAINS({schIdListStr}, c.id, true)";
  373. if (!string.IsNullOrWhiteSpace(region)) Sql += $" AND CONTAINS(c.region, '{region}')";
  374. if (!string.IsNullOrWhiteSpace(province)) Sql += $" AND CONTAINS(c.province, '{province}')";
  375. if (!string.IsNullOrWhiteSpace(city)) Sql += $" AND CONTAINS(c.city, '{city}')";
  376. if (!string.IsNullOrWhiteSpace(dist)) Sql += $" AND CONTAINS(c.dist, '{dist}')";
  377. if (areaIds.Count > 0) Sql += $" AND ARRAY_CONTAINS({areaIdsListStr}, c.areaId, true)";
  378. //實體學校
  379. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIteratorSql(queryText: Sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
  380. {
  381. using var json = await JsonDocument.ParseAsync(item.Content);
  382. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  383. {
  384. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  385. {
  386. SimpleSchoolInfo resultRow = obj.ToObject<SimpleSchoolInfo>();
  387. result.Add(resultRow);
  388. }
  389. }
  390. }
  391. //虛擬學校
  392. if (hasVirtual)
  393. {
  394. await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIteratorSql(queryText: Sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"VirtualBase") }))
  395. {
  396. using var json = await JsonDocument.ParseAsync(item.Content);
  397. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  398. {
  399. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  400. {
  401. SimpleSchoolInfo resultRow = obj.ToObject<SimpleSchoolInfo>();
  402. resultRow.isvirtual = true;
  403. result.Add(resultRow);
  404. }
  405. }
  406. }
  407. }
  408. return Ok(new { state = 200, data = result });
  409. }
  410. catch (Exception ex)
  411. {
  412. await _dingDing.SendBotMsg($"BI,{_option.Location} /prodanalysis/get-iotstics \n {ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  413. return BadRequest();
  414. }
  415. }
  416. public List<string> comeRemoveStr = new List<string>() { "省", "市", "区", "州", "县", "旗", "盟", "自治", "地區", "區", "縣" };
  417. private class SimpleSchoolInfo
  418. {
  419. public string id { get; set; }
  420. public string name { get; set; }
  421. public string region { get; set; }
  422. public string province { get; set; }
  423. public string city { get; set; }
  424. public string dist { get; set; }
  425. public string areaId { get; set; }
  426. public bool isvirtual { get; set; }
  427. }
  428. private class ProdAnalysisApiResultGeoExtend : ProdAnalysisApiResult
  429. {
  430. public string geoInfo { get; set; }
  431. }
  432. private class SchProdSerial
  433. {
  434. public string prodCode { get; set; }
  435. public long endDate { get; set; }
  436. public int deviceMax { get; set; }
  437. public List<SchAuthDataSerial> serials { get; set; } = new List<SchAuthDataSerial>();
  438. }
  439. private class SchAuthData {
  440. public string schId { get; set; }
  441. public List<SchProdSerial> authSerial { get; set; } = new();
  442. public List<SchoolProductSumDataService> authService { get; set; } = new();
  443. }
  444. private class SchAuthDataSerial
  445. {
  446. public string prodCode { get; set; }
  447. public string serial { get; set; }
  448. public int deviceBoundCnt { get; set; }
  449. public int clientQty { get; set; }
  450. public long regDate { get; set; }
  451. public long startDate { get; set; }
  452. public long endDate { get; set; }
  453. public int deviceMax { get; set; }
  454. public object aprule { get; set; }
  455. }
  456. }
  457. }