JAELYS 4 سال پیش
والد
کامیت
451a9354f7
100فایلهای تغییر یافته به همراه2601 افزوده شده و 2112 حذف شده
  1. 296 0
      TEAMModelFunction/ActivityHttpTrigger.cs
  2. 51 0
      TEAMModelFunction/CourseServiceBus.cs
  3. 0 255
      TEAMModelFunction/ExamTrigger.cs
  4. 39 12
      TEAMModelFunction/MonitorCosmosDB.cs
  5. 33 1
      TEAMModelFunction/MonitorServicesBus.cs
  6. 113 0
      TEAMModelFunction/Properties/ServiceDependencies/TEAMModelOSFunction - 压缩部署/profile.arm.json
  7. 1 0
      TEAMModelFunction/Startup.cs
  8. 0 79
      TEAMModelFunction/SurveyTrigger.cs
  9. 3 2
      TEAMModelFunction/TEAMModelFunction.csproj
  10. 580 0
      TEAMModelFunction/TriggerExam.cs
  11. 94 0
      TEAMModelFunction/TriggerStuActivity.cs
  12. 326 0
      TEAMModelFunction/TriggerSurvey.cs
  13. 263 0
      TEAMModelFunction/TriggerVote.cs
  14. 0 79
      TEAMModelFunction/VoteTrigger.cs
  15. 1 0
      TEAMModelFunction/local.settings.json
  16. 5 5
      TEAMModelGrpc/TEAMModelGrpc.csproj
  17. 0 272
      TEAMModelGrpc/TEAMModelOS.GRPC.xml
  18. 14 0
      TEAMModelOS.SDK/DI/AzureRedis/AzureRedisFactory.cs
  19. 89 1
      TEAMModelOS.SDK/DI/AzureStorage/AzureStorageBlobExtensions.cs
  20. 4 4
      TEAMModelOS.SDK/DI/AzureStorage/AzureStorageTableExtensions.cs
  21. 3 1
      TEAMModelOS.SDK/DI/DingDing/DingDing.cs
  22. 0 59
      TEAMModelOS.SDK/Extension/JsonContent.cs
  23. 0 41
      TEAMModelOS.SDK/Extension/JsonIntToStringConverter.cs
  24. 40 1
      TEAMModelOS.SDK/Extension/Utils.cs
  25. 1 16
      TEAMModelOS.SDK/Helper/Common/CollectionHelper/CollectionHelper.cs
  26. 5 24
      TEAMModelOS.SDK/Helper/Common/FileHelper/FileHelper.cs
  27. 4 4
      TEAMModelOS.SDK/Helper/Common/FileHelper/FileHelperCore.cs
  28. 0 38
      TEAMModelOS.SDK/Helper/Common/ReflectorExtensions/ClassSerializers.cs
  29. 0 21
      TEAMModelOS.SDK/Models/Cosmos/Common/CommonData.cs
  30. 8 0
      TEAMModelOS.SDK/Models/Cosmos/Common/ExamClassResult.cs
  31. 3 5
      TEAMModelOS.SDK/Models/Cosmos/Common/Homework.cs
  32. 3 1
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/BaseItem.cs
  33. 34 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/ClassChange.cs
  34. 1 1
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Exercise.cs
  35. 1 1
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Repair.cs
  36. 16 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/SurveyRecord.cs
  37. 0 25
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Target.cs
  38. 15 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/VoteRecord.cs
  39. 1 1
      TEAMModelOS.SDK/Models/Cosmos/Common/ItemInfo.cs
  40. 45 0
      TEAMModelOS.SDK/Models/Cosmos/Common/JoinList.cs
  41. 54 0
      TEAMModelOS.SDK/Models/Cosmos/Common/StuActivity.cs
  42. 18 0
      TEAMModelOS.SDK/Models/Cosmos/Common/StuCourse.cs
  43. 28 0
      TEAMModelOS.SDK/Models/Cosmos/Common/StuList.cs
  44. 118 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Survey.cs
  45. 1 12
      TEAMModelOS.SDK/Models/Cosmos/Common/Syllabus.cs
  46. 76 46
      TEAMModelOS.SDK/Models/Cosmos/Common/Vote.cs
  47. 10 3
      TEAMModelOS.SDK/Models/Cosmos/School/Class.cs
  48. 50 3
      TEAMModelOS.SDK/Models/Cosmos/School/Course.cs
  49. 25 7
      TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs
  50. 7 0
      TEAMModelOS.SDK/Models/Cosmos/School/ExamResult.cs
  51. 4 0
      TEAMModelOS.SDK/Models/Cosmos/School/Inner/Period.cs
  52. 82 0
      TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs
  53. 2 4
      TEAMModelOS.SDK/Models/Cosmos/School/School.cs
  54. 4 4
      TEAMModelOS.SDK/Models/Cosmos/School/SchoolProduct.cs
  55. 0 129
      TEAMModelOS.SDK/Models/Cosmos/School/Survey.cs
  56. 8 0
      TEAMModelOS.SDK/Models/Cosmos/Student/Student.cs
  57. 0 38
      TEAMModelOS.SDK/Models/Cosmos/Student/SurveyRecord.cs
  58. 0 41
      TEAMModelOS.SDK/Models/Cosmos/Student/VoteRecord.cs
  59. 0 303
      TEAMModelOS.SDK/Module/Cache/CSRedisCacheService.cs
  60. 0 205
      TEAMModelOS.SDK/Module/Cache/ICacheService.cs
  61. 0 311
      TEAMModelOS.SDK/Module/Cache/MemoryCacheService.cs
  62. 1 1
      TEAMModelOS.SDK/TEAMModelOS.SDK.csproj
  63. 2 2
      TEAMModelOS/ClientApp/package.json
  64. BIN
      TEAMModelOS/ClientApp/public/favicon.ico
  65. 19 54
      TEAMModelOS/ClientApp/public/index.html
  66. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/bar-bg.png
  67. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/bar.png
  68. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/bg.png
  69. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/bottom.png
  70. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/btn.png
  71. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/down.png
  72. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/top.png
  73. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/up.png
  74. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/bar-bg.png
  75. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/bar-left.png
  76. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/bar-right.png
  77. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/thumb-bg.png
  78. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/thumb-left.png
  79. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/thumb-right.png
  80. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/all_formula.png
  81. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/aleph.png
  82. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/bbbk.png
  83. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/beth.png
  84. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/circleds.png
  85. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/complement.png
  86. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/daleth.png
  87. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/ell.png
  88. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/eth.png
  89. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/finv.png
  90. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/game.png
  91. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/gimel.png
  92. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/hbar.png
  93. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/hslash.png
  94. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/im.png
  95. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/mho.png
  96. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/partial.png
  97. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/re.png
  98. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/wp.png
  99. BIN
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/arrow/circlearrowleft.png
  100. 0 0
      TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/arrow/circlearrowright.png

+ 296 - 0
TEAMModelFunction/ActivityHttpTrigger.cs

@@ -0,0 +1,296 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Azure.WebJobs;
+using Microsoft.Azure.WebJobs.Extensions.Http;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using TEAMModelOS.SDK.DI;
+using Azure.Cosmos;
+using System.Text.Json;
+using System.Collections.Generic;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
+using TEAMModelOS.SDK.Models.Cosmos;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+
+namespace TEAMModelFunction
+{
+    public   class ActivityHttpTrigger
+    {
+
+
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureRedisFactory _azureRedis;
+        public ActivityHttpTrigger(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage
+             , AzureRedisFactory azureRedis)
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis;
+        }
+        [FunctionName("fix-exam-activity")]
+        public   async Task<IActionResult> ExamActivity([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,ILogger log)
+        {
+            log.LogInformation("fix-exam-activity...");
+            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
+            List<string> datas = JsonConvert.DeserializeObject<List<string>>(requestBody);
+            var client = _azureCosmos.GetCosmosClient();
+           
+            var query = $"select  *  from c ";
+            foreach (string data in datas) {
+                List<ExamInfo> exams = new List<ExamInfo>();
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
+                    queryText: query,  requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{data}") }))
+                {
+                    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())
+                        {
+                            exams.Add(obj.ToObject<ExamInfo>());
+                        }
+                    }
+                }
+                log.LogInformation($"{exams.ToJsonString()}");
+                foreach (var info in exams)
+                {
+                    if (!info.classes.IsNotEmpty())
+                    {
+                        continue;
+                    }
+                    List<string> sub = new List<string>();
+                    foreach (ExamSubject subject in info.subjects)
+                    {
+                        sub.Add(subject.id);
+                    }
+                    (List<string> tmdids, List<Students> studentss) = await TriggerStuActivity.GetStuList(client, info.classes, info.school);
+                    List<StuActivity> stuActivities = new List<StuActivity>();
+                    List<StuActivity> tmdActivities = new List<StuActivity>();
+                    if (tmdids.IsNotEmpty())
+                    {
+                        tmdids.ForEach(x => {
+                            tmdActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = info.id,
+                                code = $"Activity-{x}",
+                                type = "exam",
+                                name = info.name,
+                                startTime = info.startTime,
+                                endTime = info.endTime,
+                                scode = info.code,
+                                scope = info.scope,
+                                school = info.school,
+                                creatorId = info.creatorId,
+                                subjects = sub,
+                                blob = null
+
+                            });
+                        });
+                    }
+                    if (studentss.IsNotEmpty())
+                    {
+                        studentss.ForEach(x => {
+                            stuActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = info.id,
+                                code = $"Activity-{info.school}-{x.id}",
+                                type = "exam",
+                                name = info.name,
+                                startTime = info.startTime,
+                                endTime = info.endTime,
+                                scode = info.code,
+                                scope = info.scope,
+                                school = info.school,
+                                creatorId = info.creatorId,
+                                subjects = sub,
+                                blob=null
+                            });
+                        });
+                    }
+                    await TriggerStuActivity.SaveStuActivity(client, stuActivities, tmdActivities);
+                }
+            }
+            return new OkObjectResult(new { });
+        }
+
+        [FunctionName("fix-vote-activity")]
+        public async Task<IActionResult> VoteActivity(
+            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
+            ILogger log)
+        {
+
+            log.LogInformation("fix-vote-activity...");
+            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
+            List<string> datas = JsonConvert.DeserializeObject<List<string>>(requestBody);
+            var client = _azureCosmos.GetCosmosClient();
+
+            var query = $"select  *  from c ";
+            foreach (string data in datas)
+            {
+                List<Vote> votes = new List<Vote>();
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
+                    queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Vote-{data}") }))
+                {
+                    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())
+                        {
+                            votes.Add(obj.ToObject<Vote>());
+                        }
+                    }
+                }
+                log.LogInformation($"{votes.ToJsonString()}");
+                foreach (var info in votes)
+                {
+                    if (!info.classes.IsNotEmpty())
+                    {
+                        continue;
+                    }
+                   
+                    (List<string> tmdids, List<Students> studentss) = await TriggerStuActivity.GetStuList(client, info.classes, info.school);
+                    List<StuActivity> stuActivities = new List<StuActivity>();
+                    List<StuActivity> tmdActivities = new List<StuActivity>();
+                    if (tmdids.IsNotEmpty())
+                    {
+                        tmdids.ForEach(x => {
+                            tmdActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = info.id,
+                                code = $"Activity-{x}",
+                                type = "vote",
+                                name = info.name,
+                                startTime = info.startTime,
+                                endTime = info.endTime,
+                                scode = info.code,
+                                scope = info.scope,
+                                school = info.school,
+                                creatorId = info.creatorId,
+                                subjects = new List<string>() { "" },
+                                blob = null
+
+                            });
+                        });
+                    }
+                    if (studentss.IsNotEmpty())
+                    {
+                        studentss.ForEach(x => {
+                            stuActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = info.id,
+                                code = $"Activity-{info.school}-{x.id}",
+                                type = "vote",
+                                name = info.name,
+                                startTime = info.startTime,
+                                endTime = info.endTime,
+                                scode = info.code,
+                                scope = info.scope,
+                                school = info.school,
+                                creatorId = info.creatorId,
+                                subjects = new List<string>() { "" },
+                                blob = null
+                            });
+                        });
+                    }
+                    await TriggerStuActivity.SaveStuActivity(client, stuActivities, tmdActivities);
+                }
+            }
+            return new OkObjectResult(new { });
+        }
+        [FunctionName("fix-survey-activity")]
+        public async Task<IActionResult> SurveyActivity(
+            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
+            ILogger log)
+        {
+            log.LogInformation("fix-survey-activity...");
+            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
+            List<string> datas = JsonConvert.DeserializeObject<List<string>>(requestBody);
+            var client = _azureCosmos.GetCosmosClient();
+
+            var query = $"select  *  from c ";
+            foreach (string data in datas)
+            {
+                List<Survey> surveys = new List<Survey>();
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(
+                    queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Survey-{data}") }))
+                {
+                    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())
+                        {
+                            surveys.Add(obj.ToObject<Survey>());
+                        }
+                    }
+                }
+                log.LogInformation($"{surveys.ToJsonString()}");
+                foreach (var info in surveys)
+                {
+                    if (!info.classes.IsNotEmpty())
+                    {
+                        continue;
+                    }
+                    (List<string> tmdids, List<Students> studentss) = await TriggerStuActivity.GetStuList(client, info.classes, info.school);
+                    List<StuActivity> stuActivities = new List<StuActivity>();
+                    List<StuActivity> tmdActivities = new List<StuActivity>();
+                    if (tmdids.IsNotEmpty())
+                    {
+                        tmdids.ForEach(x => {
+                            tmdActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = info.id,
+                                code = $"Activity-{x}",
+                                type = "survey",
+                                name = info.name,
+                                startTime = info.startTime,
+                                endTime = info.endTime,
+                                scode = info.code,
+                                scope = info.scope,
+                                school = info.school,
+                                creatorId = info.creatorId,
+                                subjects = new List<string>() { "" },
+                                blob = info.blob
+
+                            });
+                        });
+                    }
+                    if (studentss.IsNotEmpty())
+                    {
+                        studentss.ForEach(x => {
+                            stuActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = info.id,
+                                code = $"Activity-{info.school}-{x.id}",
+                                type = "survey",
+                                name = info.name,
+                                startTime = info.startTime,
+                                endTime = info.endTime,
+                                scode = info.code,
+                                scope = info.scope,
+                                school = info.school,
+                                creatorId = info.creatorId,
+                                subjects = new List<string>() { "" },
+                                blob=info.blob
+                            });
+                        });
+                    }
+                    await TriggerStuActivity.SaveStuActivity(client, stuActivities, tmdActivities);
+                }
+            }
+            return new OkObjectResult(new { });
+        }
+    }
+}

+ 51 - 0
TEAMModelFunction/CourseServiceBus.cs

@@ -0,0 +1,51 @@
+using Microsoft.Azure.WebJobs;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+
+namespace TEAMModelFunction
+{
+    public class CourseServiceBus
+    {
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        public CourseServiceBus(AzureCosmosFactory azureCosmos, DingDing dingDing)
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+        }
+        /// <summary>
+        /// 完善课程变更
+        /// </summary>
+        /// <data msg>
+        /// "ids":["s111","t111"]//学生
+        /// "opt":"join/leave",//状态
+        /// "no":"CLASS001"//教室编号
+        /// "source":1/2  //学生名单数据来源 1是不同学校的学生账号,2是扫码加入的醍摩豆ID
+        ///// </data>
+        /// <param name="msg"></param>
+        /// <returns></returns>
+        //[FunctionName("Course")]
+        //public async Task StuList([ServiceBusTrigger("active-task", "course", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
+        //{
+        //    try
+        //    {
+        //        await _dingDing.SendBotMsg($"ServiceBus,Blob(){msg}", GroupNames.醍摩豆服務運維群組);
+        //        var jsonMsg = JsonDocument.Parse(msg);
+        //        msg.ToObject<StuCourse>();
+
+
+        //    }
+        //    catch (Exception ex)
+        //    {
+        //        await _dingDing.SendBotMsg($"ServiceBus,Blob()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
+        //    }
+        //}
+
+    }
+}

+ 0 - 255
TEAMModelFunction/ExamTrigger.cs

@@ -1,255 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using Microsoft.Azure.Documents;
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Models;
-
-namespace TEAMModelFunction
-{
-    public class ExamTrigger
-    {
-        public static async void Trigger(AzureCosmosFactory _azureCosmos, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing, 
-            CosmosClient client, Document input ,string code,long stime,long etime, string school)
-        {
-            ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
-            List<ExamClassResult> examClassResults = new List<ExamClassResult>();
-            List<ExamSubject> examSubjects = new List<ExamSubject>();
-            await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{school}") }))
-            {
-                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())
-                    {
-                        examClassResults.Add(obj.ToObject<ExamClassResult>());
-                    }
-                }
-            }
-
-            List<ChangeRecord> records = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", info.progress } });
-            //ChangeRecord record = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{info.progress}"));
-            switch (info.progress)
-            {
-                case "pending":
-                    var message = new ServiceBusMessage(new { id = input.Id, progress = "going", code = code }.ToJsonString());
-                    message.ApplicationProperties.Add("name", "Exam");
-                    if (records.Count > 0)
-                    {
-                        await _serviceBus.GetServiceBusClient().cancelMessage("active-task", records[0].sequenceNumber);
-                        long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                        records[0].sequenceNumber = start;
-                        await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
-                        //await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
-                    }
-                    else
-                    {
-                        long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                        ChangeRecord changeRecord = new ChangeRecord
-                        {
-                            RowKey = input.Id,
-                            PartitionKey = "pending",
-                            sequenceNumber = start,
-                            msgId = message.MessageId
-                        };
-                        await _azureStorage.Save<ChangeRecord>(changeRecord);
-                        //await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                    }
-                    break;
-                case "going":
-                    if (examClassResults.Count == 0)
-                    {
-                        foreach (string cla in info.targetClassIds)
-                        {
-                            int m = 0;
-                            foreach (ExamSubject subject in info.subjects)
-                            {
-                                string classCode = "";
-                                if (string.IsNullOrEmpty(info.school) || !info.scope.Equals("school",StringComparison.OrdinalIgnoreCase))
-                                {
-                                    classCode = "ExamClassResult-" + info.creatorId;
-                                }
-                                else {
-                                    classCode = "ExamClassResult-" + info.school;
-                                }
-                                ExamClassResult result = new ExamClassResult
-                                {
-                                    code = classCode,
-                                    examId = info.id,
-                                    id = Guid.NewGuid().ToString(),
-                                    subjectId = subject.id,
-                                    year = info.year,
-                                    scope = info.scope
-                                };
-                                result.info.id = cla;
-                                if (info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
-                                {
-                                    var sresponse = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"Class-{info.creatorId}"));
-                                    if (sresponse.Status == 200)
-                                    {
-                                        using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
-                                        Class classroom = json.ToObject<Class>();
-                                        result.info.name = classroom.name;
-                                        result.gradeId = classroom.gradeId;
-                                        List<string> ans = new List<string>();
-                                        List<double> ansPoint = new List<double>();
-                                        foreach (double p in info.papers[m].point)
-                                        {
-                                            //ans.Add(new List<string>());
-                                            ansPoint.Add(-1);
-                                        }
-                                        foreach (StudentSimple stu in classroom.students)
-                                        {
-                                            result.studentIds.Add(stu.id);
-                                            result.studentAnswers.Add(ans);
-                                            result.studentScores.Add(ansPoint);
-                                            result.sum.Add(0);
-                                        }
-                                    }
-                                }
-                                else {
-                                    var sresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"Class-{info.school}"));
-                                    if (sresponse.Status == 200)
-                                    {
-                                        using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
-                                        Class classroom = json.ToObject<Class>();
-                                        result.info.name = classroom.name;
-                                        result.gradeId = classroom.gradeId;
-                                        List<string> ans = new List<string>();
-                                        List<double> ansPoint = new List<double>();
-                                        foreach (double p in info.papers[m].point)
-                                        {
-                                            //ans.Add(new List<string>());
-                                            ansPoint.Add(-1);
-                                        }
-                                        foreach (StudentSimple stu in classroom.students)
-                                        {
-                                            result.studentIds.Add(stu.id);
-                                            result.studentAnswers.Add(ans);
-                                            result.studentScores.Add(ansPoint);
-                                            result.sum.Add(0);
-                                        }
-                                    }
-                                }
-                                
-                                //result.progress = info.progress;
-                                result.school = info.school;
-                                m++;
-                                await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(result, new Azure.Cosmos.PartitionKey($"{result.code}"));
-                            }
-                        }
-                        // 发送信息通知
-                        var messageEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
-                        messageEnd.ApplicationProperties.Add("name", "Exam");
-                        if (records.Count > 0)
-                        {
-                            long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                            await _serviceBus.GetServiceBusClient().cancelMessage("active-task", records[0].sequenceNumber);
-                            records[0].sequenceNumber = end;
-                            await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
-                            //await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
-                        }
-                        else
-                        {
-                            long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                            ChangeRecord changeRecord = new ChangeRecord
-                            {
-                                RowKey = input.Id,
-                                PartitionKey = "going",
-                                sequenceNumber = end,
-                                msgId = messageEnd.MessageId
-                            };
-                            await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            //await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                        }
-                    }
-                    else
-                    {
-                        //处理单科结算时科目与试卷信息匹配的问题
-                        int gno = 0;
-                        foreach (ExamSubject subject in info.subjects)
-                        {
-                            if (subject.classCount == info.targetClassIds.Count)
-                            {
-                                await createClassResultAsync(info, examClassResults, subject, gno,_azureCosmos);
-                            }
-                            gno++;
-                        }
-                    }
-                    break;
-                case "finish":
-                    int fno = 0;
-                    foreach (ExamSubject subject in info.subjects)
-                    {
-                        await createClassResultAsync(info, examClassResults, subject, fno, _azureCosmos);
-                        fno++;
-                    }
-
-                    break;
-            }
-        }
-        public static async Task createClassResultAsync(ExamInfo info, List<ExamClassResult> examClassResults, ExamSubject subject, int no, AzureCosmosFactory _azureCosmos)
-        {
-            //保证试卷信息与科目信息同步
-            ExamResult result = new ExamResult();
-            //人数总和
-            int Count = 0;
-            int m = 0;
-            List<ClassRange> classRanges = new List<ClassRange>();
-            foreach (ExamClassResult classResult in examClassResults)
-            {
-                if (classResult.subjectId.Equals(subject.id))
-                {
-                    foreach (List<double> scores in classResult.studentScores)
-                    {
-                        result.studentScores.Add(scores);
-                    }
-                    //处理班级信息
-                    ClassRange range = new ClassRange();
-                    range.id = classResult.info.id;
-                    range.name = classResult.info.name;
-                    List<int> ran = new List<int>();
-                    int stuCount = classResult.studentIds.Count;
-                    Count += stuCount;
-                    if (m == 0)
-                    {
-                        ran.Add(0);
-                        ran.Add(stuCount - 1);
-                    }
-                    else
-                    {
-                        ran.Add(Count - stuCount);
-                        ran.Add(Count - 1);
-                    }
-                    m++;
-                    range.range = ran;
-                    classRanges.Add(range);
-                    //处理学生ID 
-                    foreach (string id in classResult.studentIds)
-                    {
-                        result.studentIds.Add(id);
-                    }
-                }
-            }
-            result.classes = classRanges;
-            result.code = "ExamResult-" + info.id;
-            result.school = info.school;
-            result.id = subject.id;
-            result.examId = info.id;
-            result.subjectId = subject.id;
-            result.year = info.year;
-            result.paper = info.papers[no];
-            //result.point = info.papers[j].point;
-            result.scope = info.scope;
-            result.name = info.name;
-            result.time = info.startTime;
-            await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Common").UpsertItemAsync(result, new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}"));
-
-        }
-    }
-}

