CrazyIter_Bin 4 năm trước cách đây
mục cha
commit
27f661b99c
37 tập tin đã thay đổi với 1155 bổ sung1234 xóa
  1. 40 0
      TEAMModelFunction/ClassChangeServiceBus.cs
  2. 6 5
      TEAMModelFunction/MonitorCosmosDB.cs
  3. 1 1
      TEAMModelFunction/ExamTrigger.cs
  4. 38 2
      TEAMModelFunction/SurveyTrigger.cs
  5. 141 0
      TEAMModelFunction/TriggerVote.cs
  6. 0 79
      TEAMModelFunction/VoteTrigger.cs
  7. 70 0
      TEAMModelOS.SDK/Models/Cosmos/Common/ActivityData.cs
  8. 0 21
      TEAMModelOS.SDK/Models/Cosmos/Common/CommonData.cs
  9. 12 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/VoteRecord.cs
  10. 55 37
      TEAMModelOS.SDK/Models/Cosmos/Common/Vote.cs
  11. 8 1
      TEAMModelOS.SDK/Models/Cosmos/School/Class.cs
  12. 3 3
      TEAMModelOS.SDK/Models/Cosmos/School/Survey.cs
  13. 23 23
      TEAMModelOS.SDK/Models/Cosmos/Student/VoteRecord.cs
  14. 189 339
      TEAMModelOS/Controllers/Common/VoteController.cs
  15. 0 1
      TEAMModelOS/Controllers/Core/ImportController.cs
  16. 56 0
      TEAMModelOS/Controllers/School/StudentCommonController.cs
  17. 57 0
      TEAMModelOS/Controllers/Teacher/TeacherCommonController.cs
  18. 1 1
      TEAMModelOS/Controllers/XTest/TestController.cs
  19. 0 19
      TEAMModelOS/Models/PowerPoint/Border.cs
  20. 0 173
      TEAMModelOS/Models/PowerPoint/Chart.cs
  21. 0 20
      TEAMModelOS/Models/PowerPoint/Connector.cs
  22. 0 11
      TEAMModelOS/Models/PowerPoint/Diagram.cs
  23. 0 47
      TEAMModelOS/Models/PowerPoint/Fill.cs
  24. 0 25
      TEAMModelOS/Models/PowerPoint/FontStyle.cs
  25. 0 11
      TEAMModelOS/Models/PowerPoint/Group.cs
  26. 0 43
      TEAMModelOS/Models/PowerPoint/Htex.cs
  27. 0 30
      TEAMModelOS/Models/PowerPoint/Inner/WarpObj.cs
  28. 0 23
      TEAMModelOS/Models/PowerPoint/Item.cs
  29. 0 17
      TEAMModelOS/Models/PowerPoint/Math.cs
  30. 0 21
      TEAMModelOS/Models/PowerPoint/Media.cs
  31. 0 54
      TEAMModelOS/Models/PowerPoint/Paragraph.cs
  32. 0 34
      TEAMModelOS/Models/PowerPoint/Position.cs
  33. 0 121
      TEAMModelOS/Models/PowerPoint/Shape.cs
  34. 0 26
      TEAMModelOS/Models/PowerPoint/Slide.cs
  35. 0 45
      TEAMModelOS/Models/PowerPoint/Table.cs
  36. 454 0
      TEAMModelOS/Services/Common/ActivityService.cs
  37. 1 1
      TEAMModelOS/Startup.cs

+ 40 - 0
TEAMModelFunction/ClassChangeServiceBus.cs

@@ -0,0 +1,40 @@
+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;
+
+namespace TEAMModelFunction
+{
+    public class ClassChangeServiceBus
+    {
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        delegate void DoActivityTarget(string ids,string opt,string no,string source);
+        public ClassChangeServiceBus(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("ImproveActivity")]
+        public async Task ImproveActivity([ServiceBusTrigger("active-task", "classchange", Connection = "Azure:ServiceBus:ConnectionString")] string msg) {
+            try {
+                var json = JsonDocument.Parse(msg);
+
+            } catch (Exception e) { }
+        }
+    }
+}

+ 6 - 5
TEAMModelFunction/MonitorCosmosDB.cs

@@ -21,14 +21,15 @@ namespace TEAMModelFunction
         private readonly AzureServiceBusFactory _serviceBus;
         private readonly AzureStorageFactory _azureStorage;
         private readonly DingDing _dingDing;
-
-        public MonitorCosmosDB(IHttpClientFactory clientFactory, AzureCosmosFactory azureCosmos, AzureServiceBusFactory azureServiceBus, AzureStorageFactory azureStorage, DingDing dingDing)
+        private readonly AzureRedisFactory _azureRedis;
+        public MonitorCosmosDB(IHttpClientFactory clientFactory, AzureCosmosFactory azureCosmos, AzureServiceBusFactory azureServiceBus, AzureStorageFactory azureStorage, DingDing dingDing, AzureRedisFactory azureRedis)
         {
             _clientFactory = clientFactory;
             _azureCosmos = azureCosmos;
             _serviceBus = azureServiceBus;
             _azureStorage = azureStorage;
             _dingDing = dingDing;
+            _azureRedis = azureRedis;
         }
 
         [FunctionName("Common")]
@@ -60,13 +61,13 @@ namespace TEAMModelFunction
                         switch (pk)
                         {
                             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;
                             case "Vote":
-                                VoteTrigger.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school);
+                                TriggerVote.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school, _azureRedis);
                                 break;
                             case "Survey":
-                                SurveyTrigger.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school);
+                                TriggerSurvey.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school);
                                 break;
 
                         }

+ 1 - 1
TEAMModelFunction/ExamTrigger.cs

@@ -12,7 +12,7 @@ using TEAMModelOS.SDK.Models;
 
 namespace TEAMModelFunction
 {
-    public class ExamTrigger
+    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)

+ 38 - 2
TEAMModelFunction/SurveyTrigger.cs

@@ -9,10 +9,11 @@ using System.Threading.Tasks;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Cosmos;
 
 namespace TEAMModelFunction
 {
-   public class SurveyTrigger
+   public class TriggerSurvey
     {
         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)
@@ -50,6 +51,42 @@ namespace TEAMModelFunction
                     }
                     break;
                 case "going":
+                    var tcode = code.Replace("Survey-", "");
+                    ActivityData data;
+                    if (survey.scope == "school" || survey.scope == "teacher")
+                    {
+                        data = new ActivityData
+                        {
+                            id = survey.id,
+                            code = $"Activity-{tcode}",
+                            type = "survey",
+                            name = survey.name,
+                            startTime = survey.startTime,
+                            endTime = survey.endTime,
+                            scode = survey.code,
+                            scope = survey.scope,
+                            classes = survey.classes,
+                            tmdids = survey.tmdids
+                        };
+                        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,
+                            classes = survey.classes,
+                            // tmdids = survey.tmdids
+                        };
+                        await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<ActivityData>(data, new Azure.Cosmos.PartitionKey(data.code));
+                    }
                     var messageSurveyEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
                     messageSurveyEnd.ApplicationProperties.Add("name", "Survey");
                     if (changeRecords.Count > 0)
@@ -70,7 +107,6 @@ namespace TEAMModelFunction
                             msgId = messageSurveyEnd.MessageId
                         };
                         await _azureStorage.Save<ChangeRecord>(changeRecord);
-                        //await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
                     }
                     break;
             }

+ 141 - 0
TEAMModelFunction/TriggerVote.cs

@@ -0,0 +1,141 @@
+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;
+using TEAMModelOS.SDK.Models.Cosmos;
+
+namespace TEAMModelFunction
+{
+    public static class TriggerVote
+    {
+
+        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, AzureRedisFactory _azureRedis)
+        {
+            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}"));
+            if (vote.ttl >= 1)
+            {
+                //TODO  处理TTL删除业务
+                _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Record:{vote.id}_{vote.code}");
+                _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Count:{vote.id}_{vote.code}");
+                return;
+            }
+            else {
+                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 tcode = code.Replace("Vote-", "");
+                        ActivityData data;
+                        if (vote.scope == "school" || vote.scope == "teacher")
+                        {
+                            data = new ActivityData
+                            {
+                                id = vote.id,
+                                code = $"Activity-{tcode}",
+                                type = "vote",
+                                name = vote.name,
+                                startTime = vote.startTime,
+                                endTime = vote.endTime,
+                                scode = vote.code,
+                                scope = vote.scope,
+                                classes = vote.classes,
+                                tmdids = vote.tmdids
+                            };
+                            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,
+                                classes = vote.classes,
+                                // tmdids = vote.tmdids
+                            };
+                            await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<ActivityData>(data, new Azure.Cosmos.PartitionKey(data.code));
+                        }
+                        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]);
+                        }
+                        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);
+                        }
+                        break;
+                    case "finish":
+                        //获取投票活动的所有投票记录
+                        var records= _azureRedis.GetRedisClient(8).HashValues($"Vote:Record:{vote.id}_{vote.code}");
+                        //获取投票活动的选项及投票数
+                        var counts= _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Vote:Count:{vote.id}_{vote.code}");
+                        if (counts != null && counts.Length > 0) {
+                            foreach (var count in counts) {
+                                vote.options.ForEach(x => {
+                                    if (x.code.Equals(count.Element.ToString())) {
+                                        x.count = (int)count.Score;
+                                    }
+                                });
+                            }
+                        }
+                        foreach (var rcd in records) {
+                            
+                        }
+                        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;
-            }
-        }
-    }
-}

+ 70 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/ActivityData.cs

