zhouj1203@hotmail.com 2 سال پیش
والد
کامیت
4ca85301d7
1فایلهای تغییر یافته به همراه334 افزوده شده و 6 حذف شده
  1. 334 6
      TEAMModelOS/Controllers/Analysis/ClassAnalysisController.cs

+ 334 - 6
TEAMModelOS/Controllers/Analysis/ClassAnalysisController.cs

@@ -8,10 +8,16 @@ using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
 using OpenXmlPowerTools;
+using StackExchange.Redis;
 using System;
 using System.Collections.Generic;
+using System.Configuration;
+using System.Dynamic;
 using System.Linq;
+using System.Net.Http.Headers;
+using System.Net.Http;
 using System.Text;
 using System.Text.Json;
 using System.Threading.Tasks;
@@ -23,6 +29,8 @@ using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
+using System.Net;
+using System.Net.Http.Json;
 
 namespace TEAMModelOS.Controllers.Analysis
 {
@@ -39,8 +47,11 @@ namespace TEAMModelOS.Controllers.Analysis
         private readonly Option _option;
         private readonly AzureStorageFactory _azureStorage;
         private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly AzureRedisFactory _azureRedis;
+        private readonly IConfiguration _configuration;
+        private readonly IHttpClientFactory _httpClient;
         public ClassAnalysisController(CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing,
-            IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage)
+            IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, IConfiguration configuration, IHttpClientFactory httpClient)
         {
             _azureCosmos = azureCosmos;
             _serviceBus = serviceBus;
@@ -49,6 +60,9 @@ namespace TEAMModelOS.Controllers.Analysis
             _option = option?.Value;
             _azureStorage = azureStorage;
             _coreAPIHttpService = coreAPIHttpService;
+            _azureRedis = azureRedis;
+            _configuration = configuration;
+            _httpClient = httpClient;
         }
         /// <param name="request"></param>
         /// <returns></returns>
@@ -83,6 +97,116 @@ namespace TEAMModelOS.Controllers.Analysis
                     records.Add(item);
 
                 }
+                double teacherCount = 0;
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: $"SELECT count(1) as teachers FROM c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            if (obj.TryGetProperty("teachers", out JsonElement teachers))
+                            {
+                                teacherCount = teachers.GetDouble();
+                            }
+                        }
+                    }
+
+                }
+                double studentCount = 0;
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: $"SELECT count(1) as stus FROM c where c.periodId = '{pId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            if (obj.TryGetProperty("stus", out JsonElement stus))
+                            {
+                                studentCount = stus.GetDouble();
+                            }
+                        }
+                    }
+
+                }
+                double itemCount = 0;
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: $"SELECT count(1) as items FROM c where c.periodId = '{pId}' and c.pid = null and c.scope = 'school' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            if (obj.TryGetProperty("items", out JsonElement items))
+                            {
+                                itemCount = items.GetDouble();
+                            }
+                        }
+                    }
+                }
+
+                double paperCount = 0;
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: $"SELECT count(1) as papers FROM c where c.periodId = '{pId}' and c.scope = 'school' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Paper-{code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            if (obj.TryGetProperty("papers", out JsonElement papers))
+                            {
+                                paperCount = papers.GetDouble();
+                            }
+                        }
+                    }
+                }
+                double voteCount = 0;
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"SELECT count(1) as votes FROM c where c.periodId = '{pId}' and c.scope = 'school' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Vote-{code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            if (obj.TryGetProperty("votes", out JsonElement votes))
+                            {
+                                voteCount = votes.GetDouble();
+                            }
+                        }
+                    }
+                }
+                double surveyCount = 0;
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"SELECT count(1) as surveys FROM c where c.periodId = '{pId}' and c.scope = 'school' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Survey-{code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            if (obj.TryGetProperty("surveys", out JsonElement surveys))
+                            {
+                                surveyCount = surveys.GetDouble();
+                            }
+                        }
+                    }
+                }
+                double homeworkCount = 0;
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"SELECT count(1) as works FROM c where c.periodId = '{pId}' and c.scope = 'school' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Homework-{code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            if (obj.TryGetProperty("works", out JsonElement works))
+                            {
+                                homeworkCount = works.GetDouble();
+                            }
+                        }
+                    }
+                }
+                double resourcesCount = itemCount + paperCount;
+                double classRooms = await GetTeacCount(code.GetString());
                 if (records.Count > 0)
                 {
                     var response = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(code.GetString(), new PartitionKey($"Base"));
@@ -128,12 +252,19 @@ namespace TEAMModelOS.Controllers.Analysis
                     double workCount = records.Select(c => c.collateCount).Sum();
                     double examQuizCount = records.Select(c => c.examQuizCount).Sum();
                     double interactCount = records.Select(c => c.clientInteractionCount).Sum();
+                    
                     //学校基本信息
                     School scInfo = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{code}", partitionKey: new PartitionKey("Base"));
                     var perMore = scInfo.period.Where(c => c.id.Equals(pId.GetString())).FirstOrDefault().grades;
-
-                    var realrecords = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).ToList();                       
-                    List<(string name, int? cICount, int? pCount, int? cTCount, int? eCount,int? diffCount)> tcount = new();
+                    var subjects = scInfo.period.Where(c => c.id.Equals(pId.GetString())).FirstOrDefault().subjects;
+                    var realrecords = records.Where(c => c.startTime >= stime.GetInt64() && c.startTime <= etime.GetInt64() && c.grade.Any()).ToList();
+                    double attendCount = realrecords.Select(c => c.attendCount).Sum();
+                    double duration  = realrecords.Select(c => c.duration).Sum();
+                    double clientInteractionCount = realrecords.Select(c => c.clientInteractionCount).Sum();
+                    double collateCount = realrecords.Select(c => c.collateCount).Sum();
+                    var numbers = realrecords.GroupBy(x => (x.interactionCount, x.attendCount,x.id)).Select(y => new { product = y.Key.interactionCount * y.Key.attendCount }).Select(c => c.product).Sum();
+                    List <(string name, int? cICount, int? pCount, int? cTCount, int? eCount,int? diffCount)> tcount = new();
+                    List<(string name, int? cICount, int? pCount, int? cTCount, int? eCount, int? diffCount)> subjectCount = new();
                     List<(string name, int? count)> gdCount = new();
                     int gCount = 0;
                     perMore.ForEach(x =>
@@ -149,6 +280,18 @@ namespace TEAMModelOS.Controllers.Analysis
                         gCount++;
                     });
 