+ 39 - 12
TEAMModelFunction/MonitorCosmosDB.cs

@@ -16,19 +16,18 @@ namespace TEAMModelFunction
 {
 {
     public class MonitorCosmosDB
     public class MonitorCosmosDB
     {
     {
-        private readonly IHttpClientFactory _clientFactory;
         private readonly AzureCosmosFactory _azureCosmos;
         private readonly AzureCosmosFactory _azureCosmos;
         private readonly AzureServiceBusFactory _serviceBus;
         private readonly AzureServiceBusFactory _serviceBus;
         private readonly AzureStorageFactory _azureStorage;
         private readonly AzureStorageFactory _azureStorage;
         private readonly DingDing _dingDing;
         private readonly DingDing _dingDing;
-
-        public MonitorCosmosDB(IHttpClientFactory clientFactory, AzureCosmosFactory azureCosmos, AzureServiceBusFactory azureServiceBus, AzureStorageFactory azureStorage, DingDing dingDing)
+        private readonly AzureRedisFactory _azureRedis;
+        public MonitorCosmosDB( AzureCosmosFactory azureCosmos, AzureServiceBusFactory azureServiceBus, AzureStorageFactory azureStorage, DingDing dingDing, AzureRedisFactory azureRedis)
         {
         {
-            _clientFactory = clientFactory;
             _azureCosmos = azureCosmos;
             _azureCosmos = azureCosmos;
             _serviceBus = azureServiceBus;
             _serviceBus = azureServiceBus;
             _azureStorage = azureStorage;
             _azureStorage = azureStorage;
             _dingDing = dingDing;
             _dingDing = dingDing;
+            _azureRedis = azureRedis;
         }
         }
 
 
         [FunctionName("Common")]
         [FunctionName("Common")]
@@ -49,24 +48,40 @@ namespace TEAMModelFunction
                     string pk = input.GetPropertyValue<string>("pk");
                     string pk = input.GetPropertyValue<string>("pk");
                     if (!string.IsNullOrWhiteSpace(pk))
                     if (!string.IsNullOrWhiteSpace(pk))
                     {
                     {
+                        int ttl = input.GetPropertyValue<int>("ttl");
                         long stime = input.GetPropertyValue<long>("startTime");
                         long stime = input.GetPropertyValue<long>("startTime");
                         long etime = input.GetPropertyValue<long>("endTime");
                         long etime = input.GetPropertyValue<long>("endTime");
                         string school = input.GetPropertyValue<string>("school");
                         string school = input.GetPropertyValue<string>("school");
                         string code = input.GetPropertyValue<string>("code");
                         string code = input.GetPropertyValue<string>("code");
-                        await _dingDing.SendBotMsg($"CosmosDBTrigger,{pk}\n" +
-                                        $"Start Time:{DateTimeOffset.FromUnixTimeMilliseconds(stime).AddHours(8)}\n" +
-                                        $"End Time:{DateTimeOffset.FromUnixTimeMilliseconds(etime).AddHours(8)}",
-                                        GroupNames.醍摩豆服務運維群組);
+                        string creatorId = input.GetPropertyValue<string>("creatorId");
+                        string progress = input.GetPropertyValue<string>("progress");
+                        string scope = input.GetPropertyValue<string>("scope");
+                        string name = input.GetPropertyValue<string>("name");
+                        int? status = input.GetPropertyValue<int?>("status");
+                        var data = new TriggerData {
+                            stime = stime,
+                            etime = etime,
+                            school = school,
+                            code = code,
+                            creatorId = creatorId,
+                            progress = progress,
+                            scope = scope,
+                            ttl = ttl,
+                            id = input.Id,
+                            status = status
+                        };
+                        await _dingDing.SendBotMsg($"CosmosDBTrigger,{pk}触发变更\n{data.ToJsonString()}"  ,
+                                        GroupNames.成都开发測試群組);
                         switch (pk)
                         switch (pk)
                         {
                         {
                             case "Exam":
                             case "Exam":
-                                ExamTrigger.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client,input,code,stime,etime,school);
+                                TriggerExam.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client,input,code,stime,etime,school);
                                 break;
                                 break;
                             case "Vote":
                             case "Vote":
-                                VoteTrigger.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school);
+                                TriggerVote.Trigger( _serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
                                 break;
                                 break;
                             case "Survey":
                             case "Survey":
-                                SurveyTrigger.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school);
+                                TriggerSurvey.Trigger( _serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
                                 break;
                                 break;
 
 
                         }
                         }
@@ -74,6 +89,18 @@ namespace TEAMModelFunction
                 }
                 }
             }
             }
         }
         }
-        
+    }
+    public class TriggerData {
+        public int? status { get; set; }
+        public string name { get; set; }
+        public long stime { get; set; }
+        public long etime { get; set; }
+        public string school { get; set; }
+        public string code { get; set; }
+        public string creatorId { get; set; }
+        public string progress { get; set; }
+        public string scope { get; set; }
+        public int ttl { get; set; }
+        public string id { get; set; }
     }
     }
 }
 }

+ 33 - 1
TEAMModelFunction/MonitorServicesBus.cs

@@ -6,6 +6,7 @@ using Azure.Cosmos;
 using Microsoft.Azure.WebJobs;
 using Microsoft.Azure.WebJobs;
 using Microsoft.Azure.WebJobs.Host;
 using Microsoft.Azure.WebJobs.Host;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using StackExchange.Redis;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models;
@@ -16,10 +17,16 @@ namespace TEAMModelFunction
     {
     {
         private readonly AzureCosmosFactory _azureCosmos;
         private readonly AzureCosmosFactory _azureCosmos;
         private readonly DingDing _dingDing;
         private readonly DingDing _dingDing;
-        public MonitorServicesBus(AzureCosmosFactory azureCosmos, DingDing dingDing)
+        private readonly AzureStorageFactory _azureStorage;
+        private readonly AzureRedisFactory _azureRedis;
+        public MonitorServicesBus(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage
+             , AzureRedisFactory azureRedis
+            )
         {
         {
             _azureCosmos = azureCosmos;
             _azureCosmos = azureCosmos;
             _dingDing = dingDing;
             _dingDing = dingDing;
+            _azureStorage = azureStorage;
+            _azureRedis = azureRedis;
         }
         }
         [FunctionName("Exam")]
         [FunctionName("Exam")]
         public async Task Exam([ServiceBusTrigger("active-task", "exam", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
         public async Task Exam([ServiceBusTrigger("active-task", "exam", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
@@ -140,5 +147,30 @@ namespace TEAMModelFunction
                 await _dingDing.SendBotMsg($"ServiceBus,VoteBus()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
                 await _dingDing.SendBotMsg($"ServiceBus,VoteBus()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
             }
             }
         }
         }
+        [FunctionName("Blob")]
+        public async Task Blob([ServiceBusTrigger("active-task", "blob", Connection = "Azure:ServiceBus:ConnectionString")] string msg) {
+            try
+            {
+               // await _dingDing.SendBotMsg($"ServiceBus,Blob(){msg}", GroupNames.醍摩豆服務運維群組);
+                var jsonMsg = JsonDocument.Parse(msg);
+                if(jsonMsg.RootElement.TryGetProperty("name", out JsonElement name)&& name.ValueKind==JsonValueKind.String)
+                {
+                    var client = _azureStorage.GetBlobContainerClient($"{name}");
+                    var size = await client.GetBlobsCatalogSize();
+                    await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", new RedisValue($"{name}"), new RedisValue($"{long.Parse($"{size.Item1}")}"));
+                    foreach (var key in size.Item2.Keys)
+                    {
+                        await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{name}", key);
+                        await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
+                    }
+                    await _dingDing.SendBotMsg($"ServiceBus,Blob() 容器:{name}使用:{size.Item1},文件分类:{size.Item2.ToJsonString()}",
+                            GroupNames.成都开发測試群組);
+                }
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"ServiceBus,Blob()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
+            }
+        }
     }
     }
 }
 }

+ 113 - 0
TEAMModelFunction/Properties/ServiceDependencies/TEAMModelOSFunction - 压缩部署/profile.arm.json

@@ -0,0 +1,113 @@
+{
+  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
+  "contentVersion": "1.0.0.0",
+  "metadata": {
+    "_dependencyType": "appService.windows"
+  },
+  "parameters": {
+    "resourceGroupName": {
+      "type": "string",
+      "defaultValue": "TEAMModelChengdu",
+      "metadata": {
+        "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
+      }
+    },
+    "resourceGroupLocation": {
+      "type": "string",
+      "defaultValue": "",
+      "metadata": {
+        "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
+      }
+    },
+    "resourceName": {
+      "type": "string",
+      "defaultValue": "TEAMModelOSFunction",
+      "metadata": {
+        "description": "Name of the main resource to be created by this template."
+      }
+    },
+    "resourceLocation": {
+      "type": "string",
+      "defaultValue": "[parameters('resourceGroupLocation')]",
+      "metadata": {
+        "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
+      }
+    }
+  },
+  "variables": {
+    "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
+    "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]"
+  },
+  "resources": [
+    {
+      "type": "Microsoft.Resources/resourceGroups",
+      "name": "[parameters('resourceGroupName')]",
+      "location": "[parameters('resourceGroupLocation')]",
+      "apiVersion": "2019-10-01"
+    },
+    {
+      "type": "Microsoft.Resources/deployments",
+      "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
+      "resourceGroup": "[parameters('resourceGroupName')]",
+      "apiVersion": "2019-10-01",
+      "dependsOn": [
+        "[parameters('resourceGroupName')]"
+      ],
+      "properties": {
+        "mode": "Incremental",
+        "template": {
+          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+          "contentVersion": "1.0.0.0",
+          "resources": [
+            {
+              "location": "[parameters('resourceLocation')]",
+              "name": "[parameters('resourceName')]",
+              "type": "Microsoft.Web/sites",
+              "apiVersion": "2015-08-01",
+              "tags": {
+                "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
+              },
+              "dependsOn": [
+                "[variables('appServicePlan_ResourceId')]"
+              ],
+              "kind": "app",
+              "properties": {
+                "name": "[parameters('resourceName')]",
+                "kind": "app",
+                "httpsOnly": true,
+                "reserved": false,
+                "serverFarmId": "[variables('appServicePlan_ResourceId')]",
+                "siteConfig": {
+                  "metadata": [
+                    {
+                      "name": "CURRENT_STACK",
+                      "value": "dotnetcore"
+                    }
+                  ]
+                }
+              },
+              "identity": {
+                "type": "SystemAssigned"
+              }
+            },
+            {
+              "location": "[parameters('resourceLocation')]",
+              "name": "[variables('appServicePlan_name')]",
+              "type": "Microsoft.Web/serverFarms",
+              "apiVersion": "2015-08-01",
+              "sku": {
+                "name": "S1",
+                "tier": "Standard",
+                "family": "S",
+                "size": "S1"
+              },
+              "properties": {
+                "name": "[variables('appServicePlan_name')]"
+              }
+            }
+          ]
+        }
+      }
+    }
+  ]
+}

+ 1 - 0
TEAMModelFunction/Startup.cs

@@ -21,6 +21,7 @@ namespace TEAMModelFunction
             builder.Services.AddAzureServiceBus(Environment.GetEnvironmentVariable("Azure:ServiceBus:ConnectionString"));
             builder.Services.AddAzureServiceBus(Environment.GetEnvironmentVariable("Azure:ServiceBus:ConnectionString"));
             builder.Services.AddAzureStorage(Environment.GetEnvironmentVariable("Azure:Starage:ConnectionString"));
             builder.Services.AddAzureStorage(Environment.GetEnvironmentVariable("Azure:Starage:ConnectionString"));
             builder.Services.AddAzureCosmos(Environment.GetEnvironmentVariable("Azure:Cosmos:ConnectionString"));
             builder.Services.AddAzureCosmos(Environment.GetEnvironmentVariable("Azure:Cosmos:ConnectionString"));
+            builder.Services.AddAzureRedis(Environment.GetEnvironmentVariable("Azure:Redis:ConnectionString"));
         }
         }
     }
     }
 }
 }

+ 0 - 79
TEAMModelFunction/SurveyTrigger.cs