@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos
+{
+
+    /// <summary>
+    /// 
+    /// [
+    //      Activity|-----问卷调查
+    //        |-----投票活动
+    //        |-----评测活动
+    //        |-----作业活动
+    //        |-----学习活动
+    //]
+    //[
+    //    {
+    //        "type": "vote",//"vote"/"exam"/"homework"/"learn"/"survey"
+    //        "name": "第一届紫藤小学人气教师投票",
+    //        "startTime": 1608274766154,
+    //        "endTime": 1608912000000,
+    //        "scode": "Vote-hbcn",
+    //        "id": "aaaaaaaaaaaaaaaaaaa",
+    //        "code": "Activity-hbcn",
+    //        "pk": "Activity",
+    //        "scope":"private/school/teacher",
+    //        "classes":["S-C-00001","S-C-00002","S-C-00003","S-C-00004"],
+    //        "tmdids":["TMDID0001","TMDID0002","TMDID0003","TMDID0004",]//只有问卷调查和投票活动设置,且分区键必须为学校的
+    //},
+    //    {
+    //        "type": "vote",//"vote"/"exam"/"homework"/"learn"/"survey"
+    //        "name": "第一届醍摩豆杯人气教师投票",
+    //        "startTime": 1608274766154,
+    //        "endTime": 1608912000000,
+    //        "scode": "Vote-TMDID0001",
+    //        "id": "bbbbbbbbbbbbbbbbbbbbb",
+    //        "code": "Activity-Common",//教师个人发布的活动统一使用Common,用班级子查询
+    //        "pk": "Activity",
+    //        "scope":"private/school/teacher",
+    //        "classes":["P-C-00004","S-C-00001"],//如果是醍摩豆ID则直接搜寻加入的私人教师编码,如果是校内学生则需要多搜寻一次。
+    //        "tmdids":[]
+    //    }
+    //]
+    /// </summary>
+    public class ActivityData : CosmosEntity
+    {
+        public ActivityData() {
+            pk = "Activity";
+        }
+        /// <summary>
+        /// 业务类型  vote投票 survey问卷 exam评测 learn学习活动 homework作业活动
+        /// </summary>
+        public string type { get; set; }
+        public string name { get; set; }
+        public long  startTime { get; set; }
+        public long endTime { get; set; }
+        /// <summary>
+        /// 活动的分区键 Vote-hbcn/Vote-1606294378
+        /// </summary>
+        public string scode { get; set; }
+        /// <summary>
+        /// private/school/teacher
+        /// </summary>
+        public string scope { get; set; }
+        public List<string> classes { get; set; }
+        public List<string> tmdids { get; set; }
+
+    }
+}

+ 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; }
-    }
-}

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

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
+{
+    public class VoteRecord
+    {
+        public List<string> opt { get; set; }
+        public long time { get; set; }
+    }
+}

+ 55 - 37
TEAMModelOS.SDK/Models/Cosmos/Common/Vote.cs

@@ -1,3 +1,4 @@
+
 using System;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
@@ -20,77 +21,94 @@ namespace TEAMModelOS.SDK.Models
 
         }
 
+        public string school { get; set; }
         /// <summary>
         /// 投票名称
         /// </summary>
         public string name { get; set; }
-        public string school { get; set; }
+        /// <summary>
+        /// 创建者的id 
+        /// </summary>
         public string creatorId { get; set; }
-        public int year { get; set; }
+        /// <summary>
+        /// pending 待发布|going 已发布|finish 已结束
+        /// </summary>
         public string progress { get; set; }
+        /// <summary>
+        /// 投票选项
+        /// </summary>
         public List<OptionsVote> options { get; set; }
+        /// <summary>
+        /// //匿名投票,不公布投票人相关信息
+        /// </summary>
         public bool secret { get; set; }
-        public int selectMax { get; set; }
-        public int stuCount { get; set; }
+        /// <summary>
+        /// 投票周期/once一次,day天,week周,month月,年year等
+        /// </summary>
+        public string times { get; set; }
+        //周期内可投票数
+        public int voteNum { get; set; }
+        /// <summary>
+        /// school|private
+        /// </summary>
         public string scope { get; set; }
-        public List<string> targetClassIds { get; set; }
         /// <summary>
-        /// 发布模式 0 立即发布 1 定时
+        /// 参与投票的教师醍摩豆id
         /// </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>
         public long startTime { get; set; }
+        /// <summary>
+        /// 创建时间
+        /// </summary>
         public long createTime { get; set; }
-
         /// <summary>
         /// 结束时间
         /// </summary>
         public long endTime { get; set; }
-
-
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        public long updateTime { get; set; }
         /// <summary>
         /// 投票描述
         /// </summary>
         public string description { get; set; }
-
-
-        /*        /// <summary>
-                /// 投票附件
-                /// </summary>
-                [ProtoMember(9)]
-                public List<ProcessRes> resource { get; set; }
-        */
-
         /// <summary>
-        /// 状态 (100:待发布 200:已发布 300:已结束)
+        /// (100:待发布 200:已发布 300:已结束)
         /// </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; }
     }
+    /// <summary>
+    /// 投票选项
+    /// </summary>
     public class OptionsVote
     {
+        /// <summary>
+        /// 投票编号
+        /// </summary>
         public string code { get; set; }
+        /// <summary>
+        /// 投票对象
+        /// </summary>
         public string value { get; set; }
+        /// <summary>
+        /// 投票对象描述
+        /// </summary>
         public string desc { get; set; }
+        /// <summary>
+        /// 得票数量
+        /// </summary>
+        public int? count { get; set; } 
     }
+    
 }
+

+ 8 - 1
TEAMModelOS.SDK/Models/Cosmos/School/Class.cs