+                    subjects.ForEach(x =>
+                    {
+                        var cICount = realrecords.Where(c =>!string.IsNullOrEmpty(c.subjectId) && c.subjectId.Contains(x.id)).Select(z => z.learningCategory?.interaction).Sum();
+                        var pCount = realrecords.Where(c => !string.IsNullOrEmpty(c.subjectId) && c.subjectId.Contains(x.id)).Select(z => z.learningCategory?.cooperation).Sum();
+                        var tCount = realrecords.Where(c => !string.IsNullOrEmpty(c.subjectId) && c.subjectId.Contains(x.id)).Select(z => z.learningCategory?.task).Sum();
+                        var eCount = realrecords.Where(c => !string.IsNullOrEmpty(c.subjectId) && c.subjectId.Contains(x.id)).Select(z => z.learningCategory?.exam).Sum();
+                        var diffCount = realrecords.Where(c => !string.IsNullOrEmpty(c.subjectId) && c.subjectId.Contains(x.id)).Select(z => z.learningCategory?.diffential).Sum();
+                        //var gradeCount = grades.Where(c => perMore[int.Parse(c.name)].Equals(x, StringComparison.OrdinalIgnoreCase)).FirstOrDefault().count;
+                        subjectCount.Add((x.name, cICount, pCount, tCount, eCount, diffCount));
+                        //gdCount.Add((x, gradeCount));
+                    });
+
                     var teachingCount = tcount.Select(x => new
                     {
                         x.name,
@@ -158,12 +301,24 @@ namespace TEAMModelOS.Controllers.Analysis
                         exam = x.eCount == null ? 0 : x.eCount,
                         diffential = x.diffCount == null ? 0 : x.eCount
                     });
+                    var subject = subjectCount.Select(x => new
+                    {
+                        x.name,
+                        interaction = x.cICount == null ? 0 : x.cICount,
+                        cooperation = x.pCount == null ? 0 : x.pCount,
+                        task = x.cTCount == null ? 0 : x.cTCount,
+                        exam = x.eCount == null ? 0 : x.eCount,
+                        diffential = x.diffCount == null ? 0 : x.eCount
+                    });
                     var classify_grade = gdCount.Select(x => new
                     {
                         x.name,
                         value = x.count
                     });
-                    return Ok(new { total, trend, classify_group, classify_grade, classify_type, classify_sub, teachCount, taskCount, workCount, examQuizCount, interactCount, exams, teachingCount });
+                    return Ok(new { total, trend, classify_group, classify_grade, classify_type, classify_sub, teachCount, taskCount, workCount, examQuizCount, interactCount, exams, teachingCount, 
+                        subject, attendCount, duration,teacherCount,studentCount , resourcesCount ,classRooms,voteCount,surveyCount,homeworkCount,
+                        clientInteractionCount,collateCount,numbers
+                    });
                 }
                 else
                 {
@@ -177,6 +332,179 @@ namespace TEAMModelOS.Controllers.Analysis
             }
 
         }