@@ -1,79 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using Microsoft.Azure.Documents;
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Models;
-
-namespace TEAMModelFunction
-{
-   public class SurveyTrigger
-    {
-        public static async void Trigger(AzureCosmosFactory _azureCosmos, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
-               CosmosClient client, Document input, string code, long stime, long etime, string school)
-        {
-            Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Survey>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
-            //messageSurvey.ScheduledEnqueueTime = DateTimeOffset.FromUnixTimeMilliseconds(stime);
-            //string msgid = messageSurvey.MessageId;
-            List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", survey.progress } });
-            //ChangeRecord surveyRecord = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{survey.progress}"));
-            switch (survey.progress)
-            {
-                case "pending":
-                    var messageSurvey = new ServiceBusMessage(new { id = input.Id, progress = "going", code = code }.ToJsonString());
-                    messageSurvey.ApplicationProperties.Add("name", "Survey");
-                    if (changeRecords.Count > 0)
-                    {
-                        await _serviceBus.GetServiceBusClient().cancelMessage("active-task", changeRecords[0].sequenceNumber);
-                        long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageSurvey, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                        changeRecords[0].sequenceNumber = start;
-                        await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                        //await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(surveyRecord, surveyRecord.id, new Azure.Cosmos.PartitionKey($"{surveyRecord.code}"));
-                    }
-                    else
-                    {
-                        long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageSurvey, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                        ChangeRecord changeRecord = new ChangeRecord
-                        {
-                            RowKey = input.Id,
-                            PartitionKey = "pending",
-                            sequenceNumber = start,
-                            msgId = messageSurvey.MessageId
-                        };
-                        await _azureStorage.Save<ChangeRecord>(changeRecord);
-                        //await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                    }
-                    break;
-                case "going":
-                    var messageSurveyEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
-                    messageSurveyEnd.ApplicationProperties.Add("name", "Survey");
-                    if (changeRecords.Count > 0)
-                    {
-                        long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageSurveyEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                        await _serviceBus.GetServiceBusClient().cancelMessage("active-task", changeRecords[0].sequenceNumber);
-                        changeRecords[0].sequenceNumber = end;
-                        await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
-                    }
-                    else
-                    {
-                        long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageSurveyEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                        ChangeRecord changeRecord = new ChangeRecord
-                        {
-                            RowKey = input.Id,
-                            PartitionKey = "going",
-                            sequenceNumber = end,
-                            msgId = messageSurveyEnd.MessageId
-                        };
-                        await _azureStorage.Save<ChangeRecord>(changeRecord);
-                        //await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                    }
-                    break;
-            }
-        }
-    }
-}

+ 3 - 2
TEAMModelFunction/TEAMModelFunction.csproj

@@ -2,14 +2,15 @@
   <PropertyGroup>
   <PropertyGroup>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <AzureFunctionsVersion>v3</AzureFunctionsVersion>
     <AzureFunctionsVersion>v3</AzureFunctionsVersion>
+    <_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Remove="AServiceBus.cs" />
     <Compile Remove="AServiceBus.cs" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
     <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
-    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.8" />
-    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="4.2.0" />
+    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.9" />
+    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="4.2.1" />
     <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.7" />
     <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.7" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>

+ 580 - 0
TEAMModelFunction/TriggerExam.cs

@@ -0,0 +1,580 @@
+using Azure.Cosmos;
+using Azure.Messaging.ServiceBus;
+using Microsoft.Azure.Documents;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Cosmos;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+
+namespace TEAMModelFunction
+{
+    public class TriggerExam
+    {
+        public static async void Trigger(AzureCosmosFactory _azureCosmos, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing, 
+            CosmosClient client, Document input ,string code,long stime,long etime, string school)
+        {
+            ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
+            List<ExamClassResult> examClassResults = new List<ExamClassResult>();
+            List<ExamSubject> examSubjects = new List<ExamSubject>();
+            if (info.scope.Equals("teacher", StringComparison.OrdinalIgnoreCase) || info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
+            {
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{info.creatorId}") }))
+                {
+                    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())
+                        {
+                            examClassResults.Add(obj.ToObject<ExamClassResult>());
+                        }
+                    }
+                }
+            }
+            else {
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{school}") }))
+                {
+                    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())
+                        {
+                            examClassResults.Add(obj.ToObject<ExamClassResult>());
+                        }
+                    }
+                }
+            }
+            
+
+            List<ChangeRecord> records = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", info.progress } });
+            //处理科目信息
+            List<string> sub = new List<string>();
+            foreach (ExamSubject subject in info.subjects)
+            {
+                sub.Add(subject.id);
+            }
+            //ChangeRecord record = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{info.progress}"));
+            switch (info.progress)
+            {
+                case "pending":
+                    var message = new ServiceBusMessage(new { id = input.Id, progress = "going", code = code }.ToJsonString());
+                    message.ApplicationProperties.Add("name", "Exam");
+                    if (records.Count > 0)
+                    {
+                        await _serviceBus.GetServiceBusClient().cancelMessage("active-task", records[0].sequenceNumber);
+                        long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
+                        records[0].sequenceNumber = start;
+                        await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
+                        //await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
+                    }
+                    else
+                    {
+                        long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
+                        ChangeRecord changeRecord = new ChangeRecord
+                        {
+                            RowKey = input.Id,
+                            PartitionKey = "pending",
+                            sequenceNumber = start,
+                            msgId = message.MessageId
+                        };
+                        await _azureStorage.Save<ChangeRecord>(changeRecord);
+                        //await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
+                    }
+                    break;
+                case "going":                    
+                    //ActivityData data;
+                    //if (info.scope == "school")
+                    //{
+                    //    data = new ActivityData
+                    //    {
+                    //        id = info.id,
+                    //        code = $"Activity-{info.school}",
+                    //        type = "exam",
+                    //        name = info.name,
+                    //        startTime = info.startTime,
+                    //        endTime = info.endTime,
+                    //        scode = info.code,
+                    //        scope = info.scope,
+                    //        classes = info.classes.IsNotEmpty() ? info.classes : new List<string> { "" },
+                    //        tmdids =  new List<string> { "" },
+                    //        progress = "going",
+                    //        subjects = sub
+                    //    };
+                    //    await client.GetContainer("TEAMModelOS", "School").UpsertItemAsync<ActivityData>(data, new Azure.Cosmos.PartitionKey(data.code));
+                    //}
+                    //else if (info.scope == "private")
+                    //{
+                    //    data = new ActivityData
+                    //    {
+                    //        id = info.id,
+                    //        code = $"Activity-Common",
+                    //        type = "exam",
+                    //        name = info.name,
+                    //        startTime = info.startTime,
+                    //        endTime = info.endTime,
+                    //        scode = info.code,
+                    //        scope = info.scope,
+                    //        progress = "going",
+                    //        classes = info.classes.IsNotEmpty() ? info.classes : new List<string> { "" },
+                    //        tmdids = new List<string> { "" },
+                    //        subjects = sub
+                    //    };
+                    //    await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<ActivityData>(data, new Azure.Cosmos.PartitionKey(data.code));
+                    //}
+                    (List<string> tmdids, List<Students> studentss) = await TriggerStuActivity.GetStuList(client, info.classes, info.school);
+                    List<StuActivity> stuActivities = new List<StuActivity>();
+                    List<StuActivity> tmdActivities = new List<StuActivity>();
+                    if (tmdids.IsNotEmpty())
+                    {
+                        tmdids.ForEach(x => {
+                            tmdActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = info.id,
+                                code = $"Activity-{x}",
+                                type = "exam",
+                                name = info.name,
+                                startTime = info.startTime,
+                                endTime = info.endTime,
+                                scode = info.code,
+                                scope = info.scope,
+                                school = info.school,
+                                creatorId = info.creatorId,
+                                subjects = sub,
+                                blob = null
+
+                            });
+                        });
+                    }
+                    if (studentss.IsNotEmpty())
+                    {
+                        studentss.ForEach(x => {
+                            stuActivities.Add(new StuActivity
+                            {
+                                pk = "Activity",
+                                id = info.id,
+                                code = $"Activity-{info.school}-{x.id}",
+                                type = "exam",
+                                name = info.name,
+                                startTime = info.startTime,
+                                endTime = info.endTime,
+                                scode = info.code,
+                                scope = info.scope,
+                                school = info.school,
+                                creatorId = info.creatorId,
+                                subjects = sub,
+                                blob = null
+                            });
+                        });
+                    }
+                    await TriggerStuActivity.SaveStuActivity(client, stuActivities, tmdActivities);
+                    if (examClassResults.Count == 0)
+                    {
+                        foreach (string cla in info.classes)
+                        {
+                            int m = 0;
+                            foreach (ExamSubject subject in info.subjects)
+                            {
+                                string classCode = "";
+                                if (string.IsNullOrEmpty(info.school) || !info.scope.Equals("school",StringComparison.OrdinalIgnoreCase))
+                                {
+                                    classCode = "ExamClassResult-" + info.creatorId;
+                                }
+                                else {
+                                    classCode = "ExamClassResult-" + info.school;
+                                }
+                                ExamClassResult result = new ExamClassResult
+                                {
+                                    code = classCode,
+                                    examId = info.id,
+                                    id = Guid.NewGuid().ToString(),
+                                    subjectId = subject.id,
+                                    year = info.year,
+                                    scope = info.scope
+                                };
+                                result.info.id = cla;
+                                List<string> ans = new List<string>();
+                                List<double> ansPoint = new List<double>();
+                                List<string> ids = new List<string>();
+                                foreach (double p in info.papers[m].point)
+                                {
+                                    //ans.Add(new List<string>());
+                                    ansPoint.Add(-1);
+                                }
+                                var sresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"Class-{info.school}"));
+                                if (sresponse.Status == 200)
+                                {
+                                    using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
+                                    Class classroom = json.ToObject<Class>();
+                                    //result.info.id = classroom.id;
+                                    result.info.name = classroom.name;
+                                    result.gradeId = classroom.gradeId;
+                                    //处理班级人数
+                                    await foreach (var item in client.GetContainer("TEAMModelOS", "Student").GetItemQueryStreamIterator(queryText: $"select c.id from c where c.classId = '{classroom.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{info.school}") }))
+                                    {
+                                        using var json_stu = await JsonDocument.ParseAsync(item.ContentStream);
+                                        if (json_stu.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                                        {
+                                            var accounts = json_stu.RootElement.GetProperty("Documents").EnumerateArray();
+                                            while (accounts.MoveNext())
+                                            {
+                                                JsonElement account = accounts.Current;
+                                                ids.Add(account.GetProperty("id").GetString());
+                                            }
+                                        }
+                                    }
+                                }
+                                if (info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
+                                {                                                                                                        
+                                    var stuResponse = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"StuList"));
+                                    if (stuResponse.Status == 200) {
+                                        using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
+                                        StuList stuList = json.ToObject<StuList>();
+                                        //result.info.id = stuList.id;
+                                        result.info.name = stuList.name;
+                                        //处理发布对象为自选名单(个人)
+
+                                        foreach (Students stus in stuList.students)
+                                                {
+
+                                                        ids.Add(stus.id);
+                                                }
+                                                if (stuList.tmids.Count > 0)
+                                                {
+                                                    foreach (string tid in stuList.tmids)
+                                                    {
+                                                        ids.Add(tid);
+                                                    }
+                                                }
+                                    }                                   
+                                }
+                                else {                                                                                                                                                                                                                       
+                                    var stuResponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(cla, new Azure.Cosmos.PartitionKey($"StuList-{info.school}"));
+                                    if (stuResponse.Status == 200)
+                                    {
+                                        using var json = await JsonDocument.ParseAsync(stuResponse.ContentStream);
+                                        StuList stuList = json.ToObject<StuList>();
+                                        //result.info.id = stuList.id;
+                                        result.info.name = stuList.name;
+                                        //处理发布对象为自选名单(校本)
+                                        foreach (Students stus in stuList.students)
+                                        {
+                                                ids.Add(stus.id);
+                                        }                                      
+                                    }                                    
+                                }
+                                foreach (string stu in ids)
+                                {
+                                    result.mark.Add("");
+                                    result.studentIds.Add(stu);
+                                    result.studentAnswers.Add(ans);
+                                    result.studentScores.Add(ansPoint);
+                                    result.sum.Add(0);
+                                }
+                                
+                                //result.progress = info.progress;
+                                result.school = info.school;
+                                m++;
+                                await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(result, new Azure.Cosmos.PartitionKey($"{result.code}"));
+                            }
+                        }
+                        // 发送信息通知
+                        var messageEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
+                        messageEnd.ApplicationProperties.Add("name", "Exam");
+                        if (records.Count > 0)
+                        {
+                            long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
+                            await _serviceBus.GetServiceBusClient().cancelMessage("active-task", records[0].sequenceNumber);
+                            records[0].sequenceNumber = end;
+                            await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
+                            //await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
+                        }
+                        else
+                        {
+                            long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
+                            ChangeRecord changeRecord = new ChangeRecord
+                            {
+                                RowKey = input.Id,
+                                PartitionKey = "going",
+                                sequenceNumber = end,
+                                msgId = messageEnd.MessageId
+                            };
+                            await _azureStorage.Save<ChangeRecord>(changeRecord);
+                            //await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
+                        }
+                    }
+                    else
+                    {
+                        //处理单科结算时科目与试卷信息匹配的问题
+                        int gno = 0;
+                        foreach (ExamSubject subject in info.subjects)
+                        {
+                            if (subject.classCount == info.classes.Count)
+                            {
+                                await createClassResultAsync(info, examClassResults, subject, gno,_azureCosmos, _dingDing, _azureStorage);
+                            }
+                            gno++;
+                        }
+                    }
+                    break;
+                case "finish":
+                    int fno = 0;
+                    foreach (ExamSubject subject in info.subjects)
+                    {
+                        await createClassResultAsync(info, examClassResults, subject, fno, _azureCosmos, _dingDing, _azureStorage);                       
+                        fno++;
+                    }
+                    
+                    //计算单次考试简易统计信息
+                    List<ExamResult> examResults = new List<ExamResult>();
+                    await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<ExamResult>(
+                                       queryText: $"select value(c) from c where c.examId  = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}") }))
+                    {
+                        examResults.Add(item);
+                    }
+                    //结算单科单班的标准差和平均分
+                    foreach (ExamClassResult classResult in examClassResults) {
+                        //标记单科单班总得分
+                        double subScore = 0;
+                        //标准差
+                        double sPowSum = 0;
+                        var scount = classResult.studentIds.Count;
+                        foreach (List<double> sc in classResult.studentScores)
+                        {
+                            subScore += sc.Sum();
+                        }
+                        foreach (string sid in classResult.studentIds)
+                        {
+                            double ssc = classResult.studentScores[classResult.studentIds.IndexOf(sid)].Sum();
+                            sPowSum += Math.Pow(ssc - scount > 0 ? Math.Round(subScore * 1.0 / scount, 2) : 0, 2);
+
+                        }
+                        classResult.standard = Math.Round(scount > 0 ? Math.Pow(sPowSum / scount, 0.5) : 0, 2);
+                        classResult.average = scount > 0 ? Math.Round(subScore / scount, 2) : 0;
+                        await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(classResult, classResult.id, new Azure.Cosmos.PartitionKey($"{classResult.code}"));
+                    }
+                    //记录某次考试所有学生得分总分
+                    double score = 0;
+                    double allScore = 0;
+                    int stuCount = 0;
+                    //整体平均分
+                    double average = 0;
+                    //标准差
+                    double powSum = 0;
+                    List<string> losStu = new List<string>();
+                    //先与第一个值取并集
+                    if (examResults.Count >0 ) {
+                        losStu.Union(examResults[0].lostStus);
+                        foreach (ExamResult examResult in examResults)
+                        {
+                            if (info.id == examResult.examId)
+                            {
+                                foreach (List<double> sc in examResult.studentScores)
+                                {
+                                    score += sc.Sum();
+                                }
+                                stuCount = examResult.studentIds.Count;
+                            }
+                            //powSum += Math.Pow(score - examResult.studentIds.Count > 0 ? Math.Round(score * 1.0 / examResult.studentIds.Count, 2) : 0, 2);
+                            //取交集
+                            losStu = losStu.Intersect(examResult.lostStus).ToList();
+                        }
+                    }
+                    double NewsRateScore = stuCount > 0 ? Math.Round(score * 1.0 / stuCount, 2) : 0;
+                    foreach (PaperSimple simple in info.papers)
+                    {
+                        allScore += simple.point.Sum();
+                    }
+                    //计算全科标准差
+                    foreach (string id in examResults[0].studentIds) {
+                        double sc = 0;
+                        foreach (ExamResult result in examResults) {
+                            sc += result.studentScores[result.studentIds.IndexOf(id)].Sum();
+                        }
+                        powSum += Math.Pow(sc - NewsRateScore , 2);
+                    }
+                    info.standard = Math.Round(examResults[0].studentIds.Count > 0 ? Math.Pow(powSum / examResults[0].studentIds.Count, 0.5) : 0,2);
+                    double  NewsRate= allScore > 0 ? Math.Round(NewsRateScore / allScore * 100,2) : 0;
+                    info.lostStu = losStu;
+                    //判断均分是否发生变化,便于实时的更新评测基本信息
+                    if (info.sRate != NewsRate || info.average != NewsRateScore) {
+                        info.sRate = NewsRate;
+                        info.average = NewsRateScore;
+                        await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync<ExamInfo>(info, info.id, new Azure.Cosmos.PartitionKey(info.code));
+                    }         
+                    break;
+            }
+        }
+        public static async Task examRecordCount(ExamInfo info, ExamSubject subject, DingDing _dingDing, int no,AzureStorageFactory _azureStorage,ExamResult result) {
+            try
+            {
+                string blobcntr = "";
+                if (info.scope.Equals("school"))
+                {
+                    blobcntr = info.school;
+                }
+                else {
+                    blobcntr = info.creatorId;
+                }
+                var ContainerClient = _azureStorage.GetBlobContainerClient(blobcntr);
+                List<string> items = await ContainerClient.List($"exam/{info.id}/{subject.id}");
+                List<List<List<string>>> ansList = new List<List<List<string>>>();
+                foreach (string item in items)
+                {
+                    var Download = await _azureStorage.GetBlobContainerClient(blobcntr).GetBlobClient(item).DownloadAsync();
+                    var json = await JsonDocument.ParseAsync(Download.Value.Content);
+                    var Record = json.RootElement.ToObject<List<List<string>>>();
+                    ansList.Add(Record);
+                }
+                /*foreach (List<string> str in info.papers[no].answers) { 
+                    
+                }*/
+                List<Dictionary<string, int>> recorde = new List<Dictionary<string, int>>();
+                for (int i = 0;i< info.papers[no].answers.Count;i++) {
+                    if (info.papers[no].answers[i].Count <= 0) {
+                        recorde.Add(new Dictionary<string, int>());
+                        continue;
+                    }
+                    Dictionary<string, int> optCount = new Dictionary<string, int>();
+                    foreach (List<List<string>> stu in ansList) {
+                        if (stu.Count == info.papers[no].answers.Count) {
+
+                            var item = stu[i];
+                            foreach (string opt in item) {
+                                if (optCount.ContainsKey(opt))
+                                {
+                                    optCount[opt] = optCount[opt] + 1;
+                                }
+                                else { 
+                                    optCount[opt] = 1; 
+                                }
+                            }
+                          
+                        }
+                    }
+                    recorde.Add(optCount);
+                }
+                result.record = recorde;
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"评测作答记录结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
+            }
+        }
+        public static async Task createClassResultAsync(ExamInfo info, List<ExamClassResult> examClassResults, ExamSubject subject, int no, AzureCosmosFactory _azureCosmos, DingDing _dingDing, AzureStorageFactory _azureStorage)
+        {
+            //保证试卷信息与科目信息同步
+            ExamResult result = new ExamResult();
+            //人数总和
+            int Count = 0;
+            int m = 0;
+            double score = 0;
+            //标准差
+            double powSum = 0;
+            double allScore = info.papers[no].point.Sum();
+            List<ClassRange> classRanges = new List<ClassRange>();
+            List<string> lostStu = new List<string>();
+            List<double> csRate = new List<double>();
+            foreach (ExamClassResult classResult in examClassResults)
+            {
+                double classSrate = 0;
+                if (classResult.subjectId.Equals(subject.id))
+                {
+                    //记录缺考学生索引位置
+                    int index = 0;
+                    foreach (List<double> scores in classResult.studentScores)
+                    {
+                        List<double> newScores = new List<double>();
+                        int count = 0;
+                        foreach (double sc in scores) {
+                            newScores.Add(sc > -1 ? sc : 0);
+                            if(sc == -1) {
+                                count++;
+                            }
+                        }
+                        if (count == scores.Count) {
+                            lostStu.Add(classResult.studentIds[index]);
+                            //mcount++;
+                        }
+                        classSrate += newScores.Sum();
+                        score += newScores.Sum();
+                        result.studentScores.Add(newScores);
+                        index++;
+                    }
+
+                    //处理班级信息
+                    ClassRange range = new ClassRange();
+                    range.id = classResult.info.id;
+                    range.name = classResult.info.name;
+                    range.gradeId = classResult.gradeId;
+                    List<int> ran = new List<int>();
+                    int stuCount = classResult.studentIds.Count;
+                    Count += stuCount;
+                    if (m == 0)
+                    {
+                        ran.Add(0);
+                        ran.Add(stuCount - 1);
+                    }
+                    else
+                    {
+                        ran.Add(Count - stuCount);
+                        ran.Add(Count - 1);
+                    }
+                    m++;
+                    range.range = ran;
+                    classRanges.Add(range);
+                    //处理学生ID 
+                    foreach (string id in classResult.studentIds)
+                    {
+                        result.studentIds.Add(id);
+                    }
+                    csRate.Add(result.studentIds.Count > 0 ? Math.Round(classSrate * 1.0 / classResult.studentIds.Count, 2) : 0 / allScore);
+                    //powSum += Math.Pow(classSrate - result.average, 2);
+                }
+            }
+            result.average = result.studentIds.Count > 0 ? Math.Round(score * 1.0 / result.studentIds.Count, 2) : 0;
+            foreach (ExamClassResult classResult in examClassResults) {
+
+                //double classSrate = 0;
+                if (classResult.subjectId.Equals(subject.id))
+                {
+                    foreach (string id in classResult.studentIds)
+                    {
+                         double sc =  classResult.studentScores[classResult.studentIds.IndexOf(id)].Sum();
+                         powSum += Math.Pow(sc - result.average, 2);
+                    }
+                }
+                             
+            }
+            //处理选项计数内容
+            await examRecordCount(info, subject, _dingDing, no, _azureStorage, result);
+            result.standard = Math.Round(result.studentIds.Count > 0 ? Math.Pow(powSum / result.studentIds.Count, 0.5) : 0,2);
+            result.csRate = csRate;
+            result.lostStus = lostStu;           
+            
+            result.sRate = Math.Round(result.average / allScore * 100, 2);
+            result.classes = classRanges;
+            result.code = "ExamResult-" + info.id;
+            result.school = info.school;
+            result.id = subject.id;
+            result.examId = info.id;
+            result.subjectId = subject.id;
+            result.year = info.year;
+            result.paper = info.papers[no];
+            //result.point = info.papers[j].point;
+            result.scope = info.scope;
+            result.name = info.name;
+            result.time = info.startTime;
+
+            await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Common").UpsertItemAsync(result, new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}"));
+
+        }
+    }
+}

+ 94 - 0
TEAMModelFunction/TriggerStuActivity.cs

@@ -0,0 +1,94 @@
+using Azure;
+using Azure.Cosmos;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+
+namespace TEAMModelFunction
+{
+    public class TriggerStuActivity
+    {
+
+        public static async Task<string> SaveStuActivity(CosmosClient client,List<StuActivity> stuActivities,List<StuActivity> tmdActivities) {
+            if (stuActivities.IsNotEmpty())
+            {
+                foreach (var x in stuActivities)
+                {
+                    await client.GetContainer("TEAMModelOS", "Student").UpsertItemAsync(x, new PartitionKey(x.code));
+                }
+            }
+            if (tmdActivities.IsNotEmpty())
+            {
+                foreach (var x in tmdActivities)
+                {
+                    await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync(x, new PartitionKey(x.code));
+                }
+            }
+            return ""; 
+        }
+         
+        public  static async Task<(List<string> tmdids,List<Students> studentss)> GetStuList(  CosmosClient client, List<string> classes,string  school) {
+
+            List<Students> studentss = new List<Students>();
+            List<string> sqlList = new List<string>();
+            classes.ForEach(x => { sqlList.Add($" '{x}' "); });
+            string sql = string.Join(" , ", sqlList);
+            List<StuList> schList = new List<StuList>();
+            List<Student> students = new List<Student>();
+            if (!string.IsNullOrEmpty(school)) {
+                await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<StuList>(queryText: $"select value(c) from c where c.id in ({sql})",
+                requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"StuList-{school}") }))
+                {
+                    schList.Add(item);
+                }
+
+
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Student").GetItemQueryIterator<Student>(queryText: $"select value(c) from c where c.classId in ({sql})",
+                    requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{school}") }))
+                {
+                    students.Add(item);
+                }
+            }
+            List<StuList> tchLists = new List<StuList>();
+            await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<StuList>(queryText: $"select value(c) from c where c.id in ({sql})",
+                requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"StuList") }))
+            {
+                tchLists.Add(item);
+            }
+            List<string> tmdids = new List<string>();
+            schList.ForEach(x => { 
+                if (x.students.IsNotEmpty()) 
+                { 
+                    studentss.AddRange(x.students);
+                }
+                if (x.tmids.IsNotEmpty())
+                {
+                    tmdids.AddRange(x.tmids);
+                }
+            });
+            tchLists.ForEach(x => 
+            {
+                if (x.students.IsNotEmpty()) { 
+                    studentss.AddRange(x.students);
+                }
+                if (x.tmids.IsNotEmpty())
+                {
+                    tmdids.AddRange(x.tmids);
+                }
+            });
+            students.ForEach(x => {
+                studentss.Add(new Students { id = x.id, code = x.code });
+            });
+            return (tmdids,studentss);
+        }
+    }
+}

+ 326 - 0
TEAMModelFunction/TriggerSurvey.cs