@@ -43,6 +43,10 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public string openType { 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
 {
-
+    /// <summary>
+    /// 数据来源的分区键 如果是学校的编码 则是学校编码,如果是tmdid则是Base
+    /// </summary>
+    public string scode { get; set; }
     public string id { get; set; }
 
     public string name { get; set; }

+ 3 - 3
TEAMModelOS.SDK/Models/Cosmos/School/Survey.cs

@@ -16,7 +16,7 @@ namespace TEAMModelOS.SDK.Models
         public Survey() {
             pk = "Survey";
             questions = new List<Questions>();
-            classes = new List<Classes>();
+            classes = new List<string>();
         }
        
         public string name { get; set; }   //测试问卷名称', // 问卷名称
@@ -51,8 +51,8 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public long endTime { get; set; }
         public long createTime { get; set; } // 问卷发布时间
-        public List<Classes> classes { get; set; }
-
+        public List<string> classes { get; set; }
+        public List<string> tmdids { get; set; }
         //public long sequenceNumber { get; set; }
 
         public string url { get; set; }

+ 23 - 23
TEAMModelOS.SDK/Models/Cosmos/Student/VoteRecord.cs

@@ -7,35 +7,35 @@ using TEAMModelOS.SDK.DI;
 
 namespace TEAMModelOS.SDK.Models
 {    
-    public class VoteRecord : CosmosEntity
-    {
+    //public class VoteRecord : CosmosEntity
+    //{
 
-        public VoteRecord()
-        {
-            classroom = new ClassroomItem();
-        }
+    //    public VoteRecord()
+    //    {
+    //        classroom = new ClassroomItem();
+    //    }
 
-        /// <summary>
-        /// 姓名
-        /// </summary>
-        public string name { get; set; }
+    //    /// <summary>
+    //    /// 姓名
+    //    /// </summary>
+    //    public string name { get; set; }
 
-        /// <summary>
-        /// 上课班级
-        /// </summary>
-        public ClassroomItem classroom { get; set; }
+    //    /// <summary>
+    //    /// 上课班级
+    //    /// </summary>
+    //    public ClassroomItem classroom { get; set; }
 
 
 
-        /// <summary>
-        /// 提交时间
-        /// </summary>
-        public long submitTime { get; set; }
+    //    /// <summary>
+    //    /// 提交时间
+    //    /// </summary>
+    //    public long submitTime { get; set; }
 
-        /// <summary>
-        /// 选项
-        /// </summary>
-        public string option { get; set; }
+    //    /// <summary>
+    //    /// 选项
+    //    /// </summary>
+    //    public string option { get; set; }
 
-    }
+    //}
 }

+ 189 - 339
TEAMModelOS/Controllers/Common/VoteController.cs

@@ -17,6 +17,14 @@ using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
 using TEAMModelOS.SDK.Helper.Common.StringHelper;
+using TEAMModelOS.Models;
+using Microsoft.Extensions.Options;
+using TEAMModelOS.SDK.Models.Cosmos;
+using Microsoft.AspNetCore.Authorization;
+using TEAMModelOS.Filter;
+using StackExchange.Redis;
+using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
+using TEAMModelOS.Services.Common;
 
 namespace TEAMModelOS.Controllers.Learn
 {
@@ -30,426 +38,268 @@ namespace TEAMModelOS.Controllers.Learn
     [ApiController]
     public class VoteController : ControllerBase
     {
-        private readonly SnowflakeId _snowflakeId;
+        private readonly AzureRedisFactory _azureRedis;
         private readonly AzureCosmosFactory _azureCosmos;
+        private readonly SnowflakeId _snowflakeId;
         private readonly AzureServiceBusFactory _serviceBus;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
 
-        public VoteController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId)
+        public VoteController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option,
+            AzureRedisFactory azureRedis)
         {
-            _snowflakeId = snowflakeId;
             _azureCosmos = azureCosmos;
             _serviceBus = serviceBus;
+            _snowflakeId = snowflakeId;
+            _dingDing = dingDing;
+            _option = option?.Value;
+            _azureRedis = azureRedis;
         }
-
-
         /// <summary>
         /// 新增 或 修改投票活动
         /// </summary>
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
-        [HttpPost("upsert")]
-        public async Task<IActionResult> Upsert(VoteDto request)
+        [HttpPost("save")]
+        public async Task<IActionResult> Save(Vote request)
         {
-            /*ResponseBuilder builder = ResponseBuilder.custom();
-            //新增
-            if (string.IsNullOrEmpty(request.vote.id))
-            {
-                request.vote.id = _snowflakeId.NextId()+"";
-                request.vote.status = 100;
-                request.vote.code = typeof(Vote).Name + "-" + request.vote.code;
-            }
-            if (request.vote.publishModel.Equals("0"))
-            {
-                request.vote.startTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
-                request.vote.status = 200;
-                
-            } else if (request.vote.publishModel.Equals("1")) {
-
-                string msgId = _snowflakeId.NextId() + "";
-                long SequenceNumber = await _serviceBus.GetServiceBusClient().SendLeamMessage<Vote>(Constants.TopicName, request.vote.id, request.vote.code, request.vote.startTime, 200, msgId);
-                request.vote.sequenceNumber = SequenceNumber;
-            }*/
-
-
-            //新增ote
-            //string code = request.vote.code;
-            var client = _azureCosmos.GetCosmosClient();
-            Vote vote = new Vote();
-            request.vote.school = request.vote.code;
-            request.vote.code = request.vote.pk + "-" + request.vote.code;
-            request.vote.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
-            /*if (request.vote.publishModel.Equals("0"))
-            {
-                //request.vote.startTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
-                request.vote.progress = "going";
-            }
-            else if (request.vote.publishModel.Equals("1"))
+            try
             {
+                //新增Vote
+                var client = _azureCosmos.GetCosmosClient();
+                request.code = request.pk + "-" + request.code;
+                request.createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
 
-                string msgId = _snowflakeId.NextId() + "";
-                long SequenceNumber = await _serviceBus.GetServiceBusClient().SendLeamMessage<Survey>(Constants.TopicName, request.vote.id, request.vote.code, request.vote.startTime, "going", msgId);
-                request.vote.sequenceNumber = SequenceNumber;
-
-            }*/
-            if (string.IsNullOrEmpty(request.vote.id))
-            {
-                request.vote.id = Guid.NewGuid().ToString();
-                //request.survey.status = 100;
-                request.vote.progress = "pending";
-                /* long SequenceNumber = await _serviceBus.GetServiceBusClient().SendLeamMessage<Vote>(Constants.TopicName, request.vote.id, request.vote.code, request.vote.startTime);
-                 request.vote.sequenceNumber = SequenceNumber;*/
-                vote = await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(request.vote, new PartitionKey($"{request.vote.code}"));
-                /*if (request.vote.scope.Equals("school"))
+                if (string.IsNullOrEmpty(request.id))
                 {
-                    vote = await client.GetContainer("TEAMModelOS", "School").CreateItemAsync(request.vote, new PartitionKey($"Vote-{code}"));
+                    request.id = Guid.NewGuid().ToString();
+                    request.progress = "pending";
+                    request = await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(request, new PartitionKey($"{request.code}"));
                 }
                 else
                 {
-                    vote = await client.GetContainer("TEAMModelOS", "Teacher").CreateItemAsync(request.vote, new PartitionKey($"Vote-{code}"));
-                }*/
+                    Vote info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(request.id, new PartitionKey($"{request.code}"));
+                    if (info.progress.Equals("going"))
+                    {
+                        return Ok(new { v = "活动正在进行中" });
+                    }
+                    request.progress = info.progress;
+                    request = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(request, info.id, new PartitionKey($"{info.code}"));
+                   
+                }
+                return Ok(new { request });
             }
-            else
+            catch (Exception e)
             {
-                Vote info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(request.vote.id, new PartitionKey($"{request.vote.code}"));
-                if (info.progress.Equals("going"))
-                {
-                    return Ok(new { v = "活动正在进行中" });
-                }
-                //request.vote.code = info.code;
-                request.vote.progress = info.progress;
-                /* await _serviceBus.GetServiceBusClient().cancelMessage(Constants.TopicName,info.sequenceNumber);
-                 long SequenceNumber = await _serviceBus.GetServiceBusClient().SendLeamMessage<Vote>(Constants.TopicName, request.vote.id, request.vote.code, request.vote.startTime);
-                 request.vote.sequenceNumber = SequenceNumber;*/
-                vote = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(request.vote, info.id, new PartitionKey($"{info.code}"));
-                /*if (request.vote.scope.Equals("school"))
-                {
-                    vote = await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync(request.vote, request.vote.id, new PartitionKey($"{request.vote.code}"));
-                }
-                else
-                {
-                    vote = await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync(request.vote, request.vote.id, new PartitionKey($"{request.vote.code}"));
-                }*/
+                await _dingDing.SendBotMsg($"OS,{_option.Location},common/vote/save()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest(e.StackTrace);
             }
-            //Vote homeWork = await _azureCosmos.SaveOrUpdate<Vote>(request.vote);
-
-            //设定结束时间
-            //_timerWorkService.TimerWork<Vote>(request.vote.endTime, 300, new Dictionary<string, object> { { "id", request.vote.id } });
-            //设定结束时间
-            //await _serviceBus.GetServiceBusClient().SendLeamMessage<Vote>(Constants.TopicName, request.vote.id, request.vote.code, request.vote.endTime);
-            //清除作业
-            /*  if (!request.reset)
-              {
-                  //根据作业发布对象查找到每一个具体学生生成关联关系表 HomeWorkStudent
-
-                  List<VoteRecord> voteRecords = await _azureCosmos.FindByDict<VoteRecord>(new Dictionary<string, object> { { "id", request.vote.id } });
-
-                  if (voteRecords.IsNotEmpty())
-                  {
-                      await _azureCosmos.DeleteAll(voteRecords);
-                  }*/
-            //List<Target> targets = request.@params.vote.target;
-            //List<VoteRecord> votekStudents = new List<VoteRecord>();
-            //foreach (Target target in targets)
-            //{
-            //    //查询之前是否有 关联关系表 HomeWorkStudent 有则删除
-
-            //    List<ClassStudent> classroom = await _cosmos.FindByDict<ClassStudent>(new Dictionary<string, object> { { "id", target.classroomCode } });
-            //    if (classroom.IsNotEmpty() && classroom[0].code!=null)
-            //    {
-            //        foreach (ClassStudent student in classroom)
-            //        {
-            //            VoteRecord voteStudent = new VoteRecord();
-            //            voteStudent.id = request.@params.vote.id;
-            //            voteStudent.code = student.code;
-            //            voteStudent.classroom.code = target.classroomCode;
-            //            voteStudent.classroom.name = target.classroomName;
-            //            votekStudents.Add(voteStudent);
-            //        }
-            //    }
-            //}
-            //if (votekStudents.IsNotEmpty())
-            //{
-            //    foreach (VoteRecord voteRecord in votekStudents)
-            //    {
-            //        List<Student> student = await _cosmos.FindByDict<Student>(new Dictionary<string, object> { { "studentId", voteRecord.code } });
-            //        if (student.IsNotEmpty())
-            //        {
-            //            voteRecord.name = student[0].name;
-            //            voteRecord.code = student[0].studentId;
-            //        }
-            //    }
-            //    await _cosmos.SaveOrUpdateAll(votekStudents);
-            //}
-            /*            }*/
-            //return builder.Data(homeWork).build();
-            return Ok(new { vote });
         }
-
         /// <summary>
-        /// 查询投票活动
+        /// 查询投票活动,用于列表,编辑,查看
         /// </summary>
+        /// <data>
+        ///Vote-学校/教师编码  活动分区        !"code":"hbcn"/1606285227 
+        ///时间筛选范围开始时间 默认30天之前   ?"stime":1608274766154  
+        ///时间筛选范围结束时间 默认当前时间   ?"etime":1608274766666 
+        ///每页大小     ?"count":10/null/Undefined  
+        ///分页Token    ?"continuationToken":Undefined/null/"[{\"token\":\"+RID:~omxMAP3ipcSEEwAAAAAAAA==#RT:2#TRC:20#ISV:2#IEO:65551#QCF:1#FPC:AYQTAAAAAAAAiRMAAAAAAAA=\",\"range\":{\"min\":\"\",\"max\":\"FF\"}}]"
+        /// </data>
         /// <param name="request"></param>
         /// <returns></returns>
-
         [ProducesDefaultResponseType]
         [HttpPost("find")]
         public async Task<IActionResult> Find(JsonElement requert)
         {
-
-            var client = _azureCosmos.GetCosmosClient();
-            if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
-            if (!requert.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
-            StringBuilder sql = new StringBuilder();
-            sql.Append("select c.id,c.code,c.name,c.targetClassIds,c.options,c.description,c.status,c.startTime,c.selectMax,c.endTime,c.secret,c.progress from c ");
-            /*if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
-            if (!requert.TryGetProperty("@CURRPAGE", out JsonElement page)) return BadRequest();
-            if (!requert.TryGetProperty("@PAGESIZE", out JsonElement size)) return BadRequest();
-            if (!requert.TryGetProperty("@DESC", out JsonElement desc)) return BadRequest();*/
-            Dictionary<string, object> dict = new Dictionary<string, object>();
-            var emobj = requert.EnumerateObject();
-            while (emobj.MoveNext())
-            {
-                dict[emobj.Current.Name] = emobj.Current.Value;
-            }
-            //处理code
-            if (dict.TryGetValue("code", out object _))
-            {
-                dict.Remove("code");
-            }
-            AzureCosmosQuery cosmosDbQuery = SQLHelper.GetSQL(dict, sql);
-            List<object> votes = new List<object>();
-            await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Vote-{code}") }))
+            try
             {
-                using var json = await JsonDocument.ParseAsync(item.ContentStream);
-
-                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
-                {
-                    foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                //必须有学校或者教师编码
+                if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
+                //开始时间,默认最近三十天
+                var stimestamp = DateTimeOffset.UtcNow.AddDays(-30).ToUnixTimeMilliseconds();
+                if (!requert.TryGetProperty("stime", out JsonElement stime)) {
+                    if (stime.TryGetInt64(out long data))
                     {
-                        votes.Add(obj.ToObject<object>());
-                    }
-                }
-            }
-            /*if (scope.ToString().Equals("school"))
-            {
-                await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Vote-{code}") }))
+                        stimestamp = data;
+                    };
+                };
+                //默认当前时间
+                var etimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                if (!requert.TryGetProperty("etime", out JsonElement etime))
                 {
-                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (stime.TryGetInt64(out long data))
+                    {
+                        etimestamp = data;
+                    };
 
-                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                };
+                
+                string continuationToken = null;
+                //默认不指定返回大小
+                int? topcout=null;
+                if (!requert.TryGetProperty("count", out JsonElement jcount)) {
+                    if(jcount.TryGetInt32(out int data))
                     {
-                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
-                        {
-                            votes.Add(obj.ToObject<object>());
-                        }
+                        topcout = data;
+                    };
+                };
+                //是否需要进行分页查询,默认不分页
+                bool iscontinuation = false;
+                //如果指定了返回大小
+                if (!requert.TryGetProperty("continuationToken", out JsonElement continuation))
+                {
+                    //指定了cancellationToken 表示需要进行分页
+                    if (!continuation.ValueKind.Equals(JsonValueKind.Null) && !continuation.ValueKind.Equals(JsonValueKind.String))
+                    {
+                        continuationToken = continuation.GetString();
+                        iscontinuation = true;
                     }
-                }
-            }
-            else
-            {
-                await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Vote-{code}") }))
+                };
+                List<object> votes = new List<object>();
+                var client = _azureCosmos.GetCosmosClient();
+             
+                var query =$"select   c.id,c.name,c.code,c.startTime,c.endTime,c.progress from c where c.createTime >= {stimestamp} and c.createTime <= {etimestamp} ";
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: query,
+                    requestOptions: new QueryRequestOptions() {MaxItemCount = topcout, PartitionKey = new PartitionKey($"Vote-{code}") }))
                 {
                     using var json = await JsonDocument.ParseAsync(item.ContentStream);
-
                     if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                     {
                         foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
                         {
-                            votes.Add(obj.ToObject<object>());
+                            votes.Add(obj.ToObject<JsonElement>());
+                        }
+                        //如果需要分页则跳出
+                        if (iscontinuation) {
+                            continuationToken = item.GetContinuationToken();
+                            break;
                         }
                     }
                 }
-            }*/
-
-
-            return Ok(new { votes, votes.Count });
-            /*ResponseBuilder builder = ResponseBuilder.custom();
-            List<Vote> data = new List<Vote>();
-            if (StringHelper.getKeyCount(request) > 0)
-            {
-                data = await _azureCosmos.FindByDict<Vote>(request);
+                return Ok(new { votes, continuationToken });
             }
-            else
+            catch (Exception ex)
             {
-                return builder.Error(ResponseCode.PARAMS_ERROR, "参数异常!").build();
-
+                await _dingDing.SendBotMsg($"OS,{_option.Location},common/vote/find()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest(ex.StackTrace);
             }
-            return builder.Data(data).Extend(new Dictionary<string, object> { { "count", data.Count } }).build();*/
         }
-
-        /// <summary>
-        /// 删除投票活动
+        ///<summary>
+        /// 查询投票活动,用于创建者列表,编辑,查看,投票人员查看
         /// </summary>
+        /// <data>
+        ///    ! "id":"3c075347-75ef-4bcb-ae03-68678d02d5ef",
+        ///    ! "code":"Vote-hbcn"/"code":"Vote-1606285227"
+        /// </data>
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
-        [HttpPost("delete")]
-        public async Task<IActionResult> Delete(JsonElement request)
+        [HttpPost("find-id")]
+        public async Task<IActionResult> FindById(JsonElement requert)
         {
-
             try
             {
-                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
-                if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
-                if (!request.TryGetProperty("scope", out JsonElement scope)) return BadRequest();
                 var client = _azureCosmos.GetCosmosClient();
-                var response = await client.GetContainer("TEAMModelOS", "Common").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"{code}"));
-                return Ok(new { code = response.Status });
-                /*if (scope.ToString().Equals("school"))
+                //活动id
+                if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
+                //活动分区
+                if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
+                Vote vote = null;
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<Vote>(queryText: $"select value(c) from c where c.id = '{id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
+                {
+                    vote = item;
+                    break;
+                }
+                if (vote != null)
                 {
-                    var response = await client.GetContainer("TEAMModelOS", "School").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"{code}"));
-                    return Ok(new { code = response.Status });
+                   
+                    return Ok(vote);
                 }
                 else
                 {
-                    var response = await client.GetContainer("TEAMModelOS", "Teacher").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"{code}"));
-                    return Ok(new { code = response.Status });
-                }*/
-
+                    return BadRequest("id,code不存在!");
+                }
             }
-            catch (Exception e)
+            catch (Exception ex)
             {
-                return BadRequest();
+                await _dingDing.SendBotMsg($"OS,{_option.Location},common/vote/find-id()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest(ex.StackTrace);
             }
-            //ResponseBuilder builder = ResponseBuilder.custom();
-            /* List<IdPk> idPks = await _azureCosmos.DeleteAll<Vote>(request);
-             if (idPks.IsNotEmpty())
-             {
-                 foreach (IdPk idPk in idPks) 
-                 { 
-                     List<VoteRecord> votes =  await _azureCosmos.FindByDict<VoteRecord>(new Dictionary<string, object> {  { "id", idPk.id } });
-                     await _azureCosmos.DeleteAll(votes);
-                 }
-                 //builder.Data(idPks);
-             }
-             else
-             {
-                 return Ok("删除失败!");
-                 //return builder.Error(ResponseCode.FAILED, "删除失败!").build();
-             }
-             return Ok(idPks);*/
-            //return builder.build();
-        }
 
-        // TODO 优化代码
-
-        /// <summary>
-        /// 撤消投票
-        /// </summary>
-        /// <param name="request"></param>
-        /// <returns></returns>
-        [ProducesDefaultResponseType]
-        [HttpPost("cancel")]
-        public async Task<IActionResult> Cancel(JsonElement request)
-        {
-            //request.TryGetProperty("id", out JsonElement voteId);
-            ////ResponseBuilder builder = ResponseBuilder.custom();
-            //List<Vote> votes = await _azureCosmos.FindByDict<Vote>(new Dictionary<string, object> { { "id", voteId } });
-
-            //foreach (Vote vote in votes)
-            //{
-            //    vote.status = 100;
-            //    vote.progress = "pending";
-            //}
-            //List<Vote> vote1 = await _azureCosmos.UpdateAll<Vote>(votes);
-
-            ////查询之前是否有 关联关系表 HomeWorkStudent 有则删除
-            //List<VoteRecord> voteStudents = await _azureCosmos.FindByDict<VoteRecord>(new Dictionary<string, object> { { "id", voteId } });
-            //if (voteStudents.IsNotEmpty())
-            //{
-            //    await _azureCosmos.DeleteAll(voteStudents);
-            //}
-            ////return builder.Data(vote1).build();
-            //return Ok(vote1);
-            return Ok();
         }
 
-        // TODO 代码优化
-
         /// <summary>
-        /// 查询 投票 学生关联
+        /// 删除投票活动  TODO 使用ttl删除,并处理相关事务逻辑
         /// </summary>
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
-        [HttpPost("find-record")]
-        public async Task<IActionResult> FindRecord(JsonElement request)
+        [HttpPost("delete")]
+        [AuthToken(Roles = "admin,teacher")]
+        public async Task<IActionResult> Delete(JsonElement request)
         {
-            //ResponseBuilder builder = ResponseBuilder.custom();
-            //List<VoteRecord> data = new List<VoteRecord>();
-            //List<Options> options = new List<Options>();
-
-            //if (StringHelper.getKeyCount(request) > 0)
-            //{
-            //    data = await _azureCosmos.FindByDict<VoteRecord>(request);
-            //    if (data.IsNotEmpty()) {
-            //        List< Vote > votes = await _azureCosmos.FindByDict<Vote>(new Dictionary<string, object> { { "id", data[0].id } });
-            //        List<OptionsVote> options2 = votes[0].options;
-            //        foreach (IGrouping<string, VoteRecord> voteStudents in data.GroupBy(x => x.option))
-            //        {
-            //            Options options1 = new Options();
-            //            options1.optionKey = voteStudents.Key;
-            //            options2.ForEach(x => { if (x.code == voteStudents.Key) options1.optionValue = x.value; });
-            //            if(options1.optionValue == null) options1.optionValue = "Null";
-            //            foreach (VoteRecord voteStudent in voteStudents)
-            //            {
-            //                options1.students.Add(voteStudent);
-            //            }
-            //            options.Add(options1);
-            //        }
-            //    }
-            //}
-            //else
-            //{
-            //    //return builder.Error(ResponseCode.PARAMS_ERROR, "参数异常!").build();
-            //    return Ok("参数异常!");
-            //}
-            ////return builder.Data(options).Extend(new Dictionary<string, object> { { "count", data.Count } }).build();
-            //return Ok(new { options, data.Count });
-            return Ok();
+            try
+            {
+                var (userid, _, _,school) = HttpContext.GetAuthTokenInfo();
+                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
+                if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+                var client = _azureCosmos.GetCosmosClient();
+                
+                Vote vote =await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(id.GetString(), new PartitionKey($"{code}") );
+                bool flag = false;
+                //必须是本人或者这个学校的管理者才能删除
+                if (vote.creatorId == userid)
+                {
+                    flag = true;
+                }
+                else {
+                    if (vote.scope == "school"&& vote.code.Replace("Vote-", "").Equals(school)) {
+                        flag = true;
+                    }
+                }
+                if (flag)
+                { 
+                    //使用ttl删除,并处理相关事务逻辑
+                    vote.ttl = 1;
+                    vote = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(vote, vote.id, new PartitionKey($"{vote.code}"));
+                    return Ok(new { flag });
+                }
+                else {
+                    return Ok(new { flag });
+                }
+                //var response = await client.GetContainer("TEAMModelOS", "Common").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"{code}"));
+                //   return Ok(new { code = response.Status });
+            }
+            catch (Exception e)
+            {
+                return BadRequest();
+            }
         }
 
-        // TODO 代码优化
-
         /// <summary>
-        /// 学生投票
+        /// 投票
         /// </summary>
-        /// <param name="request"></param>
-        /// <returns></returns>
+        /// <redis>
+        /// 投票活动选项计数器 使用SortedSet(有序集合)ZSET 数据集合 使用命令 ZINCRBY  key:"Vote:Count:AAA",value:"A",score:1
+        /// 投票活动 投票记录  使用Hash(哈希表)使用命令 key:"Vote:Record:AAA",feild:15283771540-20210105,value:"{"opt":["A","C","A"],"time":1608274766154}"
+        /// </redis>
+        /// <param name="request">
+        /// !"id":"aaaa"
+        /// !"code":"Vote-hbcn"/"code":"Vote-1606285227"
+        /// !"option":["A","B","B"]/["1","2","3"]
+        /// </param>
+        /// <returns>
+        /// msgid=0投票失败,1投票成功,2不在时间范围内,3不在发布范围内,4投票周期内重复投票,5周期内的可投票数不足,6未设置投票项
+        /// </returns>
         [ProducesDefaultResponseType]
-        [HttpPost("upsert-record")]
-        public async Task<IActionResult> UpsertRecord(List<VoteRecord> request)
+        [HttpPost("decide")]
+        [AuthToken(Roles = "teacher,student")]
+        public async Task<IActionResult> UpsertRecord(JsonElement request)
         {
-            //ResponseBuilder builder = ResponseBuilder.custom();
-            //await _azureCosmos.SaveOrUpdateAll<VoteRecord>(request);
-            return Ok(request);
-            //return builder.Data(request).build();
-        }
-
-
-        public class Options
-        {
-
-            public Options()
-            {
-                students = new List<VoteRecord>();
-            }
-
-            /// <summary>
-            /// 选项Key
-            /// </summary>
-            public string optionKey { get; set; }
-
-            /// <summary>
-            /// 选项value
-            /// </summary>
-            public string optionValue { get; set; }
-
-            /// <summary>
-            /// 选项人
-            /// </summary>
-            public List<VoteRecord> students { get; set; }
+            var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
+            int msgid = await ActivityService.Decide(request, _azureCosmos, _azureRedis, userid);
+            return Ok(new { msgid });
         }
 
     }

+ 0 - 1
TEAMModelOS/Controllers/Core/ImportController.cs

@@ -18,7 +18,6 @@ using System.Text.Json;
 using System.Threading.Tasks;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.Models.Dto;
-using TEAMModelOS.Models.PowerPoint;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.Context.Constant;
 using TEAMModelOS.SDK.Context.Constant.Common;

+ 56 - 0
TEAMModelOS/Controllers/School/StudentCommonController.cs

@@ -0,0 +1,56 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.Filter;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models.Cosmos;
+using TEAMModelOS.Services.Common;
+
+namespace TEAMModelOS.Controllers
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    //[Authorize(Roles = "IES5")]
+    [Route("student")]
+    [ApiController]
+    public class StudentCommonController :ControllerBase
+    {
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly AzureRedisFactory _azureRedis;
+        public StudentCommonController(AzureCosmosFactory azureCosmos, AzureRedisFactory azureRedis)
+        {
+           
+            _azureCosmos = azureCosmos;
+            _azureRedis = azureRedis;
+        }
+        /// <summary>
+        /// 查询活动所有活动类型的列表,学生端
+        /// </summary>
+        /// <param name="request">
+        ///加入的班级信息                      ?classes:[{"classid":"S-C-00001","scope":"school"},{"classid":"P-C-00004","scope":"private"}]
+        ///活动类型                            ?"type":"vote"/"exam"/"homework"/"learn"/"survey"" // vote投票 survey问卷 exam评测 learn学习活动 homework作业活动
+        ///时间筛选范围开始时间 默认30天之前   ?"stime":1608274766154  
+        ///时间筛选范围结束时间 默认当前时间   ?"etime":1608274766666 
+        ///是否展示列表的 Tips                 ? "tips":true/false
+        ///每页大小     ?"count":10/null/Undefined  
+        ///分页Token    ?"continuationToken":Undefined/null/"[{\"token\":\"+RID:~omxMAP3ipcSEEwAAAAAAAA==#RT:2#TRC:20#ISV:2#IEO:65551#QCF:1#FPC:AYQTAAAAAAAAiRMAAAAAAAA=\",\"range\":{\"min\":\"\",\"max\":\"FF\"}}]"
+        /// </param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("find-activity")]
+        [AuthToken(Roles = "student")]
+        public async Task<IActionResult> FindTch(JsonElement requert)
+        {
+            var (id, _, _, _) = HttpContext.GetAuthTokenInfo();
+            (List<ActivityData> datas, string continuationToken) = await ActivityService.FindByRole("School", requert, id, _azureCosmos,_azureRedis);
+            return Ok(new { datas, continuationToken });
+        }
+        
+    }
+}

