瀏覽代碼

Merge branch 'develop3.0-tmd' into develop3.0

CrazyIter_Bin 4 年之前
父節點
當前提交
cdce89d8e9
共有 31 個文件被更改,包括 1125 次插入234 次删除
  1. 1 1
      TEAMModelFunction/MonitorCosmosDB.cs
  2. 135 9
      TEAMModelFunction/TriggerSurvey.cs
  3. 13 15
      TEAMModelFunction/TriggerVote.cs
  4. 2 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/VoteRecord.cs
  5. 0 38
      TEAMModelOS.SDK/Models/Cosmos/Student/SurveyRecord.cs
  6. 0 41
      TEAMModelOS.SDK/Models/Cosmos/Student/VoteRecord.cs
  7. 4 0
      TEAMModelOS/ClientApp/src/api/questionnaire.js
  8. 5 2
      TEAMModelOS/ClientApp/src/api/studentWeb.js
  9. 4 0
      TEAMModelOS/ClientApp/src/assets/student-web/component_styles/vote.css
  10. 1 1
      TEAMModelOS/ClientApp/src/common/BaseKonva.vue
  11. 125 0
      TEAMModelOS/ClientApp/src/components/questionnaire/BasePie.vue
  12. 193 0
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseProgress.vue
  13. 1 1
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseQuestionnaire.vue
  14. 76 0
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseSsTable.less
  15. 94 0
      TEAMModelOS/ClientApp/src/components/questionnaire/BaseSsTable.vue
  16. 71 41
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/Vote.vue
  17. 7 5
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/composePaper.vue
  18. 4 12
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventList.vue
  19. 3 5
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/MissionListCard.vue
  20. 0 3
      TEAMModelOS/ClientApp/src/components/vote/BaseVoteForm.vue
  21. 2 2
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue
  22. 7 3
      TEAMModelOS/ClientApp/src/view/learnactivity/CreatePrivEva.vue
  23. 8 4
      TEAMModelOS/ClientApp/src/view/learnactivity/CreateSchoolEva.vue
  24. 6 3
      TEAMModelOS/ClientApp/src/view/learnactivity/PaperScore.vue
  25. 15 0
      TEAMModelOS/ClientApp/src/view/questionnaire/ManageQuestionnaire.less
  26. 111 4
      TEAMModelOS/ClientApp/src/view/questionnaire/ManageQuestionnaire.vue
  27. 185 5
      TEAMModelOS/Controllers/Common/SurveyController.cs
  28. 35 25
      TEAMModelOS/Controllers/Common/VoteController.cs
  29. 2 2
      TEAMModelOS/Controllers/Knowledge/KnowledgesController.cs
  30. 2 2
      TEAMModelOS/Controllers/knowledge/KnowledgeController.cs
  31. 13 10
      TEAMModelOS/Services/Common/ActivityStudentService.cs

+ 1 - 1
TEAMModelFunction/MonitorCosmosDB.cs

@@ -67,7 +67,7 @@ namespace TEAMModelFunction
                                 TriggerVote.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school, _azureRedis);
                                 break;
                             case "Survey":
-                                TriggerSurvey.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school, _azureRedis);
+                                TriggerSurvey.Trigger(_azureCosmos, _serviceBus, _azureStorage, _dingDing, client, input, code, stime, etime, school, _azureRedis, _clientFactory);
                                 break;
 
                         }

+ 135 - 9
TEAMModelFunction/TriggerSurvey.cs

@@ -4,6 +4,7 @@ using Azure.Storage.Blobs.Models;
 using Microsoft.Azure.Documents;
 using System;
 using System.Collections.Generic;
+using System.Net.Http;
 using System.Text;
 using System.Text.Json;
 using System.Threading.Tasks;
@@ -12,13 +13,15 @@ using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos;
+using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
+using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
 
 namespace TEAMModelFunction
 {
    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,AzureRedisFactory _azureRedis)
+               CosmosClient client, Document input, string code, long stime, long etime, string school,AzureRedisFactory _azureRedis, System.Net.Http.IHttpClientFactory _clientFactory)
         {
             Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Survey>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
             List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", survey.progress } });
@@ -117,25 +120,148 @@ namespace TEAMModelFunction
                     }
                     break;
                 case "finish":
-                    var records =await  _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
+                    var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
                     List<dynamic> recs = new List<dynamic>();
-                    foreach (var rcd in records) {
+                    foreach (var rcd in records)
+                    {
                         var value = rcd.Value.ToString().ToObject<JsonElement>();
                         recs.Add(new { index = rcd.Name.ToString(), ans = value });
                     }
                     var cods = new { records = recs };
                     //问卷整体情况
-                    await  _azureStorage.UploadFileByContainer(survey.owner, cods.ToJsonString(), "survey", $"{survey.id}/record.json");
+                    await _azureStorage.UploadFileByContainer(survey.owner, cods.ToJsonString(), "survey", $"{survey.id}/record.json");
                     //结算每道题的答题情况
-                   
-                    var ContainerClient =   _azureStorage.GetBlobContainerClient(survey.owner);
+
+                    var ContainerClient = _azureStorage.GetBlobContainerClient(survey.owner);
                     var route = ContainerClient.Uri.ToString();
                     List<BlobItem> items = await ContainerClient.List($"survey/{survey.id}/urecord");
-                    items.ForEach(x => {
-                        var url = $"{route}/{x.Name}";
-                    });
+                    List<SurveyRecord> surveyRecords = new List<SurveyRecord>();
+                    //获取
+
+                    foreach (BlobItem item in items)
+                    {
+                        BlobAuth blobAuth = _azureStorage.GetBlobSasUriRead(survey.owner, $"{item.Name}");
+                        var url = $"{route}/{item.Name}?{blobAuth.sas}";
+                        var response = await _clientFactory.CreateClient().GetAsync(new Uri(url));
+                        var json = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
+                        var Record = json.RootElement.ToObject<SurveyRecord>();
+                        surveyRecords.Add(Record);
+                    }
+                    List<Task<string>> tasks = new List<Task<string>>();
+                    for (int index = 0; index < survey.ans.Count; index++)
+                    {
+                        string url = $"{survey.id}/qrecord/{index}.json";
+                        QuestionRecord question = new QuestionRecord() { index = index };
+                        foreach (SurveyRecord record in surveyRecords)
+                        {
+                            if (record.ans.Count == survey.ans.Count)
+                            {
+                                foreach (var an in record.ans[index])
+                                {
+                                    //
+                                    if (question.opt.ContainsKey(an))
+                                    {
+                                        if (question.opt[an] != null)
+                                        {
+                                            question.opt[an].Add(record.userid);
+                                        }
+                                        else
+                                        {
+                                            question.opt[an] = new HashSet<string>() { record.userid };
+                                        }
+                                    }
+                                    else
+                                    {
+                                        if (survey.ans[index].Contains(an))
+                                        {
+                                            //如果是客观题code
+                                            question.opt.Add(an, new HashSet<string> { record.userid });
+                                        }
+                                        else
+                                        {
+                                            //如果不是客观code
+                                            question.other[record.userid] = an;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        tasks.Add(_azureStorage.UploadFileByContainer(survey.owner, question.ToJsonString(), "survey", url, false));
+                    }
+                    await Task.WhenAll(tasks);
+                    survey.recordUrl = $"/survey/{survey.id}/record.json";
+                    await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync<Survey>(survey, survey.id, new Azure.Cosmos.PartitionKey(survey.code));
+                    //更新结束状态
+                    if (survey.scope == "school")
+                    {
+                        data = new ActivityData
+                        {
+                            id = survey.id,
+                            code = $"Activity-{survey.owner}",
+                            type = "survey",
+                            name = survey.name,
+                            startTime = survey.startTime,
+                            endTime = survey.endTime,
+                            scode = survey.code,
+                            scope = survey.scope,
+                            progress = "finish",
+                            classes = survey.classes.IsNotEmpty() ? survey.classes : new List<string> { "" },
+                            tmdids = survey.tmdids.IsNotEmpty() ? survey.tmdids : new List<string> { "" },
+                            owner = survey.owner,
+                            subjects = new List<string> { "" }
+
+                        };
+                        await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
+                    }
+                    else if (survey.scope == "private")
+                    {
+                        //更新结束状态
+                        data = new ActivityData
+                        {
+                            id = survey.id,
+                            code = $"Activity-Common",
+                            type = "survey",
+                            name = survey.name,
+                            startTime = survey.startTime,
+                            endTime = survey.endTime,
+                            scode = survey.code,
+                            scope = survey.scope,
+                            progress = "finish",
+                            classes = survey.classes.IsNotEmpty() ? survey.classes : new List<string> { "" },
+                            owner = survey.owner,
+                            tmdids = new List<string> { "" },
+                            subjects = new List<string> { "" }
+                        };
+                        await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
+                    }
                     break;
             }
         }
     }
+    /**
+     * {survey.id}/qrecord/{index}.json
+        {
+            "opt": {
+                "A": [
+                    "userid1",
+                    "userid2",
+                    "userid3"
+                ],
+                "B": [
+                    "userid1",
+                    "userid2",
+                    "userid3"
+                ]
+            },
+            "other": {
+                "userid1": "建议XXXX1",
+                "userid2": "建议XXXX2"
+            }
+        }
+     **/
+    public class QuestionRecord { 
+        public int index { get; set; }
+        public Dictionary<string, HashSet<string>> opt { get; set; } = new Dictionary<string, HashSet<string>>();
+        public Dictionary<string, string> other { get; set; } = new Dictionary<string, string>();
+    }
 }

+ 13 - 15
TEAMModelFunction/TriggerVote.cs

@@ -3,6 +3,7 @@ using Azure.Messaging.ServiceBus;
 using Microsoft.Azure.Documents;
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Text;
 using System.Text.Json;
 using System.Threading.Tasks;
@@ -11,6 +12,7 @@ using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos;
+using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
 
 namespace TEAMModelFunction
 {
@@ -137,27 +139,23 @@ namespace TEAMModelFunction
                             }
                         }
                         List<Task<string>> tasks = new List<Task<string>>();
-                        List<dynamic> recordsBlob = new List<dynamic>();
+                        List<VoteRecord> recordsBlob = new List<VoteRecord>();
                         foreach (var rcd in records) {
-                            var key = rcd.Name.ToString().Split("-")[0];
-                            var value = rcd.Value.ToString().ToObject<JsonElement>();
-                            recordsBlob.Add(new { key,value});
-                            tasks.Add(_azureStorage.UploadFileByContainer(vote.owner, value.ToJsonString(), "vote", $"{vote.id}/{key}.json"));
+                            var value = rcd.Value.ToString().ToObject<VoteRecord>();
+                            recordsBlob.Add(value);
+                        }
+                        //分组每个人的 
+                        var gp= recordsBlob.GroupBy(x => x.userid).Select(x=>new { key=x.Key,list=x.ToList()});
+                        foreach (var g in gp) { 
+                            tasks.Add(_azureStorage.UploadFileByContainer(vote.owner, g.list.ToJsonString(), "vote", $"{vote.id}/urecord/{g.key}.json"));
                         }
                         //处理活动方的记录
-                        string url = $"vote/{vote.id}/index.json";
+                        string url = $"vote/{vote.id}/record.json";
                         vote.recordUrl = url;
-                        tasks.Add(_azureStorage.UploadFileByContainer(vote.owner, recordsBlob.ToJsonString(), "vote", $"{vote.id}/index.json"));
+                        tasks.Add(_azureStorage.UploadFileByContainer(vote.owner, recordsBlob.ToJsonString(), "vote", $"{vote.id}/record.json"));
                         //处理投票者的记录
                         await Task.WhenAll(tasks);
-                        if (vote.scope == "school")
-                        {
-                            await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<Vote>(vote,vote.id, new Azure.Cosmos.PartitionKey(vote.code));
-                        }
-                        else if (vote.scope == "private")
-                        {
-                            await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Vote>(vote, vote.id, new Azure.Cosmos.PartitionKey(vote.code));
-                        }
+                        await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync<Vote>(vote, vote.id, new Azure.Cosmos.PartitionKey(vote.code));
                         //更新结束状态
                         if (vote.scope == "school")
                         {

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

@@ -9,5 +9,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common.Inner
         public Dictionary<string, int> opt { get; set; } = new Dictionary<string, int>();
         public long time { get; set; }
         public string userid { get; set; }
+        public string times { get; set; }
+        public string endpoint { get; set; }
     }
 }

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

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

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

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