@@ -0,0 +1,326 @@
+using Azure.Cosmos;
+using Azure.Messaging.ServiceBus;
+using Azure.Storage.Blobs.Models;
+using Azure.Storage.Sas;
+using Microsoft.Azure.Documents;
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Cosmos;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
+using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
+
+namespace TEAMModelFunction
+{
+   public class TriggerSurvey
+    {
+        public static async void Trigger( AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
+               CosmosClient client, Document input, TriggerData tdata,AzureRedisFactory _azureRedis)
+        {
+            if ((tdata.status != null && tdata.status.Value == 404) || tdata.ttl > 0)
+            {
+                return;
+            }
+            var adid = tdata.id;
+            var adcode = "";
+            string blobcntr = null;
+            if (tdata.scope == "school")
+            {
+                  adcode = $"Activity-{tdata.school}";
+                blobcntr = tdata.school;
+            }
+            else if (tdata.scope == "private"){
+                adcode = $"Activity-{tdata.creatorId}";
+                 blobcntr = tdata.creatorId;
+            }
+            //ActivityData data = null;
+            //try
+            //{
+            //    if (tdata.scope == "school")
+            //    {
+            //        data = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ActivityData>(adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
+            //    }
+            //    else if (tdata.scope == "private")
+            //    {
+            //        data = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<ActivityData>(adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
+            //    }
+            //}
+            //catch { data = null; }
+            Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Survey>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
+            List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", survey.progress } });
+            if (survey != null) {
+                switch (survey.progress)
+                {
+                    case "pending":
+                        var messageSurvey = new ServiceBusMessage(new { id = input.Id, progress = "going", code = tdata.code }.ToJsonString());
+                        messageSurvey.ApplicationProperties.Add("name", "Survey");
+                        if (changeRecords.Count > 0)
+                        {
+                            await _serviceBus.GetServiceBusClient().cancelMessage("active-task", changeRecords[0].sequenceNumber);
+                            long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageSurvey, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
+                            changeRecords[0].sequenceNumber = start;
+                            await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
+                        }
+                        else
+                        {
+                            long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageSurvey, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
+                            ChangeRecord changeRecord = new ChangeRecord
+                            {
+                                RowKey = input.Id,
+                                PartitionKey = "pending",
+                                sequenceNumber = start,
+                                msgId = messageSurvey.MessageId
+                            };
+                            await _azureStorage.Save<ChangeRecord>(changeRecord);
+                        }
+                        break;
+                    case "going":
+                        //if (survey.scope == "school")
+                        //{
+                        //    data = new ActivityData
+                        //    {
+                        //        id = survey.id,
+                        //        code = $"Activity-{survey.school}",
+                        //        type = "survey",
+                        //        name = survey.name,
+                        //        startTime = survey.startTime,
+                        //        endTime = survey.endTime,
+                        //        scode = survey.code,
+                        //        scope = survey.scope,
+                        //        classes = survey.classes.IsNotEmpty() ? survey.classes : new List<string> { "" },
+                        //        tmdids = survey.tmdids.IsNotEmpty() ? survey.tmdids : new List<string> { "" },
+                        //        progress = "going",
+                        //        subjects = new List<string> { "" }
+                        //    };
+                        //    await client.GetContainer("TEAMModelOS", "School").UpsertItemAsync<ActivityData>(data, new Azure.Cosmos.PartitionKey(data.code));
+                        //}
+                        //else if (survey.scope == "private")
+                        //{
+                        //    data = new ActivityData
+                        //    {
+                        //        id = survey.id,
+                        //        code = $"Activity-Common",
+                        //        type = "survey",
+                        //        name = survey.name,
+                        //        startTime = survey.startTime,
+                        //        endTime = survey.endTime,
+                        //        scode = survey.code,
+                        //        scope = survey.scope,
+                        //        progress = "going",
+                        //        classes = survey.classes.IsNotEmpty() ? survey.classes : new List<string> { "" },
+                        //        tmdids = new List<string> { "" },
+                        //        subjects = new List<string> { "" }
+                        //    };
+                        //    await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<ActivityData>(data, new Azure.Cosmos.PartitionKey(data.code));
+                        //}
+
+                        (List<string> tmdids,List<Students> students) =   await TriggerStuActivity. GetStuList(client, survey.classes, survey.school);
+                        await _dingDing.SendBotMsg($"问卷调查{tdata.id}写入学生表作为活动列表!", GroupNames.成都开发測試群組);
+                        List<StuActivity> stuActivities = new List<StuActivity>();
+                        List<StuActivity> tmdActivities = new List<StuActivity>();
+                        if (tmdids.IsNotEmpty()) {
+                            tmdids.ForEach(x=> {
+                                tmdActivities.Add(new StuActivity
+                                {
+                                    pk = "Activity",
+                                    id = survey.id,
+                                    code = $"Activity-{x}",
+                                    type = "survey",
+                                    name = survey.name,
+                                    startTime = survey.startTime,
+                                    endTime = survey.endTime,
+                                    scode = survey.code,
+                                    scope = survey.scope,
+                                    school = survey.school,
+                                    creatorId = survey.creatorId,
+                                    subjects = new List<string> { "" },
+                                    blob = survey.blob
+
+                                });
+                            });
+                        }
+                        if (students.IsNotEmpty()) {
+                            students.ForEach(x => {
+                                stuActivities.Add(new StuActivity {
+                                    pk = "Activity",
+                                    id = survey.id,
+                                    code = $"Activity-{survey.school}-{x.id}",
+                                    type = "survey",
+                                    name = survey.name,
+                                    startTime = survey.startTime,
+                                    endTime = survey.endTime,
+                                    scode = survey.code,
+                                    scope = survey.scope,
+                                    school = survey.school,
+                                    creatorId = survey.creatorId,
+                                    subjects = new List<string> { "" },
+                                    blob = survey.blob
+                                });
+                            });
+                        }
+                        await TriggerStuActivity.SaveStuActivity(client, stuActivities, tmdActivities);
+                        await _dingDing.SendBotMsg($"问卷调查{tdata.id}写入完成!", GroupNames.成都开发測試群組);
+                        var messageSurveyEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = tdata.code }.ToJsonString());
+                        messageSurveyEnd.ApplicationProperties.Add("name", "Survey");
+                        if (changeRecords.Count > 0)
+                        {
+                            long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageSurveyEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
+                            await _serviceBus.GetServiceBusClient().cancelMessage("active-task", changeRecords[0].sequenceNumber);
+                            changeRecords[0].sequenceNumber = end;
+                            await _azureStorage.SaveOrUpdate<ChangeRecord>(changeRecords[0]);
+                        }
+                        else
+                        {
+                            long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageSurveyEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
+                            ChangeRecord changeRecord = new ChangeRecord
+                            {
+                                RowKey = input.Id,
+                                PartitionKey = "going",
+                                sequenceNumber = end,
+                                msgId = messageSurveyEnd.MessageId
+                            };
+                            await _azureStorage.Save<ChangeRecord>(changeRecord);
+                        }
+                        await _dingDing.SendBotMsg($"问卷调查{tdata.id}将于:{tdata.etime}完成并结算!", GroupNames.成都开发測試群組);
+                        break;
+                    case "finish":
+                        await _dingDing.SendBotMsg($"问卷调查{tdata.id}开始结算{tdata.etime}!", GroupNames.成都开发測試群組);
+                        var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
+                        var submits = await _azureRedis.GetRedisClient(8).SetMembersAsync($"Survey:Submit:{survey.id}");
+                        List<dynamic> recs = new List<dynamic>();
+                        foreach (var rcd in records)
+                        {
+                            var value = rcd.Value.ToString().ToObject<JsonElement>();
+                            recs.Add(new { index = rcd.Name.ToString(), ans = value });
+                        }
+
+                        List<dynamic> userids = new List<dynamic>();
+                        foreach (var submit in submits)
+                        {
+                            var value = submit.ToString();
+                            userids.Add(value);
+                        }
+                        var cods = new { records = recs, userids };
+                        //问卷整体情况
+                        await _azureStorage.UploadFileByContainer(blobcntr, cods.ToJsonString(), "survey", $"{survey.id}/record.json");
+                        //结算每道题的答题情况
+                        var ContainerClient =  _azureStorage.GetBlobContainerClient(blobcntr);
+                        List<Task<string>> tasks = new List<Task<string>>();
+                        //获取
+                        try {
+                            List<string> items = await ContainerClient.List($"survey/{survey.id}/urecord");
+                            List<SurveyRecord> surveyRecords = new List<SurveyRecord>();
+                            foreach (string item in items)
+                            {
+                                var Download = await _azureStorage.GetBlobContainerClient(blobcntr).GetBlobClient(item).DownloadAsync();
+                                var json = await JsonDocument.ParseAsync(Download.Value.Content);
+                                var Record = json.RootElement.ToObject<SurveyRecord>();
+                                surveyRecords.Add(Record);
+                            }
+                            await _dingDing.SendBotMsg($"问卷调查问题结算数据{surveyRecords.ToJsonString()}", GroupNames.成都开发測試群組);
+                            for (int index = 0; index < survey.answers.Count; index++)
+                            {
+                                string url = $"{survey.id}/qrecord/{index}.json";
+                                QuestionRecord question = new QuestionRecord() { index = index };
+                                foreach (SurveyRecord record in surveyRecords)
+                                {
+                                    if (record.ans.Count == survey.answers.Count)
+                                    {
+                                        foreach (var an in record.ans[index])
+                                        {
+                                            //
+                                            if (question.opt.ContainsKey(an))
+                                            {
+                                                if (question.opt[an] != null)
+                                                {
+                                                    question.opt[an].Add(record.userid);
+                                                }
+                                                else
+                                                {
+                                                    question.opt[an] = new HashSet<string>() { record.userid };
+                                                }
+                                            }
+                                            else
+                                            {
+                                                if (survey.answers[index].Contains(an))
+                                                {
+                                                    //如果是客观题code
+                                                    question.opt.Add(an, new HashSet<string> { record.userid });
+                                                }
+                                                else
+                                                {
+                                                    //如果不是客观code
+                                                    question.other[record.userid] = an;
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                                tasks.Add(  _azureStorage.UploadFileByContainer(blobcntr, question.ToJsonString(), "survey", url));
+                            }
+                            await Task.WhenAll(tasks);
+                        } catch (Exception ex) {
+                            await _dingDing.SendBotMsg($"问卷调查问题结算异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
+                        }
+                        if (string.IsNullOrEmpty(survey.recordUrl))
+                        {
+                            survey.recordUrl = $"/survey/{survey.id}/record.json";
+                            await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync<Survey>(survey, survey.id, new Azure.Cosmos.PartitionKey(survey.code));
+                        }
+                        else {
+                            _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Record:{survey.id}");
+                            _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Submit:{survey.id}");
+                            break;
+                        }
+                        
+                        //更新结束状态
+                        //data.progress = "finish";
+                        //if (survey.scope == "school")
+                        //{
+                        //    await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
+                        //}
+                        //else if (survey.scope == "private")
+                        //{
+                        //    await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
+                        //}
+                        
+                        break;
+                }
+            }
+        }
+    }
+    /**
+     * {survey.id}/qrecord/{index}.json
+        {
+            "opt": {
+                "A": [
+                    "userid1",
+                    "userid2",
+                    "userid3"
+                ],
+                "B": [
+                    "userid1",
+                    "userid2",
+                    "userid3"
+                ]
+            },
+            "other": {
+                "userid1": "建议XXXX1",
+                "userid2": "建议XXXX2"
+            }
+        }
+     **/
+    public class QuestionRecord { 
+        public int index { get; set; }
+        public Dictionary<string, HashSet<string>> opt { get; set; } = new Dictionary<string, HashSet<string>>();
+        public Dictionary<string, string> other { get; set; } = new Dictionary<string, string>();
+    }
+}

+ 263 - 0
TEAMModelFunction/TriggerVote.cs

@@ -0,0 +1,263 @@
+using Azure.Cosmos;
+using Azure.Messaging.ServiceBus;
+using Microsoft.Azure.Documents;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Cosmos;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
+
+namespace TEAMModelFunction
+{
+    public static class TriggerVote
+    {
+
+        public static async void Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
+            CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis)
+        {
+            if ((tdata.status != null && tdata.status.Value == 404)||tdata.ttl>0)
+            {
+                return;
+            }
+            var adid = tdata.id;
+            var adcode = "";
+            string blobcntr = null;
+            if (tdata.scope == "school")
+            {
+                adcode = $"Activity-{tdata.school}";
+                blobcntr = tdata.school;
+            }
+            else if (tdata.scope == "private")
+            {
+                adcode = $"Activity-{tdata.creatorId}";
+                blobcntr = tdata.creatorId;
+            }
+           // ActivityData data = null;
+            //try
+            //{
+            //    if (tdata.scope == "school")
+            //    {
+            //        data = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<ActivityData>(adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
+            //    }
+            //    else if (tdata.scope == "private")
+            //    {
+            //        data = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<ActivityData>(adid, new Azure.Cosmos.PartitionKey($"{adcode}"));
+            //    }
+            //}
+            //catch
+            //{
+            //    data = null;
+            //}
+            await _dingDing.SendBotMsg($"投票活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
+            Vote vote = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
+            List<ChangeRecord> voteRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", vote.progress } });
+            if (vote != null) {
+                switch (vote.progress)
+                {
+                    case "pending":
+                        var messageVote = new ServiceBusMessage(new { id = input.Id, progress = "going", code = tdata.code }.ToJsonString());
+                        messageVote.ApplicationProperties.Add("name", "Vote");
+                        if (voteRecords.Count > 0)
+                        {
+                            long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageVote, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
+                            await _serviceBus.GetServiceBusClient().cancelMessage("active-task", voteRecords[0].sequenceNumber);
+                            voteRecords[0].sequenceNumber = start;
+                            await _azureStorage.SaveOrUpdate<ChangeRecord>(voteRecords[0]);
+                        }
+                        else
+                        {
+                            long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageVote, DateTimeOffset.FromUnixTimeMilliseconds(tdata.stime));
+                            ChangeRecord changeRecord = new ChangeRecord
+                            {
+                                RowKey = input.Id,
+                                PartitionKey = "pending",
+                                sequenceNumber = start,
+                                msgId = messageVote.MessageId
+                            };
+                            await _azureStorage.Save<ChangeRecord>(changeRecord);
+                        }
+                        break;
+                    case "going":
+                        //if (vote.scope == "school")
+                        //{
+                        //    data = new ActivityData
+                        //    {
+                        //        id = vote.id,
+                        //        code = $"Activity-{vote.school}",
+                        //        type = "vote",
+                        //        name = vote.name,
+                        //        startTime = vote.startTime,
+                        //        endTime = vote.endTime,
+                        //        scode = vote.code,
+                        //        scope = vote.scope,
+                        //        classes = vote.classes.IsNotEmpty() ? vote.classes : new List<string> { "" },
+                        //        tmdids = vote.tmdids.IsNotEmpty() ? vote.tmdids : new List<string> { "" },
+                        //        progress = "going",
+                        //        subjects = new List<string> { "" }
+                        //    };
+                        //    await client.GetContainer("TEAMModelOS", "School").UpsertItemAsync<ActivityData>(data, new Azure.Cosmos.PartitionKey(data.code));
+                        //}
+                        //else if (vote.scope == "private")
+                        //{
+                        //    data = new ActivityData
+                        //    {
+                        //        id = vote.id,
+                        //        code = $"Activity-Common",
+                        //        type = "vote",
+                        //        name = vote.name,
+                        //        startTime = vote.startTime,
+                        //        endTime = vote.endTime,
+                        //        scode = vote.code,
+                        //        scope = vote.scope,
+                        //        progress = "going",
+                        //        classes = vote.classes.IsNotEmpty() ? vote.classes : new List<string> { "" },
+                        //        tmdids = new List<string> { "" },
+                        //        subjects = new List<string> { "" }
+                        //    };
+                        //    await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<ActivityData>(data, new Azure.Cosmos.PartitionKey(data.code));
+                        //}
+
+                        (List<string> tmdids, List<Students> students) = await TriggerStuActivity.GetStuList(client, vote.classes, vote.school);
+                        List<string> tmds = vote.tmdids.IsNotEmpty() ? vote.tmdids : new List<string>() ;
+                        if (tmdids.IsNotEmpty()) {
+                            tmds.AddRange(tmdids);
+                        }
+                        List<StuActivity> stuActivities = new List<StuActivity>();
+                        List<StuActivity> tmdActivities = new List<StuActivity>();
+                        if (tmds.IsNotEmpty())
+                        {
+                            tmds.ForEach(x => {
+                                tmdActivities.Add(new StuActivity
+                                {
+                                    pk = "Activity",
+                                    id = vote.id,
+                                    code = $"Activity-{x}",
+                                    type = "vote",
+                                    name = vote.name,
+                                    startTime = vote.startTime,
+                                    endTime = vote.endTime,
+                                    scode = vote.code,
+                                    scope = vote.scope,
+                                    school = vote.school,
+                                    creatorId = vote.creatorId,
+                                    subjects = new List<string> { "" } ,
+                                    blob = null
+                                });
+                            });
+                        }
+                        if (students.IsNotEmpty())
+                        {
+                            students.ForEach(x => {
+                                stuActivities.Add(new StuActivity
+                                {
+                                    pk = "Activity",
+                                    id = vote.id,
+                                    code = $"Activity-{vote.school}-{x.id}",
+                                    type = "vote",
+                                    name = vote.name,
+                                    startTime = vote.startTime,
+                                    endTime = vote.endTime,
+                                    scode = vote.code,
+                                    scope = vote.scope,
+                                    school = vote.school,
+                                    creatorId = vote.creatorId,
+                                    subjects = new List<string> { "" },
+                                    blob=null
+                                });
+                            });
+                        }
+                        await TriggerStuActivity.SaveStuActivity(client, stuActivities, tmdActivities);
+                        var messageVoteEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = tdata.code }.ToJsonString());
+                        messageVoteEnd.ApplicationProperties.Add("name", "Vote");
+                        if (voteRecords.Count > 0)
+                        {
+                            long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageVoteEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
+                            await _serviceBus.GetServiceBusClient().cancelMessage("active-task", voteRecords[0].sequenceNumber);
+                            voteRecords[0].sequenceNumber = end;
+                            await _azureStorage.SaveOrUpdate<ChangeRecord>(voteRecords[0]);
+                        }
+                        else
+                        {
+                            long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageVoteEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.etime));
+                            ChangeRecord changeRecord = new ChangeRecord
+                            {
+                                RowKey = input.Id,
+                                PartitionKey = "going",
+                                sequenceNumber = end,
+                                msgId = messageVoteEnd.MessageId
+                            };
+                            await _azureStorage.Save<ChangeRecord>(changeRecord);
+                        }
+                        await _dingDing.SendBotMsg($"投票活动{tdata.id}将于:{tdata.etime}完成并结算!", GroupNames.成都开发測試群組);
+                        break;
+                    case "finish":
+                        await _dingDing.SendBotMsg($"投票活动{tdata.id}开始结算{tdata.etime}!", GroupNames.成都开发測試群組);
+                        //获取投票活动的所有投票记录
+                        var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Vote:Record:{vote.id}");
+                        //获取投票活动的选项及投票数
+                        var counts = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Vote:Count:{vote.id}");
+                        List<dynamic> countcds = new List<dynamic>();
+                        if (counts != null && counts.Length > 0)
+                        {
+                            foreach (var count in counts)
+                            {
+                                countcds.Add(new { code = count.Element.ToString(), count = (int)count.Score });
+                            }
+                        }
+                        List<Task<string>> tasks = new List<Task<string>>();
+                        List<VoteRecord> recordsBlob = new List<VoteRecord>();
+                        foreach (var rcd in records)
+                        {
+                            var value = rcd.Value.ToString().ToObject<VoteRecord>();
+                            recordsBlob.Add(value);
+                        }
+                        //分组每个人的 
+                        var gp = recordsBlob.GroupBy(x => x.userid).Select(x => new { key = x.Key, list = x.ToList() });
+                        foreach (var g in gp)
+                        {
+                            tasks.Add(_azureStorage.UploadFileByContainer(blobcntr, g.list.ToJsonString(), "vote", $"{vote.id}/urecord/{g.key}.json"));
+                        }
+                        //处理活动方的记录, 
+                        string url = $"/vote/{vote.id}/record.json";
+                        tasks.Add(_azureStorage.UploadFileByContainer(blobcntr, new { options = countcds, records = recordsBlob }.ToJsonString(), "vote", $"{vote.id}/record.json"));
+                        //处理投票者的记录
+
+                        if (string.IsNullOrEmpty(vote.recordUrl))
+                        {
+                            vote.recordUrl = url;
+                            await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync<Vote>(vote, vote.id, new Azure.Cosmos.PartitionKey(vote.code));
+                        }
+                        else {
+                            //异动,且已经有结算记录则不必再继续。
+                            _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Record:{vote.id}");
+                            _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Count:{vote.id}");
+                            break; 
+                        }
+                        await Task.WhenAll(tasks);
+                        //data.progress = "finish";
+                        //更新结束状态
+                        //if (vote.scope == "school")
+                        //{
+                        //    await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
+                        //}
+                        //else if (vote.scope == "private")
+                        //{
+                        //    await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
+                        //}
+                        //_azureRedis.GetRedisClient(8).KeyDelete($"Vote:Record:{vote.id}");
+                        //_azureRedis.GetRedisClient(8).KeyDelete($"Vote:Count:{vote.id}");
+                        break;
+                }
+            }
+           
+        }
+    }
+}

+ 0 - 79
TEAMModelFunction/VoteTrigger.cs

@@ -1,79 +0,0 @@
-using Azure.Cosmos;
-using Azure.Messaging.ServiceBus;
-using Microsoft.Azure.Documents;
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-using TEAMModelOS.SDK.DI;
-using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Models;
-
-namespace TEAMModelFunction
-{
-  public static  class VoteTrigger
-    {
-
-        public static async void Trigger(AzureCosmosFactory _azureCosmos, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
-            CosmosClient client, Document input, string code, long stime, long etime, string school)
-        {
-            Vote vote = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
-            List<ChangeRecord> voteRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", vote.progress } });
-            //ChangeRecord voteRecord = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{vote.progress}"));
-            switch (vote.progress)
-            {
-                case "pending":
-                    var messageVote = new ServiceBusMessage(new { id = input.Id, progress = "going", code = code }.ToJsonString());
-                    messageVote.ApplicationProperties.Add("name", "Vote");
-                    if (voteRecords.Count > 0)
-                    {
-                        long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageVote, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                        await _serviceBus.GetServiceBusClient().cancelMessage("active-task", voteRecords[0].sequenceNumber);
-                        voteRecords[0].sequenceNumber = start;
-                        await _azureStorage.SaveOrUpdate<ChangeRecord>(voteRecords[0]);
-                        //await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(voteRecord, voteRecord.id, new Azure.Cosmos.PartitionKey($"{voteRecord.code}"));
-                    }
-                    else
-                    {
-                        long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageVote, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                        ChangeRecord changeRecord = new ChangeRecord
-                        {
-                            RowKey = input.Id,
-                            PartitionKey = "pending",
-                            sequenceNumber = start,
-                            msgId = messageVote.MessageId
-                        };
-                        await _azureStorage.Save<ChangeRecord>(changeRecord);
-                        //await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                    }
-                    break;
-                case "going":
-                    var messageVoteEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
-                    messageVoteEnd.ApplicationProperties.Add("name", "Vote");
-                    if (voteRecords.Count > 0)
-                    {
-                        long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageVoteEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                        await _serviceBus.GetServiceBusClient().cancelMessage("active-task", voteRecords[0].sequenceNumber);
-                        voteRecords[0].sequenceNumber = end;
-                        await _azureStorage.SaveOrUpdate<ChangeRecord>(voteRecords[0]);
-                        //await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(voteRecord, voteRecord.id, new Azure.Cosmos.PartitionKey($"{voteRecord.code}"));
-                    }
-                    else
-                    {
-                        long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync("active-task", messageVoteEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                        ChangeRecord changeRecord = new ChangeRecord
-                        {
-                            RowKey = input.Id,
-                            PartitionKey = "going",
-                            sequenceNumber = end,
-                            msgId = messageVoteEnd.MessageId
-                        };
-                        await _azureStorage.Save<ChangeRecord>(changeRecord);
-                        //await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                    }
-                    break;
-            }
-        }
-    }
-}

+ 1 - 0
TEAMModelFunction/local.settings.json

@@ -5,6 +5,7 @@
     "Azure:Starage:ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelstorage;AccountKey=Yq7D4dE6cFuer2d2UZIccTA/i0c3sJ/6ITc8tNOyW+K5f+/lWw9GCos3Mxhj47PyWQgDL8YbVD63B9XcGtrMxQ==;EndpointSuffix=core.chinacloudapi.cn",
     "Azure:Starage:ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelstorage;AccountKey=Yq7D4dE6cFuer2d2UZIccTA/i0c3sJ/6ITc8tNOyW+K5f+/lWw9GCos3Mxhj47PyWQgDL8YbVD63B9XcGtrMxQ==;EndpointSuffix=core.chinacloudapi.cn",
     "Azure:ServiceBus:ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
     "Azure:ServiceBus:ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
     "Azure:Cosmos:ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;",
     "Azure:Cosmos:ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;",
+    "Azure:Redis:ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False",
     "FUNCTIONS_WORKER_RUNTIME": "dotnet",
     "FUNCTIONS_WORKER_RUNTIME": "dotnet",
     "ScanModel": "TEAMModelOS",
     "ScanModel": "TEAMModelOS",
     "Database": "TEAMModelOS"
     "Database": "TEAMModelOS"

+ 5 - 5
TEAMModelGrpc/TEAMModelGrpc.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
 
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <TargetFramework>net5.0</TargetFramework>
     <UserSecretsId>eb0da4a0-e9b5-417f-944d-d7a30dbd2cf5</UserSecretsId>
     <UserSecretsId>eb0da4a0-e9b5-417f-944d-d7a30dbd2cf5</UserSecretsId>
     <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
     <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
   </PropertyGroup>
   </PropertyGroup>
@@ -29,13 +29,13 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Grpc.AspNetCore" Version="2.27.0" />
-    <PackageReference Include="Grpc.HealthCheck" Version="2.28.1" />
-    <PackageReference Include="Grpc.Tools" Version="2.27.0">
+    <PackageReference Include="Grpc.AspNetCore" Version="2.35.0" />
+    <PackageReference Include="Grpc.HealthCheck" Version="2.36.1" />
+    <PackageReference Include="Grpc.Tools" Version="2.36.1">
       <PrivateAssets>all</PrivateAssets>
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
     </PackageReference>
-    <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.3" />
+    <PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.8" />
     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.8" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>

+ 0 - 272
TEAMModelGrpc/TEAMModelOS.GRPC.xml

@@ -29,278 +29,6 @@
             <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection"/> for adding services.</param>
             <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection"/> for adding services.</param>
             <returns>An instance of <see cref="T:Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder"/> from which health checks can be registered.</returns>
             <returns>An instance of <see cref="T:Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder"/> from which health checks can be registered.</returns>
         </member>
         </member>
-        <member name="P:TEAMModelGrpc.Models.BlobSASDto.Url">
-            <summary>
-            Blob的URL地址
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.BlobSASDto.Container">
-            <summary>
-            容器名
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.BlobSASDto.SAS">
-            <summary>
-            Blob的SAS签名
-            </summary>
-        </member>
-        <member name="T:TEAMModelGrpc.Models.Dict">
-            <summary>
-            请求参数Dict
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.Dict.NMap">
-            <summary>
-            数字Dict
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.Dict.SMap">
-            <summary>
-            字符串Dict
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.Dict.BMap">
-            <summary>
-            布尔Dict
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.Dict.LSMap">
-            <summary>
-            字符串ListMap
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.Dict.LNMap">
-            <summary>
-            数字ListMap
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.Dict.LBMap">
-            <summary>
-            Byte ListMap
-            </summary>
-        </member>
-        <member name="T:TEAMModelGrpc.Models.LSMap">
-            <summary>
-            字符串ListMap
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.LSMap.Key">
-            <summary>
-            数字Dict
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.LSMap.Value">
-            <summary>
-            字符串数组
-            </summary>
-        </member>
-        <member name="T:TEAMModelGrpc.Models.LNMap">
-            <summary>
-            数字ListMap
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.LNMap.Key">
-            <summary>
-            Key
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.LNMap.Value">
-            <summary>
-            数字数组
-            </summary>
-        </member>
-        <member name="T:TEAMModelGrpc.Models.LBMap">
-            <summary>
-            Byte[] Map
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.LBMap.Key">
-            <summary>
-            Key
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.LBMap.Value">
-            <summary>
-            byte数组
-            </summary>
-        </member>
-        <member name="T:TEAMModelGrpc.Models.DictExt">
-            <summary>
-             Dict扩展
-            </summary>
-        </member>
-        <member name="M:TEAMModelGrpc.Models.DictExt.ToDict(TEAMModelGrpc.Models.Dict)">
-            <summary>
-             Dict扩展方法
-            </summary>
-            <param name="dict"></param>
-            <returns></returns>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.ListPid.idPks">
-            <summary>
-            list IdPk
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.Response.message">
-            <summary>
-            
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.Response.code">
-            <summary>
-            
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.id">
-            <summary>
-            
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.title">
-            <summary>
-            标题
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.expand">
-            <summary>
-            是否展开
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.editable">
-            <summary>
-            是否编辑
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.version">
-            <summary>
-            版本
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.order">
-            <summary>
-            排序
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.type">
-            <summary>
-            类型
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.nodeKey">
-            <summary>
-            节点Key
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.pid">
-            <summary>
-            父级
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.volumeCode">
-            <summary>
-            册别编码
-            </summary>
-        </member>
-        <member name="P:TEAMModelGrpc.Models.SyllabusTreeDto.status">
-            <summary>
-            数据状态
-            </summary>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.ClassroomService.SaveOrUpdateVolume(Grpc.Core.IAsyncStreamReader{TEAMModelOS.SDK.Models.Classroom},Grpc.Core.IServerStreamWriter{TEAMModelOS.SDK.Models.Classroom},Grpc.Core.ServerCallContext)">
-            <summary>
-            保存教室
-            </summary>
-            <param name="requestStream"></param>
-            <param name="responseStream"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.ClassroomService.FindVolume(TEAMModelGrpc.Models.Dict,Grpc.Core.IServerStreamWriter{TEAMModelOS.SDK.Models.Classroom},Grpc.Core.ServerCallContext)">
-            <summary>
-            查询教室
-            </summary>
-            <param name="request"></param>
-            <param name="responseStream"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.ClassroomService.Delete(TEAMModelGrpc.Models.ListPid,Grpc.Core.ServerCallContext)">
-            <summary>
-            删除教室
-            </summary>
-            <param name="listPid"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.ClassStudentService.SaveOrUpdateClassStudent(Grpc.Core.IAsyncStreamReader{TEAMModelOS.SDK.Models.ClassStudent},Grpc.Core.IServerStreamWriter{TEAMModelOS.SDK.Models.ClassStudent},Grpc.Core.ServerCallContext)">
-            <summary>
-            保存 或 修改 教室学生关联
-            </summary>
-            <param name="requestStream"></param>
-            <param name="responseStream"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.ClassStudentService.FindStudents(TEAMModelGrpc.Models.StringDto,Grpc.Core.IServerStreamWriter{TEAMModelOS.SDK.Models.ClassStudent},Grpc.Core.ServerCallContext)">
-            <summary>
-            查询学生在哪些教室
-            </summary>
-            <param name="request"></param>
-            <param name="responseStream"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.CourseService.FindCourseByDict(TEAMModelGrpc.Models.Dict,Grpc.Core.IServerStreamWriter{TEAMModelOS.SDK.Models.Course},Grpc.Core.ServerCallContext)">
-            <summary>
-            查询课程
-            </summary>
-            <param name="request"></param>
-            <param name="responseStream"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.CourseService.SaveCourse(Grpc.Core.IAsyncStreamReader{TEAMModelOS.SDK.Models.Course},Grpc.Core.IServerStreamWriter{TEAMModelOS.SDK.Models.Course},Grpc.Core.ServerCallContext)">
-            <summary>
-            保存课程
-            </summary>
-            <param name="requestStream"></param>
-            <param name="responseStream"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.CourseService.DeleteCourse(TEAMModelGrpc.Models.ListPid,Grpc.Core.ServerCallContext)">
-            <summary>
-            删除课程
-            </summary>
-            <param name="listPid"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.HomeWorkService.StudentScoring(TEAMModelOS.Models.Dto.HomeworkCommentDto,Grpc.Core.ServerCallContext)">
-            <summary>
-            学生作业打分评论
-            </summary>
-            <param name="homeWorkCommentDto"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.HomeWorkService.TeacherScoring(TEAMModelOS.Models.Dto.HomeworkScoringDto,Grpc.Core.ServerCallContext)">
-            <summary>
-            教师作业打分评论
-            </summary>
-            <param name="homeWorkCommentDto"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
-        <member name="M:TEAMModelGrpc.Services.HomeWorkService.FindTeacherComments(TEAMModelGrpc.Models.Dict,Grpc.Core.IServerStreamWriter{TEAMModelOS.SDK.Models.Comment},Grpc.Core.ServerCallContext)">
-            <summary>
-            查询教师评语罐头
-            </summary>
-            <param name="dict"></param>
-            <param name="responseStream"></param>
-            <param name="context"></param>
-            <returns></returns>
-        </member>
         <member name="T:TEAMModelGrpc.GreetReflection">
         <member name="T:TEAMModelGrpc.GreetReflection">
             <summary>Holder for reflection information generated from Protos/greet.proto</summary>
             <summary>Holder for reflection information generated from Protos/greet.proto</summary>
         </member>
         </member>

+ 14 - 0
TEAMModelOS.SDK/DI/AzureRedis/AzureRedisFactory.cs

@@ -43,5 +43,19 @@ namespace TEAMModelOS.SDK.DI
                 return null;
                 return null;
             }
             }
         }
         }