+
+        private async Task<double> GetTeacCount(string code)
+        {
+            try
+            {
+                var db = _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School");
+                var r8 = _azureRedis.GetRedisClient(8);
+
+                List<SchoolProductSerial> serial = new(); //承接DB資料用:序號
+                List<deviceForCoreService> uuidList = new(); //要向CoreService詢問deviceID及硬體資訊的UUID列表
+                long UTCNow = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
+
+                //軟體
+                List<string> serialPermitList = SchoolController.getSerialPermitProdcodeList();
+                string serialPermitJsonStr = JsonConvert.SerializeObject(serialPermitList);
+                string serialQueryText = $"SELECT * FROM c WHERE c.dataType = 'serial' AND ARRAY_CONTAINS({serialPermitJsonStr}, c.prodCode)";
+                await foreach (var itemsr in db.GetItemQueryStreamIterator(queryText: serialQueryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Product-{code}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(itemsr.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        deviceForCoreService uuidForCore;
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            serial.Add(obj.ToObject<SchoolProductSerial>());
+                            if (obj.TryGetProperty("deviceBound", out JsonElement deviceBoundJobj) && !string.IsNullOrWhiteSpace(deviceBoundJobj.ToString()))
+                            {
+                                foreach (var deviceBoundTmpRow in deviceBoundJobj.EnumerateArray())
+                                {
+                                    uuidForCore = new deviceForCoreService
+                                    {
+                                        sn = (!string.IsNullOrWhiteSpace(Convert.ToString(obj.GetProperty("serial")))) ? Convert.ToString(obj.GetProperty("serial")) : null,
+                                        uuid1 = (!string.IsNullOrWhiteSpace(Convert.ToString(deviceBoundTmpRow.GetProperty("uuid")))) ? Convert.ToString(deviceBoundTmpRow.GetProperty("uuid")) : null,
+                                        uuid2 = (!string.IsNullOrWhiteSpace(Convert.ToString(deviceBoundTmpRow.GetProperty("uuid2")))) ? Convert.ToString(deviceBoundTmpRow.GetProperty("uuid2")) : null,
+                                        device_id = (!string.IsNullOrWhiteSpace(Convert.ToString(deviceBoundTmpRow.GetProperty("deviceId")))) ? Convert.ToString(deviceBoundTmpRow.GetProperty("deviceId")) : null,
+                                        class_id = (!string.IsNullOrWhiteSpace(Convert.ToString(deviceBoundTmpRow.GetProperty("classId")))) ? Convert.ToString(deviceBoundTmpRow.GetProperty("classId")) : null
+                                    };
+                                    uuidList.Add(uuidForCore);
+                                }
+                            }
+                        }
+                    }
+                }
+                ////取得DeviceInfo From Core 並更新序號資料
+                List<deviceFromCoreService> coreUuidList = (List<deviceFromCoreService>)GetDeviceFromCoreAsync(uuidList).GetAwaiter().GetResult();
+                List<deviceBoundExt> deviceBoundArray;
+                List<deviceBoundExt> counts = new();
+                List<deviceFromCoreService> coreUuid;
+                deviceForCoreService deviceBoundRow;
+                deviceBoundExt deviceBoundExt;
+                List<SchoolProductSerial> updSchoolProductSerialList = new List<SchoolProductSerial>(); //更新學校產品序號用
+                foreach (SchoolProductSerial serialRow in serial)
+                {
+                    deviceBoundArray = new List<deviceBoundExt>();
+                    coreUuid = coreUuidList
+                           .Where((deviceFromCoreService x) => x.sn == serialRow.serial)
+                           .ToList();
+                    foreach (deviceFromCoreService deviceRow in coreUuid)
+                    {
+                        if (!string.IsNullOrWhiteSpace(deviceRow.uuid1) || !string.IsNullOrWhiteSpace(deviceRow.uuid2) || !string.IsNullOrWhiteSpace(deviceRow.device_id)) //uuid1、uuid2、device_id 任一欄有值
+                        {
+                            //前端顯示用
+                            deviceBoundRow = uuidList.Where(u => u.sn == deviceRow.sn && u.uuid1 == deviceRow.uuid1 && u.uuid2 == deviceRow.uuid2).FirstOrDefault();
+                            deviceBoundExt = new deviceBoundExt
+                            {
+                                uuid = deviceBoundRow.uuid1,
+                                uuid2 = deviceBoundRow.uuid2,
+                                classId = deviceBoundRow.class_id,
+                                deviceId = deviceRow.device_id,
+                                os = deviceRow.os,
+                                ip = deviceRow.local_ip,
+                                cpu = deviceRow.cpu,
+                                pcname = deviceRow.pc_name,
+                                osver = deviceRow.os_ver
+                            };
+                            deviceBoundArray.Add(deviceBoundExt);
+                        }
+                    }
+                    if (deviceBoundArray.Count.Equals(0)) //無法取得CS的硬體資訊,則用序號的硬體資訊帶入
+                    {
+                        if (serialRow.deviceBound != null)
+                        {
+                            foreach (deviceBound serialRowDeviceBound in serialRow.deviceBound)
+                            {
+                                if (!string.IsNullOrEmpty(serialRowDeviceBound.uuid) || !string.IsNullOrEmpty(serialRowDeviceBound.uuid2))
+                                {
+                                    deviceBoundExt = new deviceBoundExt
+                                    {
+                                        uuid = serialRowDeviceBound.uuid,
+                                        uuid2 = serialRowDeviceBound.uuid2,
+                                        classId = serialRowDeviceBound.classId,
+                                        deviceId = serialRowDeviceBound.deviceId
+                                    };
+                                    deviceBoundArray.Add(deviceBoundExt);
+                                }
+                            }
+                        }
+                    }
+                    //序號更新
+                    //updSchoolProductSerialList.Add(serialRow);
+                    counts.AddRange(deviceBoundArray);
+                    //await db.ReplaceItemAsync<SchoolProductSerial>(serialRow, serialRow.id, new PartitionKey($"Product-{school_code}"));
+                }
+                //取得CC授權使用狀態
+                var hashs = await r8.HashGetAllAsync($"CC:License:{code}");
+                var ccuser = hashs.Select(x => JsonDocument.Parse(x.Value.ToString())).ToList();
+
+                //更新學校產品序號
+                //_ = UpdupdSchoolProductSerialListAsync(updSchoolProductSerialList, school_code.GetString());
+                double Teachs = counts.Count + ccuser.Count;
+                return Teachs;
+            }
+            catch (Exception ex)
+            {
+                return 0;
+            }
+        }
+
+        private async Task<List<deviceFromCoreService>> GetDeviceFromCoreAsync(List<deviceForCoreService> uuidList)
+        {
+            List<deviceFromCoreService> result = new List<deviceFromCoreService>();
+            try
+            {
+                string url = _configuration.GetValue<string>("HaBookAuth:CoreService:deviceinfo");
+                string AccessToken = await getCoreAccessToken();
+                var client = _httpClient.CreateClient();
+                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
+                string uuidListJson = JsonConvert.SerializeObject(uuidList);
+                var content = new StringContent(uuidListJson, Encoding.UTF8, "application/json");
+                HttpResponseMessage responseMessage = await client.PostAsync(url, content);
+                if (responseMessage.StatusCode == HttpStatusCode.OK)
+                {
+                    string responseBody = responseMessage.Content.ReadAsStringAsync().Result;
+                    result = System.Text.Json.JsonSerializer.Deserialize<List<deviceFromCoreService>>(responseBody.ToString());
+                }
+                return result;
+            }
+            catch (Exception ex)
+            {
+                return result;
+            }
+        }
+
+        private async Task<string> getCoreAccessToken()
+        {
+            string AccessToken = "";
+            try
+            {
+                string Url = _configuration.GetValue<string>("HaBookAuth:CoreAPI") + "/oauth2/token";
+                string GrantType = "device";
+                string ClientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                string Secret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                var content = new { grant_type = GrantType, client_id = ClientID, client_secret = Secret };
+                var response = await _httpClient.CreateClient().PostAsJsonAsync($"{Url}", content);
+                if (response.IsSuccessStatusCode)
+                {
+                    string responseBody = response.Content.ReadAsStringAsync().Result;
+                    using (JsonDocument document = JsonDocument.Parse(responseBody.ToString()))
+                    {
+                        if (document.RootElement.TryGetProperty("access_token", out JsonElement AccessTokenObj))
+                        {
+                            AccessToken = AccessTokenObj.ToString();
+                        }
+                    }
+                }
+                return AccessToken;
+            }
+            catch (Exception ex)
+            {
+                return AccessToken;
+            }
+        }
+
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
@@ -884,6 +1212,6 @@ namespace TEAMModelOS.Controllers.Analysis
                 await _dingDing.SendBotMsg($"OS,{_option.Location},area/get-students()\n{e.Message}\n{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
                 return new List<string>();
             }
-        }
+        }       
     }
 }