+ 57 - 0
TEAMModelOS/Controllers/Teacher/TeacherCommonController.cs

@@ -0,0 +1,57 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.Filter;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models.Cosmos;
+using TEAMModelOS.Services.Common;
+
+namespace TEAMModelOS.Controllers
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    //[Authorize(Roles = "IES5")]
+    [Route("teacher")]
+    [ApiController]
+    public class TeacherCommonController: ControllerBase
+    {
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly AzureRedisFactory _azureRedis;
+        public TeacherCommonController(AzureCosmosFactory azureCosmos, AzureRedisFactory azureRedis)
+        {
+            _azureCosmos = azureCosmos;
+            _azureRedis = azureRedis;
+        }
+        /// <summary>
+        /// 查询活动所有活动类型的列表,教师
+        /// </summary>
+        /// <param name="request">
+        ///加入的班级信息                      ?classes:[{"classid":"S-C-00001","scope":"school"},{"classid":"P-C-00004","scope":"private"}]
+        ///活动类型                            ?"type":"vote"/"exam"/"homework"/"learn"/"survey"" // vote投票 survey问卷 exam评测 learn学习活动 homework作业活动
+        ///时间筛选范围开始时间 默认30天之前   ?"stime":1608274766154  
+        ///时间筛选范围结束时间 默认当前时间   ?"etime":1608274766666 
+        ///是否展示列表的 Tips                 ? "tips":true/false
+        ///每页大小     ?"count":10/null/Undefined  
+        ///分页Token    ?"continuationToken":Undefined/null/"[{\"token\":\"+RID:~omxMAP3ipcSEEwAAAAAAAA==#RT:2#TRC:20#ISV:2#IEO:65551#QCF:1#FPC:AYQTAAAAAAAAiRMAAAAAAAA=\",\"range\":{\"min\":\"\",\"max\":\"FF\"}}]"
+        /// </param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("find-activity")]
+        [AuthToken(Roles = "teacher")] 
+        public async Task<IActionResult> FindTch(JsonElement requert)
+        {
+            var (id, _, _, _) = HttpContext.GetAuthTokenInfo();
+            (List<ActivityData> datas, string continuationToken) = await ActivityService.FindByRole("Teacher", requert, id, _azureCosmos,_azureRedis);
+            return Ok(new { datas, continuationToken });
+        }
+       
+    }
+}