+        //public (IDatabase db , IServer server ) GetRedisDbCmClient(int dbnum = -1, string name = "Default")
+        //{
+        //    try
+        //    {
+        //        var cm = ConnectionMultiplexers.GetOrAdd(name, x => ConnectionMultiplexer.Connect(_optionsMonitor.Get(name).RedisConnectionString));
+                
+        //        return (cm.GetDatabase(dbnum),cm.GetServer(cm.GetEndPoints()[0]));
+        //    }
+        //    catch (OptionsValidationException e)
+        //    {
+        //        _logger?.LogWarning(e, e.Message);
+        //        return (null,null);
+        //    }
+        //}
     }
     }
 }
 }

+ 89 - 1
TEAMModelOS.SDK/DI/AzureStorage/AzureStorageBlobExtensions.cs

@@ -11,6 +11,8 @@ using System.IO;
 using Azure.Storage.Blobs.Specialized;
 using Azure.Storage.Blobs.Specialized;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
+using System.Text;
+using Azure.Core;
 
 
 namespace TEAMModelOS.SDK.DI
 namespace TEAMModelOS.SDK.DI
 {
 {
@@ -26,7 +28,8 @@ namespace TEAMModelOS.SDK.DI
             long? size = 0;
             long? size = 0;
             try
             try
             {
             {
-                await foreach (var item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix))
+               
+                await foreach (BlobItem item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix))
                 {
                 {
                     size += item.Properties.ContentLength;
                     size += item.Properties.ContentLength;
                 };
                 };
@@ -37,6 +40,91 @@ namespace TEAMModelOS.SDK.DI
                 return size;
                 return size;
             }
             }
         }
         }
+
+        public static async Task<List<string>> List(this BlobContainerClient client, string prefix = null) {
+            try
+            {
+                List<string> items = new List<string>();
+                await foreach (BlobItem item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix)) {
+                    items.Add(item.Name);
+                }
+                return items;
+            }
+            catch
+            {
+                return null;
+            }
+
+        }
+
+        /// <summary>
+        /// 取得指定前置詞的 Blob 名稱的總大小(Bytes),例如指定目錄名稱為前置詞
+        /// </summary>      
+        /// <param name="prefix">篩選開頭名稱,Null代表容器總大小</param>
+        /// <returns>總大小(Bytes),如果為Null代表查無前置詞或者發生錯誤</returns>
+        public static async Task<(long?, Dictionary<string, double?>)> GetBlobsCatalogSize(this BlobContainerClient client, string prefix = null)
+        {
+            long? size = 0;
+            Dictionary<string, double?> dict = new Dictionary<string, double?>();
+            try
+            {
+                List<KeyValuePair<string, double?>> foderSize = new List<KeyValuePair<string, double?>>();
+                await foreach (BlobItem item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, prefix))
+                {
+                    var len = item.Properties.ContentLength;
+                    foderSize.Add(new KeyValuePair<string, double?>(item.Name.Split("/")[0], len));
+                    size += item.Properties.ContentLength;
+                };
+                foderSize.Select(x => new { x.Key, x.Value }).GroupBy(y=>y.Key).ToList().ForEach(g=> {
+                    var gpsize = g.Select(m => m.Value).Sum();
+                    dict[g.Key] = gpsize;
+                });
+                return (size, dict);
+            }
+            catch
+            {
+                return (size, dict);
+            }
+        }
+
+        public class OptUrl
+        {
+            public string url { get; set; }
+            public long size { get; set; }
+        }
+        /// <summary>
+        /// 取得指定前置詞的 Blob 名稱的總大小(Bytes),例如指定目錄名稱為前置詞
+        /// </summary>      
+        /// <param name="urls">多个文件的连接/param>
+        /// <returns>總大小(Bytes),如果為Null代表查無前置詞或者發生錯誤</returns>
+        public static async Task<List<OptUrl>> GetBlobsSize(this BlobContainerClient client, List<string> urls)
+        {
+            List<OptUrl> optUrls = new List<OptUrl>();
+            try
+            {
+                if (urls != null) {
+                    foreach (var url in urls)
+                    {
+                        OptUrl optUrl = new OptUrl { url = url, size = 0 };
+                        var eurl = System.Web.HttpUtility.UrlDecode(url, Encoding.UTF8);
+                        var blob = client.GetBlobClient(eurl);
+                        if (blob.Exists())
+                        {
+                            var props = await blob.GetPropertiesAsync();
+                            var size = props.Value.ContentLength;
+                            optUrl.size = size;
+                        }
+                        optUrls.Add(optUrl);
+                    }
+                }
+                
+                return optUrls;
+            }
+            catch
+            {
+                return optUrls;
+            }
+        }
         /// <summary>        
         /// <summary>        
         /// 批量刪除Blobs
         /// 批量刪除Blobs
         /// </summary>      
         /// </summary>      

+ 4 - 4
TEAMModelOS.SDK/DI/AzureStorage/AzureStorageTableExtensions.cs

@@ -259,7 +259,7 @@ namespace TEAMModelOS.SDK.DI
 
 
         public static async Task<List<T>> DeleteAll<T>(this AzureStorageFactory azureStorage,  List<T> entitys) where T : TableEntity, new()
         public static async Task<List<T>> DeleteAll<T>(this AzureStorageFactory azureStorage,  List<T> entitys) where T : TableEntity, new()
         {
         {
-            if (entitys.IsEmpty())
+            if (!entitys.IsNotEmpty())
             {
             {
                 return null;
                 return null;
             }
             }
@@ -300,7 +300,7 @@ namespace TEAMModelOS.SDK.DI
 
 
         public static async Task<List<T>> SaveOrUpdateAll<T>(this AzureStorageFactory azureStorage, List<T> entitys) where T : TableEntity, new()
         public static async Task<List<T>> SaveOrUpdateAll<T>(this AzureStorageFactory azureStorage, List<T> entitys) where T : TableEntity, new()
         {
         {
-            if (entitys.IsEmpty())
+            if (!entitys.IsNotEmpty())
             {
             {
                 return null;
                 return null;
             }
             }
@@ -340,7 +340,7 @@ namespace TEAMModelOS.SDK.DI
         }
         }
         public static async Task<List<T>> UpdateAll<T>(this AzureStorageFactory azureStorageFactory, List<T> entitys) where T : TableEntity, new()
         public static async Task<List<T>> UpdateAll<T>(this AzureStorageFactory azureStorageFactory, List<T> entitys) where T : TableEntity, new()
         {
         {
-            if (entitys.IsEmpty())
+            if (!entitys.IsNotEmpty())
             {
             {
                 return null;
                 return null;
             }
             }
@@ -380,7 +380,7 @@ namespace TEAMModelOS.SDK.DI
         }
         }
         public static async Task<List<T>> SaveAll<T>(this AzureStorageFactory azureStorage, List<T> entitys) where T : TableEntity, new()
         public static async Task<List<T>> SaveAll<T>(this AzureStorageFactory azureStorage, List<T> entitys) where T : TableEntity, new()
         {
         {
-            if (entitys.IsEmpty())
+            if (!entitys.IsNotEmpty())
             {
             {
                 return null;
                 return null;
             }
             }

+ 3 - 1
TEAMModelOS.SDK/DI/DingDing/DingDing.cs

@@ -95,7 +95,9 @@ namespace TEAMModelOS.SDK.DI
         [Description("f8bf19c9363e3b288e018856014bcbf89708f19b3aae009e203edd68af25c9fe")]
         [Description("f8bf19c9363e3b288e018856014bcbf89708f19b3aae009e203edd68af25c9fe")]
         BB訂單群組,
         BB訂單群組,
         [Description("a27b099b15a054374da41b9f66f72e5fc6b378e98418859f7c0ef46408941808")]
         [Description("a27b099b15a054374da41b9f66f72e5fc6b378e98418859f7c0ef46408941808")]
-        測試群組,
+        台北開發測試群組,
+        [Description("82aba2fccfa8442c575db3ac0442fa5aea90cd7574bb9a71d5abf210ea72a3aa,SEC3f38eca87cd4fd10505d136f91071a2e8b14cd863bd6bbafb24c612fc751a59a")]
+        成都开发測試群組,
         [Description("1a316ce4edc2db88231d40d80072b00f2751d7d9e2e5871c5dc061885b01c48d,SECff60201ac9b219943b9f8fc397fda1a617d0cbc140850f5ea9cb4f131479d39a")]
         [Description("1a316ce4edc2db88231d40d80072b00f2751d7d9e2e5871c5dc061885b01c48d,SECff60201ac9b219943b9f8fc397fda1a617d0cbc140850f5ea9cb4f131479d39a")]
         醍摩豆服務運維群組
         醍摩豆服務運維群組
     }
     }

+ 0 - 59
TEAMModelOS.SDK/Extension/JsonContent.cs

@@ -1,59 +0,0 @@
-using System.Text;
-using System.Text.Json;
-
-namespace System.Net.Http
-{
-    /// <summary>
-    /// JsonContent,預設application/json,使用System.Text.Json效能最佳化
-    /// </summary>
-    public class JsonContent : StringContent
-    {
-        #region Fields
-
-        private const string JsonContentType = "application/json";
-
-        #endregion Fields
-
-        #region Constructors
-
-        /// <summary>
-        /// Initializes a new instance of the System.Net.Http.JsonContent class
-        /// with default settings.
-        /// </summary>
-        /// <param name="content">The content to used to initialize the instance.</param>
-        public JsonContent(object content) : base(JsonSerializer.Serialize(content), Encoding.UTF8, JsonContentType)
-        {
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the System.Net.Http.JsonContent class
-        /// with given serialization settings.
-        /// </summary>
-        /// <param name="content">The content to used to initialize the instance.</param>
-        /// <param name="settings">The settings to used to serialize the content.</param>
-        public JsonContent(object content, JsonSerializerOptions settings) : base(JsonSerializer.Serialize(content, settings), Encoding.UTF8, JsonContentType)
-        {
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the System.Net.Http.JsonContent class
-        /// with given json content and default settings.
-        /// </summary>
-        /// <param name="json">The json content to used to initialize the instance.</param>
-        public JsonContent(string json) : base(json, Encoding.UTF8, JsonContentType)
-        {
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the System.Net.Http.JsonContent class
-        /// with given parameters.
-        /// </summary>
-        /// <param name="json">The json content to used to initialize the instance.</param>
-        /// <param name="encoding">The encoding to used to encode the content.</param>
-        public JsonContent(string json, Encoding encoding) : base(json, encoding, JsonContentType)
-        {
-        }
-
-        #endregion Constructors
-    }
-}

+ 0 - 41
TEAMModelOS.SDK/Extension/JsonIntToStringConverter.cs

@@ -1,41 +0,0 @@
-using System;
-using System.Buffers;
-using System.Buffers.Text;
-using System.Collections.Generic;
-using System.Text;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace TEAMModelOS.SDK.Extension
-{
-    /// <summary>
-    /// 允许或写入带引号的数字,之後.NET 5就不用這個轉換,改用[JsonNumberHandling]
-    /// </summary>
-    public class JsonIntToStringConverter : JsonConverter<int>
-    {
-        public override int Read(
-            ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
-        {
-            if (reader.TokenType == JsonTokenType.String)
-            {
-                ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
-
-                if (Utf8Parser.TryParse(span, out int number, out int bytesConsumed) && span.Length == bytesConsumed)
-                {
-                    return number;
-                }
-
-                if (int.TryParse(reader.GetString(), out number))
-                {
-                    return number;
-                }
-            }
-
-            return reader.GetInt32();
-        }
-
-        public override void Write(Utf8JsonWriter writer, int longValue, JsonSerializerOptions options) =>
-            writer.WriteStringValue(longValue.ToString());
-        
-    }
-}

+ 40 - 1
TEAMModelOS.SDK/Extension/Utils.cs

@@ -3,6 +3,7 @@ using Microsoft.IdentityModel.Tokens;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Drawing;
 using System.Drawing;
+using System.Drawing.Drawing2D;
 using System.Drawing.Imaging;
 using System.Drawing.Imaging;
 using System.IdentityModel.Tokens.Jwt;
 using System.IdentityModel.Tokens.Jwt;
 using System.IO;
 using System.IO;
@@ -144,14 +145,52 @@ namespace TEAMModelOS.SDK.Extension
 
 
                 return (true, "png", depth);
                 return (true, "png", depth);
             }
             }
-
+            
             if (fileheader.StartsWith("47,49,46,38,39,61,") || fileheader.StartsWith("47,49,46,38,37,61,"))
             if (fileheader.StartsWith("47,49,46,38,39,61,") || fileheader.StartsWith("47,49,46,38,37,61,"))
                 return (true, "gif", 0);
                 return (true, "gif", 0);
+
+            if (fileheader.StartsWith("1,0,0,0,"))
+                return (true, "emf", 0);
+
+            if (fileheader.StartsWith("1,0,9,0,0,3"))
+                return (true, "wmf", 0);
             //if (fileheader.StartsWith("4D,4D") || fileheader.StartsWith("49,49") || fileheader.StartsWith("46,4F,52,4D"))
             //if (fileheader.StartsWith("4D,4D") || fileheader.StartsWith("49,49") || fileheader.StartsWith("46,4F,52,4D"))
             //    return (true, "tif");
             //    return (true, "tif");
             return (false, "", 0);
             return (false, "", 0);
 
 
         }
         }
+
+        /// <summary>
+        /// 轉換EMF為PNG格式
+        /// </summary>
+        /// <param name="stream"></param>
+        /// <returns></returns>
+        public static string ConvertEMFtoPNG(Stream stream) 
+        {
+            using var image = Image.FromStream(stream);
+
+            //GDI+報錯,Azure Web App沙箱不支持GDI+部分權限
+            //using var nbase64ms = new MemoryStream();
+            //image.Save(nbase64ms, ImageFormat.Png); //保存為PNG格式
+            //byte[] data = nbase64ms.ToArray();
+            //string base64 = Convert.ToBase64String(data);
+            //return base64;
+
+            //Azure Web App沙箱不支持GDI+渲染部分EMF指令,可以出圖但會是空白
+            var pngimage = new Bitmap(image.Width, image.Height);
+            using (var graphics = Graphics.FromImage(pngimage))
+            {
+                graphics.CompositingQuality = CompositingQuality.HighSpeed;
+                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+                graphics.CompositingMode = CompositingMode.SourceCopy;
+                graphics.DrawImage(image, 0, 0, image.Width, image.Height);
+                using var nbase64ms = new MemoryStream();
+                pngimage.Save(nbase64ms, ImageFormat.Png); //保存為PNG格式
+                byte[] data = nbase64ms.ToArray();
+                string base64 = Convert.ToBase64String(data);
+                return base64;
+            }
+        }
         #endregion
         #endregion
 
 
 
 

+ 1 - 16
TEAMModelOS.SDK/Helper/Common/CollectionHelper/CollectionHelper.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections;
 using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
@@ -8,21 +8,6 @@ namespace TEAMModelOS.SDK.Helper.Common.CollectionHelper
 {
 {
     public static class CollectionHelper
     public static class CollectionHelper
     {
     {
-        /// <summary>
-        /// 判断集合是否为空
-        /// </summary>
-        /// <param name="collection"></param>
-        /// <returns></returns>
-        public static bool IsEmpty(this ICollection collection)
-        {
-            if (collection != null && collection.Count > 0)
-            {
-                return false;
-            }
-            else {
-                return true;
-            }
-        }
         /// <summary>
         /// <summary>
         /// 判断集合是否不为空
         /// 判断集合是否不为空
         /// </summary>
         /// </summary>

+ 5 - 24
TEAMModelOS.SDK/Helper/Common/FileHelper/FileHelper.cs

@@ -222,11 +222,7 @@ namespace TEAMModelOS.SDK.Helper.Common.FileHelper
                     fs.Close();
                     fs.Close();
                 }
                 }
             }
             }
-            catch (Exception ex)
-            {
-
-                throw ex;
-            }
+            catch { throw; }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -251,11 +247,7 @@ namespace TEAMModelOS.SDK.Helper.Common.FileHelper
                     File.WriteAllBytes(filePath, buffer);
                     File.WriteAllBytes(filePath, buffer);
                 }
                 }
             }
             }
-            catch (Exception ex)
-            {
-
-                throw ex;
-            }
+            catch { throw; }
         }
         }
         #endregion
         #endregion
 
 
@@ -521,11 +513,7 @@ namespace TEAMModelOS.SDK.Helper.Common.FileHelper
             {
             {
                 return Directory.GetDirectories(directoryPath);
                 return Directory.GetDirectories(directoryPath);
             }
             }
-            catch (Exception ex)
-            {
-
-                throw ex;
-            }
+            catch { throw; }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -548,11 +536,7 @@ namespace TEAMModelOS.SDK.Helper.Common.FileHelper
                     return Directory.GetDirectories(directoryPath, searchPattern, SearchOption.TopDirectoryOnly);
                     return Directory.GetDirectories(directoryPath, searchPattern, SearchOption.TopDirectoryOnly);
                 }
                 }
             }
             }
-            catch (Exception ex)
-            {
-
-                throw ex;
-            }
+            catch { throw; }
         }
         }
         #endregion
         #endregion
 
 
@@ -663,10 +647,7 @@ namespace TEAMModelOS.SDK.Helper.Common.FileHelper
                 //读取流
                 //读取流
                 return reader.ReadToEnd();
                 return reader.ReadToEnd();
             }
             }
