TmidController.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. using Azure.Cosmos;
  2. using Microsoft.AspNetCore.Mvc;
  3. using Microsoft.Azure.Cosmos.Table;
  4. using Microsoft.Extensions.Configuration;
  5. using Microsoft.Extensions.Options;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.Text.Json;
  11. using System.Threading.Tasks;
  12. using TEAMModelOS.Models;
  13. using TEAMModelOS.SDK;
  14. using TEAMModelOS.SDK.DI;
  15. using TEAMModelOS.SDK.Extension;
  16. using TEAMModelOS.SDK.Models;
  17. using TEAMModelOS.SDK.Services;
  18. namespace TEAMModelBI.Controllers.BITmid
  19. {
  20. [Route("tmid")]
  21. [ApiController]
  22. public class TmidController : ControllerBase
  23. {
  24. private readonly AzureCosmosFactory _azureCosmos;
  25. private readonly AzureStorageFactory _azureStorage;
  26. private readonly AzureRedisFactory _azureRedis;
  27. private readonly DingDing _dingDing;
  28. private readonly Option _option;
  29. private readonly IConfiguration _configuration;
  30. private readonly HttpTrigger _httpTrigger;
  31. public TmidController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, HttpTrigger httpTrigger)
  32. {
  33. _azureCosmos = azureCosmos;
  34. _azureStorage = azureStorage;
  35. _azureRedis = azureRedis;
  36. _dingDing = dingDing;
  37. _option = option?.Value;
  38. _configuration = configuration;
  39. _httpTrigger = httpTrigger;
  40. }
  41. /// <summary>
  42. /// 取得TMID綜合資料
  43. /// </summary>
  44. /// <param name="jsonElement"></param>
  45. /// <returns></returns>
  46. [ProducesDefaultResponseType]
  47. //[AuthToken(Roles = "admin")]
  48. [HttpPost("get-tmidstics")]
  49. public async Task<IActionResult> GetTmidStics(JsonElement jsonElement)
  50. {
  51. try
  52. {
  53. if (!jsonElement.TryGetProperty("tmids", out JsonElement tmidsJobj)) return BadRequest();//TMID(array)
  54. var tmids = tmidsJobj.Deserialize<List<string>>();
  55. if (tmids.Count is 0) return BadRequest();
  56. var datetime = DateTimeOffset.UtcNow.AddDays(-1);
  57. var y = datetime.Year;
  58. var m = datetime.Month;
  59. var d = datetime.Day;
  60. //服務Client端
  61. var cosmosClientIes5 = _azureCosmos.GetCosmosClient(); //CosmosDB IES5
  62. var cosmosClientCsv2 = _azureCosmos.GetCosmosClient(name: "CoreServiceV2"); //CosmosDB CSV2
  63. var storageClientCsv2 = _azureStorage.GetCloudTableClient(name: "CoreServiceV2"); //Storage CSV2
  64. var tableCouponClient = storageClientCsv2.GetTableReference("Coupon");
  65. var tablePointsClient = storageClientCsv2.GetTableReference("Points");
  66. var redisClient = _azureRedis.GetRedisClient(4);
  67. //存放user資料
  68. Dictionary<string, TmidStics> tmidDic = new();
  69. QueryDefinition query =
  70. new QueryDefinition(@"SELECT c.id, c.name, c.mobile, c.mail FROM c WHERE (ARRAY_CONTAINS(@key, c.id) OR ARRAY_CONTAINS(@key, c.mobile))")
  71. .WithParameter("@key", tmids);
  72. await foreach (var item in cosmosClientCsv2
  73. .GetContainer("Core", "ID2")
  74. .GetItemQueryStreamIterator(query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("base") }))
  75. {
  76. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  77. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  78. {
  79. foreach (var doc in json.RootElement.GetProperty("Documents").EnumerateArray())
  80. {
  81. string id = doc.GetProperty("id").GetString();
  82. if(!tmids.Contains(id)) tmids.Add(id);
  83. //基本資料
  84. TmidStics tmidStics = (tmidDic.ContainsKey(id)) ? tmidDic[id] : new() { id = id };
  85. string tmidName = doc.GetProperty("name").GetString();
  86. string tmidMobile = GenDataMask(doc.GetProperty("mobile").GetString(), "mobile");
  87. string tmidMail = GenDataMask(doc.GetProperty("mail").GetString(), "mail");
  88. //票券
  89. var usersCoupons = tableCouponClient.Get<DynamicTableEntity>(id);
  90. foreach (var coupon in usersCoupons)
  91. {
  92. tmidStics.coupons.Add(
  93. new TmidCoupon()
  94. {
  95. code = coupon.RowKey,
  96. exchange = coupon.Properties["exchangeTime"].DateTimeOffsetValue.Value.ToUnixTimeSeconds(),
  97. });
  98. }
  99. //登入各服務的時間
  100. var loginTime = await redisClient.HashGetAllAsync(id);
  101. foreach (var t in loginTime)
  102. {
  103. if (!t.Name.StartsWith("HiTeach") && !_dicClientIds.ContainsKey(t.Name)) continue;
  104. tmidStics.login.Add(
  105. new TmidLoginTime()
  106. {
  107. product = t.Name.StartsWith("HiTeach") ? t.Name.ToString().Split("-")[0] : _dicClientIds[t.Name],
  108. time = (long)t.Value
  109. });
  110. }
  111. //積分
  112. var usersPoints = tablePointsClient.Get("Points", id);
  113. tmidStics.points.points = (usersPoints != null) ? usersPoints.Properties["Points"].Int32Value.Value : 0;
  114. tmidStics.points.level = (usersPoints != null) ? usersPoints.Properties["Level"].Int32Value.Value : 0;
  115. tmidStics.points.balance = (usersPoints != null) ? usersPoints.Properties["Balance"].Int32Value.Value : 0;
  116. //個人服務授權
  117. tmidStics.prod = await getTMIDAuthService(cosmosClientCsv2, id, "", true);
  118. //IOT
  119. tmidStics.iot.hiteach.year = await getTMIDIotData(cosmosClientIes5, id, "HiTeach", "year", y, 0, 0, 0, 0);
  120. tmidStics.iot.hiteach.month = await getTMIDIotData(cosmosClientIes5, id, "HiTeach", "month", y, m, 0, 0, 0);
  121. tmidStics.iot.hiteach.day = await getTMIDIotData(cosmosClientIes5, id, "HiTeach", "day", y, m, d, 0, 0);
  122. tmidStics.iot.hiteachcc.year = await getTMIDIotData(cosmosClientIes5, id, "HiTeachCC", "year", y, 0, 0, 0, 0);
  123. tmidStics.iot.hiteachcc.month = await getTMIDIotData(cosmosClientIes5, id, "HiTeachCC", "month", y, m, 0, 0, 0);
  124. tmidStics.iot.hiteachcc.day = await getTMIDIotData(cosmosClientIes5, id, "HiTeachCC", "day", y, m, d, 0, 0);
  125. tmidDic.Add(id, tmidStics);
  126. }
  127. }
  128. }
  129. //ID進階資料
  130. query = new QueryDefinition(@"SELECT c.id, c.name, c.mobile, c.mail, c.country, c.province, c.city, c.schoolCode, c.schoolCodeW FROM c WHERE (ARRAY_CONTAINS(@key, c.id) OR ARRAY_CONTAINS(@key, c.mobile))")
  131. .WithParameter("@key", tmids);
  132. await foreach (var item in cosmosClientCsv2
  133. .GetContainer("Core", "ID2")
  134. .GetItemQueryStreamIterator(query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("base-ex") }))
  135. {
  136. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  137. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  138. {
  139. foreach (var doc in json.RootElement.GetProperty("Documents").EnumerateArray())
  140. {
  141. string id = doc.GetProperty("id").GetString();
  142. TmidStics tmidStics = (tmidDic.ContainsKey(id)) ? tmidDic[id] : new() { id = id };
  143. if (string.IsNullOrWhiteSpace(tmidStics.name)) tmidStics.name = doc.GetProperty("name").GetString();
  144. if (string.IsNullOrWhiteSpace(tmidStics.mobile)) tmidStics.mobile = GenDataMask(doc.GetProperty("mobile").GetString(), "mobile");
  145. if (string.IsNullOrWhiteSpace(tmidStics.mail)) tmidStics.mail = GenDataMask(doc.GetProperty("mail").GetString(), "mail");
  146. tmidStics.country = doc.GetProperty("country").GetString();
  147. tmidStics.province = doc.GetProperty("province").GetString();
  148. tmidStics.city = doc.GetProperty("city").GetString();
  149. tmidStics.schoolCode = (doc.TryGetProperty("schoolCode", out JsonElement schCode)) ? schCode.GetString() : string.Empty;
  150. tmidStics.schoolCodeW = (doc.TryGetProperty("schoolCodeW", out JsonElement schCodeW)) ? schCodeW.GetString() : string.Empty;
  151. }
  152. }
  153. }
  154. //IES5
  155. query = new QueryDefinition(@"SELECT c.id, c.defaultSchool, c.schools FROM c WHERE ARRAY_CONTAINS(@key, c.id)")
  156. .WithParameter("@key", tmids);
  157. await foreach (var item in cosmosClientIes5
  158. .GetContainer(Constant.TEAMModelOS, "Teacher")
  159. .GetItemQueryStreamIterator(query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
  160. {
  161. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  162. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  163. {
  164. foreach (var doc in json.RootElement.GetProperty("Documents").EnumerateArray())
  165. {
  166. string id = doc.GetProperty("id").GetString();
  167. //TmidStics tmidStics = (tmidDic.ContainsKey(id)) ? tmidDic[id] : new() { id = id, ies5 = new TmidSticsIes5() { schools = new List<object>() } };
  168. TmidStics tmidStics;
  169. if (tmidDic.ContainsKey(id))
  170. {
  171. tmidStics = tmidDic[id];
  172. } else
  173. {
  174. tmidStics = new TmidStics();
  175. tmidStics.id = id;
  176. }
  177. //IES5學校資訊
  178. string defaultschool = (doc.TryGetProperty("defaultSchool", out JsonElement _defaultSchool)) ? _defaultSchool.ToString() : string.Empty; //預設學校
  179. List<string> schoolIds = new List<string>();
  180. if (doc.TryGetProperty("schools", out JsonElement schoolsJobj))
  181. {
  182. foreach (var obj in schoolsJobj.EnumerateArray())
  183. {
  184. string schoolCodeNow = $"{obj.GetProperty("schoolId")}";
  185. string status = $"{obj.GetProperty("status")}";
  186. if(status.Equals("join"))
  187. {
  188. schoolIds.Add(schoolCodeNow); //放入學校ID列,一次取
  189. }
  190. }
  191. }
  192. if (schoolIds.Count > 0)
  193. {
  194. QueryDefinition querysc = new QueryDefinition(@"SELECT c.id, c.name, c.region, c.province, c.city, c.dist, c.size, c.period FROM c WHERE ARRAY_CONTAINS(@key, c.id)")
  195. .WithParameter("@key", schoolIds);
  196. await foreach (var itemsc in cosmosClientIes5
  197. .GetContainer(Constant.TEAMModelOS, "School")
  198. .GetItemQueryStreamIterator(querysc, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
  199. {
  200. using var jsonsc = await JsonDocument.ParseAsync(itemsc.ContentStream);
  201. if (jsonsc.RootElement.TryGetProperty("_count", out JsonElement countsc) && countsc.GetUInt16() > 0)
  202. {
  203. foreach (var school in jsonsc.RootElement.GetProperty("Documents").EnumerateArray())
  204. {
  205. string schoolCodeNow = school.GetProperty("id").GetString();
  206. //當前學年 ※若有多學段,取第一個學段來取得學年資訊吧
  207. Period period = school.GetProperty("period").Deserialize<List<Period>>().First();
  208. var info = SchoolService.GetSemester(period, 0, DateTime.Now.ToString());
  209. int studyYear = info.studyYear;
  210. //學校Blob使用狀況
  211. (long usedSize, long teach, long total, long surplus, Dictionary<string, double?> catalog) schoolUsedBlob = await BlobService.GetSurplusSpace(schoolCodeNow, "school", _option.Location, _azureCosmos, _azureRedis, _azureStorage, _dingDing, _httpTrigger);
  212. //老師在此學校的課程數 ※只取當前學年
  213. int courseCnt = 0;
  214. var queryCrs = $"SELECT VALUE COUNT(1) FROM ( SELECT DISTINCT VALUE(c.id) FROM c JOIN schedules IN c.schedules WHERE schedules.teacherId = '{id}' AND c.year = {studyYear} )";
  215. await foreach (int itemCrs in cosmosClientIes5.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<int>(queryText: queryCrs, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"CourseTask-{schoolCodeNow}") }))
  216. {
  217. courseCnt = itemCrs;
  218. }
  219. //IES5學校資料製作
  220. TmidSticsIes5School schoolobj = new TmidSticsIes5School();
  221. long ssize = (school.TryGetProperty("size", out JsonElement ssizeJson)) ? ssizeJson.GetInt32() : 0;
  222. long sused = schoolUsedBlob.usedSize + schoolUsedBlob.teach * 1073741824;
  223. long stotal = ssize * 1073741824;
  224. object schzize = new
  225. {
  226. used = sused,
  227. total = stotal,
  228. avaliable = stotal - sused,
  229. };
  230. schoolobj.schoolId = schoolCodeNow;
  231. schoolobj.name = school.GetProperty("name").GetString();
  232. schoolobj.region = school.GetProperty("region").GetString();
  233. schoolobj.province = school.GetProperty("province").GetString();
  234. schoolobj.city = school.GetProperty("city").GetString();
  235. schoolobj.dist = school.GetProperty("dist").GetString();
  236. schoolobj.size = schzize;
  237. schoolobj.courseCnt = courseCnt;
  238. schoolobj.defaultSchool = (!string.IsNullOrWhiteSpace(defaultschool) && defaultschool.Equals(schoolCodeNow)) ? true : false;
  239. tmidStics.ies5.schools.Add(schoolobj);
  240. }
  241. }
  242. }
  243. }
  244. //IES5個人空間
  245. var (usedSize, teach, total, surplus, catalog) = await BlobService.GetSurplusSpace(id, "private", _option.Location, _azureCosmos, _azureRedis, _azureStorage, _dingDing, _httpTrigger);
  246. tmidStics.ies5.usedSize = usedSize;
  247. tmidStics.ies5.teachSize = teach * 1073741824;
  248. tmidStics.ies5.totalSize = total * 1073741824;
  249. tmidStics.ies5.surplusSize = surplus;
  250. //IES5個人資源數
  251. tmidStics.ies5.resCount = 0; //教材數
  252. tmidStics.ies5.itemCount = 0; //題目數
  253. tmidStics.ies5.paperCount = 0; //試卷數
  254. ///IES5個人題目數
  255. await foreach (int itemC in cosmosClientIes5.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<int>(queryText: $"SELECT VALUE COUNT(1) FROM c WHERE c.pid = null", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{id}") }))
  256. {
  257. tmidStics.ies5.itemCount = itemC;
  258. }
  259. ///IES5個人試卷數
  260. await foreach (int paperC in cosmosClientIes5.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<int>(queryText: $"SELECT VALUE COUNT(1) FROM c WHERE c.scope = 'private'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Paper-{id}") }))
  261. {
  262. tmidStics.ies5.paperCount = paperC;
  263. }
  264. ///IES5個人教材數
  265. List<BlobService.BlobCount> blogCountList = await BlobService.BloblogCount(cosmosClientIes5, "private", id, "", "");
  266. foreach (BlobService.BlobCount blobCountRow in blogCountList)
  267. {
  268. switch (blobCountRow.type)
  269. {
  270. case "doc":
  271. case "image":
  272. case "res":
  273. case "video":
  274. case "audio":
  275. case "other":
  276. tmidStics.ies5.resCount += blobCountRow.count;
  277. break;
  278. }
  279. }
  280. if(!tmidDic.ContainsKey(id)) tmidDic.Add(id, tmidStics);
  281. }
  282. }
  283. }
  284. //個人權益
  285. query = new QueryDefinition(@"SELECT * FROM c WHERE (ARRAY_CONTAINS(@key, c.id))")
  286. .WithParameter("@key", tmidDic.Keys.ToList());
  287. await foreach (var item in cosmosClientCsv2
  288. .GetContainer("Core", "ID2")
  289. .GetItemQueryStreamIterator(query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("benefits") }))
  290. {
  291. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  292. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  293. {
  294. foreach (var doc in json.RootElement.GetProperty("Documents").EnumerateArray())
  295. {
  296. string id = doc.GetProperty("id").GetString();
  297. if (doc.TryGetProperty("hiteach", out var elementHiteachData))
  298. {
  299. tmidDic[id].benefits.hiteach = elementHiteachData.ToObject<List<object>>();
  300. }
  301. if (doc.TryGetProperty("hiteachcc", out var elementHiteachCCData))
  302. {
  303. tmidDic[id].benefits.hiteachcc = elementHiteachCCData.ToObject<List<object>>();
  304. }
  305. }
  306. }
  307. }
  308. //蘇格拉底資料
  309. query = new QueryDefinition(@"SELECT * FROM c WHERE (ARRAY_CONTAINS(@key, c.id))")
  310. .WithParameter("@key", tmidDic.Keys.ToList());
  311. await foreach (var item in cosmosClientCsv2
  312. .GetContainer("Core", "ID2")
  313. .GetItemQueryStreamIterator(query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("sokrates") }))
  314. {
  315. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  316. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  317. {
  318. foreach (var doc in json.RootElement.GetProperty("Documents").EnumerateArray())
  319. {
  320. string id = doc.GetProperty("id").GetString();
  321. if (doc.TryGetProperty("hiteach_data", out var elementHiteachData))
  322. {
  323. tmidDic[id].sokrates.hiteach_data = elementHiteachData.ToObject<object>();
  324. }
  325. if (doc.TryGetProperty("user_channels", out var elementUserChannels))
  326. {
  327. tmidDic[id].sokrates.user_channels = elementUserChannels.ToObject<object>();
  328. }
  329. }
  330. }
  331. }
  332. //輸出
  333. List<object> data = new();
  334. foreach (KeyValuePair<string, TmidStics> dicItem in tmidDic)
  335. {
  336. data.Add(dicItem.Value);
  337. }
  338. return Ok(data);
  339. }
  340. catch (Exception ex)
  341. {
  342. //await _dingDing.SendBotMsg($"BI,{_option.Location} /tmid/get-tmidstics \n {ex.Message}\n{ex.StackTrace}", GroupNames.台北開發測試群組);
  343. return BadRequest();
  344. }
  345. }
  346. //取得TMID服務授權週期
  347. public async Task<List<object>> getTMIDAuthService(CosmosClient cosmosClientCsv2, string tmid, string prodCode, bool validFlg)
  348. {
  349. long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
  350. var qryOption = new QueryRequestOptions() { PartitionKey = new PartitionKey("servicePeriod") };
  351. string whereSql = $"c.saleClient.tmid = '{tmid}'";
  352. if (!string.IsNullOrWhiteSpace(prodCode)) whereSql += $" AND c.prodCode = '{prodCode}'";
  353. if (validFlg) whereSql += $" AND c.startDate <= {now} AND {now} <= c.endDate";
  354. string sql = $"SELECT c.id, c.prodCode, c.type, c.startDate, c.endDate, c.number, c.unit, c.aprule FROM c WHERE {whereSql}";
  355. var client = cosmosClientCsv2.GetContainer("Habb", "Auth");
  356. var result = new List<object>();
  357. await foreach (var item in client.GetItemQueryStreamIterator(queryText: sql, requestOptions: qryOption))
  358. {
  359. var json = await JsonDocument.ParseAsync(item.ContentStream);
  360. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  361. {
  362. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  363. {
  364. result.Add(
  365. new
  366. {
  367. id = obj.GetProperty("id").GetString(),
  368. prodCode = obj.GetProperty("prodCode").GetString(),
  369. type = obj.GetProperty("type").GetInt32(),
  370. startDate = obj.GetProperty("startDate").GetInt64(),
  371. endDate = obj.GetProperty("endDate").GetInt64(),
  372. number = obj.GetProperty("number").GetInt32(),
  373. aprule = obj.GetProperty("aprule")
  374. });
  375. }
  376. }
  377. }
  378. return result;
  379. }
  380. //取得TMID購買紀錄
  381. public async Task<List<Ies5OrderHis>> getTMIDAuthOrder(CosmosClient cosmosClientCsv2, string tmid, string prodCode)
  382. {
  383. SortedDictionary<string, Ies5OrderHis> OrderDic = new SortedDictionary<string, Ies5OrderHis>();
  384. var qryOption = new QueryRequestOptions() { PartitionKey = new PartitionKey("order") };
  385. //服務 ※序號、硬體 不列入購買紀錄
  386. string strQueryV = $"SELECT * FROM c WHERE IS_DEFINED(c.saleClient.tmid) AND c.saleClient.tmid = '{tmid}' AND c.prodType = 'service'";
  387. if (!string.IsNullOrWhiteSpace(prodCode))
  388. {
  389. strQueryV += $" AND c.prodCode = '{prodCode}'";
  390. }
  391. await foreach (OrderHisService orderService in cosmosClientCsv2.GetContainer("Habb", "Auth").GetItemQueryIterator<OrderHisService>(strQueryV, null, qryOption))
  392. {
  393. Ies5OrderHisService ies5OrderVRow = new Ies5OrderHisService();
  394. ies5OrderVRow.prodCode = orderService.prodCode;
  395. ies5OrderVRow.type = (orderService.contract.Equals(1)) ? "C" : (orderService.contract.Equals(2)) ? "G" : "N"; //授權方式 [FROM]contract契約型態 0:新約 1:續約 2:變更 [TO]type N:新約 C:續約 G:變更
  396. ies5OrderVRow.sdate = orderService.startDate;
  397. ies5OrderVRow.edate = orderService.endDate;
  398. ies5OrderVRow.number = orderService.number;
  399. ies5OrderVRow.unit = orderService.unit;
  400. //加入Order字典
  401. string OrderID = orderService.orderinfo.orderid.ToString();
  402. long OrderDate = orderService.orderinfo.createDate;
  403. if (OrderDic.ContainsKey(OrderID))
  404. {
  405. OrderDic[OrderID].service.Add(ies5OrderVRow);
  406. }
  407. else
  408. {
  409. Ies5OrderHis ies5OrderHisNew = new Ies5OrderHis();
  410. ies5OrderHisNew.id = OrderID;
  411. ies5OrderHisNew.date = OrderDate;
  412. ies5OrderHisNew.service.Add(ies5OrderVRow);
  413. OrderDic.Add(OrderID, ies5OrderHisNew);
  414. }
  415. }
  416. //輸出項
  417. List<Ies5OrderHis> Result = new List<Ies5OrderHis>();
  418. foreach (KeyValuePair<string, Ies5OrderHis> item in OrderDic)
  419. {
  420. Result.Add(item.Value);
  421. }
  422. return Result;
  423. }
  424. //Tool
  425. //資料遮罩
  426. ///規則:
  427. ///1.手機、電話:隱藏後4碼
  428. ///2.Mail:隱藏@前資料
  429. ///3.姓名:只顯示第一個字元
  430. ///4.身分證、護照:隱藏後4碼
  431. public string GenDataMask(string data, string type)
  432. {
  433. int length = 0;
  434. string subString = string.Empty;
  435. if (!string.IsNullOrWhiteSpace(data))
  436. {
  437. switch (type)
  438. {
  439. case "mobile":
  440. case "id":
  441. length = 4;
  442. subString = data.Substring(data.Length - length, length);
  443. data = data.Replace(subString, "****");
  444. break;
  445. case "mail":
  446. string[] dataList = data.Split("@");
  447. subString = dataList.First();
  448. data = data.Replace(subString, "****");
  449. break;
  450. case "name":
  451. length = 2;
  452. subString = data.Substring(data.Length - length, length);
  453. data = data.Replace(subString, "〇〇");
  454. break;
  455. }
  456. }
  457. return data;
  458. }
  459. public async Task<TmidAnalysisCal> getTMIDIotData(CosmosClient cosmosClientIes5, string tmid, string toolType, string dateUnit, int year, int month, int day, long from, long to)
  460. {
  461. TmidAnalysisCal result = new TmidAnalysisCal();
  462. List<string> calPropList = new List<string>() { "lessonRecord", "useIES", "useIES5Resource", "useWebIrs", "useDeviceIrs", "useHaboard", "useHita", "lessonLengMin", "lessonLeng0", "stuShow", "stuLessonLengMin", "tGreen", "lTypeCoop", "lTypeIact", "lTypeMis", "lTypeTst", "lTypeDif", "lTypeNone", "lessonCnt928", "lessonCntId", "lessonCntDevice", "lessonCntIdDevice", "mission", "missionFin", "item", "interact", "sendSok" }; //要計算的ProdAnalysis欄位列表
  463. string strQuery = $"SELECT * FROM c WHERE c.tmid = '{tmid}' AND c.toolType = '{toolType}'";
  464. var qryOption = new QueryRequestOptions() { PartitionKey = new PartitionKey("TmidAnalysis") };
  465. if (!string.IsNullOrWhiteSpace(dateUnit)) strQuery += $" AND c.dateUnit = '{dateUnit}'";
  466. if (year > 0) strQuery += $" AND c.year = {year}";
  467. if (month > 0) strQuery += $" AND c.month = {month}";
  468. if (day > 0) strQuery += $" AND c.day = {day}";
  469. if (from > 0) strQuery += $" AND c.dateTime >= {from}";
  470. if (to > 0) strQuery += $" AND c.dateTime <= {to}";
  471. await foreach (TmidAnalysisCosmos tmidAnalysis in cosmosClientIes5.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<TmidAnalysisCosmos>(strQuery, null, qryOption))
  472. {
  473. //一般項
  474. result.tmid = tmidAnalysis.tmid;
  475. result.dateUnit = tmidAnalysis.dateUnit;
  476. result.toolType = tmidAnalysis.toolType;
  477. result.date = tmidAnalysis.date;
  478. if (tmidAnalysis.year > 0) result.year = tmidAnalysis.year;
  479. if (tmidAnalysis.month > 0) result.month = tmidAnalysis.month;
  480. if (tmidAnalysis.day > 0) result.day = tmidAnalysis.day;
  481. if (result.from.Equals(0) || tmidAnalysis.dateTime <= result.from) result.from = tmidAnalysis.dateTime;
  482. if (result.to.Equals(0) || tmidAnalysis.dateTime >= result.to) result.to = tmidAnalysis.dateTime;
  483. //統計項
  484. foreach (PropertyInfo propertyInfo in tmidAnalysis.GetType().GetProperties()) //累加項目
  485. {
  486. if (calPropList.Contains(propertyInfo.Name))
  487. {
  488. var propType = propertyInfo.PropertyType;
  489. var valNow = propertyInfo.GetValue(result);
  490. var valTodo = tmidAnalysis.GetType().GetProperty(propertyInfo.Name).GetValue(tmidAnalysis);
  491. if (propType.Equals(typeof(long))) propertyInfo.SetValue(result, Convert.ToInt64(valNow.ToString(), 10) + Convert.ToInt64(valTodo.ToString(), 10));
  492. else propertyInfo.SetValue(result, Convert.ToInt32(valNow.ToString(), 10) + Convert.ToInt32(valTodo.ToString(), 10));
  493. }
  494. }
  495. result.deviceList = result.deviceList.Union(tmidAnalysis.deviceList).ToList();
  496. result.deviceCnt = result.deviceList.Count;
  497. result.deviceNoAuthList = result.deviceNoAuthList.Union(tmidAnalysis.deviceNoAuthList).ToList();
  498. result.deviceNoAuth = result.deviceNoAuthList.Count;
  499. result.deviceAuthList = result.deviceAuthList.Union(tmidAnalysis.deviceAuthList).ToList();
  500. result.deviceAuth = result.deviceAuthList.Count;
  501. result.tmidList = result.tmidList.Union(tmidAnalysis.tmidList).ToList();
  502. result.tmidCnt = result.tmidList.Count;
  503. }
  504. if (string.IsNullOrWhiteSpace(result.tmid)) result = null;
  505. return result;
  506. }
  507. //Model
  508. //TMID統計 基本資訊
  509. private class TmidStics
  510. {
  511. public string id { get; set; }
  512. public string name { get; set; }
  513. public string mobile { get; set; }
  514. public string mail { get; set; }
  515. public string country { get; set; }
  516. public string province { get; set; }
  517. public string city { get; set; }
  518. public string schoolCode { get; set; }
  519. public string schoolCodeW { get; set; }
  520. public TmidSticsIes5 ies5 { get; set; } = new(); //IES統計資料
  521. public TmidPoints points { get; set; } = new();
  522. public TmidSokrates sokrates { get; set; } = new();
  523. public TmidBenefits benefits { get; set; } = new();
  524. public List<TmidCoupon> coupons { get; set; } = new();
  525. public List<TmidLoginTime> login { get; set; } = new();
  526. public List<object> prod { get; set; } = new();
  527. public TmidIot iot { get; set; } = new();
  528. }
  529. //TMID統計 IES5資訊
  530. private class TmidSticsIes5
  531. {
  532. public long usedSize { get; set; } //已使用的存儲空間(Byte)
  533. public long teachSize { get; set; } //分配給教師的空間(Byte)
  534. public long totalSize { get; set; } //總空間(Byte)
  535. public long surplusSize { get; set; } //剩余的空間(Byte)
  536. public List<TmidSticsIes5School> schools { get; set; } = new(); //各學校資料
  537. public int resCount { get; set; } //教材數
  538. public int itemCount { get; set; } //題目數
  539. public int paperCount { get; set; } //試卷數
  540. }
  541. private class TmidSticsIes5School
  542. {
  543. public string schoolId { get; set; }
  544. public string name { get; set; }
  545. public string region { get; set; }
  546. public string province { get; set; }
  547. public string city { get; set; }
  548. public string dist { get; set; }
  549. public object size { get; set; } = new();
  550. public int courseCnt { get; set; }
  551. public bool defaultSchool { get; set; }
  552. }
  553. private class TmidPoints
  554. {
  555. public int points { get; set; } = 0; //累積的點數(只加不減)
  556. public int balance { get; set; } = 0; //可用的點數
  557. public int level { get; set; } = 0; //等級
  558. }
  559. private class TmidCoupon
  560. {
  561. public string code { get; set; }
  562. public long exchange { get; set; }
  563. }
  564. private class TmidLoginTime
  565. {
  566. public string product { get; set; }
  567. public long time { get; set; }
  568. }
  569. private class TmidSokrates
  570. {
  571. public object hiteach_data { get; set; }
  572. public object user_channels { get; set; }
  573. }
  574. private class TmidBenefits
  575. {
  576. public List<object> hiteach { get; set; }
  577. public List<object> hiteachcc { get; set; }
  578. }
  579. private class TmidIot
  580. {
  581. public TmidIotYMD hiteach { get; set; } = new();
  582. public TmidIotYMD hiteachcc { get; set; } = new();
  583. }
  584. private class TmidIotYMD
  585. {
  586. public TmidAnalysisCal year { get; set; }
  587. public TmidAnalysisCal month { get; set; }
  588. public TmidAnalysisCal day { get; set; }
  589. }
  590. //[API輸出] 訂單履歷
  591. public class Ies5OrderHis
  592. {
  593. public Ies5OrderHis()
  594. {
  595. service = new List<Ies5OrderHisService>();
  596. }
  597. public string id { get; set; }
  598. public long date { get; set; }
  599. public List<Ies5OrderHisService> service { get; set; } = new ();
  600. }
  601. //[API輸出] 訂單履歷.服務型產品
  602. public class Ies5OrderHisService
  603. {
  604. public string prodCode { get; set; } //產品代碼
  605. public string type { get; set; } //授權方式 N:新約 C:續約
  606. public long sdate { get; set; } //授權起始時間
  607. public long edate { get; set; } //授權終止時間
  608. public int number { get; set; } //購買數量
  609. public string unit { get; set; } //購買單位 無單位者為null
  610. }
  611. //[承接DB] DB: Habb.Auth
  612. //[承接DB] 訂單履歷基本Class
  613. public class OrderHisBase
  614. {
  615. public string id { get; set; } //OPID
  616. public OrderHisOrderInfo orderinfo { get; set; } //訂單資訊
  617. public string prodCode { get; set; } //產品代碼
  618. public SerialSaleClient saleClient { get; set; } = null; //銷售終端
  619. public string prodType { get; set; } //產品類型 serial:序號 service:服務 hard:硬體
  620. public string dataType { get; set; } //資料類型
  621. public long operationTime { get; set; } //最新資料變更時間戳記
  622. public int ttl { get; set; } = -1; //過期刪除秒數
  623. }
  624. //[承接DB] 訂單履歷基本Class.銷售終端
  625. public class SerialSaleClient
  626. {
  627. public string name { get; set; } //[String]銷售終端姓名
  628. public string schoolCode { get; set; } = null; //[String]銷售終端學校代碼
  629. public string clientId { get; set; } = null; //[String]銷售終端客戶ID
  630. public string tmid { get; set; } = null; //[String]TMID
  631. public string type { get; set; } //[String]銷售終端資料類型 school:學校 client:經銷商客戶
  632. public string countryId { get; set; } //[String]國家代碼
  633. public string provinceId { get; set; } //[String]省代碼
  634. public string cityId { get; set; } //[String]市代碼
  635. public string schoolShortCode { get; set; } //[String]學校簡碼
  636. public string districtId { get; set; } //[String]區代碼
  637. public string dataCenter { get; set; } //[String]數據中心
  638. }
  639. //[承接DB] 訂單履歷基本Class.訂單資訊
  640. public class OrderHisOrderInfo
  641. {
  642. public string orderid { get; set; } //[String]訂單編號
  643. public int orderAudit { get; set; } //[Int]訂單審核狀態 0:待審, 1:通過, 2:否決, 3:問題
  644. public int orderProperty { get; set; } //[Int]訂單類型 0:銷售,1:展示申請 2:內部申請
  645. public long createDate { get; set; } //訂單創建時間
  646. }
  647. //[承接DB] 訂單履歷 服務類
  648. public class OrderHisService : OrderHisBase
  649. {
  650. public int type { get; set; } //[Int]授權類型 0:銷售 1:試用
  651. public int contract { get; set; } //[Int]契約型態 0:新約 1:續約
  652. public long startDate { get; set; } //[long]授權起始日期 Timestamp(UTC)
  653. public long endDate { get; set; } //[long]授權終止日期 Timestamp(UTC)
  654. public int number { get; set; } //[Int]數量
  655. public string unit { get; set; } //[String]單位 (無者為空)
  656. }
  657. //雲端服務ClientId列表
  658. private readonly Dictionary<string, string> _dicClientIds = new()
  659. {
  660. { "917d02f2-5b91-404e-a71d-7bdd926ddd81", "HiTeach" },
  661. { "c5328340-b8eb-4489-8650-8c8862d7acfe", "HiTeach" },
  662. { "118d2d4d-32a3-44c0-808a-792ca73d3706", "HiTeachCC" },
  663. { "227082f4-8db0-4517-b281-93dba9428bc7", "HiTeachCC" },
  664. { "371a99aa-7efd-4c3a-90a8-95b7db4f42c0", "HiTA" },
  665. { "0ed38cde-e7fe-4fa6-9eaa-33ad404eb532", "HiTA" },
  666. { "531fecd1-b1a5-469a-93ca-7984e1d392f2", "IES5" },
  667. { "c7317f88-7cea-4e48-ac57-a16071f7b884", "IES5" },
  668. { "c8de822b-3fcf-4831-adba-cdd14653bf7f", "Account" },
  669. { "516148eb-6a38-4657-ba98-a3699061937f", "Account" },
  670. { "d7193896-9b12-4046-ad44-c991dd48cc39", "Sokrates" },
  671. { "59009e38-6e30-4116-814b-7605939edc47", "Sokrates" },
  672. { "626c7285-15aa-4abe-8c0d-2c5ff1381538", "SokAPP" },
  673. { "5bcc16a5-7d20-4cc4-b5c2-8ed0416f32b6", "SokAPP" },
  674. { "044482b5-d024-4f23-9b55-906884243405", "IRS" },
  675. { "5e27b7e3-b36c-4ce9-b838-e94fd0cea080", "IRS" }
  676. };
  677. //TMID IOT date
  678. public class tmidIotDate
  679. {
  680. public string dateUnit { get; set; } //[string]日期單位:年月日 year, month, day
  681. public int year { get; set; } //[Int]年
  682. public int month { get; set; } //[Int]月
  683. public int day { get; set; } //[Int]日
  684. public long from { get; set; } //[long]UTC timestamp 起始日
  685. public long to { get; set; } //[long]UTC timestamp 終止日
  686. }
  687. public class TmidAnalysisCal : TmidAnalysisCosmos
  688. {
  689. public long from { get; set; } //[long]UTC timestamp 起始日
  690. public long to { get; set; } //[long]UTC timestamp 終止日
  691. }
  692. }
  693. }