+ 1 - 1
TEAMModelOS/Controllers/XTest/TestController.cs

@@ -58,7 +58,7 @@ namespace TEAMModelOS.Controllers.XTest
                         //批量删除
                         foreach (var obj in jsonList)
                         {
-                          //  tasksFiles.Add(client.GetContainer("TEAMModelOS", "School").DeleteItemStreamAsync(obj.GetProperty("id").ToString(), new PartitionKey($"{code}")));
+                            tasksFiles.Add(client.GetContainer("TEAMModelOS", "School").DeleteItemStreamAsync(obj.GetProperty("id").ToString(), new PartitionKey($"{code}")));
                         }
                     }
                 }

+ 0 - 19
TEAMModelOS/Models/PowerPoint/Border.cs

@@ -1,19 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public  class Border
-    {
-
-        public double width { get; set; }
-        public string color { get; set; }
-        public string type { get; set; }
-        /// <summary>
-        /// 描边
-        /// </summary>
-        public string stroke{ get; set; }
-        public string dir { get; set; }
-    }
-}

+ 0 - 173
TEAMModelOS/Models/PowerPoint/Chart.cs

@@ -1,173 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public   class Chart : Item
-    {
-        public  List<CommonChart> charts { get; set; }
-        public List<Paragraph> title { get; set; }
-    }
-
-    public abstract class CommonChart {
-        /// <summary>
-        ///  bar col line pie area scatter radar plotAreaRegion stock surface
-        /// </summary>
-        public string chartType { get; set; }
-        public List<Dictionary<string, object>> datas {get;set;}
-    }
-
-    /// <summary>
-    /// surface3DChart
-    ///     三维曲面图  wireframe=0
-    ///     三维线框曲面图 wireframe=1
-    ///  surfaceChart
-    ///     曲面图  wireframe=0
-    ///     曲面图-俯视框架图  wireframe=1
-    /// </summary>
-    public class SurfaceChart : CommonChart
-    {
-        public string surfaceType { get; set; }
-        public bool is3D { get; set; }
-    }
-    /// <summary>
-    /// stockChart
-    ///     股价图 
-    ///         盘高-盘低-收盘
-    ///         开盘-盘高-盘低-收盘
-    ///         成交量-盘高-盘低-收盘
-    ///         成交量-开盘-盘高-盘低-收盘
-    /// </summary>
-    public class StockChart : CommonChart
-    {
-        public string stockType { get; set; }
-    }
-    /// <summary>
-    /// plotAreaRegion
-    ///     旭日图 sunburst  
-    ///     树状图 treemap
-    ///     直方图 排列图 clusteredColumn
-    ///     箱型图 boxWhisker
-    ///     瀑布图 waterfall
-    /// </summary>
-    public class PlotAreaChart : CommonChart
-    {
-        public string plotAreaType { get;set;}
-    }
-    /// <summary>
-    ///  type radar
-    ///  radarChart  
-    ///     雷达图 
-    ///     带数据标记的雷达图c:radarStyle val="marker"/>
-    ///     填充雷达图 c:radarStyle val="filled"/>
-    /// </summary>
-    public class RadarChart : CommonChart
-    {
-        public string radarType { get; set; }
-    }
-    /// <summary>
-    /// type scatter
-    ///  scatterChart
-    ///     散点图 c:scatterStyle val="lineMarker"/>
-    ///     带直线的散点图 c:scatterStyle val="lineMarker"/>
-    ///     带直线和数据标记的散点图c:scatterStyle val="lineMarker"/>
-    ///     
-    ///     带平滑线和数据标记的散点图c:scatterStyle val="smoothMarker"/>
-    ///     带平滑线的散点图c:scatterStyle val="smoothMarker"/>
-    ///  bubbleChart 气泡图   三维气泡图
-    /// </summary>
-    public class ScatterChart : CommonChart
-    {
-        public string scatterType { get; set; }
-       // public bool Is3D { get; set; }
-    }
-    /// <summary>
-    /// type area
-    /// areaChart
-    ///     面积图 standard
-    ///     堆积面积图 stacked
-    ///     百分比堆积面积图 percentStacked
-    /// area3DChart
-    ///     三维面积图 standard
-    ///     三维堆积面积图 stacked
-    ///     三维百分比堆积面积图 percentStacked
-    /// </summary>
-    public class AreaChart : CommonChart
-    {
-        public string areaType { get; set; }
-        public bool is3D { get; set; }
-    }
-    /// <summary>
-    /// type bar  条形图c:barDir val="bar"/>   
-    ///  barChart
-    ///     簇状条形图 clustered
-    ///     堆积条形图 stacked
-    ///     百分比堆积条形图 percentStacked
-    ///  bar3DChart
-    ///     三维堆积条形图 stacked
-    ///     三维簇状条形图 clustered
-    ///     三维百分比堆积条形图 percentStacked
-    /// </summary>
-    public class BarChart : CommonChart
-    {
-        public string barType { get; set; }
-        public bool is3D { get; set; }
-    }
-    /// <summary>
-    ///  type bar  柱状图c:barDir val="col"/>
-    ///  barChart
-    ///     簇状柱形图 clustered
-    ///     堆积柱形图 stacked
-    ///     百分比堆积柱形图 percentStacked
-    ///  bar3DChart
-    ///     三维堆积柱形图 stacked
-    ///     三维簇状柱形图 clustered
-    ///     三维百分比堆积柱形图 percentStacked
-    ///     三维柱形图 standard
-    /// </summary>
-    public class ColChart : CommonChart
-    {
-        public string colType { get; set; }
-        public bool is3D { get; set; }
-    }
-    /// <summary>
-    ///  type line   
-    ///  lineChart
-    ///  合并
-    ///     折线图 standard
-    ///     带数据标记的折线图 standard 
-    ///  合并
-    ///     堆积折线图 stacked
-    ///     带标记的堆积折线图 stacked  c:layout>不为空
-    ///  合并 
-    ///     百分比堆积折线图 percentStacked
-    ///     带数据标记的百分比堆积折线图 percentStacked
-    ///  line3DChart
-    ///     三维折线图 standard
-    /// </summary>
-    public class LineChart : CommonChart
-    {
-        public string lineType { get; set; }
-        public bool is3D { get; set; }
-    }
-    
-    /// <summary>
-    ///   type pie
-    ///  pieChart
-    ///     饼图  不包含   
-    ///  ofPieChart
-    ///     子母饼图   包含 c:ofPieType val="pie"/> 且val为 pie
-    ///     复合条饼图 包含 c:ofPieType val="bar"/> 且val为 bar
-    ///  pie3DChart
-    ///     三维饼图
-    ///  doughnutChart
-    ///     圆环饼图
-    /// </summary>
-    public class PieChart : CommonChart
-    {
-        public string pieType { get; set; }
-        public bool is3D { get; set; }
-    }
-
-}