-            catch (Exception ex)
-            {
-                throw ex;
-            }
+            catch { throw; }
             finally
             finally
             {
             {
                 //关闭流读取器
                 //关闭流读取器

+ 4 - 4
TEAMModelOS.SDK/Helper/Common/FileHelper/FileHelperCore.cs

@@ -85,9 +85,9 @@ namespace TEAMModelOS.SDK.Helper.Common.FileHelper
                 else
                 else
                     File.Create(MapPath(path)).Dispose();
                     File.Create(MapPath(path)).Dispose();
             }
             }
-            catch (Exception ex)
+            catch 
             {
             {
-                throw ex;
+                throw;
             }
             }
         }
         }
 
 
@@ -111,9 +111,9 @@ namespace TEAMModelOS.SDK.Helper.Common.FileHelper
                         File.Delete(MapPath(path));
                         File.Delete(MapPath(path));
                 }
                 }
             }
             }
-            catch (Exception ex)
+            catch 
             {
             {
-                throw ex;
+                throw;
             }
             }
         }
         }
         
         

+ 0 - 38
TEAMModelOS.SDK/Helper/Common/ReflectorExtensions/ClassSerializers.cs

@@ -1,38 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Runtime.Serialization.Formatters.Binary;
-using System.Text;
-
-namespace TEAMModelOS.SDK.Helper.Common.JsonHelper
-{
-    /// <summary>
-    ///   对象与二进制流的互相转换。
-    /// </summary>
-    public class ClassSerializers
-    {
-        #region 对象与二进制流的互相转换
-        /// <summary>
-        ///   将对象流转换成二进制流
-        /// </summary>
-        public static MemoryStream SerializeBinary(object request) //将对象流转换成二进制流
-        {
-            BinaryFormatter serializer = new BinaryFormatter();
-            MemoryStream memStream = new MemoryStream(); //创建一个内存流存储区
-            serializer.Serialize(memStream, request); //将对象序列化为内存流中
-            return memStream;
-        }
-        /// <summary>
-        ///   将二进制流转换成对象
-        /// </summary>
-        public static object DeSerializeBinary(MemoryStream memStream) //将二进制流转换成对象
-        {
-            memStream.Position = 0;
-            BinaryFormatter deserializer = new BinaryFormatter();
-            object newobj = deserializer.Deserialize(memStream); //将内存流反序列化为对象
-            memStream.Close(); //关闭内存流,并释放
-            return newobj;
-        }
-        #endregion
-    }
-}

+ 0 - 21
TEAMModelOS.SDK/Models/Cosmos/Common/CommonData.cs

@@ -1,21 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.SDK.Models.Cosmos.Student
-{
-    public class CommonData : CosmosEntity
-    {
-        public CommonData() {
-            pk = "Common";
-        }
-        /// <summary>
-        /// 业务类型  vote投票 survey问卷 exam评测 learn学习活动 homework作业活动
-        /// </summary>
-        public string type { get; set; }
-        public string name { get; set; }
-        public string startTime { get; set; }
-        public string endTime { get; set; }
-        public string scode { get; set; }
-    }
-}

+ 8 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/ExamClassResult.cs

@@ -17,6 +17,7 @@ namespace TEAMModelOS.SDK.Models
             studentIds = new List<string>();
             studentIds = new List<string>();
             studentScores = new List<List<double>>();
             studentScores = new List<List<double>>();
             sum = new List<double>();
             sum = new List<double>();
+            mark = new List<string>();
         }
         }
         public string school { get; set; }
         public string school { get; set; }
         public string examId { get; set; }
         public string examId { get; set; }
@@ -30,8 +31,15 @@ namespace TEAMModelOS.SDK.Models
         public List<string> studentIds { get; set; }
         public List<string> studentIds { get; set; }
         public List<List<string>> studentAnswers { get; set; }
         public List<List<string>> studentAnswers { get; set; }
         public List<List<double>> studentScores { get; set; }
         public List<List<double>> studentScores { get; set; }
+        //批注
+        public List<string> mark { get; set; }
         public string scope { get; set; }
         public string scope { get; set; }
         public List<double> sum { get; set; }
         public List<double> sum { get; set; }
+        public double average { get; set; }
+        //单科单班得分率
+        public double srate { get; set; }
+        //单科单班标准差
+        public double standard { get; set; }
     }
     }
 /*    public class PaperSimple {
 /*    public class PaperSimple {
         public string id { get; set; }
         public string id { get; set; }

+ 3 - 5
TEAMModelOS.SDK/Models/Cosmos/Common/Homework.cs

@@ -15,7 +15,8 @@ namespace TEAMModelOS.SDK.Models
     {        
     {        
         public Homework()
         public Homework()
         {
         {
-            target = new List<Target>();
+           
+
             resource = new List<ProcessRes>();
             resource = new List<ProcessRes>();
         }   
         }   
 
 
@@ -24,10 +25,7 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         /// </summary>
         public string name { get; set; }
         public string name { get; set; }
 
 
-        /// <summary>
-        /// 作业发布对象
-        /// </summary>
-        public List<Target> target { get; set; }
+       
 
 
         /// <summary>
         /// <summary>
         /// 发布模式 0 立即发布 1 定时
         /// 发布模式 0 立即发布 1 定时

+ 3 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/BaseItem.cs

@@ -7,6 +7,8 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
 {
 {
     public class BaseItem  : CosmosEntity
     public class BaseItem  : CosmosEntity
     {
     {
+        // 填空数量  
+        public int blankCount { get; set; }
         public bool objective { get; set; }
         public bool objective { get; set; }
         public string shaCode { get; set; }
         public string shaCode { get; set; }
         // 选项 单选 多选 判断
         // 选项 单选 多选 判断
@@ -23,7 +25,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
         /// </summary>
         /// </summary>
         public string pid { get; set; }
         public string pid { get; set; }
         //管理知识点
         //管理知识点
-        public List<string> points { get; set; }
+        public List<string> knowledge { get; set; }
         //认知层次 应用 综合 理解 评鉴 知识
         //认知层次 应用 综合 理解 评鉴 知识
         public int? field { get; set; }
         public int? field { get; set; }
 
 

+ 34 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/ClassChange.cs

@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
+{
+    /// <summary>
+    /// 学生名单变动
+    /// </summary>
+    public class ClassChange
+    {
+        /// <summary>
+        /// 教师名单加入的
+        /// </summary>
+        public List<string> tchjoin { get; set; } = new List<string>();
+        /// <summary>
+        /// 教师名单离开的
+        /// </summary>
+        public List<string> tchleave { get; set; } = new List<string>();
+        /// <summary>
+        /// 学校名单加入的
+        /// </summary>
+        public List<string> schjoin { get; set; } = new List<string>();
+        /// <summary>
+        /// 学校名单离开的
+        /// </summary>
+        public List<string> schleave { get; set; } = new List<string>();
+        public string listid { get; set; }
+        /// <summary>
+        /// 分区
+        /// </summary>
+        public string scope { get; set; }
+    }
+}

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Exercise.cs

@@ -14,7 +14,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
             pk = "Item";
             pk = "Item";
             children = new List<string>();
             children = new List<string>();
             answer = new List<string>();
             answer = new List<string>();
-            points = new List<string>();
+            knowledge = new List<string>();
             gradeIds = new List<string>();
             gradeIds = new List<string>();
             repair = new List<Repair>();
             repair = new List<Repair>();
         }
         }

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Repair.cs

@@ -16,7 +16,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
         /// <summary>
         /// <summary>
         /// 补救资源绝对地址
         /// 补救资源绝对地址
         /// </summary>
         /// </summary>
-        public string url { get; set; }
+        public string blobUrl { get; set; }
         /// 文件类型
         /// 文件类型
         /// </summary>
         /// </summary>
         public string type { get; set; }
         public string type { get; set; }

+ 16 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/SurveyRecord.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
+{
+    public  class SurveyRecord
+    {
+        /// <summary>
+        /// 问卷列表
+        /// </summary>
+        public List<List<string>> ans { get; set; }
+        public long time { get; set; }
+        public string userid { get; set; }
+    }
+}

+ 0 - 25
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/Target.cs

@@ -1,25 +0,0 @@
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.Text;
-
-namespace TEAMModelOS.SDK.Models
-{
-    /// <summary>
-    /// 发布对象
-    /// </summary>
-    
-    public class Target
-    {
-        [Required(ErrorMessage = "{0} 必须填写")]
-        
-        public string classroomCode { get; set; }
-        //[Required(ErrorMessage = "{0} 必须填写")]
-        //[ProtoMember(2)]
-        //public string code { get; set; }
-        
-        public string classroomName { get; set; }
-
-    }
-}

+ 15 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/VoteRecord.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
+{
+    public class VoteRecord
+    {
+        public Dictionary<string, int> opt { get; set; } = new Dictionary<string, int>();
+        public long time { get; set; }
+        public string userid { get; set; }
+        public string times { get; set; }
+        public string endpoint { get; set; }
+    }
+}

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/ItemInfo.cs

@@ -15,7 +15,7 @@ namespace TEAMModelOS.SDK.Models
             children = new List<ItemInfo>();
             children = new List<ItemInfo>();
             option = new List<CodeValue>();
             option = new List<CodeValue>();
             answer = new List<string>();
             answer = new List<string>();
-            points = new List<string>();
+            knowledge = new List<string>();
             gradeIds = new List<string>();
             gradeIds = new List<string>();
             repair = new List<Repair>();
             repair = new List<Repair>();
         }
         }

+ 45 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/JoinList.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.Common
+{
+
+    /*
+     * {
+            "id": "28936",
+            "code": "JoinList-hbcn",
+            "school": [
+                "schoolClassid1"
+            ],
+            "teacher": [
+                "stulistGUID"
+            ]
+        },
+        {
+            "id": "tmdid",
+            "code": "JoinList-tmdid",
+            "school": [
+                "schoolClassid1"
+            ],
+            "teacher": [
+                "schoolClassid1"
+            ]
+        }
+     */
+
+    /// <summary>
+    /// 暂时不使用
+    /// 学生已经加入的名单列表
+    /// 分学校创建的学生名单和教师创建的私人名单
+    /// </summary>
+    public class JoinList : CosmosEntity
+    {
+        public JoinList()
+        {
+            pk = "JoinList";
+        }
+        public List<string> school { get; set; } = new List<string>();
+        public List<string> teacher { get; set; } = new List<string>();
+    }
+}

+ 54 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/StuActivity.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.Common
+{
+
+    /*
+/vote/
+/survey/
+/exam/
+/learn/
+/homework/
+
+{
+    "id": "业务id",
+    "code": "学校编码-学生id",
+    "scode": "业务code",
+    "type": "业务类型,  vote投票 survey问卷 exam评测 learn学习活动 homework作业活动 课程 ",
+    "name": "业务名称",
+    "startTime": 1616411700000,
+    "endTime": 1616411700000,
+    "scope": "school/private",
+    "pk": "Activity",
+    "school": "hbcn",
+    "creatorId": "habook001",
+    "subjects": [
+        ""
+    ],
+    "classes":["class1 记录当前活动 选择包含这个学生的班级"]
+    "blob": "业务详情blob详情位置",
+    "recordUrl": "暂时不对其设计,隐藏规则调用,因为结算再次写入需要RU开销,学生参与业务的记录xxx/id/xxxx.json"
+}
+
+     */
+    /// <summary>
+    /// 学生集合的 学生活动相关列表。
+    /// </summary>
+    public class StuActivity : CosmosEntity
+    {
+       
+        public string scode { get; set; }
+        public string type { get; set; }
+        public string name { get; set; }
+        public long startTime { get; set; }
+        public long endTime { get; set; }
+        public string scope { get; set; }
+        public string school { get; set; }
+        public string creatorId { get; set; }
+        public List<string> subjects { get; set; }
+        public string blob { get; set; }
+        public string recordUrl { get; set; }
+    }
+}

+ 18 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/StuCourse.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.Common
+{
+    public class StuCourse :CosmosEntity
+    {
+        /// <summary>
+        /// 课程的分区键课程Code
+        /// </summary>
+        public string scode { get; set; } = "Course";
+        public string name { get; set; }
+        public  string scope { get; set; }
+        public string school { get; set; }
+        public string creatorId { get; set; }
+    }
+}

+ 28 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/StuList.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.Common
+{
+    public class StuList : CosmosEntity
+    {
+        public StuList()
+        {
+            pk = "StuList";
+        }
+        public List<Students> students { get; set; } = new List<Students>();
+        public List<string> tmids { get; set; }
+        public CourseInfo course { get; set; } = new CourseInfo();
+        public string name { get; set; }
+    }
+    public class Students
+    {
+        public string id { get; set; }
+        public string code { get; set; }
+    }
+    public class CourseInfo
+    {
+        public string id { get; set; }
+        public string code { get; set; }
+    }
+}

+ 118 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Survey.cs

@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+
+using TEAMModelOS.SDK.Context.Attributes.Azure;
+
+
+namespace TEAMModelOS.SDK.Models
+{
+    /// <summary>
+    /// 问卷调查
+    /// </summary>    
+    public class Survey : CosmosEntity
+    {
+        public Survey() {
+            pk = "Survey";
+            // questions = new List<Question>();
+            classes = new List<string>();
+            tmdids = new List<string>();
+        }
+        /// <summary>
+        ///发布层级 类型 school  teacher
+        /// </summary>
+        public string owner { get; set; }
+        /// <summary>
+        /// 学校编码或教室tmdid
+        /// </summary>
+        [Required(ErrorMessage = "owner 必须设置")]
+        public string school { get; set; }
+        /// <summary>
+        /// 问卷名称
+        /// </summary>
+        [Required(ErrorMessage = "name 必须设置")]
+        public string name { get; set; }
+        /// <summary>
+        ///  问卷描述
+        /// </summary>
+        public string description { get; set; }
+        //public string type { get; set; }   //normal', // 问卷类型
+        /// <summary>
+        /// 创建者的id 
+        /// </summary>
+        [Required(ErrorMessage = "creatorId 必须设置")]
+        public string creatorId { get; set; }
+        // public int year { get; set; }
+        /// <summary>
+        /// pending 待发布|going 已发布|finish 已结束
+        /// </summary>
+        //[Required(ErrorMessage = "progress 必须设置")]
+        public string progress { get; set; }
+        public string scope { get; set; }
+
+        public List<string> tmdids { get; set; }
+        public List<string> classes { get; set; }
+
+        /// <summary>
+        /// 开始时间
+        /// </summary>
+        public long startTime { get; set; }
+
+        /// <summary>
+        /// 结束时间
+        /// </summary>
+        public long endTime { get; set; }
+        public long createTime { get; set; } // 问卷发布时间
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        public long updateTime { get; set; }
+        //将问题放入Blob  hbcn/survey/问卷调查id.json  存放内容 Question的数组
+        public string  blob { get; set; }
+        // public List<Question> questions { get; set; }
+        /// <summary>
+        /// 学生作答记录/ 状态为finish时进行结算
+        /// </summary>
+        public string recordUrl { get; set; }
+        /// <summary>
+        /// 如果本题不是客观题 则为[]空数组
+        /// 客观题所有选项[["A","B","C","D"],["A","B"],[],["A","B"]]
+        /// </summary>
+        public List<List<string>> answers { get; set; }
+        /// <summary>
+        /// TTL删除改变状态使用
+        /// </summary>
+        public int? status { get; set; } = 0;
+    }
+
+    /// <summary>
+    ///问卷题目
+    /// </summary>
+    //public class Question {
+    //    /// <summary>
+    //    /// 题目id
+    //    /// </summary>
+    //    public string qid { get; set; }
+    //    /// <summary>
+    //    /// 问卷题目
+    //    /// </summary>
+    //    public string question { get; set; }
+    //    /// <summary>
+    //    /// 问卷题目的描述
+    //    /// </summary>
+    //    public string description { get; set; }
+    //    /// <summary>
+    //    /// 问卷选项
+    //    /// </summary>
+    //    public List<CodeValue> options { get; set; }
+    //    /// <summary>
+    //    /// 判断judge  多选multiple 单选single
+    //    /// </summary>
+    //    public string type { get; set; }
+    //    /// <summary>
+    //    /// 是否必需作答
+    //    /// </summary>
+    //    public bool required { get; set; }
+    //}
+}

+ 1 - 12
TEAMModelOS.SDK/Models/Cosmos/Common/Syllabus.cs

@@ -12,18 +12,7 @@ namespace TEAMModelOS.SDK.Models
     /// </summary>
     /// </summary>
     
     
     public class Syllabus : CosmosEntity
     public class Syllabus : CosmosEntity
-    {
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string code { get; set; }
-        //[PartitionKey(name = "Syllabuses")]
-        public string pk { get; set; }
-        public int? ttl { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string id { get; set; }
-
+    {  
         /// <summary>
         /// <summary>
         /// 册别编码
         /// 册别编码
         /// </summary>
         /// </summary>

+ 76 - 46
TEAMModelOS.SDK/Models/Cosmos/Common/Vote.cs

@@ -1,3 +1,4 @@
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
@@ -16,81 +17,110 @@ namespace TEAMModelOS.SDK.Models
         public Vote()
         public Vote()
         {
         {
             pk = "Vote";
             pk = "Vote";
-            options = new List<OptionsVote>();
+            options = new List<OptionVote>();
 
 
         }
         }
-
+        /// <summary>
+        /// 发布层级 类型 school  teacher
+        /// </summary>
+        public string owner { get; set; }
+        /// <summary>
+        /// 学校编码或教师tmdid
+        /// </summary>
+        [Required(ErrorMessage = "school 必须设置")]
+        public string school { get; set; }
         /// <summary>
         /// <summary>
         /// 投票名称
         /// 投票名称
         /// </summary>
         /// </summary>
+        [Required(ErrorMessage = "name 必须设置")]
         public string name { get; set; }
         public string name { get; set; }
-        public string school { get; set; }
+        /// <summary>
+        /// 创建者的id 
+        /// </summary>
+        [Required(ErrorMessage = "creatorId 必须设置")]
         public string creatorId { get; set; }
         public string creatorId { get; set; }
-        public int year { get; set; }
+        /// <summary>
+        /// 投票描述 
+        /// </summary>
+        public string description { get; set; }
+        /// <summary>
+        /// pending 待发布|going 已发布|finish 已结束
+        /// </summary>
+        //[Required(ErrorMessage = "progress 必须设置")]
         public string progress { get; set; }
         public string progress { get; set; }
-        public List<OptionsVote> options { get; set; }
+        /// <summary>
+        /// 投票选项
+        /// </summary>
+        public List<OptionVote> options { get; set; }
+        /// <summary>
+        /// //匿名投票,不公布投票人相关信息
+        /// </summary>
         public bool secret { get; set; }
         public bool secret { get; set; }
-        public int selectMax { get; set; }
-        public int stuCount { get; set; }
+        /// <summary>
+        /// 投票周期/once一次,day天,week周,month月,年year等
+        /// </summary>
+        [Required(ErrorMessage = "times 必须设置")]
+        public string times { get; set; }
+        //周期内可投票数
+        public int voteNum { get; set; }
+        //周期内是否允许重复投相同一个选项。
+        public bool repeat { get; set; } 
+        /// <summary>
+        /// school|private
+        /// </summary>
+        [Required(ErrorMessage = "scope 必须设置")]
         public string scope { get; set; }
         public string scope { get; set; }
-        public List<string> targetClassIds { get; set; }
         /// <summary>
         /// <summary>
-        /// 发布模式 0 立即发布 1 定时
+        /// 参与投票的教师醍摩豆id
         /// </summary>
         /// </summary>
-        public string publishModel { get; set; }
-
+        public List<string> tmdids { get; set; }
+        /// <summary>
+        ///  scope 为school时 是学校的班级  为private 时是私人班级
+        /// </summary>
+        public List<string> classes { get; set; }
+        
         /// <summary>
         /// <summary>
         /// 开始时间
         /// 开始时间
         /// </summary>
         /// </summary>
         public long startTime { get; set; }
         public long startTime { get; set; }
+        /// <summary>
+        /// 创建时间
+        /// </summary>
         public long createTime { get; set; }
         public long createTime { get; set; }
-
         /// <summary>
         /// <summary>
         /// 结束时间
         /// 结束时间
         /// </summary>
         /// </summary>
         public long endTime { get; set; }
         public long endTime { get; set; }
-
-
         /// <summary>
         /// <summary>
-        /// 投票描述
+        /// 更新时间
         /// </summary>
         /// </summary>
-        public string description { get; set; }
-
-
-        /*        /// <summary>
-                /// 投票附件
-                /// </summary>
-                [ProtoMember(9)]
-                public List<ProcessRes> resource { get; set; }
-        */
-
+        public long updateTime { get; set; }
         /// <summary>
         /// <summary>
-        /// 状态 (100:待发布 200:已发布 300:已结束)
+        /// 投票记录
         /// </summary>
         /// </summary>
-        public int status { get; set; }
-
-
-        /*        /// <summary>
-                /// 模式
-                /// </summary>
-                [ProtoMember(11)]
-                public List<string> other { get; set; }*/
-
-        /*
-                public string url { get; set; }
-
-                /// <summary>
-                /// 选项
-                /// </summary>
-                [ProtoMember(12)]
-                public List<Option> option { get; set; }*/
-
-        //public long sequenceNumber { get; set; }
+        public string recordUrl { get; set; }
+        /// <summary>
+        /// TTL删除改变状态使用
+        /// </summary>
+        public int? status { get; set; } = 0;
     }
     }
-    public class OptionsVote
+    /// <summary>
+    /// 投票选项
+    /// </summary>
+    public class OptionVote
     {
     {
+        /// <summary>
+        /// 投票编号
+        /// </summary>
         public string code { get; set; }
         public string code { get; set; }
+        /// <summary>
+        /// 投票对象
+        /// </summary>
         public string value { get; set; }
         public string value { get; set; }
+        /// <summary>
+        /// 投票对象描述
+        /// </summary>
         public string desc { get; set; }
         public string desc { get; set; }
     }
     }
 }
 }
+

+ 10 - 3
TEAMModelOS.SDK/Models/Cosmos/School/Class.cs

@@ -16,7 +16,7 @@ namespace TEAMModelOS.SDK.Models
         {
         {
             pk = "Class";
             pk = "Class";
             teacher = new Teachers();
             teacher = new Teachers();
-            students = new List<StudentSimple>();
+            //students = new List<StudentSimple>();
         }
         }
         /// <summary>
         /// <summary>
         /// 教室编号
         /// 教室编号
@@ -31,7 +31,7 @@ namespace TEAMModelOS.SDK.Models
         public string gradeId { get; set; }
         public string gradeId { get; set; }
         public string sn { get; set; }
         public string sn { get; set; }
 
 