+ 4 - 0
TEAMModelOS/ClientApp/src/api/questionnaire.js

@@ -28,4 +28,8 @@ export default {
 	UpsertRecord: function(data) {
 	    return post('/common/survey/upsert-record', data)
 	},
+	// 查询问卷作答记录
+	GetAnswerdRecord: function(data) {
+	    return post('/common/survey/answered', data)
+	},
 }

+ 5 - 2
TEAMModelOS/ClientApp/src/api/studentWeb.js

@@ -175,6 +175,9 @@ export default {
     //查詢學生端投票结果
     getVoteResult: function (data) {
         return post('/common/vote/record',data)
+    },
+    //提交投票结果数据
+    sendVoteResult: function (data) {
+        return post('/common/vote/decide',data)
     }
-}
-
+}

+ 4 - 0
TEAMModelOS/ClientApp/src/assets/student-web/component_styles/vote.css

@@ -22,6 +22,10 @@
   border: none;
 }
 .vote .checkAnswer .testBtn input[type="checkbox"]:checked ~ .testbg span {
+  color: #5e5a6e;
+  font-weight: bolder;
+}
+.vote .checkAnswer .testBtn input[type="checkbox"]:checked ~ .testbg .vote-info {
   color: #fff;
   font-weight: bolder;
 }

+ 1 - 1
TEAMModelOS/ClientApp/src/common/BaseKonva.vue