+ 0 - 20
TEAMModelOS/Models/PowerPoint/Connector.cs

@@ -1,20 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-
-    public class Connector : Item
-    {
-        
-        /// <summary>
-        ///连接线 p:cxnSp
-        /// </summary>
-        public string cxnType { get; set; }
-        //public string HeadEnd { get; set; }
-        //public string TailEnd { get; set; }
-        public Border border { get; set; }
-      
-    }
-}

+ 0 - 11
TEAMModelOS/Models/PowerPoint/Diagram.cs

@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public class Diagram :Item
-    {
-        public List<Item> shapes { get; set; }
-    }
-}

+ 0 - 47
TEAMModelOS/Models/PowerPoint/Fill.cs

@@ -1,47 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public class Fill
-    {
-
-        public Fill() {
-            grad = new List<string>();
-        }
-        /// <summary>
-        /// [a:noFill, solidFill, gradFill, blipFill, pattFill,        grpFill]
-        ///0,无填充 1.纯色填充 2.渐变填充 3.图片或纹理填充 4.图案填充
-        /// </summary>
-        public int type { get; set; }
-        public string color { get; set; }
-        public string image { get; set; }
-        public FillStyle style { get; set; }
-        //[Newtonsoft.Json.JsonIgnore]
-        //[System.Text.Json.Serialization.JsonIgnore]
-        //public string SvgText { get; set; }
-        //[Newtonsoft.Json.JsonIgnore]
-        //[System.Text.Json.Serialization.JsonIgnore]
-        //public string HtmlText { get; set; }
-        //渐变填充投射方向
-        public double rot { get; set; }
-        //渐变填充  以及前景色 背景色 的图案填充  颜色列表
-        public List<string> grad { get; set; }
-        /// <summary>
-        /// 图案填充的内置图形 ltDnDiag 等 48种内置图案
-        /// </summary>
-        public string patt { get; set; }
-
-    }
-    /// <summary>
-    /// 填充图片偏移量px
-    /// </summary>
-    public class FillStyle {
-        public int left { get; set; } = 0;
-        public int top { get; set; } = 0;
-        public int right { get; set; } = 0;
-        public int bottom { get; set; } = 0;
-    }
-
-}

+ 0 - 25
TEAMModelOS/Models/PowerPoint/FontStyle.cs

@@ -1,25 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public  class FontStyle
-    {
-        /// <summary>
-        /// 
-        /// font-family、font-style、font-weight、font-variant、font-stretch、font-size、font-size-adjust、
-        /// kerning、letter-spacing、word-spacing和text-decoration
-        /// </summary>
-        public string color { get; set; }
-        public double size { get; set; }
-        //inherit  继承父级
-        public string family { get; set; }
-        public string weight { get; set; }
-        public string style { get; set; }
-        public string decoration { get; set; }
-        public string vertAlign { get; set; }
-        public string align { get; set; }
-        public string shadow { get; set; }
-    }
-}

+ 0 - 11
TEAMModelOS/Models/PowerPoint/Group.cs

@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public  class Group : Item
-    {
-        public List<Item> shapes { get; set; }
-    }
-}

+ 0 - 43
TEAMModelOS/Models/PowerPoint/Htex.cs

@@ -1,43 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public class Htex
-    {
-        public Htex() {
-            slides = new List<string>();
-            //size = new PptSize();
-            //FontStyles = new Dictionary<string, FontStyle>();
-            //Fills = new Dictionary<string, Fill>();
-            //ParagraphStyles = new Dictionary<string, ParagraphStyle>();
-            //BuChars = new Dictionary<string, BuChar>();
-            //Borders = new Dictionary<string, Border>();
-
-        }
-        public HtexSize size { get; set; }
-        //缩略图
-        public string thumbnail { get; set; }
-        //PPT幻灯片集合
-        //  public List<string> HiXmls { get; set; }
-        public List<string> slides { get; set; }
-        // public string PptUrl { get; set; }
-        // public string Sha1Code { get; set; }
-        //页数
-        public int page { get; set; }
-
-        //public Dictionary<string, FontStyle> FontStyles { get;set;}
-        //public Dictionary<string, Fill> Fills { get; set; }
-        //public Dictionary<string, ParagraphStyle> ParagraphStyles { get; set; }
-        //public Dictionary<string, BuChar> BuChars { get; set; }
-        //public Dictionary<string, Border> Borders { get; set; }
-    }
-    public class HtexSize
-    {
-        //宽度
-        public double width { get; set; }
-        //高度
-        public double height { get; set; }
-    }
-}

+ 0 - 30
TEAMModelOS/Models/PowerPoint/Inner/WarpObj.cs

@@ -1,30 +0,0 @@
-using TEAMModelOS.Models.PowerPoint;
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Xml;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public class WarpObj
-    {
-        public XmlDocument zip { get; set; }
-        public NodesTable slideLayoutTables { get; set; }
-        public NodesTable slideMasterTables { get; set; }
-        public XmlNode slideMasterTextStyles { get; set; }
-        public Dictionary<string, Dictionary<string, string>> slideResObj { get; set; }
-        public Dictionary<string, Dictionary<string, string>> layoutResObj { get; set; }
-        public Dictionary<string, Dictionary<string, string>> masterResObj { get; set; }
-        public XmlNode slideLayoutContent { get; set; }
-        public XmlNode slideMasterContent { get; set; }
-        public XmlNode themeContent { get; set; }
-        public XmlNode tableStyles { get; set; }
-        public Htex htex { get; set; }
-    }
-
-
-}public class NodesTable { 
-    public Dictionary<string, XmlNode> idTable { get; set; }
-    public Dictionary<string, XmlNode> idxTable { get; set; }
-    public Dictionary<string, XmlNode> typeTable { get; set; }
-}

+ 0 - 23
TEAMModelOS/Models/PowerPoint/Item.cs

@@ -1,23 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public abstract class Item
-    {
-        // Sp  CxnSp Media Group  Table Chart Diagram
-        public string type { get; set; }
-        public Position position { get; set; }
-      //  public string Xml { get; set; }
-        public int index { get; set; }
-        public Svg svg { get; set; }
-
-        public string uid { get; set; } = Guid.NewGuid().ToString();
-        //public Picture Picture { get; set; }
-        //public Shape Shape { get; set; }
-        //public Math Math { get; set; }
-        //public Table Table { get; set; }
-        //public Chart Chart { get; set; }
-    }
-}

+ 0 - 17
TEAMModelOS/Models/PowerPoint/Math.cs

@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public class Math : Item
-    {
-    
-        public string content { get; set; }
-        
-        public Fill fill { get; set; }
-        
-        public Border border { get; set; }
-      
-    }
-}

+ 0 - 21
TEAMModelOS/Models/PowerPoint/Media.cs

@@ -1,21 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public   class Media : Item
-    {
-        //image 图片 video.视频 audio 音频
-        public string mediaType { get; set; }
-        //视频资源链接
-        public string url { get; set; }
-        //图片或视频音频缩略图链接
-        public string image { get; set; }
-     
-        public Fill fill { get; set; }
-      
-        public Border border { get; set; }
-     
-    }
-}

+ 0 - 54
TEAMModelOS/Models/PowerPoint/Paragraph.cs

@@ -1,54 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public class Paragraph
-    {
-         
-        public ParagraphStyle style { get; set; }
-        public Paragraph() {
-            texts = new List<Text>();
-        }
- 
-        public BuChar buChar { get; set; }
-        public List<Text> texts { get; set; }
-       
-    }
-    public class Text
-    {
-      //  public string StyleSha { get; set; }
-        public string content { get; set; }
-        public string href { get; set; }
-        public bool isbr { get; set; } = false;
-        
-        public FontStyle style { get; set; }
-    }
-
-    public class BuChar {
-        //TYPE_BULPIC  TYPE_NUMERIC TYPE_BULLET  TYPE_NONE  没有图标的 只有缩进
-        public string type{ get; set; }
-        public double left { get; set; }
-        public double riht { get; set; }
-        public string buchar { get; set; }
-        public string typeface { get; set; }
-        public double  size { get; set; }
-        public string @float { get; set; }
-        /// <summary>
-        /// ltr	默认。文本方向从左到右
-        /// rtl	文本方向从右到左。
-        /// inherit	规定应该从父元素继承 direction 属性的值。
-        /// </summary>
-        public string direction { get; set; } = "inherit";
-    }
-
-    public class ParagraphStyle
-    {
-        public string vert { get; set; }
-        // public string LeftMargin { get; set; }
-        public string hori { get; set; }
-        public string writing { get; set; }
-      
-    }
-}

+ 0 - 34
TEAMModelOS/Models/PowerPoint/Position.cs

@@ -1,34 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public class Position
-    {
-        //旋转角度
-        public double rot { get; set; } = 0;
-        //水平翻转
-        public int flipH { get; set; } = 0;
-        //垂直翻转
-        public int flipV { get; set; } = 0;
-        //x轴
-        public double x { get; set; } = 0;
-        //y轴
-        public double y { get; set; } = 0;
-        //宽度
-        public double cx { get; set; } = 0;
-        //高度
-        public double cy { get; set; } = 0;
-        ////初始坐标x
-        //public Int64 ChX { get; set; } = 0;
-        ////初始坐标Y
-        //public Int64 ChY { get; set; } = 0;
-        ////拉伸宽度
-        //public Int64 ChCX { get; set; } = 0;
-        ////拉伸高度
-        //public Int64 ChCY { get; set; } = 0;
-        //层级
-      
-    }
-}

+ 0 - 121
TEAMModelOS/Models/PowerPoint/Shape.cs