-        public List<StudentSimple> students { get; set; }
+        //public List<StudentSimple> students { get; set; }
         /// <summary>
         /// <summary>
         /// TBL IRS 类型区分
         /// TBL IRS 类型区分
         /// </summary>
         /// </summary>
@@ -43,6 +43,10 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         /// </summary>
         public string openType { get; set; }
         public string openType { get; set; }
         public string scope { get; set; }
         public string scope { get; set; }
+        /// <summary>
+        /// 学生名单数据来源 1是不同学校的学生账号,2是扫码加入的醍摩豆ID
+        /// </summary>
+        public int source { get; set; }
         
         
     }
     }
 }
 }
@@ -54,7 +58,10 @@ public class Point
 }
 }
 public class StudentSimple
 public class StudentSimple
 {
 {
-
+    /// <summary>
+    /// 数据来源的分区键 如果是学校的编码 则是学校编码,如果是tmdid则是Base
+    /// </summary>
+    public string scode { get; set; }
     public string id { get; set; }
     public string id { get; set; }
 
 
     public string name { get; set; }
     public string name { get; set; }

+ 50 - 3
TEAMModelOS.SDK/Models/Cosmos/School/Course.cs

@@ -16,8 +16,8 @@ namespace TEAMModelOS.SDK.Models
             pk = "Course";
             pk = "Course";
             subject = new SubjectSimple();
             subject = new SubjectSimple();
             period = new PeriodSimple();
             period = new PeriodSimple();
-            teachers = new List<Teachers>();
-        }        
+            schedule = new List<Schedule>();
+        }
         /// <summary>
         /// <summary>
         /// 课程名称
         /// 课程名称
         /// </summary>
         /// </summary>
@@ -43,11 +43,52 @@ namespace TEAMModelOS.SDK.Models
         /// <summary>
         /// <summary>
         /// 任课教师范围
         /// 任课教师范围
         /// </summary>
         /// </summary>
-        public List<Teachers> teachers { get; set; }
+        //public List<Teachers> teachers { get; set; }
         public string scope { get; set; }
         public string scope { get; set; }
+        //public string notice { get; set; }
+        public List<Schedule> schedule { get; set; }
+        //public List<Customize> classes { get; set; }
+        public string no { get; set; }
+        ///新增字段
+        /// <summary>
+        /// 创建者的id 
+        /// </summary>
+        [Required(ErrorMessage = "creatorId 必须设置")]
+        public string creatorId { get; set; }
+        /// <summary>
+        /// 学校编码或教师tmdid
+        /// </summary>
+        [Required(ErrorMessage = "school 必须设置")]
+        public string school { get; set; }
+
+    }
+
+    public class Schedule
+    {
+        public string classId { get; set; }
+        public string teacherId { get; set; }
+        public string stulist { get; set; }
+        public List<timeInfo> time { get; set; } = new List<timeInfo>();
         public string notice { get; set; }
         public string notice { get; set; }
 
 
     }
     }
+
+    public class Customize
+    {
+        public string id { get; set; }
+        public string name { get; set; }
+        public Teachers teacher { get; set; } = new Teachers();
+        public string scope { get; set; }
+        public string code { get; set; }
+
+    }
+    public class timeInfo
+    {
+        public string id { get; set; }
+        public string week { get; set; }
+        //public string start { get; set; }
+        //public string end { get; set; }
+    }
     public class PeriodSimple
     public class PeriodSimple
     {
     {
 
 
@@ -60,6 +101,12 @@ namespace TEAMModelOS.SDK.Models
         public string id { get; set; }
         public string id { get; set; }
         public string name { get; set; }
         public string name { get; set; }
     }
     }
+/*    public class Info
+    {
+
+        public string id { get; set; }
+        public string name { get; set; }
+    }*/
     public class Teachers
     public class Teachers
     {
     {
         public string id { get; set; }
         public string id { get; set; }

+ 25 - 7
TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs

@@ -20,9 +20,12 @@ namespace TEAMModelOS.SDK.Models
             grades = new List<Grade>();
             grades = new List<Grade>();
             subjects = new List<ExamSubject>();
             subjects = new List<ExamSubject>();
             papers = new List<PaperSimple>();
             papers = new List<PaperSimple>();
-            targetClassIds = new List<string>();
-        }      
-
+            classes = new List<string>();
+        }
+        /// <summary>
+        ///发布层级 类型 school  teacher
+        /// </summary>
+        public string owner { get; set; }
         public string name { get; set; }
         public string name { get; set; }
         public string school { get; set; }
         public string school { get; set; }
         public string creatorId { get; set; }
         public string creatorId { get; set; }
@@ -54,11 +57,11 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         /// </summary>
         public string publish { get; set; }
         public string publish { get; set; }
 
 
-        public int status { get; set; }
+       
         public int year { get; set; }
         public int year { get; set; }
         public string range { get; set; }
         public string range { get; set; }
         public string source { get; set; }
         public string source { get; set; }
-        public List<string> targetClassIds { get; set; }
+        public List<string> classes { get; set; }
         public List<PaperSimple> papers { get; set; }
         public List<PaperSimple> papers { get; set; }
         ///考试类型 段考 stage  联考 union 平常考 normal 其他 other
         ///考试类型 段考 stage  联考 union 平常考 normal 其他 other
         /// </summary>
         /// </summary>
@@ -76,6 +79,16 @@ namespace TEAMModelOS.SDK.Models
         /// 所有试卷阅卷状态
         /// 所有试卷阅卷状态
         /// </summary>
         /// </summary>
         //public List<int> marks { get; set; }
         //public List<int> marks { get; set; }
+        /// <summary>
+        /// TTL删除改变状态使用
+        /// </summary>
+        public int? status { get; set; } = 0;
+        public double average { get; set; }
+        //得分率
+        public double sRate { get; set; }
+        //缺考人数
+        public List<string> lostStu { get; set; } = new List<string>();
+        public double standard { get; set; }
     }
     }
     public class Custom {
     public class Custom {
         public string id { get; set; }
         public string id { get; set; }
@@ -97,8 +110,13 @@ namespace TEAMModelOS.SDK.Models
         public string scope { get; set; }
         public string scope { get; set; }
         public int multipleRule { get; set; }
         public int multipleRule { get; set; }
         //该试卷配分情况
         //该试卷配分情况
-        public List<double> point { get; set; }
-        public List<List<string>> answers { get; set; }
+        public List<double> point { get; set; } = new List<double>();
+        public List<List<string>> answers { get; set; } = new List<List<string>>();
+        public List<List<string>> knowledge { get; set; } = new List<List<string>>();
+        //题目类型
+        public List<string> type { get; set; } = new List<string>();
+        public List<int> field { get; set; } = new List<int>();
+        //public List<Dictionary<string, int>> record { get; set; } = new List<Dictionary<string, int>>();
     }
     }
     /*public class Condition
     /*public class Condition
     {
     {

+ 7 - 0
TEAMModelOS.SDK/Models/Cosmos/School/ExamResult.cs

@@ -36,9 +36,16 @@ namespace TEAMModelOS.SDK.Models
         public string examId { get; set; }
         public string examId { get; set; }
         public string school { get; set; }
         public string school { get; set; }
         public int year { get; set; }
         public int year { get; set; }
+        public double average { get; set; }
+        public double sRate { get; set; }
+        public List<double> csRate { get; set; } = new List<double>();
+        public List<string> lostStus { get; set; } = new List<string>();
+        public double standard { get; set; }
+        public List<Dictionary<string, int>> record { get; set; } = new List<Dictionary<string, int>>();
     }
     }
     public class ClassRange {
     public class ClassRange {
 
 
+        public string gradeId { get; set; }
         public string id { get; set; }
         public string id { get; set; }
         public string name { get; set; }
         public string name { get; set; }
         public List<int> range { get; set; }
         public List<int> range { get; set; }

+ 4 - 0
TEAMModelOS.SDK/Models/Cosmos/School/Inner/Period.cs

@@ -25,6 +25,10 @@ namespace TEAMModelOS.SDK.Models
         //保存校区编码
         //保存校区编码
         public string campusId { get; set; }
         public string campusId { get; set; }
         public Analysis analysis { get; set; }
         public Analysis analysis { get; set; }
+        /// <summary>
+        /// 课程计划表
+        /// </summary>
+        public List<TimeTable> timetable { get; set; }
     }
     }
     public class Analysis
     public class Analysis
     {
     {

+ 82 - 0
TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs

@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.School
+{
+    /// <summary>
+    ///Teaching materials 教学材料 --- 知识点,知识块
+    /// </summary>    
+    public class Knowledge : CosmosEntity
+    {
+        public Knowledge() {
+            points = new List<string>();
+            blocks = new List<Block>();
+            pk = "Knowledge";
+        }
+        [Required(ErrorMessage = "owner 必须设置")]
+        public string owner { get; set; }
+        [Required(ErrorMessage = "scope 必须设置")]
+        public string scope { get; set; }
+        /// <summary>
+        /// 学段id
+        /// </summary>
+       [Required(ErrorMessage = "periodId 必须设置")]
+        public string periodId { get; set; }
+        /// <summary>
+        /// 学科id
+        /// </summary>
+        [Required(ErrorMessage = "subjectId 必须设置")]
+        public string subjectId { get; set; }
+        /// <summary>
+        /// 知识点
+        /// </summary>
+        public List<string> points { get; set; }
+        /// <summary>
+        /// 知识块
+        /// </summary>
+        public List<Block> blocks { get; set; }
+
+    }
+
+    public class Block { 
+        public string name { get; set; }
+        public List<string> points { get; set; }
+    }
+    /*
+    {
+        "id": "123",
+        "code": "Knowledge-hbcn-subjectId",
+        "periodId": "uuid",
+        
+        "points": [
+            "一元一次方程","二元一次方程","一元二次方程","直线方程","三元一次方程","鸡兔同笼问题","微积分方程","函数有界性","函数单调性","函数奇偶性","函数周期性","函数连续性","函数凹凸性",
+            "常函数","一次函数","二次函数","三次函数","四次函数","五次函数","幂函数","指数函数","对数函数","三角函数","反三角函数","常数函数",
+            "正弦函数","余弦函数","正切函数","余切函数","正割函数","余割函数","正矢函数","余矢函数","半正矢函数","半余矢函数","外正割函数","外余割函数"
+        ],
+        "block":[
+            {
+                "name": "方程式" ,
+                "points":["一元一次方程","二元一次方程","一元二次方程","直线方程","三元一次方程","鸡兔同笼问题","微积分方程"]
+            },
+            {
+                "name": "函数的特性" ,
+                "points": ["函数有界性","函数单调性","函数奇偶性","函数周期性","函数连续性","函数凹凸性"]
+            },
+            {
+                "name": "多项式函数" ,
+                "points": ["常函数","一次函数","二次函数","三次函数","四次函数","五次函数"]
+            },
+            {
+                "name":  "基本初等函数" ,
+                "points": ["幂函数","指数函数","对数函数","三角函数","反三角函数","常数函数"]
+            },
+            {
+                "name": "三角函数" ,
+                "points":["正弦函数","余弦函数","正切函数","余切函数","正割函数","余割函数","正矢函数","余矢函数","半正矢函数","半余矢函数","外正割函数","外余割函数"]
+            }
+        ]
+    }
+    */
+}

+ 2 - 4
TEAMModelOS.SDK/Models/Cosmos/School/School.cs

@@ -28,10 +28,7 @@ namespace TEAMModelOS.SDK.Models
         public string city { get; set; }
         public string city { get; set; }
         public int size { get; set; }
         public int size { get; set; }
 
 
-        /// <summary>
-        /// 课程计划表
-        /// </summary>
-        public List<TimeTable> timetable { get; set; }
+
         public string address { get; set; }
         public string address { get; set; }
         public string picture { get; set; }
         public string picture { get; set; }
 
 
@@ -41,6 +38,7 @@ namespace TEAMModelOS.SDK.Models
 
 
     public class TimeTable
     public class TimeTable
     {
     {
+        public string id { get; set; }
         public string label { get; set; }
         public string label { get; set; }
         public string time { get; set; }
         public string time { get; set; }
         public string type { get; set; }
         public string type { get; set; }

+ 4 - 4
TEAMModelOS.SDK/Models/Cosmos/School/SchoolProduct.cs

@@ -24,10 +24,10 @@ namespace TEAMModelOS.SDK.Models
 
 
     public class Aclassone
     public class Aclassone
     {
     {
-        public List<string> ids { get; set; }
+        public List<string> ids { get; set; } //固定分配的學生ID
+        public List<string> outids { get; set; } //過期被回收的學生ID(無法使用,待數量購足後回復移至ids)
         public int total { get; set; }
         public int total { get; set; }
         public int used { get; set; }
         public int used { get; set; }
-        public int less { get; set; }
     }
     }
 
 
     public class SerialInfoBase
     public class SerialInfoBase
@@ -138,8 +138,8 @@ namespace TEAMModelOS.SDK.Models
     }
     }
     public class ServiceProductAclassoneResult : ServiceProductResult
     public class ServiceProductAclassoneResult : ServiceProductResult
     {
     {
-        public int used { get; set; }
-        public int less { get; set; }
+        public int staUsed { get; set; }
+        public int dynUsed { get; set; }
     }
     }
     public class ServiceProductAuth
     public class ServiceProductAuth
     {
     {

+ 0 - 129
TEAMModelOS.SDK/Models/Cosmos/School/Survey.cs

@@ -1,129 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.Text;
-
-using TEAMModelOS.SDK.Context.Attributes.Azure;
-
-
-namespace TEAMModelOS.SDK.Models
-{
-    /// <summary>
-    /// 问卷调查
-    /// </summary>    
-    public class Survey : CosmosEntity
-    {
-        public Survey() {
-            pk = "Survey";
-            questions = new List<Questions>();
-            classes = new List<Classes>();
-        }
-       
-        public string name { get; set; }   //测试问卷名称', // 问卷名称
-        public string description { get; set; }   //测试问卷描述', // 问卷描述
-        //public string type { get; set; }   //normal', // 问卷类型
-        public string school { get; set; }
-        public string creatorId { get; set; }
-        public int year { get; set; }
-        public string progress { get; set; }
-        public List<Questions> questions { get; set; }
-        public List<string> targetClassIds { get; set; }
-        public int stuCount { get; set; }
-        public int status { get; set; } // 问卷状态(100:待发布 200:已发布 300:已结束)
-        /// <summary>
-        /// 发布对象
-        /// </summary>
-        //[ProtoMember(4)]
-        //public List<Target> target { get; set; }
-
-        /// <summary>
-        /// 发布模式 0 立即发布 1 定时
-        /// </summary>
-        public string publishModel { get; set; }
-
-        /// <summary>
-        /// 开始时间
-        /// </summary>
-        public long startTime { get; set; }
-
-        /// <summary>
-        /// 结束时间
-        /// </summary>
-        public long endTime { get; set; }
-        public long createTime { get; set; } // 问卷发布时间
-        public List<Classes> classes { get; set; }
-
-        //public long sequenceNumber { get; set; }
-
-        public string url { get; set; }
-        public string scope { get; set; }
-
-    }
-    /*public class Item {
-        public string stem { get; set; }
-        /// <summary>
-        ///  Complete Single Multiple Subjective, Judge判断
-        /// </summary>
-        //public string type { get; set; }
-        public bool required { get; set; }
-        public int order { get; set; }
-        public string description { get; set; } = null;
-        public List<CodeValue> options { get; set; }
-        public List<CodeVal> result { get; set; }
-    }*/
-     public class Questions { 
-        public string qid { get; set; }
-        public string question { get; set; }
-        public List<Options> option { get; set; }
-        public string type { get; set; }
-        public QuestionResult result { get; set; }
-
-    }
-    public class Options { 
-        public string code { get; set; }
-        public string value { get; set; }
-        public Result result { get; set; }
-    }
-    public class QuestionResult
-    {
-        public double finish { get; set; }
-        public double finishRate { get; set; }
-    }
-    public class Result { 
-        public double count { get; set; }
-        public double rate { get; set; }
-    }
-    public class Classes { 
-        public string code { get; set; }
-        public string id { get; set; }
-        public string name { get; set; }
-        public string scope { get; set; }
-        public Result result { get; set; }
-        public List<StudentInfo> students { get; set; }
-        public List<AnswerRate> answers { get; set; }
-    }
-    public class AnswerRate {
-        public string qid { get; set; }
-        public double answerRate { get; set; }
-        public List<Options> option { get; set; }
-    }
-    public class StudentInfo {
-        public string id { get; set; }
-        public string name { get; set; }
-        public long finishTime { get; set; }
-        public List<AnswerInfo> answers { get; set; }
-        public ResultInfo result { get; set; }
-    }
-    public class ResultInfo
-    {
-        public double answerRate { get; set; }
-    }
-    public class AnswerInfo { 
-        public string qid { get; set; }
-        public string answer { get; set; }
-    }
-    /*public class CodeVal{
-        public string code { get; set; }
-        public int value { get; set; }
-    }*/
-}

+ 8 - 0
TEAMModelOS.SDK/Models/Cosmos/Student/Student.cs

@@ -16,5 +16,13 @@ namespace TEAMModelOS.SDK.Models
         public string pw { get; set; }
         public string pw { get; set; }
         public string salt { get; set; }
         public string salt { get; set; }
         public string year { get; set; }
         public string year { get; set; }
+        //座位号
+        public string no { get; set; }
+        //绑定班级Id
+        public string classId { get; set; }
+        //分组信息
+        public string groupId { get; set; }
+        public string groupName { get; set; }
+
     }
     }
 }
 }

+ 0 - 38
TEAMModelOS.SDK/Models/Cosmos/Student/SurveyRecord.cs

@@ -1,38 +0,0 @@
-using DocumentFormat.OpenXml.Math;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.Text;
-using TEAMModelOS.SDK.Context.Attributes.Azure;
-using TEAMModelOS.SDK.DI;
-
-namespace TEAMModelOS.SDK.Models
-{    
-    public class SurveyRecord : CosmosEntity
-    {
-        public SurveyRecord() {
-            classroom = new ClassroomItem();
-        }
-
-        /// <summary>
-        /// 姓名
-        /// </summary>
-        public string name { get; set; }
-
-        /// <summary>
-        /// 上课班级
-        /// </summary>
-        public ClassroomItem classroom { get; set; }
-
-        /// <summary>
-        /// 提交时间
-        /// </summary>
-        public long submitTime { get; set; }
-
-        public List<SurveyAnswer> answers { get; set; }
-    }
-    public class SurveyAnswer { 
-        public int order { get; set; }
-        public List<string> answer { get; set; }
-    }
-}

+ 0 - 41
TEAMModelOS.SDK/Models/Cosmos/Student/VoteRecord.cs

@@ -1,41 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.Text;
-using TEAMModelOS.SDK.Context.Attributes.Azure;
-using TEAMModelOS.SDK.DI;
-
-namespace TEAMModelOS.SDK.Models
-{    
-    public class VoteRecord : CosmosEntity
-    {
-
-        public VoteRecord()
-        {
-            classroom = new ClassroomItem();
-        }
-
-        /// <summary>
-        /// 姓名
-        /// </summary>
-        public string name { get; set; }
-
-        /// <summary>
-        /// 上课班级
-        /// </summary>
-        public ClassroomItem classroom { get; set; }
-
-
-
-        /// <summary>
-        /// 提交时间
-        /// </summary>
-        public long submitTime { get; set; }
-
-        /// <summary>
-        /// 选项
-        /// </summary>
-        public string option { get; set; }
-
-    }
-}

+ 0 - 303
TEAMModelOS.SDK/Module/Cache/CSRedisCacheService.cs