@@ -283,7 +283,7 @@
 			
 			/* 渲染背景图 */
 			doRenderImg(src){
-				console.log(src)
+				//console.log(src)
 				const image = new Image()
 				image.src = src
 				image.setAttribute('crossOrigin', 'anonymous')

+ 125 - 0
TEAMModelOS/ClientApp/src/components/questionnaire/BasePie.vue

@@ -0,0 +1,125 @@
+<template>
+	<div :id="barId" class="myBar"></div>
+</template>
+
+<script>
+	export default {
+		name: 'BaseBar',
+		props: ['barId','total', 'noAnswerdCount'],
+		data() {
+			return {
+				barDatas: []
+			}
+		},
+		methods: {
+
+			drawLine(data) {
+				let that = this
+				// 基于准备好的dom,初始化echarts实例
+				let myBar = this.$echarts.init(document.getElementById(this.barId), 'chalk')
+				let option = {
+					title: {
+						text: '参与人数统计',
+						top: 25,
+						left:'center',
+						textStyle: {
+							color: '#f3f3f3',
+							fontSize:12,
+							fontWeight:'bold'
+						}
+					},
+
+					tooltip: {
+						trigger: 'item',
+						formatter: "{b} : {c} ({d}%)"
+					},
+					series: [{
+						type: 'pie',
+						radius: '50%',
+						center: ['50%', '50%'],
+						color: ['#08ffb5', '#879c93'],
+						data: [{
+								value: this.total - this.noAnswerdCount,
+								name: '已完成'
+							},
+							{
+								value: this.noAnswerdCount,
+								name: '未完成'
+							},
+						].sort(function(a, b) {
+							return a.value - b.value
+						}),
+						label: {
+							normal: {
+								formatter: ['{c|{c}人}', '{b|{b}}'].join('\n'),
+								rich: {
+									c: {
+										color: 'rgb(246, 246, 246)',
+										fontSize: 12,
+										fontWeight: 'bold',
+										lineHeight: 2
+									},
+									b: {
+										color: 'rgb(43, 163, 169)',
+										fontSize: 12,
+										height: 40
+									},
+								},
+							}
+						},
+						labelLine: {
+							normal: {
+								lineStyle: {
+									color: 'rgb(98,137,169)',
+								},
+								smooth: 0.2,
+								length: 10,
+								length2: 20,
+
+							}
+						},
+						itemStyle: {
+							normal: {
+								shadowColor: 'rgba(0, 0, 0, 0.8)',
+								shadowBlur: 10,
+							}
+						}
+					}]
+				};
+
+				// 绘制图表
+				myBar.setOption(option)
+
+				window.addEventListener('resize', function() {
+					myBar.resize()
+				})
+			}
+		},
+		mounted() {
+			let arr = []
+			if (!this.total) return
+			this.drawLine()
+
+
+		},
+		watch: {
+			total: {
+				deep: true,
+				handler(val) {
+					this.drawLine()
+				}
+			}
+		}
+
+	}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+	.myBar {
+		width: 50%;
+		height: 280px;
+		margin: 0 auto;
+		display: block;
+	}
+</style>

+ 193 - 0
TEAMModelOS/ClientApp/src/components/questionnaire/BaseProgress.vue

@@ -0,0 +1,193 @@
+<template>
+	<div :id="barId" class="myBar"></div>
+</template>
+
+<script>
+	export default {
+		name: 'BaseBar',
+		props: ['barId','total', 'noAnswerdCount'],
+		data() {
+			return {
+				barDatas: []
+			}
+		},
+		methods: {
+
+			drawLine(data) {
+				let that = this
+				// 基于准备好的dom,初始化echarts实例
+				let myBar = this.$echarts.init(document.getElementById(this.barId), 'chalk')
+				var color = ['#12a568', '#12a568', '#17d988']
+				let option = {
+					// backgroundColor: 'rgba(255,255,255,0.05)',
+					title: {
+						text: ((this.total - this.noAnswerdCount) / this.total).toFixed(2) * 100 + '%',
+						textStyle: {
+							color: color[2],
+							fontSize: 20
+						},
+						itemGap: 20,
+						left: 'center',
+						top: 'center'
+					},
+					tooltip: {},
+					angleAxis: {
+						max: 100,
+						clockwise: false, // 逆时针
+						// 隐藏刻度线
+						show: false,
+						boundaryGap: ['40%', '40%'],
+						startAngle: 90,
+					},
+					radiusAxis: {
+						type: 'category',
+						show: true,
+						axisLabel: {
+							show: false,
+						},
+						axisLine: {
+							show: false,
+
+						},
+						axisTick: {
+							show: false
+						},
+					},
+					polar: [{
+						center: ['50%', '50%'], //中心点位置
+						radius: '80%' //图形大小
+					}],
+					series: [{
+							name: '小环',
+							type: 'gauge',
+							splitNumber: 0,
+							radius: '32%', //中间装饰环
+							center: ['50%', '50%'],
+							startAngle: 0,
+							endAngle: 359.9999,
+							axisLine: {
+								show: false
+							},
+							axisTick: {
+								show: true,
+								lineStyle: {
+									color: "#0BF4E4",
+									width: 2,
+									shadowBlur: 1,
+									shadowColor: color[1],
+								},
+								length: 20,
+								splitNumber: 2
+							},
+							splitLine: {
+								show: false
+							},
+							axisLabel: {
+								show: false
+							},
+							detail: {
+								show: true,
+								offsetCenter: ['0%', '-230%'],
+								color: '#f3f3f3',
+								formatter: function(params) {
+									return '问卷完成度'
+								},
+								textStyle: {
+									fontSize: 14,
+									fontWeight:'bold'
+								}
+							}
+						}, {
+							type: 'bar',
+							z: 10,
+							data: [((this.total - this.noAnswerdCount) / this.total).toFixed(2) * 100 ],
+							showBackground: false,
+							backgroundStyle: {
+								color: "blue",
+								borderWidth: 5,
+								width: 10
+							},
+							coordinateSystem: 'polar',
+							roundCap: true,
+							barWidth: 18, //大的占比环
+							itemStyle: {
+								normal: {
+									opacity: 1,
+									color: new that.$echarts.graphic.LinearGradient(0, 0, 1, 1, [{
+										offset: 0,
+										color: '#13d67d'
+									}, {
+										offset: 1,
+										color: '#8ddcac'
+									}])
+								}
+							},
+						},
+						{
+							type: 'pie',
+							name: '内层细圆环',
+							radius: ['50%', '30%'],
+							// radius: '50%',
+							startAngle: 90,
+							hoverAnimation: false,
+							clockWise: false,
+							itemStyle: {
+								normal: {
+									color: new that.$echarts.graphic.LinearGradient(0, 0, 1, 1, [{
+										offset: 0,
+										color: 'rgba(151,179,166,0.74)'
+									}, {
+										offset: 1,
+										color: 'rgba(151,179,166,0.74)'
+									}]),
+									shadowBlur: 5,
+									shadowColor: '#66666a',
+								}
+							},
+							tooltip: {
+								show: false,
+							},
+							label: {
+								show: false
+							},
+							data: [100],
+							
+						}
+					]
+				};
+
+				// 绘制图表
+				myBar.setOption(option)
+
+				window.addEventListener('resize', function() {
+					myBar.resize()
+				})
+			}
+		},
+		mounted() {
+			if (!this.total) return
+			this.drawLine()
+
+
+		},
+		watch: {
+			total: {
+				deep: true,
+				handler(val) {
+					this.drawLine()
+				}
+			}
+		}
+
+	}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+	.myBar {
+		width: 50%;
+		height: 280px;
+		margin: 0 auto;
+		display: block;
+	}
+</style>

+ 1 - 1
TEAMModelOS/ClientApp/src/components/questionnaire/BaseQuestionnaire.vue

@@ -11,7 +11,7 @@
 			<!-- 问卷题目单元 -->
 			<draggable class="list-group" tag="div" v-model="items" v-bind="dragOptions" @start="drag = true" @end="onDragEnd" v-else>
 				<transition-group type="transition" :name="!drag ? 'flip-list' : null">
-					<div class="qn-item" v-for="(item,index) in items" :key="index">
+					<div class="qn-item animated fadeInUp" v-for="(item,index) in items" :key="index">
 						<!-- 题干 -->
 						<p class="qn-stem">
 							<span style="color: red;" v-show="item.required">* </span>

+ 76 - 0
TEAMModelOS/ClientApp/src/components/questionnaire/BaseSsTable.less

@@ -0,0 +1,76 @@
+@main-bgColor: rgb(55, 55, 55); //主背景颜色
+@borderColor: #424242;
+@primary-color:#1CC0F3;
+@primary-textColor: #fff; //文本主颜色
+@second-textColor: #CBCBCB; //文本副级颜色
+@primary-fontSize: 14px;
+@second-fontSize: 16px;
+
+.component-vote-table {
+    padding: 20px 0 50px 0;
+
+    .ivu-table th,
+    .ivu-table td {
+        background: @main-bgColor;
+        color: @second-textColor;
+    }
+
+    .ivu-table-border td,
+    .ivu-table-border th {
+        border-color: @borderColor;
+    }
+
+    .ivu-table:before,
+    .ivu-table-border:after,
+    .ivu-table-wrapper-with-border {
+        background: @borderColor;
+        border-color: @borderColor;
+    }
+
+    .ivu-table-stripe .ivu-table-body tr:nth-child(2n) td,
+    .ivu-table-stripe .ivu-table-fixed-body tr:nth-child(2n) td {
+        background: #2e2e2e;
+    }
+
+    .ivu-table-stripe .ivu-table-body tr.ivu-table-row-hover td,
+    .ivu-table-stripe .ivu-table-fixed-body tr.ivu-table-row-hover td {
+        background: #5C5A5A;
+    }
+
+    .ivu-checkbox-inner {
+        border: none;
+        background: #b5b5b5;
+    }
+
+    .ivu-checkbox-checked .ivu-checkbox-inner {
+        background: @primary-color;
+
+        &:after {
+            top: 4px;
+            left: 6px;
+        }
+    }
+
+    .table-tools-icon {
+        .ivu-icon {
+            font-size: 22px;
+            margin-right: 14px;
+            cursor: pointer;
+        }
+    }
+
+    .ivu-progress-inner-text{
+        vertical-align:unset;
+    }
+}
+
+
+
+
+
+
+.fl-row-center{
+    display:flex;
+    justify-content:center;
+    align-items:flex-start;
+}

+ 94 - 0
TEAMModelOS/ClientApp/src/components/questionnaire/BaseSsTable.vue

@@ -0,0 +1,94 @@
+<template>
+    <div class="component-vote-table">
+        <Table border size='small' ref="selection" :columns="columns" :data="tableData" stripe></Table>
+    </div>
+</template>
+<script>
+    export default {
+        props: {
+            tableDatas: {
+                type: Array,
+                default:[]
+            }
+        },
+        data() {
+            return {
+                setScoreModal: false,
+                downloadModal: false,
+                mutualEvaluationModal: false,
+                isSaveComment: false,
+                currentUsedComment: null,
+                userInfo: this.$store.state.userInfo,
+                isScoreLoading: false,
+                currentStudent: null,
+                currentHw: null,
+                currentScore: 100,
+                currentComment: '',
+                currentFileList: [],
+                currentRateValue: 0,
+                downloadList: [],
+                usedCommentList: [],
+                columns: [
+                    {
+                        title: '姓名',
+                        key: 'name'
+                    },
+					{
+					    title: '编号',
+					    key: 'id'
+					},
+                    {
+                        title: '班级',
+                        render: (h, params) => {
+                            return h('span', params.row.classroomName)
+                        },
+                    },
+                    {
+                        title: '状态',
+                        render: (h, params) => {
+                            return h('span', '未完成')
+                        },
+                    },
+                    
+                ],
+                tableData: [],
+                commentList: [],
+                studentsNum:0
+            }
+        },
+        methods: {
+
+            /**
+             * 全选操作
+             * @param status
+             */
+            handleSelectAll(status) {
+                this.$refs.selection.selectAll(status);
+            },
+
+        },
+
+
+        mounted() {
+            
+        },
+        watch: {
+            tableDatas: {
+                handler(newValue) {
+                    /** 编辑回显 */
+                    if (Array.isArray(newValue) && newValue.length) {
+                        this.tableData = newValue
+                    } else {
+                        this.tableData = []
+                    }
+                },
+                deep: true,
+				immediate:true
+            }
+        }
+    }
+</script>
+
+<style lang="less">
+    @import "./BaseSsTable.less";
+</style>

+ 71 - 41
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/Vote.vue

@@ -68,7 +68,7 @@
               <div class="title-rect-group">
                   <div class="title-rect" />
                   <h2 class="title-rect-name">{{ $t("studentWeb.vote.bollotbox") }}</h2>
-                  <p style="margin-left:15px;margin-top:2px">剩余票数 <span @click="getVote" style="font-size:16px">{{voteInfo.voteNum}}</span><span> 票</span></p>
+                  <p style="margin-left:15px;margin-top:2px">剩余票数 <span @click="getVote" style="font-size:16px">{{voteCount}}</span><span> 票</span></p>
                   </div>
           </div>
           <!--和評測模組一樣-->
@@ -85,9 +85,9 @@
                       <InputNumber v-model="item.count" 
                                    :formatter="value => `${value}票`"
                                    :parser="value => value.replace('票', '')"
-                                   :min="1"
+                                   :min="0"
                                    v-if="voteInfo.repeat"
-                                   controls-outside
+                                   @on-change="setVoteNum(item)"
                       >
                       </InputNumber>
                   </div>
@@ -179,18 +179,18 @@ export default {
             getVoteResult() {
                 if (this.$store.getters.getItemTitle.id) {
                     this.voteRes = {}
-                    
                     let params = {
-                        "id": "ff86005f-fc57-4a73-a5b7-551b45e446e7",
-                        "code": "Vote-1595321354",
-                        "userid": "123132123"
+                        "id": this.$store.getters.getItemTitle.id,
+                        "code": this.$store.getters.getItemTitle.scode,
+                        "userid": this.$store.state.userInfo.sub
                     }
                     this.$api.studentWeb.getVoteResult(params).then(res => {
                         if (res) {
-                            console.log('获取投票结果数据')
-                            console.log(res)
                             this.voteRes = res
-                            this.timeStatus(this.voteInfo, this.voteRes)
+                           
+                            if (this.timeStatus(this.voteInfo, this.voteRes)) {
+
+                            }
                             //this.voteInfo = res.vote
                         }
                     })
@@ -205,21 +205,19 @@ export default {
                     }
                     this.$api.studentWeb.getVoteInfo(params).then(res => {
                         if (res) {
-                            console.log('获取投票数据')
                             this.voteInfo = res.vote
-                            console.log(this.voteInfo)
                             this.getVoteResult()
                         }
                         })
                 }
             },
+
             //获取投票结果
             getVote(data) {
                 if (!this.voteInfo.repeat) {
                     this.voteChecked.length = 0
                     this.voteChecked.push(data)
                 }
-                console.log(this.voteChecked)
             },
             //获取当前时间状态
             getDates(day, type) {
@@ -234,14 +232,12 @@ export default {
             },
             //投票活动的时间状态 data投票活动信息  time 已投票数据
             timeStatus(data, time) {
-                console.log(data,time)
                 let date = (new Date()).getTime() //当前时间
                 let status = false //判断时间是否过期或处于当前时间段
                 //处于活动时间内
                 let inDate = new Date(date)
                 let year = inDate.getFullYear()
                 let month = inDate.getMonth()
-                console.log('时间判定测试')
                 if (data.startTime <= date <= data.endTime && time.records.length > 0) {
                     switch (data.times) {
                         case 'day':
@@ -315,26 +311,42 @@ export default {
                     this.nextItem = nextItems[0];
                 }
             },
+            setVoteNum(data) {
+                if (this.isOverCount) {
+                    data.count = 0
+                }
+            },
             submitMessage() {
-                if (this.voteChecked != "") {
-                    this.clickbutnoChoose = false;
+                this.clickbutnoChoose = false;
+                if (this.voteChecked.length) {
                     this.WarmMessageisOpen = true;
                     this.isFirstVoted = true;
-                    this.$store.commit(
-                        "SavefinishedItemID",
-                        this.$store.getters.getItemTitle.eventID
-                    );
-                    setTimeout(() => {
-                        this.WarmMessageisOpen = false;
-                    }, 2000);
-                    this.previewNext();
-                    //加入下一個活動的提示框
-                    console.log(localStorage.getItem("hintNextItem")); //讀取是否顯示提示下一個
-                    if (localStorage.getItem("hintNextItem") != "false") {
-                        setTimeout(() => {
-                            this.isHintNextItem = true;
-                        }, 4000);
+                    let params = {
+                        "id": this.$store.getters.getItemTitle.id,
+                        "code": this.$store.getters.getItemTitle.scode,
+                        "option": {}
+                    }
+                    for (let item of this.voteChecked) {
+                        params.option[item.code] = item.count
                     }
+                    this.$api.studentWeb.sendVoteResult(params).then(res => {
+                        if (res.msgid == 1) {
+                            setTimeout(() => {
+                                this.WarmMessageisOpen = false;
+                            }, 1000);
+                        } else {
+                            this.$Message.warning("投票失败,请检查投票信息!")
+                        }
+                    })
+                    //this.previewNext();
+                    //加入下一個活動的提示框
+                    //console.log(localStorage.getItem("hintNextItem")); //讀取是否顯示提示下一個
+                    //if (localStorage.getItem("hintNextItem") != "false") {
+                    //    setTimeout(() => {
+                    //        this.isHintNextItem = true;
+                    //    }, 4000);
+                    //}
+                    this.voteChecked = []
                 } else if (this.voteChecked == "") {
                     this.clickbutnoChoose = true;
                 }
@@ -367,6 +379,23 @@ export default {
         computed: {
             listData() {
                 return this.$store.getters.getItemTitle.id;
+            },
+            voteCount() {
+                if (this.voteInfo.voteNum !== undefined) {
+                    let num = 0
+                    this.isOverCount = false
+                    for (let item of this.voteInfo.options) {
+                        if (item.count !== null) {
+                            num += item.count
+                        }
+                    }
+                    if (num > this.voteInfo.voteNum) {
+                        this.isOverCount = true
+                        this.$Message.warning("已超出最大投票数量!")
+                        return 0
+                    }
+                    return this.voteInfo.voteNum - num
+                }
             }
         },
         watch: {
@@ -379,16 +408,17 @@ export default {
                 // 深度观察监听
                 deep: true
             },
-            listData: {
-                handler() {
-                    if (this.$store.getters.getItemTitle.id !== '') {
-                        console.log('88888888888')
-                        this.getVoteInfo()
-                    }
-                },
-                // 深度观察监听
-                deep: true
-            },
+
+            //listData: {
+            //    handler() {
+            //        if (this.$store.getters.getItemTitle.id !== '') {
+            //            console.log('88888888888')
+            //            this.getVoteInfo()
+            //        }
+            //    },
+            //    // 深度观察监听
+            //    deep: true
+            //},
         },
 };
 </script>

+ 7 - 5
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/composePaper.vue

@@ -1,11 +1,10 @@
 <template>
     <div class="content">
         <div id="textArea"> </div>
-        <Modal v-model="markStatus" fullscreen title="作答" footer-hide>
-            <BaseMyCanvas v-if="markStatus" :bgImg="markBg" @onCloseModal="closeModal" :isStudent="markStatus" @onSaveCanvas="saveMark"></BaseMyCanvas>
+        <Modal v-model="markStatus" fullscreen title="作答" footer-hide  ref="compose">
+                <BaseMyCanvas v-if="markStatus" :bgImg="markBg" @onCloseModal="closeModal" :isStudent="markStatus" @onSaveCanvas="saveMark"></BaseMyCanvas>
         </Modal>
         <iframe class="frame"id="answerIframe" :srcdoc="itemInfo.question"></iframe>
-
     </div>
 </template>
 <script>
@@ -70,7 +69,6 @@
                     this.editor.txt.html(img.outerHTML)
                     this.markStatus = false
                 }
-                console.log(data)
             },
             initEditor() {
                 this.editorContent = ""
@@ -107,12 +105,13 @@
             markStuAnswer() {
                 let answerIframe = ''
                 answerIframe = document.getElementById('answerIframe')
-                console.log(answerIframe)
                 answerIframe.contentWindow.document.body.style.width = 'fit-content'
                 answerIframe.contentWindow.document.body.style.minWidth = '600px'
                 answerIframe.contentWindow.document.body.style.backgroundColor = '#f5f5f5'
                 let iframe = document.getElementById('answerIframe').contentWindow.document.getElementsByTagName('p')
+                console.log(iframe[1].style)
                 iframe[1].style.lineHeight = '50px'
+                iframe[1].style.paddingBottom = '50px'
                 html2canvas(answerIframe.contentWindow.document.body).then(canvas => {
                     this.markStatus = true
                     this.markBg = canvas.toDataURL("image/png");
@@ -159,4 +158,7 @@
         /*margin-left:10px;*/
         /*line-height: 50px;*/
     }
+    .canvas-tools {
+        bottom: -50px;
+    }
 </style>

+ 4 - 12
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventList.vue

@@ -139,10 +139,7 @@
 </template>
 
 <script>
-    import { Random } from "mockjs";
     import PreviewProgressPie from "../EventView/PreviewProgressPie";
-
-
     export default {
         name: "EventList",
         mounted() {
@@ -153,7 +150,6 @@
             }
             this.scrollList();
         },
-
         data() {
             return {
                 searchEmpty: false,
@@ -196,7 +192,6 @@
                 eventShow:[]
             };
         },
-
         components: { PreviewProgressPie },
         watch: {
             search: function (value) {
@@ -221,7 +216,6 @@
                     ) {
                         countfit += 0;
                     }
-
                 }
                 if (countfit == 0 && value != "") {
                     this.isListNoItem = true;
@@ -256,16 +250,14 @@
             getActivityInfo() {
                 if (this.$store.state.user.studentProfile.classinfo.id !== "") {
                     let params = {
-                        "userid": "123",
+                        "userid": this.$store.state.userInfo.sub,
                         "classes": [
-                            "hbcn0906",
-                            "hbcn0910",
-                            "hbcn0989"
+                            this.$store.state.user.studentProfile.classinfo.id
                         ],
-                        "school": "hbcn"
+                        "school": this.$store.state.user.schoolCode
                     }
                     this.$api.studentWeb.getActivityInfo(params).then(res => {
-                        if (res.datas.length) {
+                        if (res) {
                             let data = []
                             for (let item of res.datas) {
                                 item.eventType = item.type

+ 3 - 5
TEAMModelOS/ClientApp/src/components/student-web/HomeView/MissionListCard.vue

@@ -123,13 +123,11 @@
             getActivityInfo() {
                 if (this.$store.state.user.studentProfile.classinfo.id !== "") {
                     let params = {
-                        "userid": "123",
+                        "userid": this.$store.state.userInfo.sub,
                         "classes": [
-                            "hbcn0906",
-                            "hbcn0910",
-                            "hbcn0989"
+                            this.$store.state.user.studentProfile.classinfo.id
                         ],
-                        "school": "hbcn"
+                        "school": this.$store.state.user.schoolCode
                     }
                     this.$api.studentWeb.getActivityInfo(params).then(res => {
                         console.log(res)

+ 0 - 3
TEAMModelOS/ClientApp/src/components/vote/BaseVoteForm.vue

@@ -282,9 +282,6 @@
 								console.log(error)
 							})
 						}
-						
-						
-
 					} else {
 						this.isBtnLoading = false
 						if (this.voteOptionsContent.length) {

+ 2 - 2
TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue

@@ -511,10 +511,10 @@
 									url: item.id + '.json',
 									type: item.type,
 									scoring: {
-										score: item.score,
+										score: item.score || 0,
 										knowledge: item.knowledge || [],
 										field: item.field || 1,
-										ans: nullType.includes(item.type) ? [] : item.answer
+										ans: nullType.includes(item.type) ? [] : (item.answer || [])
 									}
 								}
 								item.type === 'compose' && delete o.scoring

+ 7 - 3
TEAMModelOS/ClientApp/src/view/learnactivity/CreatePrivEva.vue

@@ -476,7 +476,7 @@ export default {
                         let schoolBlob = undefined
                         let targetFolder = 'exam/' + examId + '/paper/'
                         let count = 0
-                        requestData.papers.forEach(async (item,index) => {
+                        requestData.papers.forEach(async (item, index) => {
                             if (item.blob.indexOf('/exam/') == 0) {
                                 if (++count == (requestData.papers.length)) {
                                     setTimeout(() => {
@@ -559,10 +559,14 @@ export default {
                         paper.field = []
                         for (let k = 0; k < rule[i].slides.length; k++) {
                             if (rule[i].slides[k].type !== 'compose') {
-                                paper.answers.push(rule[i].slides[k].scoring.ans)
+                                // paper.answers.push(rule[i].slides[k].scoring.ans)
+                                // paper.point.push(rule[i].slides[k].scoring.score)
+                                // paper.knowledge.push(rule[i].slides[k].scoring.knowledge ? rule[i].slides[k].scoring.knowledge : [])
+                                // if (rule[i].slides[k].scoring.field) paper.field.push(rule[i].slides[k].scoring.field)
+                                paper.answers.push(rule[i].slides[k].scoring.ans ? rule[i].slides[k].scoring.ans : [])
                                 paper.point.push(rule[i].slides[k].scoring.score)
                                 paper.knowledge.push(rule[i].slides[k].scoring.knowledge ? rule[i].slides[k].scoring.knowledge : [])
-                                if (rule[i].slides[k].scoring.field) paper.field.push(rule[i].slides[k].scoring.field)
+                                paper.field.push(rule[i].slides[k].scoring.field ? rule[i].slides[k].scoring.field : [])
                             }
                         }
                         paperDto.push(paper)

+ 8 - 4
TEAMModelOS/ClientApp/src/view/learnactivity/CreateSchoolEva.vue

@@ -557,7 +557,7 @@ export default {
                         let privateBlob = undefined
                         let targetFolder = 'exam/' + examId + '/paper/'
                         let count = 0
-                        requestData.papers.forEach(async (item,index) => {
+                        requestData.papers.forEach(async (item, index) => {
                             if (item.blob.indexOf('/exam/') == 0) {
                                 if (++count == (requestData.papers.length)) {
                                     setTimeout(() => {
@@ -639,10 +639,14 @@ export default {
                         paper.field = []
                         for (let k = 0; k < rule[i].slides.length; k++) {
                             if (rule[i].slides[k].type !== 'compose') {
-                                paper.answers.push(rule[i].slides[k].scoring.ans)
+                                // paper.answers.push(rule[i].slides[k].scoring.ans)
+                                // paper.point.push(rule[i].slides[k].scoring.score)
+                                // paper.knowledge.push(rule[i].slides[k].scoring.knowledge ? rule[i].slides[k].scoring.knowledge : [])
+                                // if (rule[i].slides[k].scoring.field) paper.field.push(rule[i].slides[k].scoring.field)
+                                paper.answers.push(rule[i].slides[k].scoring.ans ? rule[i].slides[k].scoring.ans : [])
                                 paper.point.push(rule[i].slides[k].scoring.score)
                                 paper.knowledge.push(rule[i].slides[k].scoring.knowledge ? rule[i].slides[k].scoring.knowledge : [])
-                                if (rule[i].slides[k].scoring.field) paper.field.push(rule[i].slides[k].scoring.field)
+                                paper.field.push(rule[i].slides[k].scoring.field ? rule[i].slides[k].scoring.field : [])
                             }
                         }
                         paperDto.push(paper)
@@ -677,7 +681,7 @@ export default {
         if (routerData !== undefined) {
             this.startTime = new Date(routerData.startTime)
             this.endTime = new Date(routerData.endTime)
-            routerData.subjectIds = routerData.subjects.map(item=>{
+            routerData.subjectIds = routerData.subjects.map(item => {
                 return item.id
             })
             routerData.paperInfo = []

+ 6 - 3
TEAMModelOS/ClientApp/src/view/learnactivity/PaperScore.vue

@@ -378,7 +378,8 @@ export default {
                 "studentId": this.studentAnswer.id,
                 "subjectId": this.subjectId,
                 "classId": this.studentAnswer.classId,
-                "code": this.paperInfo.code,
+                // "code": this.paperInfo.code,//这种方式paper code规则调整了,会多Paper-"
+                "code": this.scope == 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId,//暂时取代上面的方式
             }).then(
                 res => {
                     this.$Message.success(this.$t('learnActivity.score.markOk'))
@@ -490,11 +491,13 @@ export default {
         saveScore() {
             let requestData = {
                 "id": this.examId,
-                "code": this.paperInfo.code,
+                // "code": this.paperInfo.code,//这种方式paper code规则调整了,会多Paper-"
+                "code": this.scope == 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId,//暂时取代上面的方式
                 "point": this.studentAnswer.scores,
                 "studentId": this.studentAnswer.id,
                 "classId": this.studentAnswer.classId,
-                "school": this.paperInfo.code,
+                // "school": this.paperInfo.code,//这种方式paper code规则调整了,会多Paper-"
+                "school": this.scope == 'school' ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId,//暂时取代上面的方式
                 "subjectId": this.subjectId
             }
             this.$api.learnActivity.UpsertAllRecord(requestData).then(res => {

+ 15 - 0
TEAMModelOS/ClientApp/src/view/questionnaire/ManageQuestionnaire.less

@@ -70,6 +70,15 @@
             span {
                 color: @second-textColor;
             }
+			
+			&-tab{
+				margin-right: 10px;
+				cursor: pointer;
+			}
+			
+			&-tab-active{
+				color: #fff !important;
+			}
 
             .qn-box-header-tools {
 				display: flex;
@@ -185,6 +194,12 @@
             // height: 100%;
             min-height: 1200px;
             padding: 20px;
+			
+			.progress-wrap{
+				width: 100%;
+				display: flex;
+				background-color: #373737;
+			}
         }
     }
 }

+ 111 - 4
TEAMModelOS/ClientApp/src/view/questionnaire/ManageQuestionnaire.vue

@@ -70,7 +70,11 @@
 							<!-- 问卷提交数据 -->
 							<div class="qn-col qn-data-box">
 								<div class="qn-box-header">
-									<span>{{ $t('survey.surveyResult') }}</span>
+									<div>
+										<span :class="['qn-box-header-tab',curTab === 'progress' ? 'qn-box-header-tab-active' : '']" @click="onChangeResultTab('progress')" v-if="currentQn.progress !== 'pending'">问卷进度</span>
+										<span :class="['qn-box-header-tab',curTab === 'result' ? 'qn-box-header-tab-active' : '']" @click="onChangeResultTab('result')">{{ $t('survey.surveyResult') }}</span>
+									</div>
+									
 									<div class="qn-box-header-tools" v-show="!isEmptyData">
 										<div class="qn-box-header-tools-tool" style="margin-right: 10px" v-show="currentQn.progress !== 'finish' && editable">
 											<Icon type="md-list-box" color="#dcdcdc" />
@@ -107,9 +111,24 @@
 									</div>
 								</div>
 								<vuescroll>
-									<div class="qn-data-wrap">
-										<BaseQuestionnaire :editItem="currentQn" :isEdit="editable" ref="qnPaper" v-if="!isEmptyData"></BaseQuestionnaire>
+									<div v-show="qnList.length === 0">
+										<EmptyData :top="50"></EmptyData>
+									</div>
+									<div v-show="qnList.length">
+										<div class="qn-data-wrap" v-if="curTab === 'result'">
+											<BaseQuestionnaire :editItem="currentQn" :isEdit="editable" ref="qnPaper" v-if="!isEmptyData"></BaseQuestionnaire>
+										</div>
+										<div class="qn-data-wrap qn-progress-wrap" v-else>
+											<div class="progress-wrap">
+												<BaseProgress barId="pro1" :total="allSsList.length" :noAnswerdCount="noFinishStudents.length"></BaseProgress>
+												<BasePie barId="pie1" :total="allSsList.length" :noAnswerdCount="noFinishStudents.length"></BasePie>
+											</div>
+											<div class="no-table-wrap">
+												<BaseSsTable :tableDatas="noFinishStudents"></BaseSsTable>
+											</div>
+										</div>
 									</div>
+									
 								</vuescroll>
 							</div>
 						</div>
@@ -123,10 +142,16 @@
 	import blobTool from "@/utils/blobTool.js";
 	import BaseQuestionnaire from "@/components/questionnaire/BaseQuestionnaire.vue";
 	import BaseQnForm from "@/components/questionnaire/BaseQnForm.vue";
+	import BaseProgress from "@/components/questionnaire/BaseProgress.vue";
+	import BasePie from "@/components/questionnaire/BasePie.vue";
+	import BaseSsTable from "@/components/questionnaire/BaseSsTable.vue";
 	export default {
 		components: {
 			BaseQuestionnaire,
 			BaseQnForm,
+			BaseProgress,
+			BasePie,
+			BaseSsTable
 		},
 		data() {
 			return {
@@ -148,6 +173,9 @@
 				editItem: {},
 				activeQnIndex: null,
 				addQnModal: false,
+				curTab:'progress',
+				noFinishStudents:[],
+				allSsList:[]
 			};
 		},
 		created() {},
@@ -159,6 +187,10 @@
 					this.getQnList(index === 0 ? "school" : "private");
 				}, 500)
 			},
+			
+			onChangeResultTab(tab){
+				this.curTab = tab
+			},
 
 			/** 新增问卷 */
 			goToCreate() {
@@ -185,6 +217,7 @@
 					this.editable = true;
 					this.isEmptyData = false;
 					this.$refs.qnForm.qnFormEdit = true;
+					this.onChangeResultTab('result')
 				}
 			},
 
@@ -254,6 +287,12 @@
 				}
 				this.currentQn = item.id ? await this.getQnDetails(item) : this.currentQn;
 				this.currentQn.progress = item.progress;
+				if (item.id) this.getSurveyStudents(this.currentQn)
+				if(item.progress === 'pending'){
+					this.onChangeResultTab('result')
+				}else{
+					this.onChangeResultTab('progress')
+				}
 				console.log("获取问卷数据");
 				console.log(this.currentQn);
 				this.activeQnIndex = hasNewQn ? this.qnList.indexOf(item) : index;
@@ -294,7 +333,8 @@
 						this.isBtnLoading = false;
 					});
 			},
-
+			
+			/* 保存问卷题目到Blob */
 			async doUploadBlob(qnBaseInfo, items) {
 				console.log('上传参数', qnBaseInfo)
 				return new Promise(async (resolve, reject) => {
@@ -353,6 +393,73 @@
 					})
 				})
 			},
+			
+			/* 获取当前问卷活动学生作答数据 */
+			async getSurveyStudents(surveyItem) {
+				this.isLoading = true
+				let answerdList = await this.getAnswerdRecord(surveyItem)
+				//  先查找 投票发布对象关联的学生清单 然后再去判断学生的作答情况
+				this.$api.schoolSetting.getClassroomStudent({
+					school_code: this.$store.state.userInfo.schoolCode,
+					ids: surveyItem.classes,
+					scope:surveyItem.owner === this.$store.state.userInfo.schoolCode ? 'school' : 'private'
+				}).then(res => {
+					if (!res.error && res.classrooms.length) {
+						let list = []
+						res.classrooms.forEach(classroom => {
+							classroom.students.forEach(i => {
+								list.push({
+									id: i.id,
+									name: i.name,
+									no: i.no,
+									classroomName: classroom.name
+								})
+							})
+						})
+						this.allSsList = list
+						// 要根据作答情况 结合两张表 处理表格显示的数据 
+						if (answerdList.length) {
+							this.noFinishStudents = this.getNoFinishList(answerdList,list)
+						} else {
+							this.noFinishStudents = list
+						}
+						this.isLoading = false
+					} else {
+						this.$Message.error(this.$t('vote.getDataFailTip'))
+						this.isLoading = false
+					}
+				}).catch(err => {
+					this.$Message.error(this.$t('vote.getClassDataFailTip'))
+					this.isLoading = false
+				})
+			},
+			
+			/* 获取未作答学生清单 */
+			getNoFinishList(answerdList,allList){
+				let result = []
+				allList.forEach(i => {
+					if(!answerdList.includes(i.id)){
+						result.push(i)
+					}
+				})
+				return result
+			},
+			
+			/* 获取正在进行中的投票活动的投票数据 */
+			getAnswerdRecord(surveyItem){
+				return new Promise((r,j) => {
+					this.$api.questionnaire.GetAnswerdRecord({
+						id: surveyItem.id,
+						code: surveyItem.code,
+					}).then(res => {
+						if(!res.error){
+							r(res.userids)
+						}
+					}).catch(err => {
+						j(err)
+					})
+				})
+			},
 
 			onShowAllAnalysis() {
 				this.$refs.qnPaper.onShowAllAnalysis();

+ 185 - 5
TEAMModelOS/Controllers/Common/SurveyController.cs

@@ -19,6 +19,11 @@ using TEAMModelOS.Models;
 using Microsoft.Extensions.Options;
 using TEAMModelOS.Filter;
 using TEAMModelOS.Services.Common;
+using Azure.Storage.Blobs.Models;
+using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
+using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
+using System.Net.Http;
+using TEAMModelOS.SDK.Models.Cosmos;
 
 namespace TEAMModelOS.Controllers
 {
@@ -39,7 +44,9 @@ namespace TEAMModelOS.Controllers
         private readonly DingDing _dingDing;
         private readonly Option _option;
         private readonly AzureStorageFactory _azureStorage;
-        public SurveyController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, AzureRedisFactory azureRedis, AzureStorageFactory azureStorage)
+        private readonly IHttpClientFactory _clientFactory;
+        public SurveyController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, 
+            AzureRedisFactory azureRedis, AzureStorageFactory azureStorage, IHttpClientFactory clientFactory)
         {
             _snowflakeId= snowflakeId;
             _serviceBus = serviceBus;
@@ -48,6 +55,7 @@ namespace TEAMModelOS.Controllers
             _option = option?.Value;
             _azureRedis = azureRedis;
             _azureStorage = azureStorage;
+            _clientFactory = clientFactory;
         }
 
 
@@ -340,7 +348,6 @@ namespace TEAMModelOS.Controllers
         /// <param name="request">
         /// !"id":"aaaa"
         /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
-        /// !"record":[["A","B"],["A"],["D"],[],["建议提升服务质量"]]
         /// </param>
         /// <returns>
         /// msgid=0投票失败,1提交成功,2不在时间范围内,3不在发布范围内,6未设置投票项
@@ -360,9 +367,15 @@ namespace TEAMModelOS.Controllers
             {
                 return BadRequest();
             }
-
-
-            else { return Ok(new { msgid = 0 }); }
+            List<string> userids = new List<string>();
+            var values= await _azureRedis.GetRedisClient(8).SetMembersAsync($"Survey:Submit:{id}");
+            if (values != default && values.Length>0) {
+                foreach(var val in values) {
+                    userids.Add(val);
+                }
+            }
+            return Ok(new { userids = userids }); 
+            
         }
 
 
@@ -402,5 +415,172 @@ namespace TEAMModelOS.Controllers
             }
             return Ok(new {records = res});
         }
+
+
+        /// <summary>
+        /// 问卷记录 当活动没结算且没有BlobUrl时则调用此接口
+        /// </summary>
+        /// <redis>
+        /// {"C":2,"A":2,"other":2}
+        /// </redis>
+        /// <param name="request">
+        /// !"id":"aaaa"
+        /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
+        /// </param>
+        /// <returns>
+        /// </returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("settlement")]
+        //[AuthToken(Roles = "teacher,student")]
+        public async Task<IActionResult> Settlement(JsonElement request)
+        {
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                //活动id
+                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
+                //活动分区
+                if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+                Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Survey>(id.GetString(), new PartitionKey($"{code}"));
+                if (survey != null)
+                {
+                    ActivityData data;
+
+                    if (survey.progress == "finish") {
+                        var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}");
+                        List<dynamic> recs = new List<dynamic>();
+                        foreach (var rcd in records)
+                        {
+                            var value = rcd.Value.ToString().ToObject<JsonElement>();
+                            recs.Add(new { index = rcd.Name.ToString(), ans = value });
+                        }
+                        var cods = new { records = recs };
+                        //问卷整体情况
+                        await _azureStorage.UploadFileByContainer(survey.owner, cods.ToJsonString(), "survey", $"{survey.id}/record.json");
+                        //结算每道题的答题情况
+
+                        var ContainerClient = _azureStorage.GetBlobContainerClient(survey.owner);
+                        var route = ContainerClient.Uri.ToString();
+                        List<BlobItem> items = await ContainerClient.List($"survey/{survey.id}/urecord");
+                        List<SurveyRecord> surveyRecords = new List<SurveyRecord>();
+                        //获取
+                        
+                        foreach (BlobItem item in items)
+                        {
+                            BlobAuth blobAuth = _azureStorage.GetBlobSasUriRead(survey.owner, $"{item.Name}");
+                            var url = $"{route}/{item.Name}?{blobAuth.sas}";
+                            var response = await _clientFactory.CreateClient().GetAsync(new Uri(url));
+                            var json = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
+                            var Record = json.RootElement.ToObject<SurveyRecord>();
+                            surveyRecords.Add(Record);
+                        }
+                        List<Task<string>> tasks = new List<Task<string>>();
+                        for (int index = 0; index < survey.ans.Count; index++)
+                        {
+                            string url = $"{survey.id}/qrecord/{index}.json";
+                            QuestionRecord question = new QuestionRecord() { index = index };
+                            foreach (SurveyRecord record in surveyRecords)
+                            {
+                                if (record.ans.Count == survey.ans.Count)
+                                {
+                                    foreach (var an in record.ans[index])
+                                    {
+                                        //
+                                        if (question.opt.ContainsKey(an))
+                                        {
+                                            if (question.opt[an] != null)
+                                            {
+                                                question.opt[an].Add(record.userid);
+                                            }
+                                            else
+                                            {
+                                                question.opt[an] = new HashSet<string>() { record.userid };
+                                            }
+                                        }
+                                        else
+                                        {
+                                            if (survey.ans[index].Contains(an))
+                                            {
+                                                //如果是客观题code
+                                                question.opt.Add(an, new HashSet<string> { record.userid });
+                                            }
+                                            else
+                                            {
+                                                //如果不是客观code
+                                                question.other[record.userid] = an;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                            tasks.Add(_azureStorage.UploadFileByContainer(survey.owner, question.ToJsonString(), "survey", url, false));
+                        }
+                        await Task.WhenAll(tasks);
+                        survey.recordUrl = $"/survey/{survey.id}/record.json";
+                        await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync<Survey>(survey, survey.id, new Azure.Cosmos.PartitionKey(survey.code));
+                        //更新结束状态
+                        if (survey.scope == "school")
+                        {
+                            data = new ActivityData
+                            {
+                                id = survey.id,
+                                code = $"Activity-{survey.owner}",
+                                type = "survey",
+                                name = survey.name,
+                                startTime = survey.startTime,
+                                endTime = survey.endTime,
+                                scode = survey.code,
+                                scope = survey.scope,
+                                progress = "finish",
+                                classes = survey.classes.IsNotEmpty() ? survey.classes : new List<string> { "" },
+                                tmdids = survey.tmdids.IsNotEmpty() ? survey.tmdids : new List<string> { "" },
+                                owner = survey.owner,
+                                subjects = new List<string> { "" }
+
+                            };
+                            await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
+                        }
+                        else if (survey.scope == "private")
+                        {
+                            //更新结束状态
+                            data = new ActivityData
+                            {
+                                id = survey.id,
+                                code = $"Activity-Common",
+                                type = "survey",
+                                name = survey.name,
+                                startTime = survey.startTime,
+                                endTime = survey.endTime,
+                                scode = survey.code,
+                                scope = survey.scope,
+                                progress = "finish",
+                                classes = survey.classes.IsNotEmpty() ? survey.classes : new List<string> { "" },
+                                owner = survey.owner,
+                                tmdids = new List<string> { "" },
+                                subjects = new List<string> { "" }
+                            };
+                            await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<ActivityData>(data, data.id, new Azure.Cosmos.PartitionKey(data.code));
+                        }
+                    }
+                    return Ok(new { survey });
+                }
+                else
+                {
+                    return BadRequest("id,code不存在!");
+                }
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},common/survey/find-id()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest(ex.StackTrace);
+            }
+        }
+
+    }
+    public class QuestionRecord
+    {
+        public int index { get; set; }
+        public Dictionary<string, HashSet<string>> opt { get; set; } = new Dictionary<string, HashSet<string>>();
+        public Dictionary<string, string> other { get; set; } = new Dictionary<string, string>();
     }
 }

+ 35 - 25
TEAMModelOS/Controllers/Common/VoteController.cs

@@ -331,17 +331,6 @@ namespace TEAMModelOS.Controllers.Learn
         //[AuthToken(Roles = "teacher,student")]
         public async Task<IActionResult> Record(JsonElement request)
         {
-            string uid = null;
-            if (request.TryGetProperty("userid", out JsonElement userid)) {
-                if (userid.ValueKind.Equals(JsonValueKind.String)) {
-                    uid = userid.GetString();
-                }
-            }
-            //if (string.IsNullOrWhiteSpace(uid)) {
-            //    var (auid, _, _, _) = HttpContext.GetAuthTokenInfo();
-            //    uid = auid;
-            //}
-           
             if (!request.TryGetProperty("id", out JsonElement id))
             {
                 return BadRequest();
@@ -366,23 +355,44 @@ namespace TEAMModelOS.Controllers.Learn
             List<JsonElement> res = new List<JsonElement>();
             foreach (var rcd in records)
             {
-                var key = rcd.Name.ToString().Split("-")[0];
-                if (!string.IsNullOrWhiteSpace(uid))
-                {
-                    if (uid.Equals(key))
-                    {
-                        var value = rcd.Value.ToString().ToObject<JsonElement>();
-                        res.Add(value);
-                    }
-                }
-                else {
-                    var value = rcd.Value.ToString().ToObject<JsonElement>();
-                    res.Add(value);
-                }
+                var value = rcd.Value.ToString().ToObject<JsonElement>();
+                res.Add(value);
             }
-            return Ok(new { options, records= res,now =DateTimeOffset.UtcNow });
+            return Ok(new { options, records= res});
         }
 
+        /// <summary>
+        /// 个人已投票记录查询
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("decided")]
+        [AuthToken(Roles = "teacher,student")]
+        public async Task<IActionResult> Decided(JsonElement request)
+        {
+            var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
+            if (!request.TryGetProperty("id", out JsonElement id))
+            {
+                return BadRequest();
+            }
+            //活动分区
+            if (!request.TryGetProperty("code", out JsonElement code))
+            {
+                return BadRequest();
+            }
+            //获取投票活动的所有投票记录
+            var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Vote:Record:{id}:{userid}");
+            List<JsonElement> res = new List<JsonElement>();
+            foreach (var rcd in records)
+            {
+                var value = rcd.Value.ToString().ToObject<JsonElement>();
+                res.Add(value);
+            }
+            return Ok(new { records= res });
+        }
+
+
         /// <summary>
         /// 投票
         /// </summary>

+ 2 - 2
TEAMModelOS/Controllers/Knowledge/KnowledgesController.cs

@@ -123,7 +123,7 @@ namespace TEAMModelOS.Controllers
                 var countBlock = 0;
                 if (!string.IsNullOrWhiteSpace(kp.Value))
                 {
-                    var value = _azureRedis.GetRedisClient(8).HashGet($"Knowledge:Count:{kp.Key}", kp.Value);
+                    var value =await _azureRedis.GetRedisClient(8).HashGetAsync($"Knowledge:Count:{kp.Key}", kp.Value);
                     if (value != default && !value.IsNullOrEmpty)
                     {
                         
@@ -139,7 +139,7 @@ namespace TEAMModelOS.Controllers
                     }
                 }
                 else {
-                    var values = _azureRedis.GetRedisClient(8).HashGetAll($"Knowledge:Count:{kp.Key}");
+                    var values = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Knowledge:Count:{kp.Key}");
                     if (values != null) {
                         foreach (var value in values) 
                         {

+ 2 - 2
TEAMModelOS/Controllers/knowledge/KnowledgeController.cs

@@ -22,8 +22,8 @@ namespace TEAMModelOS.Controllers
     [ProducesResponseType(StatusCodes.Status200OK)]
     [ProducesResponseType(StatusCodes.Status400BadRequest)]
     //[Authorize(Roles = "IES5")]
-    [Route("knowledge")]
-    [ApiController]
+    //[Route("knowledge")]
+    //[ApiController]
     //[Authorize]
     public class KnowledgeController : ControllerBase
     {       

+ 13 - 10
TEAMModelOS/Services/Common/ActivityStudentService.cs

@@ -86,32 +86,33 @@ namespace TEAMModelOS.Services.Common
                                             break;
                                         }
                                     }
-                                    msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid);
+                                    msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid,vote.times, "once");
                                 }
                                 else
                                 {
-                                    msgid = await VoteIng(vote, new RedisValue(), msgid, option, Field, curr, _azureRedis, userid);
+                                    msgid = await VoteIng(vote, new RedisValue(), msgid, option, Field, curr, _azureRedis, userid, vote.times, "once");
                                 }
                                 break;
                             case "day": //周期内每天
                                 Field = $"{userid}-day-{now.ToString("yyyyMMdd")}";
                                 value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
-                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis,userid);
+                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis,userid, vote.times, now.ToString("yyyyMMdd"));
                                 break;
                             case "week": //自然周
-                                Field = $"{userid}-week-{now.ToString("yyyy")}{GetWeek(now)}";
+                                int week = GetWeek(now);
+                                Field = $"{userid}-week-{now.ToString("yyyy")}{week}";
                                 value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
-                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid); 
+                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times,$"{now.ToString("yyyy")}{week}"); 
                                 break;
                             case "month":  //月份
                                 Field = $"{userid}-month-{now.ToString("yyyyMM")}";
                                 value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
-                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid); 
+                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times, now.ToString("yyyyMM")); 
                                 break;
                             case "year"://年份
                                 Field = $"{userid}-year-{now.ToString("yyyy")}";
                                 value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
-                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid);
+                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times, now.ToString("yyyy"));
                                 break;
                         }
                     }
@@ -127,7 +128,7 @@ namespace TEAMModelOS.Services.Common
             }
             return msgid;
         }
-        public static async Task<byte> VoteIng(Vote vote, RedisValue value, byte msgid, Dictionary<string, int> option, string Field, long curr, AzureRedisFactory _azureRedis,string userid)
+        public static async Task<byte> VoteIng(Vote vote, RedisValue value, byte msgid, Dictionary<string, int> option, string Field, long curr, AzureRedisFactory _azureRedis,string userid,string times,string endpoint)
         {
             if (!value.IsNullOrEmpty)
             {
@@ -156,6 +157,8 @@ namespace TEAMModelOS.Services.Common
                     }
                     record.time = curr;
                     record.userid = userid;
+                    record.times = times;
+                    record.endpoint = endpoint;
                     //保存投票记录
                     bool status = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}", Field, record.ToJsonString());
                     //单独保存每个人方便查询的记录
@@ -177,7 +180,7 @@ namespace TEAMModelOS.Services.Common
                 if (option.Count <= vote.voteNum)
                 {
                     //保存投票记录
-                    VoteRecord record = new VoteRecord { opt = option, time = curr, userid = userid };
+                    VoteRecord record = new VoteRecord { opt = option, time = curr, userid = userid ,times=times,endpoint=endpoint};
                     bool status = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}", Field, record.ToJsonString());
                     //单独保存每个人方便查询的记录
                     bool stuallstatus = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}:{userid}", Field, record.ToJsonString());
@@ -541,7 +544,7 @@ namespace TEAMModelOS.Services.Common
                                 //处理other ,这里暂不处理, 结算再处理other 
                                 //await Task.WhenAll(tasks);
                                 //保存当前提交人的记录
-                                await _azureStorage.UploadFileByContainer(survey.owner,new { record= record, userid, time = curr }.ToJsonString(), "survey", $"{survey.id}/urecord/{userid}.json");
+                                await _azureStorage.UploadFileByContainer(survey.owner,new SurveyRecord { ans= recs, userid=userid, time = curr }.ToJsonString(), "survey", $"{survey.id}/urecord/{userid}.json");
                                 await azureRedis.GetRedisClient(8).SetAddAsync($"Survey:Submit:{survey.id}", userid);
                                 msgid = 1;
                             }