@@ -1,121 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-     public class Shape : Item
-    { 
-        public string shapeType;
-        public List<Paragraph> paragraph { get; set; }
-        public Fill fill { get; set; }
-        public Border border { get; set; }
-       
-        //public List<ShapeGuide> ShapeGuides { get; set; }
-        //public List<Path> Paths { get; set; }
-        //public string BorderSha { get; set; }
-        //public string FillSha { get; set; }
-
-    }
-
-    public class Svg {
-        public string id { get; set; }
-        //public string Width { get; set; }
-        //public string Height { get; set; }
-        //public string Top { get; set; }
-        //public string Left { get; set; }
-        //public string Style { get; set; }
-        public List<SvgShape> svgShape { get; set; }
-        //public string Defs { get; set; }
-      //  public string Transform { get; set; }
-  
-       // public string SvgData { get; set; }
-       
-    }
-
-    public abstract class SvgShape {
-        // rect ,circle ,ellipse ,line ,polygon ,polyline ,path
-        public string type { get; set; }
-       // public string Style { get; set; }
-       // public string Stroke { get; set; }
-        //描边的不透明度
-       // public string StrokeOpacity { get; set; } = "1";
-      //  public string StrokeWidth { get; set; }
-        // 虚线类型描边
-       // public string StrokeDasharray { get; set; }
-       // public string Fill { get; set; }
-        public string transform { get; set; }
-        public string start { get; set; }
-        public string end { get; set; }
-        //填充色的不透明度
-        //  public string FillOpacity { get; set; } = "1";
-    }
-    public class Rect : SvgShape
-    { 
-        //矩形左上角的x位置
-        public string x { get; set; }
-        //矩形左上角的y位置
-        public string y { get; set; }
-        //矩形的宽度
-        public string width { get; set; }
-        //矩形的高度
-        public string height { get; set; }
-        // 圆角的x方位的半径
-        public string rx { get; set; }
-        // 圆角的y方位的半径
-        public string ry { get; set; }
-    }
-    public class Circle : SvgShape
-    {
-        //圆的半径
-        public string r { get; set; }
-        //圆心的x位置
-        public string cx { get; set; }
-        //圆心的y位置
-        public string cy { get; set; }
-    }
-    public class Ellipse : SvgShape
-    {
-        // 椭圆的x方位的半径
-        public string rx { get; set; }
-        // 椭圆的y方位的半径
-        public string ry { get; set; }
-
-        //椭圆的x位置
-        public string cx { get; set; }
-        //椭圆的y位置
-        public string cy { get; set; }
-    }
-    public class Line : SvgShape
-    {
-        //起点的x位置
-        public string x1 { get; set; }
-        //起点的Y位置
-        public string y1 { get; set; }
-        //终点的X位置
-        public string x2 { get; set; }
-        //终点的Y位置
-        public string y2 { get; set; }
-    }
-    public class Polyline : SvgShape
-    {
-        /// <summary>
-        /// 点集数列。每个数字用空白、逗号、终止命令符或者换行符分隔开。每个点必须包含2个数字,一个是x坐标,一个是y坐标。所以点列表 (0,0), (1,1) 和(2,2)可以写成这样:“0 0, 1 1, 2 2”。
-        /// </summary>
-        public string points { get; set; }
-    }
-    public class Polygon : SvgShape
-    {
-        /// <summary>
-        /// 点集数列。每个数字用空白符、逗号、终止命令或者换行符分隔开。每个点必须包含2个数字,一个是x坐标,一个是y坐标。
-        /// 所以点列表 (0,0), (1,1) 和(2,2)可以写成这样:“0 0, 1 1, 2 2”。路径绘制完后闭合图形,所以最终的直线将从位置(2,2)连接到位置(0,0)。
-        /// </summary>
-        public string points { get; set; }
-
-    }
-    public class SvgPath : SvgShape
-    {
-        public string d { get; set; }
-    
-    }
-}

+ 0 - 26
TEAMModelOS/Models/PowerPoint/Slide.cs

@@ -1,26 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using TEAMModelOS.Models;
-using TEAMModelOS.SDK.Models;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public class Slide
-    {
-        public List<Item> item { get; set; }
-        public Fill fill { get; set; }
-        public int index { get; set; }
-        //宽度
-        public double width { get; set; }
-        //高度
-        public double height { get; set; }
-        public ItemInfo exercise { get; set; }
-        //1 PPTX  2 HTML  来源
-        public int source { get; set; }
-        /// <summary>
-        /// 1默认为普通页面,2为题目
-        /// </summary>
-        public int flag { get; set; } 
-    }
-}

+ 0 - 45
TEAMModelOS/Models/PowerPoint/Table.cs

@@ -1,45 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.Models.PowerPoint
-{
-    public class Table :Item
-    {
-        public Table() {
-            tr = new List<Tr>();
-        }
-        //内容排版方向 左书写 右书写
-        public string dir { get; set; }
-        public string collapse { get; set; } = "collapse";
-       // public Border Border { get; set; }
-       // public Fill Fill { get; set; }
-        public List<Tr> tr { get; set; }
-    }
-
-    public class Tr {
-        public Tr()
-        {
-            td = new List<Td>();
-        }
-       
-        public Fill fill { get; set; }
-        public  double height { get; set; }
-        public List<Td> td { get; set; }
-    
-        public List<Border> borders { get; set; }
-    }
-    public class Td
-    {
-        public double width { get; set; }
-    
-        public Fill fill { get; set; }
-        public int rowspan { get; set; }
-        public int colspan { get; set; }
-
-        public int vmerge { get; set; }
-        public int hmerge { get; set; }
-        public List<Paragraph> paragraphs { get; set; }
-      
-    }
-}

+ 454 - 0
TEAMModelOS/Services/Common/ActivityService.cs

