using Microsoft.Azure.Cosmos; using Newtonsoft.Json; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; using TEAMModelOS.SDK.DI; using TEAMModelOS.SDK.Extension; using TEAMModelOS.SDK.Models.Cosmos; using TEAMModelOS.SDK.Models.Cosmos.BI.BISchool; using TEAMModelOS.SDK.Models.Cosmos.Common; namespace TEAMModelOS.SDK.Models.Service.BI { public static class BIProdAnalysis { /// /// 1.取得某日CS IOT 資料 /// 2.生成IES5各校產品分析統計資料 /// 3.生成TMID產品分析統計資料 /// 4.生成DeviceID產品分析統計資料 /// /// /// /// 年 /// 月(2位數) /// 日(2位數) /// public static async Task BICreatDailyAnalData(AzureRedisFactory _azureRedis, CosmosClient _azureCosmosClient, CosmosClient _azureCosmosClientCsv2, CosmosClient _azureCosmosClientCsv2CnRead, DingDing _dingDing, string y, string m, string d) { List IotTeachingDataList = await BIGetDailyRedisProdAnalData(_azureRedis, _azureCosmosClientCsv2, _dingDing, y, m, d); //取得Redis IOT 每日資訊 await CreatIes5ProdAnalData(_azureRedis, _azureCosmosClient, _azureCosmosClientCsv2CnRead, _dingDing, y, m, d, IotTeachingDataList); //生成學校CosmosDB年月日統計資料 await CreatTmidProdAnalData(_azureRedis, _azureCosmosClient, _dingDing, y, m, d, IotTeachingDataList); //生成TMID CosmosDB年月日統計資料 } /// /// 取得某日CS IOT 資料 /// /// /// /// 年 /// 月(2位數) /// 日(2位數) /// public static async Task> BIGetDailyRedisProdAnalData(AzureRedisFactory _azureRedis, CosmosClient _azureCosmosClientCsv2, DingDing _dingDing, string y, string m, string d) { List IotTeachingDataList = new List(); try { var redisClinet2 = _azureRedis.GetRedisClient(2); var datetime = DateTimeOffset.UtcNow; var ynow = datetime.Year; HashSet tmids = new HashSet(); Dictionary tmidSchidDic = new Dictionary(); //取得CS Redis TeachingData (IOT紀錄只有三個月分) if (y.Equals(ynow.ToString())) { bool TeachingDataExist = await redisClinet2.KeyExistsAsync($"TeachingData:{m}{d}"); if (TeachingDataExist) { RedisValue[] TeachingData = redisClinet2.ListRange($"TeachingData:{m}{d}"); foreach (RedisValue tdataRow in TeachingData) { string[] tdata = tdataRow.ToString().Split(','); IotTeachingData IotTeachingData = new IotTeachingData(); IotTeachingData.timestamp = Convert.ToInt64(tdata[0]); IotTeachingData.deviceId = tdata[1]; IotTeachingData.channel = tdata[2]; IotTeachingData.tmid = tdata[3]; IotTeachingData.schoolId = tdata[4]; IotTeachingData.useIES = tdata[5]; IotTeachingData.useIES5Resource = (!string.IsNullOrWhiteSpace(tdata[6])) ? Convert.ToInt32(tdata[6]) : 0; IotTeachingData.useWebIrs = tdata[7]; IotTeachingData.useDeviceIrs = tdata[8]; IotTeachingData.useHaboard = tdata[9]; IotTeachingData.useHita = tdata[10]; IotTeachingData.lessonLengMin = (!string.IsNullOrWhiteSpace(tdata[11])) ? Convert.ToInt32(tdata[11]) : 0; IotTeachingData.stuShow = (!string.IsNullOrWhiteSpace(tdata[12])) ? Convert.ToInt32(tdata[12]) : 0; IotTeachingData.tPoint = (!string.IsNullOrWhiteSpace(tdata[13])) ? Convert.ToInt32(tdata[13]) : 0; IotTeachingData.lTypeCoop = tdata[14]; IotTeachingData.lTypeIact = tdata[15]; IotTeachingData.lTypeMis = tdata[16]; IotTeachingData.lTypeTst = tdata[17]; IotTeachingData.lTypeDif = tdata[18]; IotTeachingData.authType = tdata[19]; IotTeachingData.mission = (!string.IsNullOrWhiteSpace(tdata[20])) ? Convert.ToInt32(tdata[20]) : 0; IotTeachingData.missionFin = (!string.IsNullOrWhiteSpace(tdata[21])) ? Convert.ToInt32(tdata[21]) : 0; IotTeachingData.item = (!string.IsNullOrWhiteSpace(tdata[22])) ? Convert.ToInt32(tdata[22]) : 0; IotTeachingData.interact = (!string.IsNullOrWhiteSpace(tdata[23])) ? Convert.ToInt32(tdata[23]) : 0; IotTeachingData.ip = (tdata.Length > 24) ? tdata[24] : ""; IotTeachingData.version = (tdata.Length > 25) ? tdata[25] : ""; IotTeachingData.sendSok = (tdata.Length > 26 && !string.IsNullOrWhiteSpace(tdata[26])) ? tdata[26] : "0"; IotTeachingData.learnPeer = (tdata.Length > 27 && !string.IsNullOrWhiteSpace(tdata[27])) ? tdata[27] : "0"; IotTeachingData.learnCoop = (tdata.Length > 28 && !string.IsNullOrWhiteSpace(tdata[28])) ? tdata[28] : "0"; IotTeachingData.useWordCloud = (tdata.Length > 29 && !string.IsNullOrWhiteSpace(tdata[29])) ? tdata[29] : "0"; IotTeachingData.useClouDAS = (tdata.Length > 30 && !string.IsNullOrWhiteSpace(tdata[30])) ? tdata[30] : "0"; IotTeachingData.useGPT = (tdata.Length > 31 && !string.IsNullOrWhiteSpace(tdata[31])) ? tdata[31] : "0"; IotTeachingData.useIes5Test = (tdata.Length > 32 && !string.IsNullOrWhiteSpace(tdata[32])) ? tdata[32] : "0"; IotTeachingData.usePaperTest = (tdata.Length > 33 && !string.IsNullOrWhiteSpace(tdata[33])) ? tdata[33] : "0"; IotTeachingData.useExcelTest = (tdata.Length > 34 && !string.IsNullOrWhiteSpace(tdata[34])) ? tdata[34] : "0"; IotTeachingData.useScoreBoard = (tdata.Length > 35 && !string.IsNullOrWhiteSpace(tdata[35])) ? tdata[35] : "0"; //課堂中使用記分板 IotTeachingData.learnParticipation = (tdata.Length > 36 && !string.IsNullOrWhiteSpace(tdata[36])) ? Convert.ToInt32(tdata[36]) : 0; //學習參與度指數 IotTeachingData.learnParticipationCnt = (IotTeachingData.learnParticipation > 0) ? "1" : "0"; //是否計算學習參與度 IotTeachingData.coopMission = (tdata.Length > 37 && !string.IsNullOrWhiteSpace(tdata[37])) ? Convert.ToInt32(tdata[37]) : 0; //協作任務數 IotTeachingData.coopWork = (tdata.Length > 38 && !string.IsNullOrWhiteSpace(tdata[38])) ? Convert.ToInt32(tdata[38]) : 0; //協作作品數 IotTeachingData.coopContributionT = (tdata.Length > 39 && !string.IsNullOrWhiteSpace(tdata[39])) ? Convert.ToInt32(tdata[39]) : 0; //協作總貢獻度 IotTeachingData.peerAct = (tdata.Length > 40 && !string.IsNullOrWhiteSpace(tdata[40])) ? Convert.ToInt32(tdata[40]) : 0; //互評活動次數 IotTeachingData.peerStuParticipationT = (tdata.Length > 41 && !string.IsNullOrWhiteSpace(tdata[41])) ? Convert.ToInt32(tdata[41]) : 0; //互評學生參與總次數 IotTeachingData.useTransMode = (tdata.Length > 42 && !string.IsNullOrWhiteSpace(tdata[42])) ? tdata[42] : "0"; //有使用透明模式 IotTeachingData.useMiniMode = (tdata.Length > 43 && !string.IsNullOrWhiteSpace(tdata[43])) ? tdata[43] : "0"; //有使用最小化模式 IotTeachingDataList.Add(IotTeachingData); if(!string.IsNullOrWhiteSpace(IotTeachingData.tmid)) { tmids.Add(IotTeachingData.tmid); } } } } //取得TMID進階資料,以弱強歸戶學校補足學校ID QueryDefinition querye = new QueryDefinition(@"SELECT c.id, c.schoolCode, c.schoolCodeW FROM c WHERE (ARRAY_CONTAINS(@key, c.id) AND ( (IS_DEFINED(c.schoolCode) AND IS_STRING(c.schoolCode)) OR (IS_DEFINED(c.schoolCodeW) AND IS_STRING(c.schoolCodeW)) ))").WithParameter("@key", tmids); await foreach (var item in _azureCosmosClientCsv2.GetContainer("Core", "ID2") .GetItemQueryStreamIteratorQuery(querye, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("base-ex")})) { using var json = await JsonDocument.ParseAsync(item.Content); if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0) { foreach (var doc in json.RootElement.GetProperty("Documents").EnumerateArray()) { string id = doc.GetProperty("id").GetString(); string schoolCode = (doc.TryGetProperty("schoolCode", out JsonElement _tmidSchoolCode)) ? _tmidSchoolCode.GetString() : string.Empty; string schoolCodeW = (doc.TryGetProperty("schoolCodeW", out JsonElement _tmidSchoolCodeW)) ? _tmidSchoolCodeW.GetString() : string.Empty; List IotTeachingDatas = IotTeachingDataList.Where(x => x.tmid.Equals(id) && string.IsNullOrWhiteSpace(x.schoolId)).ToList(); if(IotTeachingDatas.Count > 0) { foreach(IotTeachingData IotTeachingDataRow in IotTeachingDatas) { if (!string.IsNullOrWhiteSpace(schoolCode)) { IotTeachingDataRow.schoolId = schoolCode; } else if (!string.IsNullOrWhiteSpace(schoolCodeW)) { IotTeachingDataRow.schoolId = schoolCodeW; } } } } } } return IotTeachingDataList; } catch (Exception ex) { _ = _dingDing.SendBotMsg($"BI,{Environment.GetEnvironmentVariable("Option:Location")},BIGetDailyRedisProdAnalData() 取得每日CoreServiceIOT資料錯誤\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組); return IotTeachingDataList; } } //年月日 IES5學校IOT產品分析數據生成 ///參數:某日IOT 教學資料列 ///1.生成 Redis ProdAnalysis:Month ///2.生成 CosmosDB Month ///3.生成 CosmosDB 系統所有學校數值加總 private static async Task CreatIes5ProdAnalData(AzureRedisFactory _azureRedis, CosmosClient _azureCosmosClient, CosmosClient _azureCosmosClientCsv2CnRead, DingDing _dingDing, string y, string m, string d, List IotTeachingDataList) { try { var redisClinet8 = _azureRedis.GetRedisClient(8); List crtVirtualSchoolId = new List(); //虛擬學校創建ID列表 List calPropList = new List() { "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" }; //要計算的ProdAnalysis欄位列表 List ProdAnalysisList = new List(); if (IotTeachingDataList.Count > 0) { foreach (IotTeachingData IotTeachingDatRow in IotTeachingDataList) { string schoolId = (!string.IsNullOrWhiteSpace(IotTeachingDatRow.schoolId)) ? IotTeachingDatRow.schoolId.ToLower() : "noschoolid"; //noschoolid:無任何學校ID if (!schoolId.Equals("noschoolid") && !schoolId.Equals("allschool") && !crtVirtualSchoolId.Contains(schoolId)) { crtVirtualSchoolId.Add(schoolId); } string toolType = string.Empty; if (!string.IsNullOrWhiteSpace(IotTeachingDatRow.deviceId)) { if (IotTeachingDatRow.deviceId.Contains("HiTeachCC-")) toolType = "HiTeachCC"; else if (IotTeachingDatRow.deviceId.Contains("HiTeach-")) toolType = "HiTeach"; else if (IotTeachingDatRow.deviceId.Contains("HiTA-")) toolType = "HiTA"; } //學校數據生成 if (!string.IsNullOrWhiteSpace(schoolId) && !string.IsNullOrWhiteSpace(toolType)) { bool addFlg = false; ProdAnalysis prodAnalysisRow = ProdAnalysisList.Where(s => s.schoolId.Equals(schoolId) && s.toolType.Equals(toolType)).FirstOrDefault(); //無此校數據=>創建 if (prodAnalysisRow == null) { prodAnalysisRow = new ProdAnalysis(); prodAnalysisRow.schoolId = schoolId; prodAnalysisRow.toolType = toolType; addFlg = true; } //欄位加總 if (!string.IsNullOrWhiteSpace(IotTeachingDatRow.deviceId) && !prodAnalysisRow.deviceList.Contains(IotTeachingDatRow.deviceId)) { prodAnalysisRow.deviceList.Add(IotTeachingDatRow.deviceId); } prodAnalysisRow.deviceCnt = prodAnalysisRow.deviceList.Count; switch (IotTeachingDatRow.authType) { case "0": //928授權 if (!prodAnalysisRow.deviceNoAuthList.Contains(IotTeachingDatRow.deviceId)) prodAnalysisRow.deviceNoAuthList.Add(IotTeachingDatRow.deviceId); prodAnalysisRow.lessonCnt928++; break; case "1": //ID授權 if (!prodAnalysisRow.deviceNoAuthList.Contains(IotTeachingDatRow.deviceId)) prodAnalysisRow.deviceNoAuthList.Add(IotTeachingDatRow.deviceId); prodAnalysisRow.lessonCntId++; break; case "2": //機器授權 if (!prodAnalysisRow.deviceAuthList.Contains(IotTeachingDatRow.deviceId)) prodAnalysisRow.deviceAuthList.Add(IotTeachingDatRow.deviceId); prodAnalysisRow.lessonCntDevice++; break; case "3": //ID+機器授權 if (!prodAnalysisRow.deviceAuthList.Contains(IotTeachingDatRow.deviceId)) prodAnalysisRow.deviceAuthList.Add(IotTeachingDatRow.deviceId); prodAnalysisRow.lessonCntIdDevice++; break; } prodAnalysisRow.deviceNoAuth = prodAnalysisRow.deviceNoAuthList.Count; prodAnalysisRow.deviceAuth = prodAnalysisRow.deviceAuthList.Count; if (!string.IsNullOrWhiteSpace(IotTeachingDatRow.tmid) && !prodAnalysisRow.tmidList.Contains(IotTeachingDatRow.tmid)) { prodAnalysisRow.tmidList.Add(IotTeachingDatRow.tmid); } prodAnalysisRow.tmidCnt = prodAnalysisRow.tmidList.Count; prodAnalysisRow.lessonRecord++; if (IotTeachingDatRow.useIES.Equals("1")) prodAnalysisRow.useIES++; prodAnalysisRow.useIES5Resource += IotTeachingDatRow.useIES5Resource; if (IotTeachingDatRow.useWebIrs.Equals("1")) prodAnalysisRow.useWebIrs++; if (IotTeachingDatRow.useDeviceIrs.Equals("1")) prodAnalysisRow.useDeviceIrs++; if (IotTeachingDatRow.useHaboard.Equals("1")) prodAnalysisRow.useHaboard++; if (IotTeachingDatRow.useHita.Equals("1")) prodAnalysisRow.useHita++; prodAnalysisRow.lessonLengMin += IotTeachingDatRow.lessonLengMin; if (IotTeachingDatRow.lessonLengMin.Equals(0)) prodAnalysisRow.lessonLeng0++; prodAnalysisRow.stuShow += IotTeachingDatRow.stuShow; prodAnalysisRow.stuLessonLengMin += IotTeachingDatRow.lessonLengMin * IotTeachingDatRow.stuShow; if (IotTeachingDatRow.tPoint >= 70) prodAnalysisRow.tGreen++; if (IotTeachingDatRow.lessonLengMin >= 10 && IotTeachingDatRow.tPoint > 0) prodAnalysisRow.tLesson++; if (IotTeachingDatRow.lTypeCoop.Equals("1")) prodAnalysisRow.lTypeCoop++; if (IotTeachingDatRow.lTypeIact.Equals("1")) prodAnalysisRow.lTypeIact++; if (IotTeachingDatRow.lTypeMis.Equals("1")) prodAnalysisRow.lTypeMis++; if (IotTeachingDatRow.lTypeTst.Equals("1")) prodAnalysisRow.lTypeTst++; if (IotTeachingDatRow.lTypeDif.Equals("1")) prodAnalysisRow.lTypeDif++; if (IotTeachingDatRow.lTypeCoop.Equals("0") && IotTeachingDatRow.lTypeIact.Equals("0") && IotTeachingDatRow.lTypeMis.Equals("0") && IotTeachingDatRow.lTypeTst.Equals("0") && IotTeachingDatRow.lTypeDif.Equals("0")) prodAnalysisRow.lTypeNone++; prodAnalysisRow.mission += IotTeachingDatRow.mission; prodAnalysisRow.missionFin += IotTeachingDatRow.missionFin; prodAnalysisRow.item += IotTeachingDatRow.item; prodAnalysisRow.interact += IotTeachingDatRow.interact; if (IotTeachingDatRow.sendSok.Equals("1")) prodAnalysisRow.sendSok++; if (IotTeachingDatRow.learnPeer.Equals("1")) prodAnalysisRow.learnPeer++; if (IotTeachingDatRow.learnCoop.Equals("1")) prodAnalysisRow.learnCoop++; if (IotTeachingDatRow.useWordCloud.Equals("1")) prodAnalysisRow.useWordCloud++; if (IotTeachingDatRow.useClouDAS.Equals("1")) prodAnalysisRow.useClouDAS++; if (IotTeachingDatRow.useGPT.Equals("1")) prodAnalysisRow.useGPT++; if (IotTeachingDatRow.useIes5Test.Equals("1")) prodAnalysisRow.useIes5Test++; if (IotTeachingDatRow.usePaperTest.Equals("1")) prodAnalysisRow.usePaperTest++; if (IotTeachingDatRow.useExcelTest.Equals("1")) prodAnalysisRow.useExcelTest++; if (IotTeachingDatRow.useScoreBoard.Equals("1")) prodAnalysisRow.useScoreBoard++; //課堂中使用記分板 if (IotTeachingDatRow.learnParticipationCnt.Equals("1")) prodAnalysisRow.learnParticipationCnt++; //學習參與度次數 prodAnalysisRow.learnParticipationT += IotTeachingDatRow.learnParticipation; //學習參與度指數(總和) decimal learnParticipationTmp = (prodAnalysisRow.learnParticipationCnt > 0) ? (decimal)prodAnalysisRow.learnParticipationT / (decimal)prodAnalysisRow.learnParticipationCnt : 0; prodAnalysisRow.learnParticipation = Math.Round(learnParticipationTmp, 2); //學習參與度指數(平均) prodAnalysisRow.coopMission += IotTeachingDatRow.coopMission; //協作任務數 prodAnalysisRow.coopWork += IotTeachingDatRow.coopWork; //協作作品數 prodAnalysisRow.coopContributionT += IotTeachingDatRow.coopContributionT; //協作總貢獻度 prodAnalysisRow.peerAct += IotTeachingDatRow.peerAct; //互評活動次數 prodAnalysisRow.peerStuParticipationT += IotTeachingDatRow.peerStuParticipationT; //互評學生參與總次數 if (IotTeachingDatRow.useTransMode.Equals("1")) prodAnalysisRow.useTransMode++; //有使用透明模式 if (IotTeachingDatRow.useMiniMode.Equals("1")) prodAnalysisRow.useMiniMode++; //有使用最小化模式 if (addFlg) { ProdAnalysisList.Add(prodAnalysisRow); } } } } //1.記入IES5 Redis ProdAnalysis:Day //2.記入IES5 CosmosDB Day if (ProdAnalysisList.Count > 0) { //資料整形 Dictionary> redisSchFieldDic = new Dictionary>(); //架構: key => schId => schJsonContent List cosmosSchList = new List(); Dictionary cosmosAllSchSumDayDic = new Dictionary(); foreach (ProdAnalysis prodAnalysisRow in ProdAnalysisList) { //Redis整形 string toolType = prodAnalysisRow.toolType; string schoolId = prodAnalysisRow.schoolId; string hkey = $"ProdAnalysis:Day:{toolType}:{y}{m}{d}"; string fieldContent = prodAnalysisRow.ToJsonString(); if (redisSchFieldDic.ContainsKey(hkey)) redisSchFieldDic[hkey].Add(schoolId, fieldContent); else redisSchFieldDic.Add(hkey, new Dictionary() { { schoolId, fieldContent } }); //CosmosDB整形 ProdAnalysisCosmos ProdAnalysisCosmosRow = prodAnalysisRow.ToJsonString().ToObject(); ProdAnalysisCosmosRow.date = $"{y}{m}{d}"; ProdAnalysisCosmosRow.year = Convert.ToInt32(y, 10); ProdAnalysisCosmosRow.month = Convert.ToInt32(m, 10); ProdAnalysisCosmosRow.day = Convert.ToInt32(d, 10); DateTimeOffset dateTime = new DateTimeOffset(ProdAnalysisCosmosRow.year, ProdAnalysisCosmosRow.month, ProdAnalysisCosmosRow.day, 0, 0, 0, TimeSpan.Zero); ProdAnalysisCosmosRow.dateTime = dateTime.ToUnixTimeSeconds(); ProdAnalysisCosmosRow.id = $"{ProdAnalysisCosmosRow.toolType}-{ProdAnalysisCosmosRow.date}-{schoolId}"; ProdAnalysisCosmosRow.dateUnit = "day"; ProdAnalysisCosmosRow.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); cosmosSchList.Add(ProdAnalysisCosmosRow); } //記入Redis if (redisSchFieldDic.Count > 0) { foreach (KeyValuePair> hkeyItem in redisSchFieldDic) { //記入Redis string hkey = hkeyItem.Key; List hvalList = new List(); Dictionary fieldDic = hkeyItem.Value; foreach (KeyValuePair schItem in fieldDic) { string schoolId = schItem.Key; string fieldContent = schItem.Value; hvalList.Add(new HashEntry($"{schoolId}", fieldContent)); } await redisClinet8.HashSetAsync(hkey, hvalList.ToArray()); } } //記入CosmosDB if (cosmosSchList.Count > 0) { foreach (ProdAnalysisCosmos cosmosSchRow in cosmosSchList) { //各校每日CosmosDB記入 await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(cosmosSchRow); //所有學校數值加總 數值生成 cosmosAllSchSumDayDic -> key:toolType val:cosmosAllSchSumDay cosmosAllSchSumDayDic = GenAnalysisRowSumData(cosmosAllSchSumDayDic, cosmosSchRow, calPropList, "day"); } //每日所有學校數據總計CosmosDB記入 foreach (KeyValuePair schItem in cosmosAllSchSumDayDic) { string toolType = schItem.Key; ProdAnalysisCosmos cosmosAllSchSumDay = schItem.Value; cosmosAllSchSumDay.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(cosmosAllSchSumDay); } } } //取 Redis 該月所有 ProdAnalysis:Day //1.生成 Redis ProdAnalysis:Month //2.生成 CosmosDB Month Dictionary> ProdAnalysisListMonth = new Dictionary>(); Dictionary cosmosAllSchSumMonthDic = new Dictionary(); List cosmosSchListMonth = new List(); string patternD = $"ProdAnalysis:Day:HiT*:{y}{m}*"; List keysDayList = ScanRedisKeysByPattern(_azureRedis, patternD); if (keysDayList.Count > 0) { foreach (string keyDay in keysDayList) { string[] keyItemList = keyDay.Split(':'); //ProdAnalysis:Day:HiTeach:20230326 string toolType = keyItemList[2]; string dateStrD = keyItemList[3]; string dateStrD_y = string.Empty; string dateStrD_m = string.Empty; string dateStrD_d = string.Empty; Regex rgx = new Regex(@"[0-9]{8}"); if (rgx.IsMatch(dateStrD)) { dateStrD_y = dateStrD.Substring(0, 4); dateStrD_m = dateStrD.Substring(4, 2); dateStrD_d = dateStrD.Substring(6, 2); } string prodAnalMonthKey = $"ProdAnalysis:Month:{toolType}:{dateStrD_y}{dateStrD_m}"; bool ProdAnalysisDayExist = await redisClinet8.KeyExistsAsync(keyDay); if (ProdAnalysisDayExist && !string.IsNullOrWhiteSpace(dateStrD_y) && !string.IsNullOrWhiteSpace(dateStrD_m) && !string.IsNullOrWhiteSpace(dateStrD_d)) { HashEntry[] hsetDay = redisClinet8.HashGetAll(keyDay); //某日 ProdAnalysis:Day所有學校的統計項目 foreach (HashEntry hset in hsetDay) { string keySchId = hset.Name; string valSchDataJson = hset.Value; ProdAnalysis SchDataTodo = valSchDataJson.ToObject(); //Redis Month 資料生成 if (ProdAnalysisListMonth.ContainsKey(prodAnalMonthKey)) //月Dic已有此key => 分校累加 { if (ProdAnalysisListMonth[$"{prodAnalMonthKey}"].ContainsKey($"{keySchId}")) { ProdAnalysis SchDataNow = ProdAnalysisListMonth[$"{prodAnalMonthKey}"][$"{keySchId}"]; foreach (PropertyInfo propertyInfo in SchDataNow.GetType().GetProperties()) { if (calPropList.Contains(propertyInfo.Name)) { var propType = propertyInfo.PropertyType; var valNow = propertyInfo.GetValue(SchDataNow); var valTodo = SchDataTodo.GetType().GetProperty(propertyInfo.Name).GetValue(SchDataTodo); if (propType.Equals(typeof(long))) propertyInfo.SetValue(SchDataNow, Convert.ToInt64(valNow.ToString(), 10) + Convert.ToInt64(valTodo.ToString(), 10)); else propertyInfo.SetValue(SchDataNow, Convert.ToInt32(valNow.ToString(), 10) + Convert.ToInt32(valTodo.ToString(), 10)); } } SchDataNow.deviceList = SchDataNow.deviceList.Union(SchDataTodo.deviceList).ToList(); SchDataNow.deviceCnt = SchDataNow.deviceList.Count; SchDataNow.deviceAuthList = SchDataNow.deviceAuthList.Union(SchDataTodo.deviceAuthList).ToList(); SchDataNow.deviceAuth = SchDataNow.deviceAuthList.Count; SchDataNow.deviceNoAuthList = SchDataNow.deviceNoAuthList.Union(SchDataTodo.deviceNoAuthList).ToList(); SchDataNow.deviceNoAuth = SchDataNow.deviceNoAuthList.Count; SchDataNow.tmidList = SchDataNow.tmidList.Union(SchDataTodo.tmidList).ToList(); SchDataNow.tmidCnt = SchDataNow.tmidList.Count; } //無此校資料 => 該校資料放入 else { ProdAnalysisListMonth[$"{prodAnalMonthKey}"][$"{keySchId}"] = SchDataTodo; } } else //無此月資料 => 所有學校資料放入 { ProdAnalysisListMonth.Add(prodAnalMonthKey, new Dictionary() { { keySchId, SchDataTodo } }); } } } } } if (ProdAnalysisListMonth.Count > 0) { foreach (KeyValuePair> item in ProdAnalysisListMonth) { string monthRedisKey = item.Key; List hvalList = new List(); Dictionary monthRedisSchDIc = item.Value; foreach (KeyValuePair monthRedisSchItem in monthRedisSchDIc) { string monthRedisSchId = monthRedisSchItem.Key; ProdAnalysis monthRedisSchData = monthRedisSchItem.Value; //Redis資料製作 hvalList.Add(new HashEntry(monthRedisSchId, monthRedisSchData.ToJsonString())); //CosmosDB資料製作 ProdAnalysisCosmos cosmosSchRow = monthRedisSchData.ToJsonString().ToObject(); cosmosSchRow.date = $"{y}{m}"; cosmosSchRow.year = Convert.ToInt32(y, 10); cosmosSchRow.month = Convert.ToInt32(m, 10); DateTimeOffset dateTime = new DateTimeOffset(cosmosSchRow.year, cosmosSchRow.month, 1, 0, 0, 0, TimeSpan.Zero); cosmosSchRow.dateTime = dateTime.ToUnixTimeSeconds(); cosmosSchRow.id = $"{monthRedisSchData.toolType}-{cosmosSchRow.date}-{monthRedisSchId}"; cosmosSchRow.dateUnit = "month"; cosmosSchRow.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); cosmosSchListMonth.Add(cosmosSchRow); } //記入Redis await redisClinet8.HashSetAsync($"{monthRedisKey}", hvalList.ToArray()); } //記入CosmosDB if (cosmosSchListMonth.Count > 0) { foreach (ProdAnalysisCosmos cosmosSchRow in cosmosSchListMonth) { await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(cosmosSchRow); //所有學校數值加總 數值生成 cosmosAllSchSumDayDic -> key:toolType val:cosmosAllSchSumDay cosmosAllSchSumMonthDic = GenAnalysisRowSumData(cosmosAllSchSumMonthDic, cosmosSchRow, calPropList, "month"); } //每月所有學校數據總計CosmosDB記入 foreach (KeyValuePair schItem in cosmosAllSchSumMonthDic) { string toolType = schItem.Key; ProdAnalysisCosmos cosmosAllSchSumMonth = schItem.Value; cosmosAllSchSumMonth.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(cosmosAllSchSumMonth); } } } //取該年所有 CosmosDB 該年所有月份 生成CosmosDB年資料 Dictionary> ProdAnalysisListYear = new Dictionary>(); Dictionary cosmosAllSchSumYearDic = new Dictionary(); var query = $"SELECT * FROM c WHERE c.year = {y} AND c.dateUnit = 'month' AND c.schoolId != 'allschool'"; await foreach (var itemcr in _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIteratorSql(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("ProdAnalysis") })) { var json = await JsonDocument.ParseAsync(itemcr.Content); if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0) { foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray()) { ProdAnalysisCosmos SchDataTodo = obj.ToObject(); string toolType = SchDataTodo.toolType; string schId = SchDataTodo.schoolId; //年Dic已有此key => 分校累加 if (ProdAnalysisListYear.ContainsKey(toolType)) { if (ProdAnalysisListYear[$"{toolType}"].ContainsKey($"{schId}")) { ProdAnalysisCosmos SchDataNow = ProdAnalysisListYear[$"{toolType}"][$"{schId}"]; foreach (PropertyInfo propertyInfo in SchDataNow.GetType().GetProperties()) { if (calPropList.Contains(propertyInfo.Name)) { var propType = propertyInfo.PropertyType; var valNow = propertyInfo.GetValue(SchDataNow); var valTodo = SchDataTodo.GetType().GetProperty(propertyInfo.Name).GetValue(SchDataTodo); if (propType.Equals(typeof(long))) propertyInfo.SetValue(SchDataNow, Convert.ToInt64(valNow.ToString(), 10) + Convert.ToInt64(valTodo.ToString(), 10)); else propertyInfo.SetValue(SchDataNow, Convert.ToInt32(valNow.ToString(), 10) + Convert.ToInt32(valTodo.ToString(), 10)); } } SchDataNow.deviceList = SchDataNow.deviceList.Union(SchDataTodo.deviceList).ToList(); SchDataNow.deviceCnt = SchDataNow.deviceList.Count; SchDataNow.deviceAuthList = SchDataNow.deviceAuthList.Union(SchDataTodo.deviceAuthList).ToList(); SchDataNow.deviceAuth = SchDataNow.deviceAuthList.Count; SchDataNow.deviceNoAuthList = SchDataNow.deviceNoAuthList.Union(SchDataTodo.deviceNoAuthList).ToList(); SchDataNow.deviceNoAuth = SchDataNow.deviceNoAuthList.Count; SchDataNow.tmidList = SchDataNow.tmidList.Union(SchDataTodo.tmidList).ToList(); SchDataNow.tmidCnt = SchDataNow.tmidList.Count; } //無此校資料 => 該校資料放入 else { ProdAnalysisCosmos SchDataNow = SchDataTodo; SchDataNow.date = $"{y}"; SchDataNow.year = Convert.ToInt32(y, 10); SchDataNow.month = 0; DateTimeOffset dateTime = new DateTimeOffset(SchDataNow.year, 1, 1, 0, 0, 0, TimeSpan.Zero); SchDataNow.dateTime = dateTime.ToUnixTimeSeconds(); SchDataNow.id = $"{toolType}-{y}-{schId}"; SchDataNow.dateUnit = "year"; ProdAnalysisListYear[$"{toolType}"][$"{schId}"] = SchDataNow; } } //無此年資料 => 所有學校資料放入 else { ProdAnalysisCosmos SchDataNow = SchDataTodo; SchDataNow.date = $"{y}"; SchDataNow.year = Convert.ToInt32(y, 10); SchDataNow.month = 0; DateTimeOffset dateTime = new DateTimeOffset(SchDataNow.year, 1, 1, 0, 0, 0, TimeSpan.Zero); SchDataNow.dateTime = dateTime.ToUnixTimeSeconds(); SchDataNow.id = $"{toolType}-{y}-{schId}"; SchDataNow.dateUnit = "year"; ProdAnalysisListYear.Add(toolType, new Dictionary() { { schId, SchDataNow } }); } } } } if (ProdAnalysisListYear.Count > 0) { foreach (KeyValuePair> item in ProdAnalysisListYear) { //string toolType = item.Key; ProdAnalysisCosmos SchDataNow = new ProdAnalysisCosmos(); //當年某產品所有學校總和 Dictionary yearCosmosSchDIc = item.Value; foreach (KeyValuePair yearCosmosSchItem in yearCosmosSchDIc) { string schId = yearCosmosSchItem.Key; ProdAnalysisCosmos cosmosSchRow = yearCosmosSchItem.Value; await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(cosmosSchRow); //每年所有學校數據總計CosmosDB記入 cosmosAllSchSumYearDic = GenAnalysisRowSumData(cosmosAllSchSumYearDic, cosmosSchRow, calPropList, "year"); } //每年所有學校數據總計CosmosDB記入 foreach (KeyValuePair schItem in cosmosAllSchSumYearDic) { string toolType = schItem.Key; ProdAnalysisCosmos cosmosAllSchSumYear = schItem.Value; cosmosAllSchSumYear.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(cosmosAllSchSumYear); } //await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync(SchDataNow); } } //虛擬學校創建 if (crtVirtualSchoolId.Count > 0) { //取得IES5 school Base string schIdListStr = JsonConvert.SerializeObject(crtVirtualSchoolId); string schBaseQueryText = $"SELECT c.id FROM c where ARRAY_CONTAINS({schIdListStr}, c.id, true)"; await foreach (var itemsr in _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIteratorSql(queryText: schBaseQueryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") })) { using var json = await JsonDocument.ParseAsync(itemsr.Content); if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0) { foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray()) { string existSchid = obj.GetProperty("id").GetString(); if (crtVirtualSchoolId.Contains(existSchid)) { crtVirtualSchoolId.Remove(existSchid); } } } } //取得IES5 school VirtualBase schIdListStr = JsonConvert.SerializeObject(crtVirtualSchoolId); schBaseQueryText = $"SELECT c.id FROM c where ARRAY_CONTAINS({schIdListStr}, c.id, true)"; await foreach (var itemsr in _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIteratorSql(queryText: schBaseQueryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"VirtualBase") })) { using var json = await JsonDocument.ParseAsync(itemsr.Content); if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0) { foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray()) { string existSchid = obj.GetProperty("id").GetString(); if (crtVirtualSchoolId.Contains(existSchid)) { crtVirtualSchoolId.Remove(existSchid); } } } } //VirtualBase school 建立 if (crtVirtualSchoolId.Count > 0) { //取得CSV2 School,存在者建立IES5 VirtualBase school List crtVSchoolList = new List(); string csv2SchIdListStr = JsonConvert.SerializeObject(crtVirtualSchoolId); string schCsv2QueryText = $"SELECT c.shortCode, c.name, c.countryName, c.provinceName, c.cityName, c.distName, c.address FROM c where ARRAY_CONTAINS({csv2SchIdListStr}, c.shortCode, true)"; await foreach (var item in _azureCosmosClientCsv2CnRead.GetContainer("Core", "School").GetItemQueryStreamIteratorSql(queryText: schCsv2QueryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("base") })) { using var json = await JsonDocument.ParseAsync(item.Content); if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0) { foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray()) { VirtualBase crtVSchool = new VirtualBase(); crtVSchool.code = "VirtualBase"; crtVSchool.id = obj.GetProperty("shortCode").GetString(); crtVSchool.pk = "School"; crtVSchool.schoolCode = obj.GetProperty("shortCode").GetString(); crtVSchool.name = obj.GetProperty("name").GetString(); crtVSchool.region = (obj.TryGetProperty("countryName", out JsonElement countryNameJ)) ? Convert.ToString(countryNameJ) : null; crtVSchool.province = (obj.TryGetProperty("provinceName", out JsonElement provinceNameJ)) ? Convert.ToString(provinceNameJ) : null; crtVSchool.city = (obj.TryGetProperty("cityName", out JsonElement cityNameJ)) ? Convert.ToString(cityNameJ) : null; crtVSchool.dist = (obj.TryGetProperty("distName", out JsonElement distNameJ)) ? Convert.ToString(distNameJ) : null; crtVSchool.address = (obj.TryGetProperty("address", out JsonElement addressJ)) ? Convert.ToString(addressJ) : null; crtVSchool.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync(crtVSchool); } } } } } } catch (Exception ex) { _ = _dingDing.SendBotMsg($"BI,{Environment.GetEnvironmentVariable("Option:Location")},CreatIes5ProdAnalData() 生成學校年月日日IOT統計資料錯誤\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組); } } //年月日 TMID IOT產品分析數據生成 ///1.生成 Redis TmidAnalysis:Month ///2.生成 CosmosDB Month ///3.生成 CosmosDB 系統所有TMID數值加總 private static async Task CreatTmidProdAnalData(AzureRedisFactory _azureRedis, CosmosClient _azureCosmosClient, DingDing _dingDing, string y, string m, string d, List IotTeachingDataList) { try { var redisClinet8 = _azureRedis.GetRedisClient(8); List calPropList = new List() { "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" }; //要計算的ProdAnalysis欄位列表 List TmidAnalysisList = new List(); if (IotTeachingDataList.Count > 0) { foreach (IotTeachingData IotTeachingDatRow in IotTeachingDataList) { bool addTmidFlg = false; string tmid = (!string.IsNullOrWhiteSpace(IotTeachingDatRow.tmid)) ? IotTeachingDatRow.tmid.ToString() : string.Empty; string deviceId = (!string.IsNullOrWhiteSpace(IotTeachingDatRow.deviceId)) ? IotTeachingDatRow.deviceId.ToString() : string.Empty; string ver = (!string.IsNullOrWhiteSpace(IotTeachingDatRow.version)) ? IotTeachingDatRow.version : string.Empty; string toolType = string.Empty; if (!string.IsNullOrWhiteSpace(IotTeachingDatRow.deviceId)) { if (IotTeachingDatRow.deviceId.Contains("HiTeachCC-")) toolType = "HiTeachCC"; else if (IotTeachingDatRow.deviceId.Contains("HiTeach-")) toolType = "HiTeach"; else if (IotTeachingDatRow.deviceId.Contains("HiTA-")) toolType = "HiTA"; } if (!string.IsNullOrWhiteSpace(tmid) && !string.IsNullOrWhiteSpace(deviceId) && !string.IsNullOrWhiteSpace(toolType)) { bool addFlg = false; TmidAnalysis tmidAnalysisRow = TmidAnalysisList.Where(s => s.tmid.Equals(tmid) && s.toolType.Equals(toolType)).FirstOrDefault(); //無此tmid數據=>創建 if (tmidAnalysisRow == null) { tmidAnalysisRow = new TmidAnalysis(); tmidAnalysisRow.tmid = tmid; tmidAnalysisRow.toolType = toolType; addFlg = true; } //欄位加總 if (!tmidAnalysisRow.deviceList.Contains(IotTeachingDatRow.deviceId)) { tmidAnalysisRow.deviceList.Add(IotTeachingDatRow.deviceId); } tmidAnalysisRow.deviceCnt = tmidAnalysisRow.deviceList.Count; switch (IotTeachingDatRow.authType) { case "0": //928授權 if (!tmidAnalysisRow.deviceNoAuthList.Contains(IotTeachingDatRow.deviceId)) tmidAnalysisRow.deviceNoAuthList.Add(IotTeachingDatRow.deviceId); tmidAnalysisRow.lessonCnt928++; break; case "1": //ID授權 if (!tmidAnalysisRow.deviceNoAuthList.Contains(IotTeachingDatRow.deviceId)) tmidAnalysisRow.deviceNoAuthList.Add(IotTeachingDatRow.deviceId); tmidAnalysisRow.lessonCntId++; break; case "2": //機器授權 if (!tmidAnalysisRow.deviceAuthList.Contains(IotTeachingDatRow.deviceId)) tmidAnalysisRow.deviceAuthList.Add(IotTeachingDatRow.deviceId); tmidAnalysisRow.lessonCntDevice++; break; case "3": //ID+機器授權 if (!tmidAnalysisRow.deviceAuthList.Contains(IotTeachingDatRow.deviceId)) tmidAnalysisRow.deviceAuthList.Add(IotTeachingDatRow.deviceId); tmidAnalysisRow.lessonCntIdDevice++; break; } tmidAnalysisRow.deviceNoAuth = tmidAnalysisRow.deviceNoAuthList.Count; tmidAnalysisRow.deviceAuth = tmidAnalysisRow.deviceAuthList.Count; if (!tmidAnalysisRow.tmidList.Contains(IotTeachingDatRow.tmid)) { tmidAnalysisRow.tmidList.Add(IotTeachingDatRow.tmid); } tmidAnalysisRow.tmidCnt = tmidAnalysisRow.tmidList.Count; tmidAnalysisRow.lessonRecord++; if (IotTeachingDatRow.useIES.Equals("1")) tmidAnalysisRow.useIES++; tmidAnalysisRow.useIES5Resource += IotTeachingDatRow.useIES5Resource; if (IotTeachingDatRow.useWebIrs.Equals("1")) tmidAnalysisRow.useWebIrs++; if (IotTeachingDatRow.useDeviceIrs.Equals("1")) tmidAnalysisRow.useDeviceIrs++; if (IotTeachingDatRow.useHaboard.Equals("1")) tmidAnalysisRow.useHaboard++; if (IotTeachingDatRow.useHita.Equals("1")) tmidAnalysisRow.useHita++; tmidAnalysisRow.lessonLengMin += IotTeachingDatRow.lessonLengMin; if (IotTeachingDatRow.lessonLengMin.Equals(0)) tmidAnalysisRow.lessonLeng0++; tmidAnalysisRow.stuShow += IotTeachingDatRow.stuShow; tmidAnalysisRow.stuLessonLengMin += IotTeachingDatRow.lessonLengMin * IotTeachingDatRow.stuShow; if (IotTeachingDatRow.tPoint >= 70) tmidAnalysisRow.tGreen++; if (IotTeachingDatRow.lessonLengMin >= 10 && IotTeachingDatRow.tPoint > 0) tmidAnalysisRow.tLesson++; if (IotTeachingDatRow.lTypeCoop.Equals("1")) tmidAnalysisRow.lTypeCoop++; if (IotTeachingDatRow.lTypeIact.Equals("1")) tmidAnalysisRow.lTypeIact++; if (IotTeachingDatRow.lTypeMis.Equals("1")) tmidAnalysisRow.lTypeMis++; if (IotTeachingDatRow.lTypeTst.Equals("1")) tmidAnalysisRow.lTypeTst++; if (IotTeachingDatRow.lTypeDif.Equals("1")) tmidAnalysisRow.lTypeDif++; if (IotTeachingDatRow.lTypeCoop.Equals("0") && IotTeachingDatRow.lTypeIact.Equals("0") && IotTeachingDatRow.lTypeMis.Equals("0") && IotTeachingDatRow.lTypeTst.Equals("0") && IotTeachingDatRow.lTypeDif.Equals("0")) tmidAnalysisRow.lTypeNone++; tmidAnalysisRow.mission += IotTeachingDatRow.mission; tmidAnalysisRow.missionFin += IotTeachingDatRow.missionFin; tmidAnalysisRow.item += IotTeachingDatRow.item; tmidAnalysisRow.interact += IotTeachingDatRow.interact; if (IotTeachingDatRow.sendSok.Equals("1")) tmidAnalysisRow.sendSok++; if (IotTeachingDatRow.learnPeer.Equals("1")) tmidAnalysisRow.learnPeer++; if (IotTeachingDatRow.learnCoop.Equals("1")) tmidAnalysisRow.learnCoop++; if (IotTeachingDatRow.useWordCloud.Equals("1")) tmidAnalysisRow.useWordCloud++; if (IotTeachingDatRow.useClouDAS.Equals("1")) tmidAnalysisRow.useClouDAS++; if (IotTeachingDatRow.useGPT.Equals("1")) tmidAnalysisRow.useGPT++; if (IotTeachingDatRow.useIes5Test.Equals("1")) tmidAnalysisRow.useIes5Test++; if (IotTeachingDatRow.usePaperTest.Equals("1")) tmidAnalysisRow.usePaperTest++; if (IotTeachingDatRow.useExcelTest.Equals("1")) tmidAnalysisRow.useExcelTest++; if (IotTeachingDatRow.useScoreBoard.Equals("1")) tmidAnalysisRow.useScoreBoard++; //課堂中使用記分板 if (IotTeachingDatRow.learnParticipationCnt.Equals("1")) tmidAnalysisRow.learnParticipationCnt++; //學習參與度次數 tmidAnalysisRow.learnParticipationT += IotTeachingDatRow.learnParticipation; //學習參與度指數(總和) decimal learnParticipationTmp = (tmidAnalysisRow.learnParticipationCnt > 0) ? (decimal)tmidAnalysisRow.learnParticipationT / (decimal)tmidAnalysisRow.learnParticipationCnt : 0; tmidAnalysisRow.learnParticipation = Math.Round(learnParticipationTmp, 2); //學習參與度指數(平均) tmidAnalysisRow.coopMission += IotTeachingDatRow.coopMission; //協作任務數 tmidAnalysisRow.coopWork += IotTeachingDatRow.coopWork; //協作作品數 tmidAnalysisRow.coopContributionT += IotTeachingDatRow.coopContributionT; //協作總貢獻度 tmidAnalysisRow.peerAct += IotTeachingDatRow.peerAct; //互評活動次數 tmidAnalysisRow.peerStuParticipationT += IotTeachingDatRow.peerStuParticipationT; //互評學生參與總次數 if (IotTeachingDatRow.useTransMode.Equals("1")) tmidAnalysisRow.useTransMode++; //有使用透明模式 if (IotTeachingDatRow.useMiniMode.Equals("1")) tmidAnalysisRow.useMiniMode++; //有使用最小化模式 if (!string.IsNullOrWhiteSpace(ver) && !tmidAnalysisRow.verList.Contains(ver)) { tmidAnalysisRow.verList.Add(ver); } if (addFlg) { TmidAnalysisList.Add(tmidAnalysisRow); } } } } //1.記入CSV2 Redis TmidAnalysis:Day //2.記入CSV2 CosmosDB Day if (TmidAnalysisList.Count > 0) { //資料整形 Dictionary> redisTmidFieldDic = new Dictionary>(); //架構: key => tmid => JsonContent List cosmosTmidList = new List(); Dictionary cosmosAllTmidSumDayDic = new Dictionary(); foreach (TmidAnalysis tmidAnalysisRow in TmidAnalysisList) { //Redis整形 string toolType = tmidAnalysisRow.toolType; string tmid = tmidAnalysisRow.tmid; string hkey = $"TmidAnalysis:Day:{toolType}:{y}{m}{d}"; string fieldContent = tmidAnalysisRow.ToJsonString(); if (redisTmidFieldDic.ContainsKey(hkey)) redisTmidFieldDic[hkey].Add(tmid, fieldContent); else redisTmidFieldDic.Add(hkey, new Dictionary() { { tmid, fieldContent } }); //CosmosDB整形 TmidAnalysisCosmos TmidAnalysisCosmosRow = tmidAnalysisRow.ToJsonString().ToObject(); TmidAnalysisCosmosRow.date = $"{y}{m}{d}"; TmidAnalysisCosmosRow.year = Convert.ToInt32(y, 10); TmidAnalysisCosmosRow.month = Convert.ToInt32(m, 10); TmidAnalysisCosmosRow.day = Convert.ToInt32(d, 10); DateTimeOffset dateTime = new DateTimeOffset(TmidAnalysisCosmosRow.year, TmidAnalysisCosmosRow.month, TmidAnalysisCosmosRow.day, 0, 0, 0, TimeSpan.Zero); TmidAnalysisCosmosRow.dateTime = dateTime.ToUnixTimeSeconds(); TmidAnalysisCosmosRow.id = $"{TmidAnalysisCosmosRow.toolType}-{TmidAnalysisCosmosRow.date}-{tmid}"; TmidAnalysisCosmosRow.dateUnit = "day"; TmidAnalysisCosmosRow.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); cosmosTmidList.Add(TmidAnalysisCosmosRow); } //記入Redis if (redisTmidFieldDic.Count > 0) { foreach (KeyValuePair> hkeyItem in redisTmidFieldDic) { string hkey = hkeyItem.Key; List hvalList = new List(); Dictionary fieldDic = hkeyItem.Value; foreach (KeyValuePair tmidItem in fieldDic) { string tmid = tmidItem.Key; string fieldContent = tmidItem.Value; hvalList.Add(new HashEntry($"{tmid}", fieldContent)); } await redisClinet8.HashSetAsync(hkey, hvalList.ToArray()); } } //記入CosmosDB if (cosmosTmidList.Count > 0) { foreach (TmidAnalysisCosmos cosmosTmidRow in cosmosTmidList) { //各TMID每日CosmosDB記入 await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(cosmosTmidRow); //所有TMID每日數值加總 數值生成 cosmosAllSchSumDayDic -> key:toolType val:cosmosAllSchSumDay cosmosAllTmidSumDayDic = GenAnalysisRowSumData(cosmosAllTmidSumDayDic, cosmosTmidRow, calPropList, "day"); } //每日所有TMID數據總計CosmosDB記入 foreach (KeyValuePair tmidItem in cosmosAllTmidSumDayDic) { string toolType = tmidItem.Key; TmidAnalysisCosmos cosmosAllTmidSumDay = tmidItem.Value; cosmosAllTmidSumDay.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(cosmosAllTmidSumDay); } } } //取 Redis 該月所有 TmidAnalysis:Day //1.生成 Redis TmidAnalysis:Month //2.生成 CosmosDB Month Dictionary> TmidAnalysisListMonth = new Dictionary>(); Dictionary cosmosAllTmidSumMonthDic = new Dictionary(); List cosmosTmidListMonth = new List(); string patternD = $"TmidAnalysis:Day:HiT*:{y}{m}*"; List keysDayList = ScanRedisKeysByPattern(_azureRedis, patternD); if (keysDayList.Count > 0) { foreach (string keyDay in keysDayList) { string[] keyItemList = keyDay.Split(':'); //TmidAnalysis:Day:HiTeach:20230326 string toolType = keyItemList[2]; string dateStrD = keyItemList[3]; string dateStrD_y = string.Empty; string dateStrD_m = string.Empty; string dateStrD_d = string.Empty; Regex rgx = new Regex(@"[0-9]{8}"); if (rgx.IsMatch(dateStrD)) { dateStrD_y = dateStrD.Substring(0, 4); dateStrD_m = dateStrD.Substring(4, 2); dateStrD_d = dateStrD.Substring(6, 2); } string tmidAnalMonthKey = $"TmidAnalysis:Month:{toolType}:{dateStrD_y}{dateStrD_m}"; bool tmidAnalysisDayExist = await redisClinet8.KeyExistsAsync(keyDay); if (tmidAnalysisDayExist && !string.IsNullOrWhiteSpace(dateStrD_y) && !string.IsNullOrWhiteSpace(dateStrD_m) && !string.IsNullOrWhiteSpace(dateStrD_d)) { HashEntry[] hsetDay = redisClinet8.HashGetAll(keyDay); //某日 ProdAnalysis:Day所有學校的統計項目 foreach (HashEntry hset in hsetDay) { string keyTMID = hset.Name; string valTmidDataJson = hset.Value; TmidAnalysis tmidDataTodo = valTmidDataJson.ToObject(); //Redis Month 資料生成 if (TmidAnalysisListMonth.ContainsKey(tmidAnalMonthKey)) //月Dic已有此key => TMID累加 { if (TmidAnalysisListMonth[$"{tmidAnalMonthKey}"].ContainsKey($"{keyTMID}")) { TmidAnalysis TmidDataNow = TmidAnalysisListMonth[$"{tmidAnalMonthKey}"][$"{keyTMID}"]; foreach (PropertyInfo propertyInfo in TmidDataNow.GetType().GetProperties()) { if (calPropList.Contains(propertyInfo.Name)) { var propType = propertyInfo.PropertyType; var valNow = propertyInfo.GetValue(TmidDataNow); var valTodo = tmidDataTodo.GetType().GetProperty(propertyInfo.Name).GetValue(tmidDataTodo); if (propType.Equals(typeof(long))) propertyInfo.SetValue(TmidDataNow, Convert.ToInt64(valNow.ToString(), 10) + Convert.ToInt64(valTodo.ToString(), 10)); else propertyInfo.SetValue(TmidDataNow, Convert.ToInt32(valNow.ToString(), 10) + Convert.ToInt32(valTodo.ToString(), 10)); } } TmidDataNow.deviceList = TmidDataNow.deviceList.Union(tmidDataTodo.deviceList).ToList(); TmidDataNow.deviceCnt = TmidDataNow.deviceList.Count; TmidDataNow.deviceAuthList = TmidDataNow.deviceAuthList.Union(tmidDataTodo.deviceAuthList).ToList(); TmidDataNow.deviceAuth = TmidDataNow.deviceAuthList.Count; TmidDataNow.deviceNoAuthList = TmidDataNow.deviceNoAuthList.Union(tmidDataTodo.deviceNoAuthList).ToList(); TmidDataNow.deviceNoAuth = TmidDataNow.deviceNoAuthList.Count; TmidDataNow.tmidList = TmidDataNow.tmidList.Union(tmidDataTodo.tmidList).ToList(); TmidDataNow.tmidCnt = TmidDataNow.tmidList.Count; TmidDataNow.verList = TmidDataNow.verList.Union(tmidDataTodo.verList).ToList(); } //無TMID資料 => 該TMID資料放入 else { TmidAnalysisListMonth[$"{tmidAnalMonthKey}"][$"{keyTMID}"] = tmidDataTodo; } } else //無此月資料 => 所有TMID資料放入 { TmidAnalysisListMonth.Add(tmidAnalMonthKey, new Dictionary() { { keyTMID, tmidDataTodo } }); } } } } } if (TmidAnalysisListMonth.Count > 0) { foreach (KeyValuePair> item in TmidAnalysisListMonth) { string monthRedisKey = item.Key; List hvalList = new List(); Dictionary monthRedisTmidDIc = item.Value; foreach (KeyValuePair monthRedisTmidItem in monthRedisTmidDIc) { string monthRedisTmid = monthRedisTmidItem.Key; TmidAnalysis monthRedisTmidData = monthRedisTmidItem.Value; //Redis資料製作 hvalList.Add(new HashEntry(monthRedisTmid, monthRedisTmidData.ToJsonString())); //CosmosDB資料製作 TmidAnalysisCosmos cosmosTmidRow = monthRedisTmidData.ToJsonString().ToObject(); cosmosTmidRow.date = $"{y}{m}"; cosmosTmidRow.year = Convert.ToInt32(y, 10); cosmosTmidRow.month = Convert.ToInt32(m, 10); DateTimeOffset dateTime = new DateTimeOffset(cosmosTmidRow.year, cosmosTmidRow.month, 1, 0, 0, 0, TimeSpan.Zero); cosmosTmidRow.dateTime = dateTime.ToUnixTimeSeconds(); cosmosTmidRow.id = $"{monthRedisTmidData.toolType}-{cosmosTmidRow.date}-{monthRedisTmid}"; cosmosTmidRow.dateUnit = "month"; cosmosTmidRow.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); cosmosTmidListMonth.Add(cosmosTmidRow); } //記入Redis await redisClinet8.HashSetAsync($"{monthRedisKey}", hvalList.ToArray()); } //記入CosmosDB if (cosmosTmidListMonth.Count > 0) { foreach (TmidAnalysisCosmos cosmosTmidRow in cosmosTmidListMonth) { await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(cosmosTmidRow); //所有學校數值加總 數值生成 cosmosAllSchSumDayDic -> key:toolType val:cosmosAllSchSumDay cosmosAllTmidSumMonthDic = GenAnalysisRowSumData(cosmosAllTmidSumMonthDic, cosmosTmidRow, calPropList, "day"); } //每月所有TMID數據總計CosmosDB記入 foreach (KeyValuePair tmidItem in cosmosAllTmidSumMonthDic) { string toolType = tmidItem.Key; TmidAnalysisCosmos cosmosAllTmidSumMonth = tmidItem.Value; cosmosAllTmidSumMonth.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(cosmosAllTmidSumMonth); } } } //取該年所有 CosmosDB 該年所有月份 生成CosmosDB年資料 Dictionary> TmidAnalysisListYear = new Dictionary>(); Dictionary cosmosAllTmidSumYearDic = new Dictionary(); var query = $"SELECT * FROM c WHERE c.year = {y} AND c.dateUnit = 'month' AND c.tmid != 'alltmid'"; await foreach (var itemcr in _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIteratorSql(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("TmidAnalysis") })) { var json = await JsonDocument.ParseAsync(itemcr.Content); if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0) { foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray()) { TmidAnalysisCosmos TmidDataTodo = obj.ToObject(); string toolType = TmidDataTodo.toolType; string tmid = TmidDataTodo.tmid; //年Dic已有此key => 分校累加 if (TmidAnalysisListYear.ContainsKey(toolType)) { if (TmidAnalysisListYear[$"{toolType}"].ContainsKey($"{tmid}")) { TmidAnalysisCosmos TmidDataNow = TmidAnalysisListYear[$"{toolType}"][$"{tmid}"]; foreach (PropertyInfo propertyInfo in TmidDataNow.GetType().GetProperties()) { if (calPropList.Contains(propertyInfo.Name)) { var propType = propertyInfo.PropertyType; var valNow = propertyInfo.GetValue(TmidDataNow); var valTodo = TmidDataTodo.GetType().GetProperty(propertyInfo.Name).GetValue(TmidDataTodo); if (propType.Equals(typeof(long))) propertyInfo.SetValue(TmidDataNow, Convert.ToInt64(valNow.ToString(), 10) + Convert.ToInt64(valTodo.ToString(), 10)); else propertyInfo.SetValue(TmidDataNow, Convert.ToInt32(valNow.ToString(), 10) + Convert.ToInt32(valTodo.ToString(), 10)); } } TmidDataNow.deviceList = TmidDataNow.deviceList.Union(TmidDataTodo.deviceList).ToList(); TmidDataNow.deviceCnt = TmidDataNow.deviceList.Count; TmidDataNow.deviceAuthList = TmidDataNow.deviceAuthList.Union(TmidDataTodo.deviceAuthList).ToList(); TmidDataNow.deviceAuth = TmidDataNow.deviceAuthList.Count; TmidDataNow.deviceNoAuthList = TmidDataNow.deviceNoAuthList.Union(TmidDataTodo.deviceNoAuthList).ToList(); TmidDataNow.deviceNoAuth = TmidDataNow.deviceNoAuthList.Count; TmidDataNow.tmidList = TmidDataNow.tmidList.Union(TmidDataTodo.tmidList).ToList(); TmidDataNow.tmidCnt = TmidDataNow.tmidList.Count; TmidDataNow.verList = TmidDataNow.verList.Union(TmidDataTodo.verList).ToList(); } //無此校資料 => 該校資料放入 else { TmidAnalysisCosmos TmidDataNow = TmidDataTodo; TmidDataNow.date = $"{y}"; TmidDataNow.year = Convert.ToInt32(y, 10); TmidDataNow.month = 0; DateTimeOffset dateTime = new DateTimeOffset(TmidDataNow.year, 1, 1, 0, 0, 0, TimeSpan.Zero); TmidDataNow.dateTime = dateTime.ToUnixTimeSeconds(); TmidDataNow.id = $"{toolType}-{y}-{tmid}"; TmidDataNow.dateUnit = "year"; TmidAnalysisListYear[$"{toolType}"][$"{tmid}"] = TmidDataNow; } } //無此年資料 => 所有學校資料放入 else { TmidAnalysisCosmos TmidDataNow = TmidDataTodo; TmidDataNow.date = $"{y}"; TmidDataNow.year = Convert.ToInt32(y, 10); TmidDataNow.month = 0; DateTimeOffset dateTime = new DateTimeOffset(TmidDataNow.year, 1, 1, 0, 0, 0, TimeSpan.Zero); TmidDataNow.dateTime = dateTime.ToUnixTimeSeconds(); TmidDataNow.id = $"{toolType}-{y}-{tmid}"; TmidDataNow.dateUnit = "year"; TmidAnalysisListYear.Add(toolType, new Dictionary() { { tmid, TmidDataNow } }); } } } } if (TmidAnalysisListYear.Count > 0) { foreach (KeyValuePair> item in TmidAnalysisListYear) { //string toolType = item.Key; TmidAnalysisCosmos TmidDataNow = new TmidAnalysisCosmos(); //當年某產品所有學校總和 Dictionary yearCosmosTmidDIc = item.Value; foreach (KeyValuePair yearCosmosTmidItem in yearCosmosTmidDIc) { string tmid = yearCosmosTmidItem.Key; TmidAnalysisCosmos cosmosTmidRow = yearCosmosTmidItem.Value; await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(cosmosTmidRow); //每年所有學校數據總計CosmosDB記入 cosmosAllTmidSumYearDic = GenAnalysisRowSumData(cosmosAllTmidSumYearDic, cosmosTmidRow, calPropList, "year"); } //每年所有學校數據總計CosmosDB記入 foreach (KeyValuePair tmidItem in cosmosAllTmidSumYearDic) { string toolType = tmidItem.Key; TmidAnalysisCosmos cosmosAllTmidSumYear = tmidItem.Value; cosmosAllTmidSumYear.createDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(cosmosAllTmidSumYear); } //await _azureCosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(TmidDataNow); } } } catch (Exception ex) { _ = _dingDing.SendBotMsg($"BI,{Environment.GetEnvironmentVariable("Option:Location")},CreatTmidProdAnalData() 生成TMID年月日日IOT統計資料錯誤\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.研發C組); } } //生成年月日 Device IOT產品分析數據 [待做] private static async Task CreatDeviceAnalData(AzureRedisFactory _azureRedis, CosmosClient _azureCosmosClient, DingDing _dingDing, string y, string m, string d, List IotTeachingDataList) { try { var redisClinet8 = _azureRedis.GetRedisClient(8); //1. 從IOT 取得DeviceID 或 IP //2. 從DeviceID 或 IP 算出地理位置(國省市區) //3. 依照各地理位置進行項目統計;統計項目和學校及TMID統計項目相同 } catch (Exception ex) { _ = _dingDing.SendBotMsg($"BI,{Environment.GetEnvironmentVariable("Option:Location")},CreatDeviceAnalData() 生成TMID年月日日IOT統計資料錯誤\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.研發C組); } } //累加各校每日/月總計資料,生成所有學校每日/月總計資料 private static Dictionary GenAnalysisRowSumData(Dictionary cosmosAllSumDic, ProdAnalysisCosmos cosmosRow, List calPropList, string dataType) //dataType:"day","month","year" { try { string toolType = cosmosRow.toolType; string schoolId = "allschool"; int year = 0; int month = 1; int day = 1; switch (dataType) { case "day": year = cosmosRow.year; month = cosmosRow.month; day = cosmosRow.day; break; case "month": year = cosmosRow.year; month = cosmosRow.month; break; case "year": year = cosmosRow.year; break; } ProdAnalysisCosmos cosmosAllSum = new ProdAnalysisCosmos(); if (cosmosAllSumDic.ContainsKey(toolType)) cosmosAllSum = cosmosAllSumDic[toolType]; foreach (PropertyInfo propertyInfo in cosmosAllSum.GetType().GetProperties()) //累加項目 { if (calPropList.Contains(propertyInfo.Name)) { var propType = propertyInfo.PropertyType; var valNow = propertyInfo.GetValue(cosmosAllSum); var valTodo = cosmosRow.GetType().GetProperty(propertyInfo.Name).GetValue(cosmosRow); if (propType.Equals(typeof(long))) propertyInfo.SetValue(cosmosAllSum, Convert.ToInt64(valNow.ToString(), 10) + Convert.ToInt64(valTodo.ToString(), 10)); else propertyInfo.SetValue(cosmosAllSum, Convert.ToInt32(valNow.ToString(), 10) + Convert.ToInt32(valTodo.ToString(), 10)); } } cosmosAllSum.schoolId = schoolId; cosmosAllSum.toolType = cosmosRow.toolType; cosmosAllSum.date = cosmosRow.date; cosmosAllSum.id = $"{cosmosAllSum.toolType}-{cosmosAllSum.date}-{schoolId}"; cosmosAllSum.dateUnit = dataType; cosmosAllSum.year = year; cosmosAllSum.month = month; cosmosAllSum.day = day; DateTimeOffset dateTime = new DateTimeOffset(year, month, day, 0, 0, 0, TimeSpan.Zero); cosmosAllSum.dateTime = dateTime.ToUnixTimeSeconds(); cosmosAllSum.deviceList = cosmosAllSum.deviceList.Union(cosmosRow.deviceList).ToList(); cosmosAllSum.deviceCnt = cosmosAllSum.deviceList.Count; cosmosAllSum.deviceAuthList = cosmosAllSum.deviceAuthList.Union(cosmosRow.deviceAuthList).ToList(); cosmosAllSum.deviceAuth = cosmosAllSum.deviceAuthList.Count; cosmosAllSum.deviceNoAuthList = cosmosAllSum.deviceNoAuthList.Union(cosmosRow.deviceNoAuthList).ToList(); cosmosAllSum.deviceNoAuth = cosmosAllSum.deviceNoAuthList.Count; cosmosAllSum.tmidList = cosmosAllSum.tmidList.Union(cosmosRow.tmidList).ToList(); cosmosAllSum.tmidCnt = cosmosAllSum.tmidList.Count; decimal learnParticipationTmp = (cosmosAllSum.learnParticipationCnt > 0) ? (decimal)cosmosAllSum.learnParticipationT / (decimal)cosmosAllSum.learnParticipationCnt : 0; cosmosAllSum.learnParticipation = Math.Round(learnParticipationTmp, 2); //學習參與度指數(平均) if (cosmosAllSumDic.ContainsKey(toolType)) cosmosAllSumDic[toolType] = cosmosAllSum; else cosmosAllSumDic.Add(toolType, cosmosAllSum); return cosmosAllSumDic; } catch (Exception ex) { return cosmosAllSumDic; } } //累加各TMID每日/月總計資料,生成所有TMID每日/月總計資料 private static Dictionary GenAnalysisRowSumData(Dictionary cosmosAllSumDic, TmidAnalysisCosmos cosmosRow, List calPropList, string dataType) //dataType:"day","month","year" { try { string toolType = cosmosRow.toolType; string tmid = "alltmid"; int year = 0; int month = 1; int day = 1; switch (dataType) { case "day": year = cosmosRow.year; month = cosmosRow.month; day = cosmosRow.day; break; case "month": year = cosmosRow.year; month = cosmosRow.month; break; case "year": year = cosmosRow.year; break; } TmidAnalysisCosmos cosmosAllSum = new TmidAnalysisCosmos(); if (cosmosAllSumDic.ContainsKey(toolType)) cosmosAllSum = cosmosAllSumDic[toolType]; foreach (PropertyInfo propertyInfo in cosmosAllSum.GetType().GetProperties()) //累加項目 { if (calPropList.Contains(propertyInfo.Name)) { var propType = propertyInfo.PropertyType; var valNow = propertyInfo.GetValue(cosmosAllSum); var valTodo = cosmosRow.GetType().GetProperty(propertyInfo.Name).GetValue(cosmosRow); if (propType.Equals(typeof(long))) propertyInfo.SetValue(cosmosAllSum, Convert.ToInt64(valNow.ToString(), 10) + Convert.ToInt64(valTodo.ToString(), 10)); else propertyInfo.SetValue(cosmosAllSum, Convert.ToInt32(valNow.ToString(), 10) + Convert.ToInt32(valTodo.ToString(), 10)); } } cosmosAllSum.tmid = tmid; cosmosAllSum.toolType = cosmosRow.toolType; cosmosAllSum.date = cosmosRow.date; cosmosAllSum.id = $"{cosmosAllSum.toolType}-{cosmosAllSum.date}-{tmid}"; cosmosAllSum.dateUnit = dataType; cosmosAllSum.year = year; cosmosAllSum.month = month; cosmosAllSum.day = day; DateTimeOffset dateTime = new DateTimeOffset(year, month, day, 0, 0, 0, TimeSpan.Zero); cosmosAllSum.dateTime = dateTime.ToUnixTimeSeconds(); cosmosAllSum.deviceList = cosmosAllSum.deviceList.Union(cosmosRow.deviceList).ToList(); cosmosAllSum.deviceCnt = cosmosAllSum.deviceList.Count; cosmosAllSum.deviceAuthList = cosmosAllSum.deviceAuthList.Union(cosmosRow.deviceAuthList).ToList(); cosmosAllSum.deviceAuth = cosmosAllSum.deviceAuthList.Count; cosmosAllSum.deviceNoAuthList = cosmosAllSum.deviceNoAuthList.Union(cosmosRow.deviceNoAuthList).ToList(); cosmosAllSum.deviceNoAuth = cosmosAllSum.deviceNoAuthList.Count; cosmosAllSum.tmidList = cosmosAllSum.tmidList.Union(cosmosRow.tmidList).ToList(); cosmosAllSum.tmidCnt = cosmosAllSum.tmidList.Count; cosmosAllSum.verList = cosmosAllSum.verList.Union(cosmosRow.verList).ToList(); decimal learnParticipationTmp = (cosmosAllSum.learnParticipationCnt > 0) ? (decimal)cosmosAllSum.learnParticipationT / (decimal)cosmosAllSum.learnParticipationCnt : 0; cosmosAllSum.learnParticipation = Math.Round(learnParticipationTmp, 2); //學習參與度指數(平均) if (cosmosAllSumDic.ContainsKey(toolType)) cosmosAllSumDic[toolType] = cosmosAllSum; else cosmosAllSumDic.Add(toolType, cosmosAllSum); return cosmosAllSumDic; } catch (Exception ex) { return cosmosAllSumDic; } } /// /// 取得Redis(8)符合搜尋模式的key /// /// /// public static List ScanRedisKeysByPattern(AzureRedisFactory _azureRedis, string pattern) { var redisClinet8 = _azureRedis.GetRedisClient(8); var keys = new HashSet(); int nextCursor = 0; do { RedisResult redisResult = redisClinet8.Execute("SCAN", nextCursor.ToString(), "MATCH", pattern, "COUNT", "1000"); var innerResult = (RedisResult[])redisResult; nextCursor = int.Parse((string)innerResult[0]); List resultLines = ((RedisKey[])innerResult[1]).ToList(); keys.UnionWith(resultLines); } while (nextCursor != 0); List result = new List(); if (keys.Count > 0) { foreach (RedisKey key in keys) { result.Add(key.ToString()); } } return result; } } }