@@ -1,303 +0,0 @@
-using Microsoft.Extensions.Caching.Distributed;
-using Microsoft.Extensions.Caching.Redis;
- 
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-
-namespace TEAMModelOS.SDK.Module.Cache
-{
-    public class CSRedisCacheService :ICacheService//,IDisposable
-    {
-        protected IDistributedCache _cache;
-
-        public CSRedisCacheService(IDistributedCache cache  )
-        {
-            _cache = cache;
-        }
-
-    
-     /// <summary>
-     /// 验证缓存项是否存在
-     /// </summary>
-     /// <param name="key">缓存Key</param>
-     /// <returns></returns>
-    public bool Exists(string key)
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-          return  RedisHelper.Instance.Exists(key);
-          //  return _cache.KeyExists(GetKeyForRedis(key));
-    }/// <summary>
-     /// 添加缓存
-     /// </summary>
-     /// <param name="key">缓存Key</param>
-     /// <param name="value">缓存Value</param>
-     /// <returns></returns>
-    public bool Add(string key, object value)
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-         _cache.Set(key, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value)));
-        return Exists(key);
-    }
-    /// <summary>
-    /// 添加缓存
-    /// </summary>
-    /// <param name="key">缓存Key</param>
-    /// <param name="value">缓存Value</param>
-    /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效)</param>
-    /// <param name="expiressAbsoulte">绝对过期时长</param>
-    /// <returns></returns>
-    public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-             _cache.Set(key, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value)), new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow=expiressAbsoulte,SlidingExpiration=expiresSliding});
-            return Exists(key);
-        }
-    /// <summary>
-    /// 添加缓存
-    /// </summary>
-    /// <param name="key">缓存Key</param>
-    /// <param name="value">缓存Value</param>
-    /// <param name="expiresIn">缓存时长</param>
-    /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效)</param>
-    /// <returns></returns>
-    public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false)
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-            _cache.Set(key, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value)), new DistributedCacheEntryOptions() { SlidingExpiration = expiresIn });
-            return Exists(key);
-          //  return _cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), expiresIn);
-    }/// <summary>
-     /// 删除缓存
-     /// </summary>
-     /// <param name="key">缓存Key</param>
-     /// <returns></returns>
-    public bool Remove(string key)
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-         _cache.Remove(key);
-        return !Exists(key);
-     }
-    /// <summary>
-    /// 批量删除缓存
-    /// </summary>
-    /// <param name="key">缓存Key集合</param>
-    /// <returns></returns>
-    public void RemoveAll(IEnumerable<string> keys)
-    {
-        if (keys == null)
-        {
-            throw new ArgumentNullException(nameof(keys));
-        }
-
-        keys.ToList().ForEach(item => Remove(item));
-    }
-
-
-    /// <summary>
-    /// 获取缓存
-    /// </summary>
-    /// <param name="key">缓存Key</param>
-    /// <returns></returns>
-    public T Get<T>(string key) where T : class
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-
-        var value = _cache.GetString(key);
-
-        if ( string.IsNullOrEmpty(value))
-        {
-            return default(T);
-        }
-
-            return JsonSerializer.Deserialize<T>(value);
-    }
-
-    /// <summary>
-    /// 获取缓存
-    /// </summary>
-    /// <param name="key">缓存Key</param>
-    /// <returns></returns>
-    public object Get(string key)
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-
-        var value = _cache.GetString(key);
-
-        if (string.IsNullOrEmpty(value))
-        {
-            return null;
-        }
-        return JsonSerializer.Deserialize<object>(value);
-    }   /// <summary>
-        /// 获取缓存集合
-        /// </summary>
-        /// <param name="keys">缓存Key集合</param>
-        /// <returns></returns>
-    public IDictionary<string, object> GetAll(IEnumerable<string> keys)
-    {
-        if (keys == null)
-        {
-            throw new ArgumentNullException(nameof(keys));
-        }
-        var dict = new Dictionary<string, object>();
-
-        keys.ToList().ForEach(item => dict.Add(item, Get(item)));
-
-        return dict;
-    }
-
-    /// <summary>
-    /// 修改缓存
-    /// </summary>
-    /// <param name="key">缓存Key</param>
-    /// <param name="value">新的缓存Value</param>
-    /// <returns></returns>
-    public bool Replace(string key, object value)
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-
-        if (Exists(key))
-            if (!Remove(key))
-                return false;
-
-        return Add(key, value);
-
-    }
-    /// <summary>
-    /// 修改缓存
-    /// </summary>
-    /// <param name="key">缓存Key</param>
-    /// <param name="value">新的缓存Value</param>
-    /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-    /// <param name="expiressAbsoulte">绝对过期时长</param>
-    /// <returns></returns>
-    public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-
-        if (Exists(key))
-            if (!Remove(key))
-                return false;
-
-        return Add(key, value, expiresSliding, expiressAbsoulte);
-    }
-    /// <summary>
-    /// 修改缓存
-    /// </summary>
-    /// <param name="key">缓存Key</param>
-    /// <param name="value">新的缓存Value</param>
-    /// <param name="expiresIn">缓存时长</param>
-    /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-    /// <returns></returns>
-    public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false)
-    {
-        if (key == null)
-        {
-            throw new ArgumentNullException(nameof(key));
-        }
-
-        if (Exists(key))
-            if (!Remove(key)) return false;
-
-        return Add(key, value, expiresIn, isSliding);
-    }
-    //public void Dispose()
-    //{
-    //    if (_connection != null)
-    //        _connection.Dispose();
-    //    GC.SuppressFinalize(this);
-    //}
-
-
-    public async Task<bool> ExistsAsync(string key)
-    {
-        return await Task.Run(() => Exists(key));
-    }
-
-    public async Task<bool> AddAsync(string key, object value)
-    {
-        return await Task.Run(() => Add(key, value));
-    }
-
-    public async Task<bool> AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
-    {
-        return await Task.Run(() => Add(key, value, expiresSliding, expiressAbsoulte));
-    }
-
-    public async Task<bool> AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false)
-    {
-        return await Task.Run(() => Add(key, value, expiresIn, isSliding));
-    }
-
-    public async Task<bool> RemoveAsync(string key)
-    {
-        return await Task.Run(() => Remove(key));
-    }
-
-    public async Task RemoveAllAsync(IEnumerable<string> keys)
-    {
-        await Task.Run(() => RemoveAll(keys));
-    }
-
-    public async Task<T> GetAsync<T>(string key) where T : class
-    {
-        return await Task.Run(() => Get<T>(key));
-    }
-
-    public async Task<object> GetAsync(string key)
-    {
-        return await Task.Run(() => Get(key));
-    }
-
-    public async Task<IDictionary<string, object>> GetAllAsync(IEnumerable<string> keys)
-    {
-        return await Task.Run(() => GetAll(keys));
-    }
-
-    public async Task<bool> ReplaceAsync(string key, object value)
-    {
-        return await Task.Run(() => Replace(key, value));
-    }
-
-    public async Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
-    {
-        return await Task.Run(() => Replace(key, value, expiresSliding, expiressAbsoulte));
-    }
-
-    public async Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false)
-    {
-        return await Task.Run(() => Replace(key, value, expiresIn, isSliding));
-    }
-}
-}

+ 0 - 205
TEAMModelOS.SDK/Module/Cache/ICacheService.cs

@@ -1,205 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace TEAMModelOS.SDK.Module.Cache
-{
-    public interface ICacheService
-    {
-        /// <summary>
-        /// 验证缓存项是否存在
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <returns></returns>
-        bool Exists(string key);
-
-        /// <summary>
-        /// 验证缓存项是否存在(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <returns></returns>
-        Task<bool> ExistsAsync(string key);
-        /// <summary>
-        /// 添加缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">缓存Value</param>
-        /// <returns></returns>
-        bool Add(string key, object value);
-
-        /// <summary>
-        /// 添加缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">缓存Value</param>
-        /// <returns></returns>
-        Task<bool> AddAsync(string key, object value);
-
-        /// <summary>
-        /// 添加缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">缓存Value</param>
-        /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <param name="expiressAbsoulte">绝对过期时长</param>
-        /// <returns></returns>
-        bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
-
-        /// <summary>
-        /// 添加缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">缓存Value</param>
-        /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <param name="expiressAbsoulte">绝对过期时长</param>
-        /// <returns></returns>
-        Task<bool> AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
-
-        /// <summary>
-        /// 添加缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">缓存Value</param>
-        /// <param name="expiresIn">缓存时长</param>
-        /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <returns></returns>
-        bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false);
-
-        /// <summary>
-        /// 添加缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">缓存Value</param>
-        /// <param name="expiresIn">缓存时长</param>
-        /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <returns></returns>
-        Task<bool> AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false);
-        /// <summary>
-        /// 删除缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <returns></returns>
-        bool Remove(string key);
-
-        /// <summary>
-        /// 删除缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <returns></returns>
-        Task<bool> RemoveAsync(string key);
-
-        /// <summary>
-        /// 批量删除缓存
-        /// </summary>
-        /// <param name="key">缓存Key集合</param>
-        /// <returns></returns>
-        void RemoveAll(IEnumerable<string> keys);
-
-        /// <summary>
-        /// 批量删除缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key集合</param>
-        /// <returns></returns>
-        Task RemoveAllAsync(IEnumerable<string> keys);
-
-        /// <summary>
-        /// 获取缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <returns></returns>
-        T Get<T>(string key) where T : class;
-
-        /// <summary>
-        /// 获取缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <returns></returns>
-        Task<T> GetAsync<T>(string key) where T : class;
-
-        /// <summary>
-        /// 获取缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <returns></returns>
-        object Get(string key);
-
-        /// <summary>
-        /// 获取缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <returns></returns>
-        Task<object> GetAsync(string key);
-
-        /// <summary>
-        /// 获取缓存集合
-        /// </summary>
-        /// <param name="keys">缓存Key集合</param>
-        /// <returns></returns>
-        IDictionary<string, object> GetAll(IEnumerable<string> keys);
-
-        /// <summary>
-        /// 获取缓存集合(异步方式)
-        /// </summary>
-        /// <param name="keys">缓存Key集合</param>
-        /// <returns></returns>
-        Task<IDictionary<string, object>> GetAllAsync(IEnumerable<string> keys);
-
-        /// <summary>
-        /// 修改缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">新的缓存Value</param>
-        /// <returns></returns>
-        bool Replace(string key, object value);
-
-        /// <summary>
-        /// 修改缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">新的缓存Value</param>
-        /// <returns></returns>
-        Task<bool> ReplaceAsync(string key, object value);
-
-        /// <summary>
-        /// 修改缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">新的缓存Value</param>
-        /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <param name="expiressAbsoulte">绝对过期时长</param>
-        /// <returns></returns>
-        bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
-
-        /// <summary>
-        /// 修改缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">新的缓存Value</param>
-        /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <param name="expiressAbsoulte">绝对过期时长</param>
-        /// <returns></returns>
-        Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
-
-        /// <summary>
-        /// 修改缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">新的缓存Value</param>
-        /// <param name="expiresIn">缓存时长</param>
-        /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <returns></returns>
-        bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false);
-
-        /// <summary>
-        /// 修改缓存(异步方式)
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">新的缓存Value</param>
-        /// <param name="expiresIn">缓存时长</param>
-        /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <returns></returns>
-        Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false);
-
-    }
-}

+ 0 - 311
TEAMModelOS.SDK/Module/Cache/MemoryCacheService.cs

@@ -1,311 +0,0 @@
-using Microsoft.Extensions.Caching.Memory;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace TEAMModelOS.SDK.Module.Cache
-{
-    public class MemoryCacheService : ICacheService ,IDisposable
-    {
-        protected IMemoryCache _cache;
-
-        public MemoryCacheService(IMemoryCache cache)
-        {
-            _cache = cache;
-        }/// <summary>
-         /// 验证缓存项是否存在
-         /// </summary>
-         /// <param name="key">缓存Key</param>
-         /// <returns></returns>
-        public bool Exists(string key)
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            object cached;
-            return _cache.TryGetValue(key, out cached);
-        }/// <summary>
-         /// 添加缓存
-         /// </summary>
-         /// <param name="key">缓存Key</param>
-         /// <param name="value">缓存Value</param>
-         /// <returns></returns>
-        public bool Add(string key, object value)
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            if (value == null)
-            {
-                throw new ArgumentNullException(nameof(value));
-            }
-            _cache.Set(key, value);
-            return Exists(key);
-        }
-        /// <summary>
-        /// 添加缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">缓存Value</param>
-        /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <param name="expiressAbsoulte">绝对过期时长</param>
-        /// <returns></returns>
-        public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            if (value == null)
-            {
-                throw new ArgumentNullException(nameof(value));
-            }
-            _cache.Set(key, value,
-                    new MemoryCacheEntryOptions()
-                    .SetSlidingExpiration(expiresSliding)
-                    .SetAbsoluteExpiration(expiressAbsoulte)
-                    );
-
-            return Exists(key);
-        }
-        /// <summary>
-        /// 添加缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">缓存Value</param>
-        /// <param name="expiresIn">缓存时长</param>
-        /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <returns></returns>
-        public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false)
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            if (value == null)
-            {
-                throw new ArgumentNullException(nameof(value));
-            }
-            if (isSliding)
-                _cache.Set(key, value,
-                    new MemoryCacheEntryOptions()
-                    .SetSlidingExpiration(expiresIn)
-                    );
-            else
-                _cache.Set(key, value,
-                new MemoryCacheEntryOptions()
-                .SetAbsoluteExpiration(expiresIn)
-                );
-
-            return Exists(key);
-        }/// <summary>
-         /// 删除缓存
-         /// </summary>
-         /// <param name="key">缓存Key</param>
-         /// <returns></returns>
-        public bool Remove(string key)
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            _cache.Remove(key);
-
-            return !Exists(key);
-        }
-        /// <summary>
-        /// 批量删除缓存
-        /// </summary>
-        /// <param name="key">缓存Key集合</param>
-        /// <returns></returns>
-        public void RemoveAll(IEnumerable<string> keys)
-        {
-            if (keys == null)
-            {
-                throw new ArgumentNullException(nameof(keys));
-            }
-
-            keys.ToList().ForEach(item => _cache.Remove(item));
-        }/// <summary>
-         /// 获取缓存
-         /// </summary>
-         /// <param name="key">缓存Key</param>
-         /// <returns></returns>
-        public T Get<T>(string key) where T : class
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            return _cache.Get(key) as T;
-        }
-        /// <summary>
-        /// 获取缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <returns></returns>
-        public object Get(string key)
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            return _cache.Get(key);
-        }
-        /// <summary>
-        /// 获取缓存集合
-        /// </summary>
-        /// <param name="keys">缓存Key集合</param>
-        /// <returns></returns>
-        public IDictionary<string, object> GetAll(IEnumerable<string> keys)
-        {
-            if (keys == null)
-            {
-                throw new ArgumentNullException(nameof(keys));
-            }
-
-            var dict = new Dictionary<string, object>();
-
-            keys.ToList().ForEach(item => dict.Add(item, _cache.Get(item)));
-
-            return dict;
-        }/// <summary>
-         /// 修改缓存
-         /// </summary>
-         /// <param name="key">缓存Key</param>
-         /// <param name="value">新的缓存Value</param>
-         /// <returns></returns>
-        public bool Replace(string key, object value)
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            if (value == null)
-            {
-                throw new ArgumentNullException(nameof(value));
-            }
-            if (Exists(key))
-                if (!Remove(key)) return false;
-
-            return Add(key, value);
-
-        }
-        /// <summary>
-        /// 修改缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">新的缓存Value</param>
-        /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <param name="expiressAbsoulte">绝对过期时长</param>
-        /// <returns></returns>
-        public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            if (value == null)
-            {
-                throw new ArgumentNullException(nameof(value));
-            }
-            if (Exists(key))
-                if (!Remove(key)) return false;
-
-            return Add(key, value, expiresSliding, expiressAbsoulte);
-        }
-        /// <summary>
-        /// 修改缓存
-        /// </summary>
-        /// <param name="key">缓存Key</param>
-        /// <param name="value">新的缓存Value</param>
-        /// <param name="expiresIn">缓存时长</param>
-        /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
-        /// <returns></returns>
-        public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false)
-        {
-            if (key == null)
-            {
-                throw new ArgumentNullException(nameof(key));
-            }
-            if (value == null)
-            {
-                throw new ArgumentNullException(nameof(value));
-            }
-            if (Exists(key))
-                if (!Remove(key)) return false;
-
-            return Add(key, value, expiresIn, isSliding);
-        }
-        public void Dispose()
-        {
-            if (_cache != null)
-                _cache.Dispose();
-            GC.SuppressFinalize(this);
-        }
-
-        public async Task<bool> ExistsAsync(string key)
-        {
-            return await Task.Run(() => Exists(key));
-        }
-
-        public async Task<bool> AddAsync(string key, object value)
-        {
-            return await Task.Run(() => Add(key, value));
-        }
-
-        public async Task<bool> AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
-        {
-            return await Task.Run(() => Add(key, value, expiresSliding, expiressAbsoulte));
-        }
-
-        public async Task<bool> AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false)
-        {
-            return await Task.Run(() => Add(key, value, expiresIn, isSliding));
-        }
-
-        public async Task<bool> RemoveAsync(string key)
-        {
-            return await Task.Run(() => Remove(key));
-        }
-
-        public async Task RemoveAllAsync(IEnumerable<string> keys)
-        {
-            await Task.Run(() => RemoveAll(keys));
-        }
-
-        public async  Task<T> GetAsync<T>(string key) where T : class
-        {
-          return  await Task.Run(() => Get<T>(key));
-        }
-
-        public async Task<object> GetAsync(string key)
-        {
-            return await Task.Run(() => Get(key));
-        }
-
-        public async Task<IDictionary<string, object>> GetAllAsync(IEnumerable<string> keys)
-        {
-            return await Task.Run(() => GetAll(keys));
-        }
-
-        public async Task<bool> ReplaceAsync(string key, object value)
-        {
-            return await Task.Run(() => Replace(key,value));
-        }
-
-        public async Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
-        {
-            return await Task.Run(() => Replace(key, value, expiresSliding, expiressAbsoulte));
-        }
-
-        public async Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false)
-        {
-            return await Task.Run(() => Replace(key, value, expiresIn, isSliding));
-        }
-    }
-}

+ 1 - 1
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -8,7 +8,7 @@
     <PackageReleaseNotes>发版</PackageReleaseNotes>
     <PackageReleaseNotes>发版</PackageReleaseNotes>
   </PropertyGroup>
   </PropertyGroup>
 
 
-  
+
 
 
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="AspectCore.Extensions.Reflection" Version="2.2.0" />
     <PackageReference Include="AspectCore.Extensions.Reflection" Version="2.2.0" />

+ 2 - 2
TEAMModelOS/ClientApp/package.json

@@ -21,7 +21,7 @@
 		"@vue/eslint-config-standard": "^4.0.0",
 		"@vue/eslint-config-standard": "^4.0.0",
 		"animate.css": "^3.7.2",
 		"animate.css": "^3.7.2",
 		"apexcharts": "^3.20.0",
 		"apexcharts": "^3.20.0",
-		"axios": "^0.19.0",
+		"axios": "^0.21.1",
 		"bcryptjs": "^2.4.3",
 		"bcryptjs": "^2.4.3",
 		"core-js": "^3.1.2",
 		"core-js": "^3.1.2",
 		"d3": "^5.9.2",
 		"d3": "^5.9.2",
@@ -32,7 +32,6 @@
 		"file-saver": "^2.0.2",
 		"file-saver": "^2.0.2",
 		"firebase": "^7.19.0",
 		"firebase": "^7.19.0",
 		"firestore": "^1.1.6",
 		"firestore": "^1.1.6",
-		"hammer-touchemulator": "0.0.2",
 		"html2canvas": "^1.0.0-rc.7",
 		"html2canvas": "^1.0.0-rc.7",
 		"increase-memory-limit": "^1.0.7",
 		"increase-memory-limit": "^1.0.7",
 		"js-sha1": "^0.6.0",
 		"js-sha1": "^0.6.0",
@@ -67,6 +66,7 @@
 		"vue-infinite-loading": "^2.4.4",
 		"vue-infinite-loading": "^2.4.4",
 		"vue-loading-overlay": "^3.3.3",
 		"vue-loading-overlay": "^3.3.3",
 		"vue-msal": "^2.0.0",
 		"vue-msal": "^2.0.0",
+		"vue-pdf": "^4.2.0",
 		"vue-router": "^3.0.6",
 		"vue-router": "^3.0.6",
 		"vue-scroll": "^2.1.12",
 		"vue-scroll": "^2.1.12",
 		"vue-server-renderer": "^2.6.12",
 		"vue-server-renderer": "^2.6.12",

BIN
TEAMModelOS/ClientApp/public/favicon.ico


+ 19 - 54
TEAMModelOS/ClientApp/public/index.html

@@ -6,11 +6,25 @@
 		<meta name="viewport" content="width=device-width,initial-scale=1.0">
 		<meta name="viewport" content="width=device-width,initial-scale=1.0">
 		<link rel="icon" href="<%= BASE_URL %>favicon.ico">
 		<link rel="icon" href="<%= BASE_URL %>favicon.ico">
 		<link id="theme" type="text/css" rel="stylesheet" href="<%= BASE_URL %>theme/dark-theme.css">
 		<link id="theme" type="text/css" rel="stylesheet" href="<%= BASE_URL %>theme/dark-theme.css">
-		<title>vuex-oidc-example</title><!-- 
-		<script type="text/javascript" id="MathJax-script" async src="https://teammodelstorage.blob.core.chinacloudapi.cn/download/MathJax/MathJax.js"></script>
-		<script type="text/javascript" id="MathJax-script" async src="https://teammodelstorage.blob.core.chinacloudapi.cn/download/MathJax/MathJax-load.js"></script> -->
-		<script type="text/javascript" id="MathJax-script" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>
-		
+		<title>IES5 云平台</title>
+		<script>
+		MathJax = {
+		  loader: {load: ["input/tex", "output/svg"]},
+		  // mml:{
+			 //  forceReparse:true
+		  // },
+		  tex: {
+		    inlineMath: [['$', '$'], ['\\(', '\\)']],
+			displayMath: [["$$", "$$"], ["\\[", "\\]"]]
+		  },
+		  svg: {
+		    fontCache: 'local'
+		  }
+		};
+		</script>
+		<script type="text/javascript" id="MathJax-script" async
+		  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-svg.js">
+		</script>
 		<script>
 		<script>
 			let cloudSetting = localStorage.getItem('cloudSetting')
 			let cloudSetting = localStorage.getItem('cloudSetting')
 			if (cloudSetting) {
 			if (cloudSetting) {
@@ -19,55 +33,6 @@
 					document.getElementById('theme').href = '/theme/light-theme.css'
 					document.getElementById('theme').href = '/theme/light-theme.css'
 				}
 				}
 			}
 			}
-			/* 性能监听 */
-			window.addEventListener("load", function() {
-				setTimeout(function() {
-					var e = window.performance;
-					if (e) {
-						var t = e.getEntriesByType("navigation")[0],
-							r = 0;
-						t || (r = (t = e.timing).navigationStart);
-						var n = [{
-							key: "Redirect",
-							desc: "\u7f51\u9875\u91cd\u5b9a\u5411\u7684\u8017\u65f6",
-							value: t.redirectEnd - t.redirectStart
-						}, {
-							key: "AppCache",
-							desc: "\u68c0\u67e5\u672c\u5730\u7f13\u5b58\u7684\u8017\u65f6",
-							value: t.domainLookupStart - t.fetchStart
-						}, {
-							key: "DNS",
-							desc: "DNS\u67e5\u8be2\u7684\u8017\u65f6",
-							value: t.domainLookupEnd - t.domainLookupStart
-						}, {
-							key: "TCP",
-							desc: "TCP\u8fde\u63a5\u7684\u8017\u65f6",
-							value: t.connectEnd - t.connectStart
-						}, {
-							key: "Waiting(TTFB)",
-							desc: "\u4ece\u5ba2\u6237\u7aef\u53d1\u8d77\u8bf7\u6c42\u5230\u63a5\u6536\u5230\u54cd\u5e94\u7684\u65f6\u95f4 / Time To First Byte",
-							value: t.responseStart - t.requestStart
-						}, {
-							key: "Content Download",
-							desc: "\u4e0b\u8f7d\u670d\u52a1\u7aef\u8fd4\u56de\u6570\u636e\u7684\u65f6\u95f4",
-							value: t.responseEnd - t.responseStart
-						}, {
-							key: "HTTP Total Time",
-							desc: "http\u8bf7\u6c42\u603b\u8017\u65f6",
-							value: t.responseEnd - t.requestStart
-						}, {
-							key: "DOMContentLoaded",
-							desc: "dom\u52a0\u8f7d\u5b8c\u6210\u7684\u65f6\u95f4",
-							value: t.domContentLoadedEventEnd - r
-						}, {
-							key: "Loaded",
-							desc: "\u9875\u9762load\u7684\u603b\u8017\u65f6",
-							value: t.loadEventEnd - r
-						}];
-						console && console.log && console.log(n)
-					}
-				}, 0)
-			});
 		</script>
 		</script>
 
 
 	</head>
 	</head>

BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/bar-bg.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/bar.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/bg.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/bottom.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/btn.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/down.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/top.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/custom/up.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/bar-bg.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/bar-left.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/bar-right.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/thumb-bg.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/thumb-left.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/scrollbar/edit/thumb-right.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/all_formula.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/aleph.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/bbbk.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/beth.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/circleds.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/complement.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/daleth.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/ell.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/eth.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/finv.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/game.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/gimel.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/hbar.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/hslash.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/im.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/mho.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/partial.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/re.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/alphabetic/wp.png


BIN
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/arrow/circlearrowleft.png


+ 0 - 0
TEAMModelOS/ClientApp/public/kityformula/assets/images/toolbar/arrow/circlearrowright.png


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است