@@ -0,0 +1,454 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Models.Cosmos;
+using TEAMModelOS.SDK.Extension;
+using Azure.Cosmos;
+using TEAMModelOS.SDK.DI;
+using HTEXLib.COMM.Helpers;
+using System.Text;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
+using StackExchange.Redis;
+
+namespace TEAMModelOS.Services.Common
+{
+    public static class ActivityService
+    {
+
+        /// <summary>
+        /// 活动委托
+        /// </summary>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        delegate dynamic DoActivityTips(ActivityData data, AzureCosmosFactory _azureCosmos,string id, AzureRedisFactory _azureRedis);
+
+        public static async Task<int> Decide(JsonElement request,AzureCosmosFactory _azureCosmos,AzureRedisFactory _azureRedis,string userid ) {
+
+            DateTimeOffset now = DateTimeOffset.UtcNow;
+            long curr = now.ToUnixTimeMilliseconds();
+            byte msgid = 0;//0投票失败,1投票成功,2不在时间范围内,3不在发布范围内,4投票周期内重复投票,5周期内的可投票数不足,6未设置投票项
+            //活动id
+            if (!request.TryGetProperty("id", out JsonElement id)) {
+                return msgid;
+            }
+            //活动分区
+            if (!request.TryGetProperty("code", out JsonElement code)) {
+                return msgid;
+            }
+            List<string> option = new List<string>();
+            if (request.TryGetProperty("option", out JsonElement joption))
+            {
+                option = joption.ToObject<List<string>>();
+                if (option.IsEmpty())
+                {
+                    msgid = 6;
+                    return msgid; 
+                }
+            }
+            else
+            {
+                return msgid;
+            }
+         
+            try
+            {
+                //1.再次检查投票
+                var client = _azureCosmos.GetCosmosClient();
+                Vote vote = null;
+                ///TODO 检查是否在投票范围内,包括在tmdids 及班级  但是需要处理认证金钥中的班级问题
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<Vote>(queryText: $"select c.progress,c.times,c.voteNum,c.startTime,c.endTime from c where c.id = '{id}'",
+                    requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
+                {
+                    vote = item;
+                    break;
+                }
+                if (vote != null)
+                {
+                    //判断投票时间是否在起止时间内
+                    if (curr >= vote.startTime && curr <= vote.endTime)
+                    {
+                        string Field = "";
+                        RedisValue value;
+                        switch (vote.times) {
+                            case "once":
+                                // //如果是只能投票一次的活动则直接获取Redis的第一条 只能投一次
+                                Field = $"{userid}-once";
+                                RedisValue[] values = _azureRedis.GetRedisClient(8).HashValues($"Vote:Record:{vote.id}_{vote.code}");
+                                if (values != null  && values.Length > 0)
+                                {
+                                    msgid = await VoteIng(vote, values[0], msgid, option, Field, curr, _azureRedis);
+                                }
+                                else
+                                {
+                                    msgid = 1;
+                                }
+                                break;
+                            case "day": //周期内每天
+                                Field = $"{userid}-day-{now.ToString("yyyyMMdd")}";
+                                value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}_{vote.code}", Field);
+                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis);
+                                break;
+                            case "week": //自然周
+                                Field = $"{userid}-week-{now.ToString("yyyy")}{GetWeek(now)}";
+                                value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}_{vote.code}", Field);
+                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis); 
+                                break;
+                            case "month":  //月份
+                                Field = $"{userid}-month-{now.ToString("yyyyMM")}";
+                                value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}_{vote.code}", Field);
+                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis); 
+                                break;
+                            case "year"://年份
+                                Field = $"{userid}-year-{now.ToString("yyyy")}";
+                                value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}_{vote.code}", Field);
+                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis);
+                                break;
+                        }
+                    }
+                    else
+                    {
+                        msgid = 2;
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+            }
+            return msgid;
+        }
+        public static async Task<byte> VoteIng(Vote vote, RedisValue value, byte msgid, List<string> option, string Field, long curr, AzureRedisFactory _azureRedis)
+        {
+            if (!value.IsNullOrEmpty)
+            {
+                VoteRecord record=value.ToString().ToObject<VoteRecord>();
+                //处理记录投票+当前设置的投票是否小于等于周期内最大投票数
+                if (record.opt.Count + option.Count <= vote.voteNum)
+                {
+                    record.opt.AddRange(option);
+                    record.time = curr;
+                    //保存投票记录
+                    bool status = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}_{vote.code}", Field, record.ToJsonString());
+                    //当前投票分组计数存入活动的Redis
+                    var group_opt= option.GroupBy(x => x);
+                    foreach (var opt in group_opt) {
+                        await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Vote:Count:{vote.id}_{vote.code}", opt.Key, opt.Count());
+                    }
+                    if (status)
+                    {
+                        msgid = 1;
+                    }
+                }
+                else
+                {
+                    msgid = 5;
+                }
+            }
+            else
+            {
+                //保存投票记录
+                VoteRecord record = new VoteRecord { opt = option, time = curr };
+                bool status = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}_{vote.code}", Field, record.ToJsonString());
+                //当前投票分组计数存入活动的Redis
+                var group_opt = option.GroupBy(x => x);
+                foreach (var opt in group_opt)
+                {
+                    await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Vote:Count:{vote.id}_{vote.code}", opt.Key, opt.Count());
+                }
+                if (status)
+                {
+                    msgid = 1;
+                }
+            }
+            return msgid;
+        }
+        /// <summary>
+        /// 获取时间的在当年的第几周
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <returns></returns>
+        public static int GetWeek(DateTimeOffset dt)
+        {
+            DateTimeOffset time = Convert.ToDateTime(dt.ToString("yyyy") + "-01-01");
+            TimeSpan ts = dt - time;
+            int iii = (int)time.DayOfWeek;
+            int day = int.Parse(ts.TotalDays.ToString("F0"));
+            if (iii == 0)
+            {
+                day--;
+            }
+            else
+            {
+                day = day - (7 - iii) - 1;
+            }
+            int week = ((day + 7) / 7) + 1;
+            return week;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="containerId">容器</param>
+        /// <param name="requert"></param>
+        /// <param name="id">登录者ID</param>
+        /// <param name="_azureCosmos"></param>
+        /// <returns></returns>
+        public static async Task<(List<ActivityData> datas, string continuationToken)> FindByRole(string containerId, JsonElement requert, string id, AzureCosmosFactory _azureCosmos,AzureRedisFactory _azureRedis)
+        {
+            //开始时间,默认最近三十天
+            var stimestamp = DateTimeOffset.UtcNow.AddDays(-30).ToUnixTimeMilliseconds();
+            if (!requert.TryGetProperty("stime", out JsonElement stime))
+            {
+                if (stime.TryGetInt64(out long data))
+                {
+                    stimestamp = data;
+                } 
+            } 
+            if (!requert.TryGetProperty("type", out JsonElement type))
+            {
+                //if (stime.TryGetInt64(out long data))
+                //{
+                //    stimestamp = data;
+                //} 
+            } 
+            //默认当前时间,  未开始的不能查询
+            var etimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+            //if (!requert.TryGetProperty("etime", out JsonElement etime))
+            //{
+            //    if (etime.TryGetInt64(out long data))
+            //    {
+            //        etimestamp = data;
+            //    };
+            //};
+            string continuationToken = null;
+            //默认不指定返回大小
+            int? topcout = null;
+            if (!requert.TryGetProperty("count", out JsonElement jcount))
+            {
+                if (jcount.TryGetInt32(out int data))
+                {
+                    topcout = data;
+                } 
+            } 
+            //是否需要进行分页查询,默认不分页
+            bool iscontinuation = false;
+            //如果指定了返回大小
+            if (!requert.TryGetProperty("continuationToken", out JsonElement continuation))
+            {
+                //指定了cancellationToken 表示需要进行分页
+                if (!continuation.ValueKind.Equals(JsonValueKind.Null) && continuation.ValueKind.Equals(JsonValueKind.String))
+                {
+                    continuationToken = continuation.GetString();
+                    iscontinuation = true;
+                }
+            } 
+            //班级
+            List<string> classes=null;
+            if (!requert.TryGetProperty("classes", out JsonElement jclasses))
+            {
+                if (jclasses.ValueKind is JsonValueKind.Array ) {
+                    classes = jclasses.ToObject<List<string>>();
+                }
+            } 
+            string query = null;
+            if (classes.IsNotEmpty() )
+            {
+                StringBuilder insql =new StringBuilder();
+                classes.ForEach( x => { insql.Append($"'{x}',"); });
+                string sql = insql.ToString();
+                sql = sql.ToString().Substring(0, sql.Length - 2);
+                query = $" SELECT distinct  value c   FROM c   JOIN A0 IN c.classes join A1 in c.tmdids   where c.startTime >= {stimestamp} and c.startTime <= {etimestamp} and  c.pk='Activity'  and   (A0 in('{sql}') or A1 in ('{id}')) ";
+            }
+            else {
+                query = $" SELECT distinct  value c   FROM c    join A1 in c.tmdids   where c.startTime >= {stimestamp} and c.startTime <= {etimestamp}  and c.pk='Activity'  and   A1 ='{id}' ";
+            }
+            
+            List<ActivityData> datas = new List<ActivityData>();
+            var client = _azureCosmos.GetCosmosClient();
+            await foreach (var item in client.GetContainer("TEAMModelOS", containerId).GetItemQueryStreamIterator(query, continuationToken: continuationToken, requestOptions: new QueryRequestOptions() { MaxItemCount = topcout, PartitionKey = new PartitionKey($"Common-{id}") }))
+            {
+                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())
+                    {
+                        datas.Add(obj.ToObject<ActivityData>());
+                    }
+                    //如果需要分页则跳出
+                    if (iscontinuation)
+                    {
+                        continuationToken = item.GetContinuationToken();
+                        break;
+                    }
+                }
+            }
+            bool tips = false;
+            if (!requert.TryGetProperty("tips", out JsonElement jtips))
+            {
+                //指定了cancellationToken 表示需要进行分页
+                if (!jtips.ValueKind.Equals(JsonValueKind.Null) && !jtips.ValueKind.Equals(JsonValueKind.True))
+                {
+                    tips = jtips.GetBoolean();
+                }
+            }
+            if (tips)
+            {
+                DoActivityTips activityTips;
+                dynamic res = default;
+                foreach (var data in datas)
+                {
+                    switch (data.type)
+                    {
+                        //投票
+                        case "vote":
+                            activityTips = DoVoteTips;
+                            //msgid, //0不能投票,1可以投票,2不在时间范围内,3周期内的可投票数不足
+                            //voteCount 可用投票数
+                            res = activityTips(data, _azureCosmos, id, _azureRedis);
+                            break;
+                        //问卷
+                        case "survey":
+                            //msgid 0 已作答, 1未作答,2,未完成
+                            activityTips = DoSurveyTips;
+                            res = activityTips(data, _azureCosmos, id, _azureRedis);
+                            break;
+                        //评测
+                        case "exam":
+                            //msgid 0 已作答, 1未作答,2,未完成, 用时间控制 相关发布状态,并且展示相应的结果
+                            activityTips = DoExamTips;
+                            res = activityTips(data, _azureCosmos, id, _azureRedis);
+                            break;
+                        //学习活动
+                        case "learn":
+                            //msgid 0 已完成, 1未开始,2,未完成
+                            activityTips = DoLearnTips;
+                            res = activityTips(data, _azureCosmos, id, _azureRedis);
+                            break;
+                        //作业活动
+                        case "homework":
+                            //msgid 0 已作答, 1未作答,2,未完成,3已批改,且有错误,4已批改,已完成
+                            //index:0,1,5 错误题序
+                            activityTips = DoHomeworkTips;
+                            res = activityTips(data, _azureCosmos, id, _azureRedis);
+                            break;
+                        default: break;
+                    }
+                }
+            }
+            return (datas, continuationToken);
+        }
+        private async static Task<dynamic> DoVoteTips(ActivityData commonData , AzureCosmosFactory _azureCosmos,string userid,AzureRedisFactory _azureRedis)
+        {
+            Vote vote=null;
+            var client = _azureCosmos.GetCosmosClient();
+            await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<Vote>($"select value c from c where c.id='{commonData.id}'", 
+                requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey(commonData.scode) }))
+            {
+                vote = item;
+                break;
+            }
+            byte msgid = 0;
+            int voteCount = 0;
+            if (vote != null) {
+                DateTimeOffset now = DateTimeOffset.UtcNow;
+                long curr = now.ToUnixTimeMilliseconds();
+                //判断投票时间是否在起止时间内
+                if (curr >= vote.startTime && curr <= vote.endTime)
+                {
+                    string Field = "";
+                    RedisValue value = default;
+                    switch (vote.times)
+                    {
+                        case "once":
+                            // //如果是只能投票一次的活动则直接获取Redis的第一条 只能投一次
+                            Field = $"{userid}-once";
+                            RedisValue[] values = _azureRedis.GetRedisClient(8).HashValues($"Vote:Record:{vote.id}_{vote.code}");
+                            if (values != null && values.Length>0)
+                            {
+                                value = values[0];
+                            }
+                            break;
+                        case "day": //周期内每天
+                            Field = $"{userid}-day-{now.ToString("yyyyMMdd")}";
+                            value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}_{vote.code}", Field);
+                            break;
+                        case "week": //自然周
+                            Field = $"{userid}-week-{now.ToString("yyyy")}{GetWeek(now)}";
+                            value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}_{vote.code}", Field);
+                            
+                            break;
+                        case "month":  //月份
+                            Field = $"{userid}-month-{now.ToString("yyyyMM")}";
+                            value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}_{vote.code}", Field);
+                           
+                            break;
+                        case "year"://年份
+                            Field = $"{userid}-year-{now.ToString("yyyy")}";
+                            value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}_{vote.code}", Field);
+                           
+                            break;
+                    }
+                    if (value != default && !value.IsNullOrEmpty)
+                    {
+                        List<string> opt = null;
+                        JsonElement record = value.ToString().ToObject<JsonElement>();
+                        if (record.TryGetProperty("opt", out JsonElement jopt)) {
+                            opt = jopt.ToObject<List<string>>();
+                        }
+                        if (opt != null)
+                        {
+                            //处理记录投票是否小于等于周期内最大投票数
+                            if (opt.Count <= vote.voteNum)
+                            {
+                                voteCount = vote.voteNum - opt.Count;
+                                msgid = 1;
+                            }
+                            else
+                            {
+                                //3周期内的可投票数不足
+                                msgid = 3;
+                                voteCount = 0;
+                            }
+                        }
+                        else {
+                            msgid = 1;
+                            voteCount = vote.voteNum;
+                        }
+                    }
+                    else {
+                        //未投票,可以投票
+                        msgid = 1;
+                        voteCount = vote.voteNum;
+                    }
+                }
+                else
+                {
+                    msgid = 2; 
+                    voteCount = 0;
+
+                }
+            }
+            return new {msgid,voteCount };
+        }
+
+        private static dynamic DoHomeworkTips(ActivityData commonData, AzureCosmosFactory _azureCosmos, string id, AzureRedisFactory _azureRedis)
+        {
+            return null;
+        }
+        private static dynamic DoLearnTips(ActivityData commonData, AzureCosmosFactory _azureCosmos, string id, AzureRedisFactory _azureRedis)
+        {
+            return null;
+        }
+        private static dynamic DoExamTips(ActivityData commonData, AzureCosmosFactory _azureCosmos, string id, AzureRedisFactory _azureRedis)
+        {
+            return null;
+        }
+        private static dynamic DoSurveyTips(ActivityData commonData, AzureCosmosFactory _azureCosmos, string id, AzureRedisFactory _azureRedis)
+        {
+            return null;
+        }
+       
+    }
+}

+ 1 - 1
TEAMModelOS/Startup.cs

@@ -107,7 +107,7 @@ namespace TEAMModelOS
             services.Configure<Option>(options => Configuration.GetSection("Option").Bind(options));
 
             //注入CSRedis  
-            var csredis = new CSRedis.CSRedisClient(Configuration.GetSection("Azure:Redis:ConnectionString").Get<string>());
+            var csredis = new CSRedis.CSRedisClient(Configuration.GetSection("Azure:Redis:ConnectionString").Get<string>()+ ",defaultDatabase=8,writeBuffer=10240,poolsize=50,prefix=habook:");
             CSRedis.CSRedisClient.Serialize = obj => System.Text.Json.JsonSerializer.Serialize(obj);
             CSRedis.CSRedisClient.Deserialize = (json, type) => System.Text.Json.JsonSerializer.Deserialize(json, type);
             RedisHelper.Initialization(csredis);