Explorar o código

Merge branch 'develop' of http://52.130.252.100:10000/TEAMMODEL/TEAMModelOS into develop

onepsycho@163.com hai 11 meses
pai
achega
361f1aab51
Modificáronse 35 ficheiros con 1733 adicións e 938 borrados
  1. 26 3
      TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue
  2. 3 3
      TEAMModelBI/TEAMModelBI.csproj
  3. 168 162
      TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs
  4. 3 3
      TEAMModelOS.FunctionV4/CosmosDB/TriggerVote.cs
  5. 551 551
      TEAMModelOS.FunctionV4/HttpTrigger/BIHttpTrigger.cs
  6. 1 35
      TEAMModelOS.FunctionV4/HttpTrigger/IESHttpTrigger.cs
  7. 3 3
      TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj
  8. 1 1
      TEAMModelOS.FunctionV4/TimeTrigger/IESTimerTrigger.cs
  9. 2 1
      TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs
  10. 1 1
      TEAMModelOS.SDK/Models/Service/BI/BIStats.cs
  11. 10 10
      TEAMModelOS.SDK/Models/Service/Common/TeacherService.cs
  12. 5 4
      TEAMModelOS.SDK/Models/Service/Third/ThirdService.cs
  13. 3 3
      TEAMModelOS.SDK/TEAMModelOS.SDK.csproj
  14. 4 1
      TEAMModelOS/ClientApp/src/api/http.js
  15. 6 2
      TEAMModelOS/ClientApp/src/api/learnActivity.js
  16. 26 6
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseChild.vue
  17. 312 0
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseEditAnsScore.vue
  18. 43 16
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseExerciseList.vue
  19. 210 12
      TEAMModelOS/ClientApp/src/view/evaluation/index/TestPaper.vue
  20. 2 2
      TEAMModelOS/ClientApp/src/view/iot/areaiot.vue
  21. 1 1
      TEAMModelOS/ClientApp/src/view/iot/schooliot.vue
  22. 5 4
      TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.vue
  23. 6 2
      TEAMModelOS/ClientApp/src/view/learnactivity/tabs/ExamPaper.vue
  24. 2 1
      TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxAddTable.vue
  25. 5 1
      TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreBody.vue
  26. 73 65
      TEAMModelOS/Controllers/Both/ScoreCalcController.cs
  27. 5 5
      TEAMModelOS/Controllers/Client/HiScanController.cs
  28. 5 5
      TEAMModelOS/Controllers/Client/HiTAControlller.cs
  29. 10 10
      TEAMModelOS/Controllers/Client/HiTeachController.cs
  30. 220 4
      TEAMModelOS/Controllers/Common/ExamController.cs
  31. 10 10
      TEAMModelOS/Controllers/Student/StudentController.cs
  32. 5 5
      TEAMModelOS/Controllers/Student/TmdUserController.cs
  33. 4 4
      TEAMModelOS/TEAMModelOS.csproj
  34. 1 1
      TEAMModelOS/appsettings.Development.json
  35. 1 1
      TEAMModelOS/appsettings.json

+ 26 - 3
TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue

@@ -185,7 +185,7 @@
             <div class="haveSchool">
               <div class="schoolLeft" v-loading="loadingSchoolList" element-loading-text="数据加载中..." v-if="PowerShow">
                 <div class="haveSchool-title">
-                  <div class="select-text">{{ $t(`areaManages.operational.areaAddSchool.schooltitle`) }}</div>
+                  <div class="select-text">{{ $t(`areaManages.operational.areaAddSchool.schooltitle`) }}</div>                                  
                   <div class="select-click">
                     <el-dropdown trigger="click" @command="handleCommand">
                       <span class="el-dropdown-link">
@@ -218,6 +218,10 @@
                   </div>
                   <div class="synchronization-title" v-show="currentlySelect.cutArea"><span>已同步省平台</span></div>
                 </div>
+                <div  class="search-school-btn">
+                <el-button type="primary"  @click="selectAll" size="small">全選</el-button>
+                  <el-button type="primary"  @click="deselectAll" size="small">全不選</el-button>
+                </div>
                 <ul>
                   <li class="details-list-school" v-for="(item, index) in notjoinSchool" :key="item.id" :class="{ active: position === index }">
                     <div class="details-list-checkboxs" @change="multipleChange">
@@ -1449,7 +1453,10 @@ export default {
     //学校列表 未加入学区
     function notjoinSchoolarea () {
       let values = schoolSeach.value
-      let newdata = notjoinPrimitive.value.filter((item) => { return item.name.includes(values) })
+      let newdata = notjoinPrimitive.value.filter((item) => {        
+        // 撈出名稱跟地址包含關鍵字的學校
+         return item.name.includes(values) || item.city?.includes(values) 
+        })        
       notjoinSchool.value = JSON.parse(JSON.stringify(newdata))
     }
     //学校显示(虚拟、实体)
@@ -1518,6 +1525,20 @@ export default {
       return jsonData.map((v) => filterVal.map((j) => v[j]))
     }
 
+    function selectAll() {                
+      notjoinSchool.value.forEach(item => {
+        item.checkstate = true;
+      });      
+      multiplecheck.value = true;
+    }
+    function deselectAll() {      
+      notjoinSchool.value.forEach(item => {
+        item.checkstate = false;
+      });    
+      multiplecheck.value = false;
+    }
+
+
     watch(abilityModel, (newdata) => {
       console.log(newdata)
       newdata
@@ -1653,7 +1674,9 @@ export default {
       exportAreadata,
       exportData,
       exportExcel,
-      formatJson
+      formatJson,
+      selectAll,
+      deselectAll
     }
   },
 }

+ 3 - 3
TEAMModelBI/TEAMModelBI.csproj

@@ -65,9 +65,9 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2406.12</Version>
-		<AssemblyVersion>5.2406.12.1</AssemblyVersion>
-		<FileVersion>5.2406.12.1</FileVersion>
+		<Version>5.2406.19</Version>
+		<AssemblyVersion>5.2406.19.1</AssemblyVersion>
+		<FileVersion>5.2406.19.1</FileVersion>
 		<Description>TEAMModelBI(BI)</Description>
 		<PackageReleaseNotes>BI版本说明版本切换标记2022000908</PackageReleaseNotes>
 		<PackageId>TEAMModelBI</PackageId>

+ 168 - 162
TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs

@@ -1912,201 +1912,207 @@ namespace TEAMModelOS.FunctionV4
                 pk = $"Item-{info.creatorId}";
                 table = "Teacher";
             }
-            string sqlqueryText = $"select value(c) from c where c.activityId = '{info.id}'and c.subjectId = '{info.subjects[no].id}' and c.stuId in ({string.Join(",", result.studentIds.Select(x => $"'{x}'"))})";
-            await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Student").GetItemQueryIterator<ErrorItems>(queryText: sqlqueryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
-            {
-                errorItems.Add(item);
-            }
-            try {
-               /* bool isError =  examClassResults.SelectMany(c => c.status).ToList().Exists(z => z == 1);
-                if () { 
-                
-                }*/
-                if (errorItems.Count == 0 && info.qamode != 2)
+
+            if (result.studentIds.Any()) {
+                string sqlqueryText = $"select value(c) from c where c.activityId = '{info.id}'and c.subjectId = '{info.subjects[no].id}' and c.stuId in ({string.Join(",", result.studentIds.Select(x => $"'{x}'"))})";
+                await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Student").GetItemQueryIterator<ErrorItems>(queryText: sqlqueryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
                 {
-                    // 新增逻辑 收集错题内容
-                    BlobDownloadResult index_json;
-                    if (info.scope.Equals("school"))
-                    {
-                        index_json = await _azureStorage.GetBlobContainerClient($"{info.school}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
-                    }
-                    else
-                    {
-                        index_json = await _azureStorage.GetBlobContainerClient($"{info.creatorId}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
-                    }
-                    //BlobDownloadResult index_json = await _azureStorage.GetBlobContainerClient($"{info.school}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
-                    JsonElement RecordingJson = JsonDocument.Parse(new MemoryStream(Encoding.UTF8.GetBytes(index_json.Content.ToString()))).RootElement;
-                    RecordingJson.TryGetProperty("slides", out JsonElement slides);
-                    int qamode = info.qamode;
-                    if (RecordingJson.TryGetProperty("qamode", out JsonElement element)) {
-                        qamode = element.GetInt32();
-                    }
-                    var sdes = slides.ToObject<List<Slides>>();
-                    List<string> attachments = new List<string>();
-                    if (qamode == 1)
-                    {
-                        attachments = RecordingJson.GetProperty("attachments").ToObject<List<string>>();
-                        if (attachments.Count == 0)
-                        {
-                            return;
-                        }
-                    }
-                    List<string> urls = new();
+                    errorItems.Add(item);
+                }
+                try
+                {
+                    /* bool isError =  examClassResults.SelectMany(c => c.status).ToList().Exists(z => z == 1);
+                     if () { 
 
-                    foreach (var ne in sdes)
-                    {
-                        if (!ne.type.Equals("compose"))
-                        {
-                            urls.Add(ne.url);
-                        }
-                    }
-                    // 获取整体的题目ID集合
-                    List<string> ids = new();
-                    List<(string id, string pid, int level, string type, List<string> knows)> itemInfos = new();
-                    foreach (string url in urls)
+                     }*/
+                    if (errorItems.Count == 0 && info.qamode != 2)
                     {
-                        string id = url.Replace(".json", "");
-                        BlobDownloadResult index_item_json;
+                        // 新增逻辑 收集错题内容
+                        BlobDownloadResult index_json;
                         if (info.scope.Equals("school"))
                         {
-                            index_item_json = await _azureStorage.GetBlobContainerClient($"{info.school}").GetBlobClient($"{info.papers[no].blob}/{url}").DownloadContentAsync();
+                            index_json = await _azureStorage.GetBlobContainerClient($"{info.school}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
                         }
                         else
                         {
-                            index_item_json = await _azureStorage.GetBlobContainerClient($"{info.creatorId}").GetBlobClient($"{info.papers[no].blob}/{url}").DownloadContentAsync();
+                            index_json = await _azureStorage.GetBlobContainerClient($"{info.creatorId}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
                         }
-                        JsonElement itemJson = JsonDocument.Parse(new MemoryStream(Encoding.UTF8.GetBytes(index_item_json.Content.ToString()))).RootElement;
-                        itemJson.TryGetProperty("exercise", out JsonElement exercise);
-                        //itemJson.TryGetProperty("pid", out JsonElement pid);
-                        var item_json = exercise.ToObject<Exercise>();
-                        //JObject keys = JObject.Parse(index_item_json.Content.ToString());
-                        string type = item_json.type;
-                        int level = item_json.level;
-                        var knowledge = item_json.knowledges;
-                        //string pid = keys.Value<string>("pid");
-                        if (itemJson.TryGetProperty("pid", out JsonElement pid))
+                        //BlobDownloadResult index_json = await _azureStorage.GetBlobContainerClient($"{info.school}").GetBlobClient($"{info.papers[no].blob}/index.json").DownloadContentAsync();
+                        JsonElement RecordingJson = JsonDocument.Parse(new MemoryStream(Encoding.UTF8.GetBytes(index_json.Content.ToString()))).RootElement;
+                        RecordingJson.TryGetProperty("slides", out JsonElement slides);
+                        int qamode = info.qamode;
+                        if (RecordingJson.TryGetProperty("qamode", out JsonElement element))
                         {
-                            itemInfos.Add((id, pid.ToString(), level, type, knowledge));
+                            qamode = element.GetInt32();
                         }
-                        else {
-                            itemInfos.Add((id, "", level, type, knowledge));
+                        var sdes = slides.ToObject<List<Slides>>();
+                        List<string> attachments = new List<string>();
+                        if (qamode == 1)
+                        {
+                            attachments = RecordingJson.GetProperty("attachments").ToObject<List<string>>();
+                            if (attachments.Count == 0)
+                            {
+                                return;
+                            }
                         }
-                        
-                    }
+                        List<string> urls = new();
 
-                    /* double[] point = StringHelper.ListTodouble(result.paper.point);
-                     double[,] res = StringHelper.ListToDouble(result.studentScores);
-                     var cdm = new ClouDASMatrix(res, point);*/
-                    //需要努力的题目
-                    //var ss = cdm.StriveTopic;
-                    int n = 0;
-                    List<Task<ItemResponse<ErrorItems>>> task_error = new();
-                    List<ErrorItems> errors = new();
-                    foreach (var sIds in result.studentIds)
-                    {
-                        ErrorItems error = new()
+                        foreach (var ne in sdes)
                         {
-                            ttl = -1,
-                            code = code,
-                            id = Guid.NewGuid().ToString(),
-                            stuId = sIds,
-                            school = info.school,
-                            activityId = info.id,
-                            subjectId = result.subjectId,
-                            time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
-                        };
-                        int index_stu = result.studentIds.IndexOf(sIds);
-                        //顺序学生错题的索引
-                        var itemScore = result.studentScores[index_stu];
-                        List<int> index = new();
-                        int index_item = 0;
-                        foreach (var sc in itemScore)
-                        {
-                            if (sc == 0)
+                            if (!ne.type.Equals("compose"))
                             {
-                                index.Add(index_item + 1);
+                                urls.Add(ne.url);
                             }
-                            index_item++;
                         }
-                        if (index.Count == 0)
+                        // 获取整体的题目ID集合
+                        List<string> ids = new();
+                        List<(string id, string pid, int level, string type, List<string> knows)> itemInfos = new();
+                        foreach (string url in urls)
                         {
-                            continue;
+                            string id = url.Replace(".json", "");
+                            BlobDownloadResult index_item_json;
+                            if (info.scope.Equals("school"))
+                            {
+                                index_item_json = await _azureStorage.GetBlobContainerClient($"{info.school}").GetBlobClient($"{info.papers[no].blob}/{url}").DownloadContentAsync();
+                            }
+                            else
+                            {
+                                index_item_json = await _azureStorage.GetBlobContainerClient($"{info.creatorId}").GetBlobClient($"{info.papers[no].blob}/{url}").DownloadContentAsync();
+                            }
+                            JsonElement itemJson = JsonDocument.Parse(new MemoryStream(Encoding.UTF8.GetBytes(index_item_json.Content.ToString()))).RootElement;
+                            itemJson.TryGetProperty("exercise", out JsonElement exercise);
+                            //itemJson.TryGetProperty("pid", out JsonElement pid);
+                            var item_json = exercise.ToObject<Exercise>();
+                            //JObject keys = JObject.Parse(index_item_json.Content.ToString());
+                            string type = item_json.type;
+                            int level = item_json.level;
+                            var knowledge = item_json.knowledges;
+                            //string pid = keys.Value<string>("pid");
+                            if (itemJson.TryGetProperty("pid", out JsonElement pid))
+                            {
+                                itemInfos.Add((id, pid.ToString(), level, type, knowledge));
+                            }
+                            else
+                            {
+                                itemInfos.Add((id, "", level, type, knowledge));
+                            }
+
                         }
-                        //int[] item_index = ss[n];
-                        foreach (var item in index)
+
+                        /* double[] point = StringHelper.ListTodouble(result.paper.point);
+                         double[,] res = StringHelper.ListToDouble(result.studentScores);
+                         var cdm = new ClouDASMatrix(res, point);*/
+                        //需要努力的题目
+                        //var ss = cdm.StriveTopic;
+                        int n = 0;
+                        List<Task<ItemResponse<ErrorItems>>> task_error = new();
+                        List<ErrorItems> errors = new();
+                        foreach (var sIds in result.studentIds)
                         {
-                            Items items = new()
+                            ErrorItems error = new()
                             {
-                                id = urls[item - 1].Replace(".json", ""),
-                                blob = info.papers[no].blob
-
+                                ttl = -1,
+                                code = code,
+                                id = Guid.NewGuid().ToString(),
+                                stuId = sIds,
+                                school = info.school,
+                                activityId = info.id,
+                                subjectId = result.subjectId,
+                                time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
                             };
-                            items.level = itemInfos.Where(c => c.id.Equals(items.id)).FirstOrDefault().level;
-                            items.type = itemInfos.Where(c => c.id.Equals(items.id)).FirstOrDefault().type;
-                            items.pId = itemInfos.Where(c => c.id.Equals(items.id)).FirstOrDefault().pid;
-                            items.knowledge = itemInfos.Where(c => c.id.Equals(items.id)).FirstOrDefault().knows;
-                            items.qamode = qamode;
-                            error.its.Add(items);
+                            int index_stu = result.studentIds.IndexOf(sIds);
+                            //顺序学生错题的索引
+                            var itemScore = result.studentScores[index_stu];
+                            List<int> index = new();
+                            int index_item = 0;
+                            foreach (var sc in itemScore)
+                            {
+                                if (sc == 0)
+                                {
+                                    index.Add(index_item + 1);
+                                }
+                                index_item++;
+                            }
+                            if (index.Count == 0)
+                            {
+                                continue;
+                            }
+                            //int[] item_index = ss[n];
+                            foreach (var item in index)
+                            {
+                                Items items = new()
+                                {
+                                    id = urls[item - 1].Replace(".json", ""),
+                                    blob = info.papers[no].blob
+
+                                };
+                                items.level = itemInfos.Where(c => c.id.Equals(items.id)).FirstOrDefault().level;
+                                items.type = itemInfos.Where(c => c.id.Equals(items.id)).FirstOrDefault().type;
+                                items.pId = itemInfos.Where(c => c.id.Equals(items.id)).FirstOrDefault().pid;
+                                items.knowledge = itemInfos.Where(c => c.id.Equals(items.id)).FirstOrDefault().knows;
+                                items.qamode = qamode;
+                                error.its.Add(items);
+                            }
+                            errors.Add(error);
+                            n++;
+                            task_error.Add(_azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").CreateItemAsync(error, new PartitionKey($"{error.code}")));
                         }
-                        errors.Add(error);
-                        n++;
-                        task_error.Add(_azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").CreateItemAsync(error, new PartitionKey($"{error.code}")));
-                    }
-                    //string connect = _configuration.GetValue<string>("HaBookAuth:Crtmabank") + "https://malearnfunction.chinacloudsites.cn/api/crtmabank";
-                    string location = $"{Environment.GetEnvironmentVariable("Option:Location")}";
-                    string urlAction = string.Empty;
-                    string accessKey = string.Empty;
-                    if (location.Contains("China"))
-                    {
-                        if (location.Equals("China")) //大陸正式站
+                        //string connect = _configuration.GetValue<string>("HaBookAuth:Crtmabank") + "https://malearnfunction.chinacloudsites.cn/api/crtmabank";
+                        string location = $"{Environment.GetEnvironmentVariable("Option:Location")}";
+                        string urlAction = string.Empty;
+                        string accessKey = string.Empty;
+                        if (location.Contains("China"))
+                        {
+                            if (location.Equals("China")) //大陸正式站
+                            {
+                                urlAction = "https://malearn.teammodel.cn";
+                                accessKey = "2BcXFR_hvzG1pZjqIkaM7Dx74Hcu6m0PwwOacFpDpq44AzFuHJBRXA==";
+                            }
+                            else if (location.Equals("China-Dep") || location.Equals("China-Test")) //大陸測試站
+                            {
+                                urlAction = "https://malearn-rc.teammodel.cn";
+                                accessKey = "lghWhJduNiAlo-e8isqEoROjdR7DAC-50XNtanIwHKYlAzFu1aog_A==";
+                            }
+                        }
+                        else if (location.Contains("Global"))
                         {
-                            urlAction = "https://malearn.teammodel.cn";
-                            accessKey = "2BcXFR_hvzG1pZjqIkaM7Dx74Hcu6m0PwwOacFpDpq44AzFuHJBRXA==";
+                            if (location.Equals("Global")) //國際正式站
+                            {
+                                urlAction = "https://malearn.teammodel.net";
+                                accessKey = "I-2lTcdggJkZWSBwOXQIm4oHx-huwX3d0wLe-9pgojThAzFuq_KNFg==";
+                            }
+                            else if (location.Equals("Global-Test")) //國際測試站
+                            {
+                                urlAction = "https://malearn-rc.teammodel.net";
+                                accessKey = "_l4Cb_tHIRBw_iv3ZuwVqjkMwjg4_HtDaxhAmZ8OwJraAzFu_DAY8A==";
+                            }
                         }
-                        else if (location.Equals("China-Dep") || location.Equals("China-Test")) //大陸測試站
+                        string connect = $"{urlAction}/api/crtmabank";
+                        var htc = _httpClient.CreateClient();
+                        if (htc.DefaultRequestHeaders.Contains("x-functions-key"))
                         {
-                            urlAction = "https://malearn-rc.teammodel.cn";
-                            accessKey = "lghWhJduNiAlo-e8isqEoROjdR7DAC-50XNtanIwHKYlAzFu1aog_A==";
+                            htc.DefaultRequestHeaders.Remove("x-functions-key");
                         }
-                    }
-                    else if (location.Contains("Global"))
-                    {
-                        if (location.Equals("Global")) //國際正式站
+                        htc.DefaultRequestHeaders.Add("x-functions-key", accessKey);
+                        ///智慧題庫school欄位修正
+                        foreach (ErrorItems error in errors)
                         {
-                            urlAction = "https://malearn.teammodel.net";
-                            accessKey = "I-2lTcdggJkZWSBwOXQIm4oHx-huwX3d0wLe-9pgojThAzFuq_KNFg==";
+                            error.school = (info.scope.Equals("school")) ? info.school : string.Empty;
                         }
-                        else if (location.Equals("Global-Test")) //國際測試站
+                        string paramJson = JsonConvert.SerializeObject(errors);
+                        var content = new StringContent(paramJson, Encoding.UTF8, "application/json");
+                        var response = await htc.PostAsync(connect, content);
+                        if ((int)response.StatusCode == 200)
                         {
-                            urlAction = "https://malearn-rc.teammodel.net";
-                            accessKey = "_l4Cb_tHIRBw_iv3ZuwVqjkMwjg4_HtDaxhAmZ8OwJraAzFu_DAY8A==";
+                            await task_error.TaskPage(10);
                         }
                     }
-                    string connect = $"{urlAction}/api/crtmabank";
-                    var htc = _httpClient.CreateClient();
-                    if (htc.DefaultRequestHeaders.Contains("x-functions-key"))
-                    {
-                        htc.DefaultRequestHeaders.Remove("x-functions-key");
-                    }
-                    htc.DefaultRequestHeaders.Add("x-functions-key", accessKey);
-                    ///智慧題庫school欄位修正
-                    foreach (ErrorItems error in errors)
-                    {
-                        error.school = (info.scope.Equals("school")) ? info.school : string.Empty;
-                    }
-                    string paramJson = JsonConvert.SerializeObject(errors);
-                    var content = new StringContent(paramJson, Encoding.UTF8, "application/json");
-                    var response = await htc.PostAsync(connect, content);
-                    if ((int)response.StatusCode == 200)
-                    {
-                        await task_error.TaskPage(10);
-                    }
                 }
-            }
-            catch (Exception e)
-            {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测错题异常{e.Message}\n{e.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
-            }
+                catch (Exception e)
+                {
+                    await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测错题异常{e.Message}\n{e.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
+                }
+            }                      
         }
 
         public class Settlement

+ 3 - 3
TEAMModelOS.FunctionV4/CosmosDB/TriggerVote.cs

@@ -345,6 +345,8 @@ namespace TEAMModelOS.FunctionV4
                             await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}投票活动{tdata.id}开始结算{tdata.endTime}!", GroupNames.醍摩豆服務運維群組);
 #endif
                             //获取投票活动的所有投票记录
+                            string pkey = string.Format("{0}{1}{2}", vote.code, "-", "going");
+                            await table.DeleteSingle<ChangeRecord>(pkey, tdata.id);
                             var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Vote:Record:{vote.id}");
                             //获取投票活动的选项及投票数
                             var counts = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Vote:Count:{vote.id}");
@@ -401,9 +403,7 @@ namespace TEAMModelOS.FunctionV4
                                 _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Count:{vote.id}");
                                 break;
                             }
-                            await Task.WhenAll(tasks);
-                            string pkey = string.Format("{0}{1}{2}", vote.code, "-", "going");
-                            await table.DeleteSingle<ChangeRecord>(pkey, tdata.id);
+                            await Task.WhenAll(tasks);                         
                             break;
                     }
                 }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 551 - 551
TEAMModelOS.FunctionV4/HttpTrigger/BIHttpTrigger.cs


+ 1 - 35
TEAMModelOS.FunctionV4/HttpTrigger/IESHttpTrigger.cs

@@ -74,41 +74,7 @@ namespace TEAMModelOS.FunctionV4
             _option = option?.Value;
             _configuration = configuration;
         }
-        // <summary>
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [Function("http-log")]
-        public async Task<HttpResponseData> HttpLog([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req) {
-            var response = req.CreateResponse(HttpStatusCode.OK);
-            try {
-                string data;
-                using (var reader = new StreamReader(req.Body))
-                {
-                    data = await reader.ReadToEndAsync();
-                }
-                var gmt8Time = DateTimeOffset.UtcNow.GetGMTTime(8);
-                var appendBlob = _azureStorage.GetBlobContainerClient("0-service-log").GetAppendBlobClient($"http-log/{gmt8Time:yyyy}/{gmt8Time:MM}/{gmt8Time:dd}/{gmt8Time:HH}.log");
-                if (!await appendBlob.ExistsAsync())
-                {
-                    await appendBlob.CreateAsync();
-                }
-                using (var stream = new MemoryStream(Encoding.UTF8.GetBytes($"{data},\n")))
-                {
-                    await appendBlob.AppendBlockAsync(stream);
-                }
-                await response.WriteAsJsonAsync(new { code = 1 });
-                return response;  
-
-            } catch(Exception ex ) {
-                await _dingDing.SendBotMsg($"{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
-                await response.WriteAsJsonAsync(new { code = 1 });
-                return response;
-            }
-           
-        }
-
+       
          /// <summary>
          /// </summary>
          /// <param name="req"></param>

+ 3 - 3
TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj

@@ -5,9 +5,9 @@
 		<OutputType>Exe</OutputType>
 		<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
 		<SignAssembly>true</SignAssembly>
-		<Version>5.2406.12</Version>
-		<AssemblyVersion>5.2406.12.1</AssemblyVersion>
-		<FileVersion>5.2406.12.1</FileVersion>
+		<Version>5.2406.19</Version>
+		<AssemblyVersion>5.2406.19.1</AssemblyVersion>
+		<FileVersion>5.2406.19.1</FileVersion>
 		<PackageId>TEAMModelOS.FunctionV4</PackageId>
 		<Authors>teammodel</Authors>
 		<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 1 - 1
TEAMModelOS.FunctionV4/TimeTrigger/IESTimerTrigger.cs

@@ -136,7 +136,7 @@ namespace TEAMModelOS.FunctionV4.TimeTrigger
         /// <param name="req"></param>
         /// <param name="log"></param>
         /// <returns></returns>
-        [Function("FireWallFileLog")]
+       // [Function("FireWallFileLog")]
         //https://docs.azure.cn/zh-cn/azure-functions/functions-bindings-timer?tabs=in-process&pivots=programming-language-csharp
         //0 1 * * * * 一天中每小时的第 1 分钟
         //0 */10 * * * *  每五分钟一次

+ 2 - 1
TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs

@@ -67,7 +67,7 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public string source { get; set; }
         /// <summary>
-        /// 書面問答類型 0:書面問答 1:紙本測驗 2:艺术评测
+        /// 書面問答類型 0:書面問答 1:紙本測驗 2:艺术评测3:多分同步活动
         /// </summary>
         public int qamode { get; set; }
         
@@ -131,6 +131,7 @@ namespace TEAMModelOS.SDK.Models
         public bool cloudas { get; set;}
         //統測ID [測試中]
         //public string jointExamId { get; set; }
+        public string moofenCode { get; set; }
     }
     public class Custom {
         public string id { get; set; }

+ 1 - 1
TEAMModelOS.SDK/Models/Service/BI/BIStats.cs

@@ -34,7 +34,7 @@ namespace TEAMModelOS.SDK.Models.Service.BI
         {
             try
             {
-                if (string.IsNullOrEmpty(scId))
+                if (string.IsNullOrEmpty(scId) || scId.Equals("SYSTEM_NO_SCHOOL",StringComparison.OrdinalIgnoreCase))
                     return;
 
                 DateTimeOffset cuurDateOff = DateTimeOffset.UtcNow;

+ 10 - 10
TEAMModelOS.SDK/Models/Service/Common/TeacherService.cs

@@ -184,11 +184,11 @@ namespace TEAMModelOS.Services
             //換取AuthToken,提供給前端
 
             //用户在线记录
-            try
-            {
-                _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
-            }
-            catch { }
+            //try
+            //{
+            //    _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
+            //}
+            //catch { }
 
             //換取AuthToken,提供給前端
             var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name?.ToString(), picture?.ToString(), _option.JwtSecretKey, Website: "IES", timezone: timezone, scope: Constant.ScopeTeacher, standard:  "", roles: roles.ToArray(), expire: 1);
@@ -496,11 +496,11 @@ namespace TEAMModelOS.Services
             var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name?.ToString(), picture?.ToString(), _option.JwtSecretKey, Website: "IES", timezone: timezone, scope: Constant.ScopeTeacher, standard: areaa != null ? areaa.standard : "", roles: roles.ToArray(), expire: 1);
 
             //用户在线记录
-            try
-            {
-                _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
-            }
-            catch { }
+            //try
+            //{
+            //    _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
+            //}
+            //catch { }
 
 
             //取得Teacher Blob 容器位置及SAS 

+ 5 - 4
TEAMModelOS.SDK/Models/Service/Third/ThirdService.cs

@@ -957,7 +957,7 @@ namespace TEAMModelOS.SDK.Models
 
                     var data = content.ToObject<JsonElement>();
                     if (data.TryGetProperty("data", out JsonElement _data)) {
-                        return _data.GetString();
+                        return _data.ToString();
                     }
 
                 }
@@ -976,7 +976,7 @@ namespace TEAMModelOS.SDK.Models
                 Dictionary<string, string> dict = new Dictionary<string, string>();
                 if (json.TryGetProperty("examCode", out JsonElement examCode) && !string.IsNullOrWhiteSpace($"{examCode}"))
                 {
-                    dict.Add("examName", $"{examCode}");
+                    dict.Add("examCode", $"{examCode}");
                 }                
                 if (json.TryGetProperty("subjects", out JsonElement subjects) && subjects.ValueKind.Equals(JsonValueKind.Array))
                 {
@@ -1050,12 +1050,13 @@ namespace TEAMModelOS.SDK.Models
             public double value { get; set; }
         }
         public class stuAns { 
-            public string stuId { get; set; }
+            public string stuNo { get; set; }
             public List<moofenAns> scoreData { get; set; } = new List<moofenAns>();
+            public string subject { get; set; }
         }
         public class moofenAns
         {
-            public double questionNo { get; set; }
+            public string questionNo { get; set; }
             public double score  { get; set; }
             public string answer { get; set; }
         }

+ 3 - 3
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -2,9 +2,9 @@
 
 	<PropertyGroup>
 		<TargetFramework>net6.0</TargetFramework>
-		<Version>5.2406.12</Version>
-		<AssemblyVersion>5.2406.12.1</AssemblyVersion>
-		<FileVersion>5.2406.12.1</FileVersion>
+		<Version>5.2406.19</Version>
+		<AssemblyVersion>5.2406.19.1</AssemblyVersion>
+		<FileVersion>5.2406.19.1</FileVersion>
 		<PackageReleaseNotes>发版</PackageReleaseNotes>
 	</PropertyGroup>
 

+ 4 - 1
TEAMModelOS/ClientApp/src/api/http.js

@@ -292,13 +292,16 @@ export function fetch(url, params) {
  * @returns {Promise}
  */
 
-export function post(url, params) {
+export function post(url, params, timeout) {
     //params['id_token'] = localStorage.getItem('id_token')
     let data = {}
     data.method = url
     data.params = params
     data.lang = localStorage.getItem('local')
     return new Promise((resolve, reject) => {
+        if(timeout){
+            axios.defaults.timeout = timeout // 设置超时时长
+        }
         axios.post(url, params)
             .then(response => {
                 if (response) {

+ 6 - 2
TEAMModelOS/ClientApp/src/api/learnActivity.js

@@ -54,6 +54,10 @@ export default {
     FindExamInfo: function (data) {
         return post('/common/exam/find-summary', data)
     },
+    // 评测试卷修改答案、配分
+    updateAns: function(data) {
+        return post('/common/exam/update-ans', data)
+    },
     /*
      *自动组题
      */
@@ -369,8 +373,8 @@ export default {
 	    return post('/score/update-scorecalc', data)
 	},  
     /* 新增成績表 */
-	addScorecalc: function (data) {
-	    return post('/score/add-scorecalc', data)
+	addScorecalc: function (data, timeout) {
+	    return post('/score/add-scorecalc', data, timeout)
 	},
     /* 刪除成績表 */
 	deleteScorecalc: function (data) {

+ 26 - 6
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseChild.vue

@@ -6,6 +6,9 @@
         <div class="child-tools-t flex-row-center" v-if="isShowScore" @click.stop="handleChildEdit(item,index)">
           {{$t('evaluation.editItem')}}{{$t('evaluation.child')}}
         </div>
+        <div class="child-tools-t flex-row-center" v-if="isChangePaper" @click.stop="handleChildEdit(item,index)">
+          调整{{$t('evaluation.child')}}
+        </div>
         <div class="child-tools-t flex-row-center" v-if="canFix" @click.stop="handleFixChild(item,index)">
           {{ $t('evaluation.fixTip1') }}
         </div>
@@ -23,13 +26,13 @@
       </div>
       <div class="item-btn-toggle">
         <template v-if="!inBank">
-          <template v-if="isShowScore">
+          <template v-if="isShowScore || isChangePaper">
             <InputNumber :min="0" v-model="item.score" v-if="df" :step="0.5" @on-change="val => scoreChange(val, item.pid, item.id)" style="display: inline-block ;width: 60px;margin-right: 10px;height: 30px;" @click.stop>
             </InputNumber>
             <InputNumber :min="0" v-model="item.score" v-else :step="0.5" style="display: inline-block ;width: 60px;margin-right: 10px;height: 30px;" @click.stop>
             </InputNumber>
           </template>
-          <span v-if="!isShowScore" style="margin-right: 10px;color: #2db7f5;font-weight: bold;">{{ item.score }}</span>
+          <span v-else style="margin-right: 10px;color: #2db7f5;font-weight: bold;">{{ item.score }}</span>
           <span style="margin-right: 20px;">{{$t('evaluation.paperList.score')}}</span>
         </template>
         <Icon :type="collapseList.includes(children.indexOf(item)) ? 'ios-arrow-dropup' : 'ios-arrow-dropdown'" />
@@ -128,6 +131,14 @@
         <Button type="success" @click="onSaveChild">{{$t('evaluation.confirm')}}</Button>
       </div>
     </Modal>
+    <!-- 修改试题答案、配分弹窗 -->
+    <Modal v-model="editAnsScoreModal" width="1080" class="edit-exercise-modal" :styles="{top: '20px'}" :mask-closable="false">
+      <div class="modal-header" slot="header">{{$t('evaluation.exerciseList.editChild')}}</div>
+      <BaseEditAnsScore v-if="editAnsScoreModal" :exerciseItem="curItem" @onEditSuccess="onEditChildFinish" refId="paperEdit" ref="paperEdit"></BaseEditAnsScore>
+      <div slot="footer">
+        <Button type="success" @click="onSaveChild">{{$t('evaluation.confirm')}}</Button>
+      </div>
+    </Modal>
 
     <!-- 补充解析和补救资源弹窗 -->
     <Modal v-model="addExplainModal" :styles="{top: '20px'}" width="1000px" :title="$t('evaluation.fixTip1')">
@@ -178,6 +189,10 @@ export default {
       type: Boolean,
       default: false
     },
+    isChangePaper: { //评测页面需修改答案、配分等
+      type: Boolean,
+      default: false
+    },
     inBank: {
       type: Boolean,
       default: false
@@ -210,7 +225,8 @@ export default {
       collapseList: [],
       surPlusScore: 0,
       exersicesField: this.$GLOBAL.EXERCISE_LEVELS(),
-      scatterData: []
+      scatterData: [],
+      editAnsScoreModal: false,
     }
   },
   created() {
@@ -251,12 +267,16 @@ export default {
       this.scatterData = newArr
     },
     onSaveChild() {
-      this.$refs.createChildRef.getContent(this.curItem.type)
+      if(this.isChangePaper) {
+        this.$refs.paperEdit.saveContent(this.curItem.type)
+      } else {
+        this.$refs.createChildRef.getContent(this.curItem.type)
+      }
     },
     handleChildEdit(item, index) {
       this.curItem = item
       this.curIndex = index
-      this.editChildModal = true
+      this.isChangePaper ? this.editAnsScoreModal = true : this.editChildModal = true
     },
     handleFixChild(item, index) {
       this.curItem = item
@@ -284,7 +304,7 @@ export default {
     },
     onEditChildFinish(item) {
       console.log(item)
-      this.editChildModal = false
+      this.isChangePaper ? this.editAnsScoreModal = false : this.editChildModal = false
       this.$emit('onEditChildFinish', item)
     },
     getOptionLineData(item, index) {

+ 312 - 0
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseEditAnsScore.vue

@@ -0,0 +1,312 @@
+<template>
+    <div class="ev-container" ref="editContainer">
+        <div>
+            <div>
+                <div class="exersices-content">
+                    <IconText :text="$t('evaluation.connector') + $t('evaluation.newExercise.stem')" :color="'#2d8cf0'" :icon="'ios-create'" style="margin-bottom:15px;"></IconText>
+                    <p v-html="editInfo.question"></p>
+                </div>
+                <div class="exersices-option" ref="optionRefs">
+                    <template v-if="exersicesType === 'single' || exersicesType === 'multiple'">
+                        <IconText :text="$t(`evaluation.newExercise.${exersicesType}Option`)" :color="'#FF871C'" :icon="'md-reorder'"></IconText>
+                        <div v-for="(item, index) in editInfo.option" :key="index" :ref="'optionBox' + index" :class="'editor-wrap-' + item" style="margin-top:10px;display:flex">
+                            <span class="fl-center option-order" :ref="'optionOrder' + index" :data-index="index">{{ renderIndex(index) }}</span>
+                            <!-- <span class="fl-center option-order">{{String.fromCharCode(64 + parseInt(index+1))}}</span> -->
+                            <div class="option-editor" v-html="item.value" style="display: flex; align-items: center; padding-left: 10px;"></div>
+                            <span :class="['fl-center', 'option-setting', trueArr.indexOf(index) > -1 ? 'option-true':'']" @click="settingAnswer(index)">{{ trueArr.indexOf(index) > -1 ? $t('evaluation.newExercise.trueAnswer') :$t('evaluation.newExercise.setAnswer') }}</span>
+                        </div>
+			            <p class="option-add">
+                            <span style="color:rgb(60,196,82);margin-left:15px;font-weight:bold">{{ $t('evaluation.newExercise.trueAnswer') }}:{{ paperAnswers.join("") }}</span>
+                        </p>
+                    </template>
+                    <template v-else-if="exersicesType === 'judge'">
+                        <IconText :text="$t('evaluation.newExercise.option')" :color="'#FF871C'" :icon="'md-reorder'"></IconText>
+                        <RadioGroup v-model="paperAnswers[0]" type="button" size="large">
+                            <Radio label="A">{{ $t('evaluation.isTrue') }}</Radio>
+                            <Radio label="B">{{ $t('evaluation.isFalse') }}</Radio>
+                        </RadioGroup>
+                    </template>
+                    <template v-else>
+                        <IconText :text="$t('evaluation.newExercise.answerTitle')" :color="'#FF871C'" :icon="'md-reorder'"></IconText>
+                        <div style="margin-top:15px;">
+                            <div ref="answerEditor" style="text-align:left"></div>
+                        </div>
+                    </template>
+                </div>
+            </div>
+            <div class="exersices-attr my-radio-style">
+                <IconText :text="$t('evaluation.newExercise.knowledge')" :color="'#00b8ff'" :icon="'md-infinite'"></IconText>
+                <Button type="info" style="margin-top: 20px" @click="onSelectPoints" v-if="exercisePoints.length === 0">{{$t('evaluation.newExercise.choosePoint')}}</Button>
+                <div v-else style="margin-top: 10px">
+                <span v-for="(item, index) in exercisePoints" :key="index" class="exercise-item-point">
+                    {{ item }}
+                    <span class="exercise-item-point-close">
+                        <Icon type="md-close" @click="onDeletePoint(index)" />
+                    </span>
+                </span>
+                <span class="exercise-item-point-modify" @click="selectPointsModal = true">{{ this.$t('evaluation.newExercise.modify') }}</span>
+                </div>
+            </div>
+        </div>
+        <Modal v-model="selectPointsModal" :title="$t('evaluation.newExercise.choosePoint')" footer-hide ref="editPointRef" width="600px" style="z-index: 99999">
+            <BasePoints v-if="selectPointsModal" :period="schoolInfo.period[exercisePeriod].id" :subject="schoolInfo.period[exercisePeriod].subjects[exerciseSubject].id" @onCheckChange="onCheckChange" @onCancel="selectPointsModal = false" :points="exercisePoints" ref="pointRef" :scope="curScope"></BasePoints>
+        </Modal>
+    </div>
+</template>
+
+<script>
+import E from 'wangeditor'
+import IconText from '@/components/evaluation/IconText.vue'
+export default {
+    components: {
+        IconText
+    },
+    props: {
+        exerciseItem: {
+            type: Object,
+            default: () => null
+        },
+        refId: {
+            type: String,
+            default: () => ''
+        },
+    },
+    data () {
+        return {
+            editInfo: null,
+            selectPointsModal: false,
+            schoolInfo: {
+                period: [],
+            },
+            exercisePeriod: 0,
+            exercisePoints: [],
+            exerciseScope: 0,
+            exerciseSubject: 0,
+            subjectList: [],
+            exersicesType: null,
+            oldChildList: [],
+			optionTrueIndex: 0,
+			trueArr: [0],
+			paperAnswers: ["A"],
+			answerEditor: null,
+        }
+    },
+    mounted () {
+        
+    },
+    watch: {
+        exerciseItem: {
+            handler(newValue, oldValue) {
+                if (Object.keys(newValue).length) {
+                    console.log("BaseEditExerciese接受的", newValue);
+                    this.renderExercise(JSON.parse(JSON.stringify(newValue)));
+                }
+            },
+            immediate: true,
+            deep: true
+        },
+    },
+    computed: {
+        curScope() {
+            return this.exerciseScope === 1 ? 'school' : 'private'
+        },
+        hasSchool() {
+            return this.$store.state.userInfo.hasSchool
+        },
+    },
+    methods: {
+        // 渲染编辑习题内容回显
+        async renderExercise(editItem) {
+            console.log('edit-item', editItem);
+            this.editInfo = editItem;
+            // this.curId = editItem.id
+
+            let schoolProfile = await this.$store.dispatch('user/getSchoolProfile')
+            let schoolInfo = schoolProfile.school_base;
+
+            if (editItem.scope === "school" && schoolInfo) {
+                this.schoolInfo = schoolInfo;
+                this.exercisePeriod = schoolInfo.period.map((item) => item.id).indexOf(editItem.periodId);
+                this.subjectList = schoolInfo.period[this.exercisePeriod].subjects;
+                // this.gradeList = schoolInfo.period[this.exercisePeriod].grades;
+                // this.exerciseGrade = editItem.gradeIds.map(i => +i);
+                this.exerciseSubject = this.subjectList.map((item) => item.id).indexOf(editItem.subjectId);
+            }
+            // this.fieldList = [this.$t('evaluation.level1'), this.$t('evaluation.level2'), this.$t('evaluation.level3'), this.$t('evaluation.level4'), this.$t('evaluation.level5'), this.$t('evaluation.level6')]
+            // this.isEdit = true;
+            // this.exersicesDiff = editItem.level.toString() || "0";
+            this.exerciseScope = editItem.scope === "private" ? 0 : 1;
+            this.exersicesType = editItem.type;
+            // this.exerciseField = editItem.field - 1;
+            this.exercisePoints = editItem.knowledge || editItem.points || [];
+
+            if (editItem.type === 'compose') {
+                this.oldChildList = JSON.parse(JSON.stringify(editItem.children)) || []
+            }
+            // this.childList = editItem.children || [];
+            // this.stemContent = editItem.question;
+            // this.relateFileList = editItem.repair || [];
+            // this.optionsContent = editItem.option;
+            this.trueArr = editItem.answer.map((item) => item.charCodeAt() - 65)
+            this.paperAnswers = editItem.answer
+            // this.analysisContent = editItem.explain;
+            // this.analysisEditor.txt.html(editItem.explain);
+            console.log('当前编辑的试题', this.editInfo)
+            if(!['single', 'multiple', 'judge'].includes(this.exersicesType)) {
+                let answerEditor = new E(this.$refs.answerEditor)
+                answerEditor.config.onchange = (html) => {
+                    this.paperAnswers = [html]
+                }
+                answerEditor.config.uploadImgShowBase64 = true;
+                this.$editorTools.initMyEditor(answerEditor,this)
+                answerEditor.create()
+
+                this.answerEditor = answerEditor
+                this.answerEditor.txt.html(this.paperAnswers[0])
+            }
+        },
+        /* 根据下标渲染对应的字母顺序 */
+        renderIndex(index) {
+            return String.fromCharCode(64 + parseInt(index + 1))
+        },
+        /* 设置正确答案 */
+        settingAnswer(index) {
+            this.$nextTick(() => {
+                if(this.exersicesType === 'single') {
+                    if (this.trueArr.indexOf(index) === -1) {
+                        this.trueArr = [index]
+                    }
+                } else {
+                    if (this.trueArr.indexOf(index) > -1) {
+                        if (this.trueArr.length === 1) {
+                            this.$Message.warning(this.$t("evaluation.addTip3"));
+                        } else {
+                            this.trueArr.splice(this.trueArr.indexOf(index), 1);
+                        }
+                    } else {
+                        this.trueArr.push(index);
+                        this.trueArr = this.trueArr.sort(); // 选项排序
+                    }
+                }
+                this.getAnswerOrder(this.trueArr);
+            });
+        },
+        /* 获取最新答案选项 */
+        getAnswerOrder(arr) {
+            let arr2 = [];
+            arr.forEach((i) => {
+                arr2.push(this.getOrderCode(i));
+            });
+            this.paperAnswers = arr2.sort();
+        },
+        /* 根据index获取对应选项字母的值 */
+        getOrderCode(index) {
+            let wraps = Array.from(this.$refs.optionRefs.getElementsByClassName("option-order"));
+            for (let i = 0; i < wraps.length; i++) {
+                let item = wraps[i];
+                if (+index === +item.dataset.index) {
+                    return item.innerText;
+                    break;
+                }
+            }
+        },
+        onSelectPoints() {
+            if (this.hasSchool) {
+                this.selectPointsModal = true
+            } else {
+                this.$Message.warning(this.$t('evaluation.newExercise.noSchoolTip'))
+            }
+        },
+        /**
+         * 删除选好的关联知识点
+         * @param index
+         */
+        onDeletePoint(index) {
+            this.exercisePoints.splice(index, 1);
+        },
+        onCheckChange(val, list) {
+            console.log(val);
+            this.exercisePoints = val;
+            this.selectPointsModal = false
+        },
+        /* 滚回顶部 */
+        backToTop() {
+            this.$refs.editContainer.scrollIntoView();
+            // this.exersicesType = ''
+        },
+        saveContent(type) {
+            let exerciseItem = JSON.parse(JSON.stringify(this.editInfo))
+            this.isLoading = true;
+            
+            exerciseItem.answer = this.paperAnswers
+            // exerciseItem.explain = this.analysisContent;
+            // exerciseItem.repair = this.formatRepairResource(this.$refs.repairRef.datas);
+            // exerciseItem.field = this.exerciseField + 1;
+            exerciseItem.knowledge = this.exercisePoints;
+            // exerciseItem.periodId = this.isSchool ? this.schoolInfo.period[this.exercisePeriod].id : null;
+            // exerciseItem.gradeIds = this.isSchool ? this.exerciseGrade.length ? this.exerciseGrade.map(i => i + '') : this.gradeList.map((i, index) => index + '') : null;
+            // exerciseItem.subjectId = this.isSchool ? this.schoolInfo.period[this.exercisePeriod].subjects[this.exerciseSubject].id : null;
+            // exerciseItem.code = this.editInfo.scope === "school" ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId;
+            // exerciseItem.scope = this.exerciseScope === 0 ? "private" : "school";
+            // 收集编辑器宽度 方便压缩富文本图片中宽度为百分比的图片
+            /* let editorWidth = {}
+            if (exerciseItem.type === 'single') {
+                editorWidth.questionWidth = this.$refs.single.stemEditor.$textContainerElem.elems[0].clientWidth
+                editorWidth.optionWidth = this.$refs.single.optionEditors[0].$textContainerElem.elems[0].clientWidth
+            } else if (exerciseItem.type === 'multiple') {
+                editorWidth.questionWidth = this.$refs.multiple.stemEditor.$textContainerElem.elems[0].clientWidth
+                editorWidth.optionWidth = this.$refs.multiple.optionEditors[0].$textContainerElem.elems[0].clientWidth
+            } else {
+                editorWidth.questionWidth = this.analysisEditor.$textContainerElem.elems[0].clientWidth
+            } */
+            console.log('333333333333333', exerciseItem);
+            this.$emit("onEditSuccess", exerciseItem)
+        },
+        // 排除对象空属性
+        checkContent(Obj) {
+            return new Promise(async (r, j) => {
+                let flag = true;
+                let whiteList = this.getWhiteListByType(Obj.type);
+                console.log("富文本获取的原始试题数据", Obj);
+                for (let key in Obj) {
+                    if (whiteList.includes(key) && typeof Obj[key] === "string") {
+                        if (!this.getSimpleText(Obj[key])) {
+                            flag = await this.emptyConfirm(key)
+                            r(flag);
+                            return
+                        }
+                    } else {
+                        if (whiteList.includes(key) && !Obj[key]) {
+                            flag = await this.emptyConfirm(key)
+                            r(flag);
+                            return
+                        }
+                    }
+                }
+                r(flag);
+            })
+        },
+        // 根据不同题型 给出需要必填选项
+        getWhiteListByType(type) {
+            switch (type) {
+                case "single":
+                    return ["question", "option", "answer"];
+                    break;
+                case "multiple":
+                    return ["question", "option", "answer"];
+                    break;
+                case "complete":
+                    return ["question", "answer"];
+                    break;
+                default:
+                    return ["question"];
+                    break;
+            }
+        },
+    }
+}
+</script>
+
+<style lang="less" scoped>
+@import "../index/CreateExercises.less";
+</style>

+ 43 - 16
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseExerciseList.vue

@@ -21,6 +21,7 @@
 						<!-- <div class="item-tools-t flex-row-center" v-show="isShowTools" @click.stop="handleSetScore(item,exerciseList.indexOf(item),typeItem.list,index)">
 							<Icon type="ios-list-box-outline" />配分</div> -->
 						<div class="item-tools-t flex-row-center" v-show="isShowTools && !isExamPaper" @click.stop="handleToolEdit(typeItem.list, item, index)"><Icon type="md-create" />{{ $t("evaluation.editItem") }}</div>
+						<div class="item-tools-t flex-row-center" v-show="isChangePaper && item.type !== 'compose'" @click.stop="handleToolEdit(typeItem.list, item, index)"><Icon type="md-create" />{{ '调整' }}</div>
 						<div class="item-tools-t flex-row-center" v-show="isAutoMode" @click.stop="handleToolChange(typeItem.list, item, index)"><Icon type="md-repeat" />{{ $t("evaluation.exchange") }}</div>
 						<div class="item-tools-t flex-row-center" v-show="isShowTools && !isExamPaper && noAnswerList.indexOf(item) > -1" @click.stop="onSetAnswer(item, exerciseList.indexOf(item), typeItem.list, index)"><Icon type="ios-brush-outline" />{{ $t("evaluation.exerciseList.setAnswer") }}</div>
 						<div class="item-tools-t flex-row-center" v-show="isShowTools && !isExamPaper" @click.stop="handleDelete(typeItem.list, item, index)"><Icon type="ios-archive-outline" />{{ $t("evaluation.deleteItem") }}</div>
@@ -55,11 +56,11 @@
 						</div>
 					</div>
 					<div class="exercise-item-children" v-if="item.children.length">
-						<BaseChild :children="item.children" :totalScore="item.score" :isShowScore="!isExamPaper" :canFix="canFix" @onEditChildFinish="onEditChildFinish"> </BaseChild>
+						<BaseChild :children="item.children" :totalScore="item.score" :isChangePaper="isChangePaper" :isShowScore="!isExamPaper" :canFix="canFix" @onEditChildFinish="onEditChildFinish"> </BaseChild>
 					</div>
 					<div class="item-btn-toggle" v-show="isShowTools && !isPreview">
 						<!-- 可调整分数 -->
-						<template @click.stop v-if="!isExamPaper">
+						<template @click.stop v-if="!isExamPaper || isChangePaper">
 							<InputNumber v-if="item.type !== 'compose'" :max="item.score + surPlusScore" :min="scoreStep" :step="scoreStep" v-model="item.score" style="display: inline-block; width: 60px; margin-right: 10px; height: 30px" @click.stop> </InputNumber>
 							<span style="margin-right: 10px" v-if="item.type === 'compose'">{{ getComposeScore(item) }}</span>
 							<span style="margin-right: 10px">{{ $t("evaluation.paperList.score") }}</span>
@@ -239,6 +240,13 @@
 				<Button type="success" :loading="editLoading" @click="doSaveEdit">{{ $t("evaluation.confirm") }}</Button>
 			</div>
 		</Modal>
+		<!-- 修改试题答案、配分弹窗 -->
+		<Modal v-model="editAnsScoreModal" :mask-closable="false" :styles="{ top: '20px' }" class-name="edit-exercise-modal" width="1200px" :title="$t('evaluation.exerciseList.editExercise')" @on-visible-change="editModalChange">
+			<BaseEditAnsScore v-if="editAnsScoreModal" :exerciseItem="currentExercise" @onEditSuccess="onEditSuccess" refId="paperEdit" ref="paperEdit"></BaseEditAnsScore>
+			<div slot="footer">
+				<Button type="success" :loading="editLoading" @click="doSaveEdit">{{ $t("evaluation.confirm") }}</Button>
+			</div>
+		</Modal>
 		<!-- 编辑题型说明弹窗 -->
 		<Modal v-model="editSumaryModal" class-name="ex-score-modal" width="600px" :title="exersicesType[curEditType] + $t('evaluation.summaryText')" @on-visible-change="editModalChange" @on-ok="onConfirmChangeSummary">
 			<Input v-model="curSummary" />
@@ -255,7 +263,11 @@
 </template>
 
 <script>
+	import BaseEditAnsScore from './BaseEditAnsScore.vue'
 	export default {
+		components: {
+			BaseEditAnsScore,
+		},
 		props: {
 			paper: {
 				type: Object,
@@ -273,6 +285,10 @@
 				type: Boolean,
 				default: false
 			},
+			isChangePaper: { //评测页面需修改答案、配分等
+				type: Boolean,
+				default: false
+			},
 			canFix: {
 				type: Boolean,
 				default: false
@@ -347,6 +363,7 @@
 				typeScoreModel: false,
 				setPaperInfoModal: false,
 				editExerciseModal: false,
+				editAnsScoreModal: false,
 				exersicesType: this.$GLOBAL.EXERCISE_TYPES(),
 				exersicesDiff: this.$GLOBAL.EXERCISE_DIFFS(),
 				exersicesField: this.$GLOBAL.EXERCISE_LEVELS(),
@@ -399,7 +416,11 @@
 			/* 手动保存 */
 			doSaveEdit() {
 				this.editLoading = true;
-				this.$refs.paperEdit.getContent(this.currentExercise.type);
+				if(this.isChangePaper) {
+					this.$refs.paperEdit.saveContent(this.currentExercise.type)
+				} else {
+					this.$refs.paperEdit.getContent(this.currentExercise.type);
+				}
 			},
 			/* 保存补充解析的题目 */
 			doSaveFixItem() {
@@ -563,21 +584,27 @@
 			handleToolEdit(arr, item, index) {
 				console.error(this.errorList);
 				console.error(item);
-				this.currentExerciseIndex = this.exerciseList.indexOf(item); // 清单列表下的index
-				this.curOrderIndex = index;
-				if (item.scope === "school") {
-					this.getSchoolBaseInfo().then((res) => {
-						if (!res) return;
-						item.periodId = res.period[this.paperInfo.paperPeriod].id;
-						item.subjectId = res.period[this.paperInfo.paperPeriod].subjects[this.paperInfo.paperSubject].id;
+				if(this.isChangePaper) {
+					this.curTypeItems = arr;
+					this.currentExercise = item;
+					this.editAnsScoreModal = true;
+				} else {
+					this.currentExerciseIndex = this.exerciseList.indexOf(item); // 清单列表下的index
+					this.curOrderIndex = index;
+					if (item.scope === "school") {
+						this.getSchoolBaseInfo().then((res) => {
+							if (!res) return;
+							item.periodId = res.period[this.paperInfo.paperPeriod].id;
+							item.subjectId = res.period[this.paperInfo.paperPeriod].subjects[this.paperInfo.paperSubject].id;
+							this.curTypeItems = arr;
+							this.currentExercise = item;
+							this.editExerciseModal = true;
+						});
+					} else {
 						this.curTypeItems = arr;
 						this.currentExercise = item;
 						this.editExerciseModal = true;
-					});
-				} else {
-					this.curTypeItems = arr;
-					this.currentExercise = item;
-					this.editExerciseModal = true;
+					}
 				}
 				console.log("试卷当前编辑的题目", item);
 			},
@@ -765,7 +792,7 @@
 				if (this.$refs.paperEdit) {
 					this.$refs.paperEdit.isLoading = false;
 				}
-				this.editExerciseModal = false;
+				this.isChangePaper ? this.editAnsScoreModal = false : this.editExerciseModal = false;
 				this.$Message.success(this.$t("evaluation.editSuc"));
 				if (localStorage.getItem("curCreateType") === "import") {
 					// 导题编辑过需要把blob置空 防止复制试题过来造成数据复原

+ 210 - 12
TEAMModelOS/ClientApp/src/view/evaluation/index/TestPaper.vue

@@ -33,13 +33,16 @@
               <Button class="base-info-btn" type="info" @click="goAnswerSheet" v-show="paperInfo.item.length && paperInfo.id">{{ paper.sheetNo ?  $t('evaluation.paperList.reCreateSheet') : $t('evaluation.paperList.createSheet') }}</Button>
             </div>
             <div v-if="isExamPaper && !isPreviewItems && paperInfo.item.length">
-               <Button class="base-info-btn" type="info" @click="showPaperAttachments" v-if="isHiteachPaper">{{ $t('evaluation.quickPaper.attachments') }}</Button>
-              <Button class="base-info-btn" type="info" @click="onHandleToggle" v-show="!isShowAnalysis">{{ isAllOpen ? $t('evaluation.index.collapseAll') : $t('evaluation.index.openAll')}}</Button>
-              <Button class="base-info-btn" type="info" @click="onViewModelChange" v-show="!isShowAnalysis">{{ `${ viewModel === 'type' ? this.$t('evaluation.paperList.sortByOrder') : this.$t('evaluation.paperList.sortByType') }` }}</Button>
-              <Button class="base-info-btn" type="info" @click="isShowAnalysis = !isShowAnalysis" v-show="!isHideAnalysis">{{ isShowAnalysis ? this.$t('evaluation.paperList.paperDetails') : this.$t('evaluation.paperList.paperAnalysis')}}</Button>
-              <Button class="base-info-btn" type="info" @click="downloadSheet" :loading="downLoading" v-show="paperInfo.id && paper.sheetNo && !hideSheet && !isSharePreview">{{ $t('evaluation.paperList.goAnswerSheet') }}<span v-if="paperInfo.mode">-{{ paperInfo.mode }}</span></Button>
-              <Button class="base-info-btn" type="info" @click="goAnswerSheet" v-show="paperInfo.id && !hideSheet && !isSharePreview">{{ paper.sheetNo ?  $t('evaluation.paperList.reCreateSheet') : $t('evaluation.paperList.createSheet') }}</Button>
-              <Button class="base-info-btn" type="info" @click="exitPreview" v-show="paperInfo.id && isSharePreview">{{ $t('evaluation.index.backList') }}</Button>
+              <Button class="base-info-btn" type="info" @click="showPaperAttachments" v-show="!isChangePaper" v-if="isHiteachPaper">{{ $t('evaluation.quickPaper.attachments') }}</Button>
+              <Button class="base-info-btn" type="info" @click="showChangePaper" v-show="isExamInfoPaper && !isChangePaper">{{ '修改试卷' }}</Button>
+              <Button class="base-info-btn" type="info" @click="onHandleToggle" v-show="!isShowAnalysis && !isChangePaper">{{ isAllOpen ? $t('evaluation.index.collapseAll') : $t('evaluation.index.openAll')}}</Button>
+              <Button class="base-info-btn" type="info" @click="onViewModelChange" v-show="!isShowAnalysis && !isChangePaper">{{ `${ viewModel === 'type' ? this.$t('evaluation.paperList.sortByOrder') : this.$t('evaluation.paperList.sortByType') }` }}</Button>
+              <Button class="base-info-btn" type="info" @click="isShowAnalysis = !isShowAnalysis" v-show="!isHideAnalysis && !isChangePaper">{{ isShowAnalysis ? this.$t('evaluation.paperList.paperDetails') : this.$t('evaluation.paperList.paperAnalysis')}}</Button>
+              <Button class="base-info-btn" type="info" @click="downloadSheet" :loading="downLoading" v-show="paperInfo.id && paper.sheetNo && !hideSheet && !isSharePreview && !isChangePaper">{{ $t('evaluation.paperList.goAnswerSheet') }}<span v-if="paperInfo.mode">-{{ paperInfo.mode }}</span></Button>
+              <Button class="base-info-btn" type="info" @click="goAnswerSheet" v-show="paperInfo.id && !hideSheet && !isSharePreview && !isChangePaper">{{ paper.sheetNo ?  $t('evaluation.paperList.reCreateSheet') : $t('evaluation.paperList.createSheet') }}</Button>
+              <Button class="base-info-btn" type="info" @click="exitPreview" v-show="paperInfo.id && isSharePreview && !isChangePaper">{{ $t('evaluation.index.backList') }}</Button>
+              <Button class="base-info-btn" type="success" @click="showChangePaper(1)" v-show="isChangePaper">{{ '保存' }}</Button>
+              <Button class="base-info-btn" @click="showChangePaper" v-show="isChangePaper">{{ '取消' }}</Button>
             </div>
           </div>
           <!-- 试卷头部信息 -->
@@ -50,7 +53,7 @@
           <ExamPaperAnalysis :testPaper="paperInfo" v-if="isShowAnalysis" :hidePie="hidePie">
           </ExamPaperAnalysis>
           <!-- 题目类型及列表 -->
-          <BaseExerciseList :paper="paperInfo" @dataUpdate="onListUpdate" v-show="!isShowAnalysis" ref="exList" :isShowTools="!isPreview" :canFix="canFix" :isExamPaper="isExamPaper || isPreviewItems" @toggleChange="onToggleChange" @scoreUpdate="scoreUpdate"></BaseExerciseList>
+          <BaseExerciseList :paper="paperInfo" @dataUpdate="onListUpdate" v-show="!isShowAnalysis" ref="exList" :isChangePaper="isChangePaper" :isShowTools="!isPreview" :canFix="canFix" :isExamPaper="isExamPaper || isPreviewItems" @toggleChange="onToggleChange" @scoreUpdate="scoreUpdate"></BaseExerciseList>
         </div>
         <!-- <BaseHiteachPaper v-if="isHiteachPaper" :paper="paperInfo"></BaseHiteachPaper> -->
       </div>
@@ -98,6 +101,7 @@
   </div>
 </template>
 <script>
+import blobTool from '@/utils/blobTool.js'
 import ExamPaperAnalysis from '@/view/learnactivity/ExamPaperAnalysis.vue'
 import ManualCreate from '@/view/learnactivity/ManualCreate.vue'
 
@@ -127,6 +131,10 @@ export default {
       type: Boolean,
       default: false
     },
+    isExamInfoPaper: { //评测页面下的试卷,需调整答案、配分等
+      type: Boolean,
+      default: false
+    },
     hidePie: {
       type: Boolean,
       default: false
@@ -162,7 +170,15 @@ export default {
     periodCode: {
       type: String,
       default: ''
-    }
+    },
+    activityIndex: {
+        type: Number,
+        default: 0
+    },
+    subjectIndex: {
+        type: Number,
+        default: 0
+    },
   },
   data() {
     return {
@@ -195,6 +211,7 @@ export default {
         paperSubject: 0,
         paperPeriod: 0
       },
+      paperInfoOld: {},
       exersicesType: this.$GLOBAL.EXERCISE_TYPES(),
       exersicesDiff: this.$GLOBAL.EXERCISE_DIFFS(),
       exersicesField: this.$GLOBAL.EXERCISE_LEVELS(),
@@ -215,8 +232,8 @@ export default {
       analysisTableData: [],
       viewModel: 'type',
       paperDiff: 0,
-      curModalTab: ''
-
+      curModalTab: '',
+      isChangePaper: false,
     }
   },
   methods: {
@@ -453,8 +470,176 @@ export default {
 
     scoreUpdate(score) {
       this.allocatedScore = this.paperInfo.score - score
-    }
+    },
+    async showChangePaper(type) {
+        if(type === 1) {
+            if(this.allocatedScore != this.paperInfo.score) {
+                this.$Message.warning(this.$t('evaluation.paperList.noCompleteScoreTip'))
+                return
+            }
+            // 重新保存试卷 && 调接口保存答案、配分
+            let params = {
+                id: this.paperInfo.examId, //活动ID
+                code: this.paperInfo.examScope === 'school' ? this.paperInfo.examSchool : this.paperInfo.creatorId, //个人ID或者学校编码
+                scode: this.paperInfo.examCode, //原本评测活动的完整code:'Exam-hbcn'
+                paperId: this.paperInfo.id, //试卷ID
+                subjectId: this.paperInfo.subjectId, //科目ID
+                paperAns: [], //作答记录的完整数组
+                point: [], //完整配分的数组
+                kno: [], //知识点
+                multipleRule: this.paperInfo.multipleRule, //评分规则
+            }
+            this.paperInfo.item.forEach(item => {
+              if(item.type === 'compose') {
+                item.children.forEach(child => {
+                  if(child.type === 'single' || child.type === 'multiple' || child.type === 'judge') {
+                    params.paperAns.push(child.answer)
+                  } else {
+                    params.paperAns.push([])
+                  }
+                  params.point.push(child.score)
+                  params.kno.push(child.knowledge)
+                })
+              } else {
+                if(item.type === 'single' || item.type === 'multiple' || item.type === 'judge') {
+                  params.paperAns.push(item.answer)
+                } else {
+                  params.paperAns.push([])
+                }
+                params.point.push(item.score)
+                params.kno.push(item.knowledge)
+              }
+            })
+            this.$api.learnActivity.updateAns(params).then(async res => {
+              if(res.code === 200) {
+                const itemJsonFile = await this.$evTools.createBlobPaper(this.paperInfo, this.paperInfo.slides);
+                // let blobPaper = await this.$evTools.createBlobPaper(paperItem, res.slides)
+                // 首先保存新题目的JSON文件到Blob 然后返回URL链接
+                let paperFile = new File([JSON.stringify(itemJsonFile)], "index.json");
+                // 获取初始化Blob需要的数据
+                let sasData = this.paperInfo.scope === 'school' ? await this.$tools.getSchoolSas() : await this.$tools.getPrivateSas()
+                //初始化Blob
+                let containerClient = new blobTool(sasData.url, sasData.name, sasData.sas, this.paperInfo.scope)
+                try {
+                    let promiseArr = []
+                    let blobFile = null
+                    let blobUrl = this.paperInfo.blob.slice(1)
+                    // 放入试题json文件
+                    for (let i = 0; i < this.paperInfo.item.length; i++) {
+                        promiseArr.push(new Promise(async (r, j) => {
+                            try {
+                                let item = this.paperInfo.item[i]
+                                const itemJsonFile = await this.$evTools.createBlobItem(item)
+                                let file = new File([JSON.stringify(itemJsonFile)], item.id + ".json");
+                                containerClient.upload(file, {
+                                    path: blobUrl,
+                                    checkSize: false
+                                }).then(res => {
+                                    r(200)
+                                })
+                            } catch (e) {
+                                console.log(e)
+                            }
+                        }))
+                        if(this.paperInfo.item[i].type === 'compose') {
+                          this.paperInfo.item[i].children.forEach(child => {
+                            promiseArr.push(new Promise(async (r, j) => {
+                              try {
+                                  let item = child
+                                  const itemJsonFile = await this.$evTools.createBlobItem(item)
+                                  let file = new File([JSON.stringify(itemJsonFile)], item.id + ".json");
+                                  containerClient.upload(file, {
+                                      path: blobUrl,
+                                      checkSize: false
+                                  }).then(res => {
+                                      r(200)
+                                  })
+                              } catch (e) {
+                                  console.log(e)
+                              }
+                          }))
+                          })
+                        }
+                    }
+                    // 放入index.json文件
+                    promiseArr.push(new Promise(async (r, j) => {
+                        try {
+                            blobFile = await containerClient.upload(paperFile, {
+                                path: blobUrl,
+                                checkSize: false
+                            })
+                            console.log('上传到试卷目录下', blobFile)
+                            r(blobFile)
+                        } catch (e) {
+                            j(e)
+                            this.$Message.error(e.spaceError)
+                            this.isLoading = false
+                        }
+                    }))
+                    // 不存在多媒体
+
+                    // 进行试卷文件上传Blob 先上传所有题目 再上传index.json文件
+                    Promise.all(promiseArr).then(async result => {
+                        try {
+                            if (blobFile.blob) {
+                                // 试卷保存更新后需要重新生成答题卡
+                                /* paperItem.blob = blobFile.blob.split('/index.json')[0]
 
+                                let params = {
+                                    paper: await this.$evTools.createCosmosPaper(paperItem),
+                                    option: this.isEditPaper ? 'update' : 'insert'
+                                }
+                                //  保存试卷到cosmos
+                                this.$api.learnActivity.SaveExamPaper(params).then(res => {
+                                    if (res.error == null) {
+                                        this.$Message.success(this.$t('evaluation.paperList.saveSuc'))
+                                        this.isLoading = false
+                                        this.$Spin.hide()
+                                        // this.savePeriodInfos()
+                                        // 清空已选试题
+                                        this.showQues = false
+                                        this.selectedArr = []
+                                        this.groupList = []
+                                        this.orderList = []
+                                        this.selShowList = []
+                                    } else {
+                                        this.$Message.error(this.$t('evaluation.paperList.saveFail'))
+                                        this.$Spin.hide()
+                                        this.isLoading = false
+                                    }
+                                },err => {
+                                    this.$Message.error(this.$t('evaluation.paperList.saveFail'))
+                                    this.isLoading = false
+                                    this.$Spin.hide()
+                                }) */
+                            } else {
+                                console.error(blobFile)
+                            }
+                        } catch (e) {
+                            console.log(e)
+                        }
+                        this.$Message.success(this.$t("evaluation.editSuc"))
+                        this.isChangePaper = !this.isChangePaper
+                    })
+                } catch (e) {
+                    console.log(e)
+                    this.$Message.error(this.$t('evaluation.paperList.saveItemsFailTip'))
+                    this.isLoading = false
+                    this.isChangePaper = !this.isChangePaper
+                }
+              } else {
+                this.$t('learnActivity.mgtScEv.updErr')
+              }
+            })
+        } else {
+            this.isChangePaper = !this.isChangePaper
+            if(!this.isChangePaper) {
+              this.paperInfo = JSON.parse(JSON.stringify(this.paperInfoOld))
+              this.paper.item = this.paperInfo.item
+              this.$forceUpdate()
+            }
+        }
+    },
 
 
   },
@@ -463,6 +648,7 @@ export default {
     this.$Spin.hide()
     let paper = this.paper || this.$route.params.paper || JSON.parse(localStorage.getItem('c_edit_paper'))
     if (!paper || !paper.item) return
+    this.paperInfoOld = JSON.parse(JSON.stringify(paper))
     console.log('xxxx', paper)
     this.$EventBus.$emit('getNewPaper', paper)
     // localStorage.setItem('_paperInfo', JSON.stringify(paper))
@@ -510,6 +696,18 @@ export default {
       },
       immediate: true,
       deep: true
+    },
+    activityIndex: {
+      handler(n, o) {
+        if(this.isExamInfoPaper) this.isChangePaper = false
+        this.paperInfoOld = JSON.parse(JSON.stringify(this.paper))
+      }
+    },
+    subjectIndex: {
+      handler(n, o) {
+        if(this.isExamInfoPaper) this.isChangePaper = false
+        this.paperInfoOld = JSON.parse(JSON.stringify(this.paper))
+      }
     }
   }
 }

+ 2 - 2
TEAMModelOS/ClientApp/src/view/iot/areaiot.vue

@@ -672,7 +672,7 @@ export default {
       let totalClassRoom = []
       areaIotDatas.forEach((item) => {
         let years = item.year; let months = item.month;
-        if (item.toolType === 'HiTeach') {
+        if (item.toolType === 'HiTeach'|| item.toolType === 'HiTeachCC') {
           let result = monthAreaData.find(items => items.monthNum == months && items.year == years)
           if (result !== undefined) {
             // result.schoolName = item.school.name
@@ -749,7 +749,7 @@ export default {
 
       areaIotDatas.forEach((item) => {
         let years = item.year; let months = item.month; let schoolCodes = item.schoolId
-        if (item.toolType === 'HiTeach') {
+        if (item.toolType === 'HiTeach' || item.toolType === 'HiTeachCC') {
           let result = monthSchoolData.find(items => items.month == months && items.year == years)
           if (result !== undefined) {
             let resultSchool = result.data.find(itemc => itemc.schoolCode === schoolCodes)

+ 1 - 1
TEAMModelOS/ClientApp/src/view/iot/schooliot.vue

@@ -456,7 +456,7 @@ export default {
       initData.forEach((item) => {
         let years = item.year; let months = item.month; let days = item.day
         let isScope = this.isDateInRange(years, months, days, n)
-        if (isScope && item.toolType === 'HiTeach') {
+        if (isScope && item.toolType === 'HiTeach' || item.toolType === 'HiTeachCC') {
           let result = monthData.find(items => items.monthNum == months && items.year == years)
           if (result !== undefined) {
             result.schoolName = item.school.name

+ 5 - 4
TEAMModelOS/ClientApp/src/view/learnactivity/ExamMgt.vue

@@ -141,7 +141,7 @@
 				<!-- 作答详情 -->
 				<AnswerTable v-else-if="curBarIndex == 3" :examInfo="examDetaiInfo" :correctData="correctData" class="evaluation-base-info"></AnswerTable>
 				<!-- 评测试卷 -->
-				<ExamPaper v-else-if="curBarIndex == 1" :examInfo="examDetaiInfo" class="evaluation-base-info"></ExamPaper>
+				<ExamPaper v-else-if="curBarIndex == 1" :examInfo="examDetaiInfo" :activityIndex="curEvaIndex" class="evaluation-base-info"></ExamPaper>
 				<!-- 学情分析 -->
 				<CloudDAS v-else-if="curBarIndex == 4" :evInfo="examDetaiInfo"></CloudDAS>
 				<!-- 阅卷任务 -->
@@ -617,7 +617,7 @@
 				sessionStorage.setItem("examScope", this.evaListShow[index].scope);
 				//跨校个人评测
 				if (!this.evaListShow[this.curEvaIndex].curSchool) {
-					this.examDetaiInfo = this.evaListShow[this.curEvaIndex];
+					this.examDetaiInfo = JSON.parse(JSON.stringify(this.evaListShow[this.curEvaIndex]));
 					this.isLoading = false;
 					return;
 				}
@@ -627,7 +627,7 @@
 				if (this.evaListShow[this.curEvaIndex] && this.evaListShow[this.curEvaIndex].papers.length == 0) {
 					this.findExamInfo();
 				} else {
-					this.examDetaiInfo = this.evaListShow[this.curEvaIndex];
+					this.examDetaiInfo = JSON.parse(JSON.stringify(this.evaListShow[this.curEvaIndex]));
 					if (this.examDetaiInfo.progress === "finish") {
 						this.findSimpleAna();
 					}
@@ -675,6 +675,7 @@
 									resData.papers[index].examScope = resData.scope;
 									resData.papers[index].examCode = resData.code;
 									resData.papers[index].examId = resData.id;
+									resData.papers[index].examSchool = resData.school;
 									resData.papers[index].owner = resData.owner;
 									resData.papers[index].sheetNo = sheetNo;
 									resData.papers[index].totlaSocre = totlaSocre;
@@ -696,7 +697,7 @@
 									this.setPaperQuInfo(resData.papers);
 								}
 								this.evaListShow.splice(this.curEvaIndex, 1, resData);
-								this.examDetaiInfo = resData;
+								this.examDetaiInfo = JSON.parse(JSON.stringify(resData));
 								// if (this.examDetaiInfo.progress === 'finish' && !this.dataErr) {
 								if (this.examDetaiInfo.progress === "finish") {
 									this.findSimpleAna();

+ 6 - 2
TEAMModelOS/ClientApp/src/view/learnactivity/tabs/ExamPaper.vue

@@ -10,7 +10,7 @@
                 </RadioGroup>
             </div>
             <div class="paper-wrap" v-if="!examInfo.examPaperErr">
-                <TestPaper v-if="examInfo && examInfo.papers && examInfo.papers[curSubIndex] && examInfo.papers[curSubIndex].item" :paper="examInfo.papers[curSubIndex]" style="color:#515a6e;" :isShowTools="false" isExamPaper :examId="examInfo.id" canFix></TestPaper>
+                <TestPaper v-if="examInfo && examInfo.papers && examInfo.papers[curSubIndex] && examInfo.papers[curSubIndex].item" :paper="examInfo.papers[curSubIndex]" style="color:#515a6e;" :isShowTools="false" isExamPaper isExamInfoPaper :examId="examInfo.id" :activityIndex="activityIndex" :subjectIndex="curSubIndex" canFix></TestPaper>
                 <EmptyData v-else style="padding-top:60px;" :textContent="$t('learnActivity.simple.paperErr')"></EmptyData>
             </div>
             <div v-else class="paper-err-wrap">
@@ -32,7 +32,11 @@ export default {
             default: () => {
                 return {}
             }
-        }
+        },
+        activityIndex: {
+            type: Number,
+            default: 0
+        },
     },
     data() {
         return {

+ 2 - 1
TEAMModelOS/ClientApp/src/view/mycourse/score/DialogBoxAddTable.vue

@@ -83,7 +83,8 @@ export default {
         "copyid": chooseID
       };
       //console.log("dataInfo=" + JSON.stringify(dataInfo));
-      this.$api.learnActivity.addScorecalc(dataInfo).then(
+      this.$emit('loadingStart');
+      this.$api.learnActivity.addScorecalc(dataInfo, 180000).then(
         res => {  
           this.$emit('closeModal', { value1: false, value2: res.id });    
         },

+ 5 - 1
TEAMModelOS/ClientApp/src/view/mycourse/score/ScoreBody.vue

@@ -646,7 +646,7 @@
       :classInfo="classInfo" :listType="listType">
     </DialogBoxScoreCont>
     <DialogBoxAddTable class="scoreDialogBox" :modalVisible="modalVisibleAddTable"
-      @closeModal="modalVisibleAddTableFun" :class_name="modalVisibleClassName" :Count_attend="Count_attend"
+    @loadingStart="loadingStart"  @closeModal="modalVisibleAddTableFun" :class_name="modalVisibleClassName" :Count_attend="Count_attend"
       :classInfo="classInfo" :listType="listType" :paramsInfo="paramsInfo" :lists="lists">
     </DialogBoxAddTable>
     <!-- 刪除視窗 -->
@@ -2211,7 +2211,11 @@ export default {
         this.Count_interact = data.value3;
       }
     },
+    loadingStart(){
+      this.isLoading = true;
+    },
     modalVisibleAddTableFun(data) {
+      this.isLoading = false;
       this.modalVisibleAddTable = data.value1;
       if (data.value2 !== null) {
         //this.Count_attend = data.value2;

+ 73 - 65
TEAMModelOS/Controllers/Both/ScoreCalcController.cs

@@ -2028,8 +2028,8 @@ namespace TEAMModelOS.Controllers
             string tbname = "";
             string code = "";
             string school = null;
-            string sqlPrivate = "";
-            List<string> autoTch = new List<string>();
+            //string sqlPrivate = "";
+            //List<string> autoTch = new List<string>();
 
             // 如果是學校課程
             if (scope.GetString().Equals("school"))
@@ -2038,32 +2038,12 @@ namespace TEAMModelOS.Controllers
                 {
                     code = $"LessonRecord-{schoolId}";// 組合區域碼
                     tbname = "School";
-                    school = $"{schoolId}";
-                    List<string> ids = new List<string>();
+                    school = $"{schoolId}";                    
                     //只查询某个老师的课例
-                    if (!string.IsNullOrWhiteSpace($"{teammodelId}"))
+                    if (string.IsNullOrWhiteSpace($"{teammodelId}"))                                                            
                     {
-                        ids.Add($"{teammodelId}");// 組合老師id
-                    }
-                    else
-                    {
-                        return false;
-                        //string sqltch = "select distinct value(c.id) from c ";
-                        //await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
-                        //    .GetItemQueryIterator<string>(queryText: sqltch, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Teacher-{schoolId}") }))
-                        //{
-                        //    ids.Add(item);// 如果沒給老師id  撈出全部這間學校的老師ID
-                        //}
-                    }
-                    if (ids.Any())
-                    {
-                        string sqlTechbase = $"select distinct value(c.id) from c  where c.id in ({string.Join(",", ids.Select(x => $"'{x}'"))})  and (array_contains(c.lessonShow,'student') or array_contains(c.lessonShow,'all')) ";
-                        await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
-                           .GetItemQueryIterator<string>(queryText: sqlTechbase, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Base") }))
-                        {
-                            autoTch.Add(item);
-                        }
-                    }
+                        return false;                        
+                    }                   
                 }
                 else
                 {
@@ -2074,22 +2054,7 @@ namespace TEAMModelOS.Controllers
             {
                 code = $"LessonRecord";
                 tbname = "Teacher";
-                if (!string.IsNullOrEmpty($"{teammodelId}"))
-                {
-                    sqlPrivate = $" and c.tmdid='{teammodelId}'";
-                    List<string> ids = new List<string>();
-                    ids.Add($"{teammodelId}");
-                    if (ids.Any())
-                    {
-                        string sqlTechbase = $"select distinct value(c.id) from c  where c.id in ({string.Join(",", ids.Select(x => $"'{x}'"))})  and (array_contains(c.lessonShow,'student') or array_contains(c.lessonShow,'all')) ";
-                        await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
-                           .GetItemQueryIterator<string>(queryText: sqlTechbase, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Base") }))
-                        {
-                            autoTch.Add(item);
-                        }
-                    }
-                }
-                else
+                if (string.IsNullOrEmpty($"{teammodelId}"))                
                 {
                     //如果不传tmdid, 则必须传递,课程id或者名单列表
                     // 如果不传递tmdid
@@ -2109,7 +2074,7 @@ namespace TEAMModelOS.Controllers
             {
                 string sql_status_managePage = "(c.status<>404 or IS_DEFINED(c.status) = false ) and  ";
 
-                cosmosDbQuery.QueryText = cosmosDbQuery.QueryText.Replace("where", $" where  {sql_status_managePage}  array_length(c.groupIds)>0 {sqlPrivate}  and  ");
+                cosmosDbQuery.QueryText = cosmosDbQuery.QueryText.Replace("where", $" where  {sql_status_managePage}  array_length(c.groupIds)>0  and  ");
 
                 await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname)
                    .GetItemQueryStreamIterator(queryDefinition: cosmosDbQuery.CosmosQueryDefinition, continuationToken: continuationToken,
@@ -2206,34 +2171,64 @@ namespace TEAMModelOS.Controllers
             #endregion
 
             List<ScoreLessonBase> lessonBases = new List<ScoreLessonBase>();
-            string blobname = "";
-            if (ishaveClassId)
-            {// 如果有ClassId 要用schoolId去取JSON
-                blobname = $"{schoolId}";
-            }
-            else if (ishaveGrouplistId)
-            {// 如果沒有ClassId 要用teammodelId去取JSON
-                blobname = $"{teammodelId}";
-            }
+            string blobname = "";         
 
             foreach (var item in lessonRecords)
             {// 先檢查課堂紀錄是否存在再取資料
-                blobname = (item.scope.Equals("school")) ? $"{schoolId}" : $"{teammodelId}"; //[Jeff] 修正blobname:改用課堂紀錄的scope欄位判斷
-                if (_azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{item.id}/IES/base.json").Exists())
-                {
-                    ScoreCalcActivityItems scoreCalcActivityItems = new ScoreCalcActivityItems();
-                    scoreCalcActivityItems.id = item.id;
-                    scoreCalcActivityItems.use = true;
+                if (item.scope.Equals("school"))
+                {// 學校課程 用學校id取blob
+                    blobname = schoolId.GetString();
+                    if (_azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{item.id}/IES/base.json").Exists())
+                    {
+                        ScoreCalcActivityItems scoreCalcActivityItems = new ScoreCalcActivityItems();
+                        scoreCalcActivityItems.id = item.id;
+                        scoreCalcActivityItems.use = true;
 
-                    scoreCalcLsRecord.items.Add(scoreCalcActivityItems);
+                        scoreCalcLsRecord.items.Add(scoreCalcActivityItems);
 
-                    BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{item.id}/IES/base.json").DownloadContentAsync();
-                    ScoreLessonBase lessonBase = baseblobDownload.Content.ToObjectFromJson<ScoreLessonBase>();
-                    if (lessonBase != null && lessonBase.summary != null)
-                    {
-                        lessonBases.Add(lessonBase);
+                        BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{item.id}/IES/base.json").DownloadContentAsync();
+                        ScoreLessonBase lessonBase = baseblobDownload.Content.ToObjectFromJson<ScoreLessonBase>();
+                        if (lessonBase != null && lessonBase.summary != null)
+                        {
+                            lessonBases.Add(lessonBase);
+                        }
                     }
                 }
+                else 
+                { // 個人課程
+                    List<CourseTask_ta> ctList = new();
+                    // 檢查這個課程的助教跟教授裡面有沒有包含傳進來的teammodelId   有的話用教授取blob的資料
+                    string sqlCourseTask = $"SELECT distinct b.teacherId, b.assistants FROM c join b in c.schedules where c.pk = 'CourseTask' and (ARRAY_CONTAINS(b.assistants, '{teammodelId}') or  b.teacherId = '{teammodelId}') and b.groupId = '{grouplistId}' and c.code = 'CourseTask' and c.courseId = '{courseId}' AND ARRAY_LENGTH(b.assistants) > 0";
+
+                    //string sqlCourseTask = $"SELECT s.groupId, s.assistants FROM c JOIN s IN c.schedules WHERE c.pk='CourseTask'AND c.courseId = '{courseId}' AND s.groupId = '{grouplistId}' AND ARRAY_LENGTH(s.assistants) > 0";
+                    await foreach (var ctitem in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<CourseTask_ta>(queryText: sqlCourseTask))
+                    {
+                        ctList.Add(ctitem);
+                    }
+                    if (ctList.Count > 0)
+                    {
+                        blobname = ctList[0].teacherId;
+                        if (_azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{item.id}/IES/base.json").Exists())
+                        {
+                            ScoreCalcActivityItems scoreCalcActivityItems = new ScoreCalcActivityItems();
+                            scoreCalcActivityItems.id = item.id;
+                            scoreCalcActivityItems.use = true;
+
+                            scoreCalcLsRecord.items.Add(scoreCalcActivityItems);
+
+                            BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/records/{item.id}/IES/base.json").DownloadContentAsync();
+                            ScoreLessonBase lessonBase = baseblobDownload.Content.ToObjectFromJson<ScoreLessonBase>();
+                            if (lessonBase != null && lessonBase.summary != null)
+                            {
+                                lessonBases.Add(lessonBase);
+                            }
+                        }
+                    }
+                    else { return false; }
+
+                    
+                }                
+                
             }
             List<ScoreLessonBase> lessonBasesCalcList = new List<ScoreLessonBase>();
             // 重新比對資料以防  班級人數跟分數的數量對不上             
@@ -2782,8 +2777,21 @@ namespace TEAMModelOS.Controllers
             }
         }
 
+        /// <summary>
+        /// 查詢CourseTask用類別
+        /// </summary>
+        private class CourseTask_ta
+        {
+            /// <summary>
+            /// teacherId
+            /// </summary>
+            public string teacherId { get; set; }
+            /// <summary>
+            /// assistants
+            /// </summary>            
+            public List<string> assistants { get; set; } = new List<string>();
 
-
+        }
 
     }
 }

+ 5 - 5
TEAMModelOS/Controllers/Client/HiScanController.cs

@@ -122,11 +122,11 @@ namespace TEAMModelOS.Controllers.Core
                 }
 
                 //用户在线记录
-                try
-                {
-                    _ = _httpTrigger.RequestHttpTrigger(new { school = response.defaultSchool, scope = Constant.ScopeTeacher, id = $"{id}", ip = ip, expire = 1 }, _option.Location, "online-record");
-                }
-                catch { }
+                //try
+                //{
+                //    _ = _httpTrigger.RequestHttpTrigger(new { school = response.defaultSchool, scope = Constant.ScopeTeacher, id = $"{id}", ip = ip, expire = 1 }, _option.Location, "online-record");
+                //}
+                //catch { }
 
                 var (tblob_uri, tblob_sas) = _azureStorage.GetBlobContainerSAS($"{id}", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);
                 return Ok(new { schools, teacher = new { name, picture, id, bloburl = tblob_uri, blobsas = tblob_sas } });

+ 5 - 5
TEAMModelOS/Controllers/Client/HiTAControlller.cs

@@ -630,11 +630,11 @@ namespace TEAMModelOS.Controllers.Client
                     //}
 
                     //用户在线记录
-                    try
-                    {
-                        _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
-                    }
-                    catch { }
+                    //try
+                    //{
+                    //    _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
+                    //}
+                   // catch { }
                     await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new SDK.Models.Dtos.Accumulate { client="hita", count=1, id="ies", key="tmd_login", name="醍摩豆账号登录", scope="ies", target="ies" });
                     return Ok(new { schools, defaultschool, courses, size, resCount, itemCount, paperCount, activityCount });
                 }

+ 10 - 10
TEAMModelOS/Controllers/Client/HiTeachController.cs

@@ -2394,11 +2394,11 @@ namespace TEAMModelOS.Controllers.Client
                     }
                 }
                 //用户在线记录
-                try
-                {
-                    _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
-                }
-                catch { }
+                //try
+                //{
+                //    _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
+                //}
+                //catch { }
 
                 //取得Teacher Blob 容器位置及SAS 
                 var container = _azureStorage.GetBlobContainerClient(id);
@@ -2969,11 +2969,11 @@ namespace TEAMModelOS.Controllers.Client
                 }
 
                 //用户在线记录
-                try
-                {
-                    _ = _httpTrigger.RequestHttpTrigger(new { school = school_code.GetString(), scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
-                }
-                catch { }
+                //try
+                //{
+                //    _ = _httpTrigger.RequestHttpTrigger(new { school = school_code.GetString(), scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
+                //}
+                //catch { }
 
                 //取得School Blob 容器位置及SAS
                 string school_code_blob = school_code.GetString().ToLower();

+ 220 - 4
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -189,12 +189,13 @@ namespace TEAMModelOS.Controllers
                     }
                     stuCount += ids.Count;
                 }*/
-                /*var (grade, per) = await ThirdService.GetGradeAsync(client, request);
-                var data = new
+                //var (grade, per) = await ThirdService.GetGradeAsync(client, request);
+                /*var data = new
                 {
                     examName = request.name,
                     examCategory = 1,
-                    grade = int.Parse(grade),
+                    //grade = int.Parse(grade),
+                    grade = 7,
                     term = 2,
                     examType = "单元测试",
                     examDate = request.startTime,
@@ -234,7 +235,8 @@ namespace TEAMModelOS.Controllers
                     }
                    
 
-                    //string moofenCode = await ThirdService.CreateMoofenExam(_httpClient, data.ToJsonString().ToObject<JsonElement>());
+                    //string moofenCode = await ThirdService.CreateMoofenExam(_httpClient, data.ToJsonString().ToObject<JsonElement>(),_dingDing);
+                    //request.moofenCode = moofenCode;
                     exam = await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(request, new PartitionKey($"{request.code}"));
                     
                     await BIStats.SetTypeAddStats(client, _dingDing, exam.school, "Exam", 1);//BI统计增/减量
@@ -1308,6 +1310,210 @@ namespace TEAMModelOS.Controllers
                 return BadRequest();
             }
         }
+
+
+
+        [ProducesDefaultResponseType]
+        [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "student,teacher")]
+        [HttpPost("update-ans")]
+        public async Task<IActionResult> updateAns(JsonElement request)
+        {
+
+            if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
+            if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+            if (!request.TryGetProperty("paperId", out JsonElement paperId)) return BadRequest();
+            if (!request.TryGetProperty("subjectId", out JsonElement subjectId)) return BadRequest();
+            if (!request.TryGetProperty("paperAns", out JsonElement paperAns)) return BadRequest();
+            if (!request.TryGetProperty("point", out JsonElement point)) return BadRequest();
+            if (!request.TryGetProperty("multipleRule", out JsonElement multipleRule)) return BadRequest();
+            //根据不同评测的类型返回对应的编码
+            if (!request.TryGetProperty("scode", out JsonElement scode)) return BadRequest();
+            //var (userId, name, picture, school) = HttpContext.GetAuthTokenInfo();
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                ExamInfo info = new();
+                var response = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemStreamAsync(id.ToString(), new PartitionKey($"{scode}"));
+                if (response.Status == 200)
+                {
+                    using var cJson = await JsonDocument.ParseAsync(response.ContentStream);
+                    info = cJson.ToObject<ExamInfo>();
+                }
+                else
+                {
+                    return Ok(new { code = 404, msg = "该活动未被找到" });
+                }
+                
+                //if (string.IsNullOrEmpty(userId)) return Ok(new { code = 404, msg = "当前用户信息未找到" });
+                
+                List<ExamClassResult> examClassResults = new List<ExamClassResult>();
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(
+                    queryText: $"select value(c) from c where c.examId = '{id}' and c.subjectId = '{subjectId}'",
+                    requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{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())
+                        {
+                            examClassResults.Add(obj.ToObject<ExamClassResult>());
+                        }
+                    }
+                }
+                //examClassResults = examClassResults.Where(c => c.studentIds.Contains(userId)).ToList(); wo
+                ExamClassResult classResult = new ExamClassResult();                
+                List<List<string>> standard = paperAns.ToObject<List<List<string>>>();
+                int rule = int.Parse(multipleRule.ToString());
+                List<double> points = point.ToObject<List<double>>();
+                List<Task<string>> tasks = new List<Task<string>>();
+                info.papers.ForEach(c => {
+                    if (c.id.Equals(paperId.GetString())) {
+                        c.answers = standard;
+                    }
+                });
+                foreach (ExamClassResult result in examClassResults)
+                {
+                    int index = 0;
+                    foreach (var ans in result.ans) {
+                        if (ans.Count == 0) continue;
+                        for (int i = 0; i < ans.Count; i++)
+                        {
+                            var sc = standard[i].Count;
+                            var ac =ans[i].Where(a => a.Trim().Length > 0).ToList().Count;
+                            //算分处理
+                            if (sc > 0)
+                            {
+                                if (ac == sc && sc == 1)
+                                {
+                                    foreach (string right in ans[i])
+                                    {
+                                        if (standard[i].Contains(right.Trim()))
+                                        {
+                                            result.studentScores[index][i] = points[i];
+                                        }
+                                        else
+                                        {
+                                            result.studentScores[index][i] = 0;
+                                        }
+                                    }
+
+                                }
+                                else
+                                {
+                                    if (rule > 0)
+                                    {
+                                        int falseCount = 0;
+                                        if (ac > 0)
+                                        {
+                                            foreach (string obj in ans[i])
+                                            {
+                                                if (!standard[i].Contains(obj))
+                                                {
+                                                    falseCount++;
+                                                }
+                                            }
+                                            switch (rule)
+                                            {
+                                                case 1:
+                                                    if (ac == sc)
+                                                    {
+                                                        if (falseCount == 0)
+                                                        {
+                                                            result.studentScores[index][i] = points[i];
+                                                        }
+                                                        else
+                                                        {
+                                                            result.studentScores[index][i] = 0;
+                                                        }
+                                                    }
+                                                    else
+                                                    {
+                                                        result.studentScores[index][i] = 0;
+                                                    }
+                                                    break;
+                                                case 2:
+                                                    if (falseCount > 0)
+                                                    {
+                                                        result.studentScores[index][i] = 0;
+                                                    }
+                                                    else
+                                                    {
+                                                        if (ac == sc)
+                                                        {
+                                                            result.studentScores[index][i] = points[i];
+                                                        }
+                                                        else
+                                                        {
+                                                            result.studentScores[index][i] = points[i] / 2;
+                                                        }
+
+                                                    }
+                                                    break;
+                                                case 3:
+                                                    if (falseCount > 0)
+                                                    {
+                                                        result.studentScores[index][i] = 0;
+                                                    }
+                                                    else
+                                                    {
+                                                        if (ac == sc)
+                                                        {
+                                                            result.studentScores[index][i] = points[i];
+                                                        }
+                                                        else
+                                                        {
+                                                            result.studentScores[index][i] = System.Math.Round((double)ac / sc * points[i], 1);
+                                                        }
+
+                                                    }
+                                                    break;
+                                                case 4:
+                                                    if (ac == sc)
+                                                    {
+                                                        result.studentScores[index][i] = points[i];
+                                                    }
+                                                    else
+                                                    {
+                                                        double persent = (double)(sc - 2 * falseCount) / sc;
+                                                        if (persent <= 0)
+                                                        {
+                                                            result.studentScores[index][i] = 0;
+                                                        }
+                                                        else
+                                                        {
+                                                            result.studentScores[index][i] = System.Math.Round(persent * points[i], 1);
+                                                        }
+                                                    }
+                                                    break;
+                                            }
+                                        }
+                                        else
+                                        {
+                                            result.studentScores[index][i] = 0;
+                                        }
+
+                                    }
+                                }
+                            }
+                        }
+                        result.sum[index] = result.studentScores[index].Sum();
+                        index++;
+                    }                                      
+                    classResult = await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(result, result.id, new PartitionKey($"{result.code}"));
+                    
+                }
+
+              await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(info, id.ToString(), new PartitionKey($"{scode}"));
+                
+                return Ok(new { code= 200, info = info });
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},exam/updateAns()\n{e.Message}\n{e.StackTrace}\n\n{id.GetString()}\n{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
         private async Task getArtInfoAsync(CosmosClient client, string artId, string school, double score, string acId, string subject, string quotaId, string userid, string picture, string name, int userType, List<string> cIds)
         {
             var aresponse = await client.GetContainer("TEAMModelOS", "Common").ReadItemStreamAsync(artId, new PartitionKey($"Art-{school}"));
@@ -1620,6 +1826,14 @@ namespace TEAMModelOS.Controllers
             if (!request.TryGetProperty("startTime", out JsonElement startTime)) return BadRequest();
             try
             {
+
+               /* var data = new
+                {
+                    examCode = 2001717656163218,
+                    subjects = new List<string> {"语文"}
+                };
+                var info = await ThirdService.CreateMoofenExamResult(_httpClient, data.ToJsonString().ToObject<JsonElement>(), _dingDing);*/
+
                 // 如果只有学生id则返回学生参加过的考试 只返回相关摘要信息
                 var client = _azureCosmos.GetCosmosClient();
                 var (_, _, _, school) = HttpContext.GetAuthTokenInfo();
@@ -1642,6 +1856,8 @@ namespace TEAMModelOS.Controllers
                 {
                     classId.GetString()
                 };
+
+
                 (List<RMember> members, List<RGroupList> groups) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, cid, $"{school}", null, -1, startTime.GetInt64());
                 //await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<GroupList>(classId.GetString, new PartitionKey($"Exam-{code}"));
                 ///获取真实的名称 

+ 10 - 10
TEAMModelOS/Controllers/Student/StudentController.cs

@@ -744,11 +744,11 @@ namespace TEAMModelOS.Controllers
             var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name, picture, _option.JwtSecretKey, scope: Constant.ScopeStudent, Website: "IES", timezone: timezone, areaId: areaId, schoolID: school_code, roles: new[] { "student" }, expire: 4,year: student.year);
 
             //用户在线记录
-            try
-            {
-                _ = _httpTrigger.RequestHttpTrigger(new { school = school_code, scope = $"{Constant.ScopeStudent}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
-            }
-            catch {}
+            //try
+            //{
+            //    _ = _httpTrigger.RequestHttpTrigger(new { school = school_code, scope = $"{Constant.ScopeStudent}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
+            //}
+            //catch {}
 
             await cosmosClient.GetContainer("TEAMModelOS", "Student").ReplaceItemAsync<Student>(student, id, new PartitionKey($"Base-{school_code}"));
           
@@ -1337,11 +1337,11 @@ namespace TEAMModelOS.Controllers
                         var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id.GetString(), name.GetString(), picture.GetString(), _option.JwtSecretKey, Website: "IES", timezone: timezone, areaId: schoolInfo.areaId, scope: Constant.ScopeStudent, schoolID: school_code.GetString(), roles: new[] { "student" }, expire: 4);
                         
                         //用户在线记录
-                        try
-                        {
-                            _ = _httpTrigger.RequestHttpTrigger(new { school = school_code.GetString(), scope = $"{Constant.ScopeStudent}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
-                        }
-                        catch { }
+                        //try
+                        //{
+                        //    _ = _httpTrigger.RequestHttpTrigger(new { school = school_code.GetString(), scope = $"{Constant.ScopeStudent}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
+                        //}
+                        //catch { }
 
 
                         //保存学生登录信息

+ 5 - 5
TEAMModelOS/Controllers/Student/TmdUserController.cs

@@ -167,11 +167,11 @@ namespace TEAMModelOS.Controllers
                 var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name?.ToString(), picture?.ToString(), _option.JwtSecretKey, Website: "IES", timezone: timezone, scope: Constant.ScopeTmdUser, roles: new[] { "student" }, expire: 1);
 
                 //用户在线记录
-                try
-                {
-                    _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTmdUser}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
-                }
-                catch { }
+                //try
+                //{
+                //    _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTmdUser}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
+                //}
+                //catch { }
 
                 if (!string.IsNullOrEmpty(defaultschool))
                 {

+ 4 - 4
TEAMModelOS/TEAMModelOS.csproj

@@ -79,11 +79,11 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2406.12</Version>
-		<AssemblyVersion>5.2406.12.1</AssemblyVersion>
-		<FileVersion>5.2406.12.1</FileVersion>
+		<Version>5.2406.19</Version>
+		<AssemblyVersion>5.2406.19.1</AssemblyVersion>
+		<FileVersion>5.2406.19.1</FileVersion>
 		<Description>TEAMModelOS(IES5)</Description>
-		<PackageReleaseNotes>IES版本说明版本切换标记5.2406.12.1</PackageReleaseNotes>
+		<PackageReleaseNotes>IES版本说明版本切换标记5.2406.19.1</PackageReleaseNotes>
 		<PackageId>TEAMModelOS</PackageId>
 		<Authors>teammodel</Authors>
 		<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 1 - 1
TEAMModelOS/appsettings.Development.json

@@ -18,7 +18,7 @@
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction-test.chinacloudsites.cn/api/",
     //"HttpTrigger": "http://localhost:7071/api/"
-    "Version": "5.2406.12.1"
+    "Version": "5.2406.19.1"
   },
   "Azure": {
     // 测试站数据库

+ 1 - 1
TEAMModelOS/appsettings.json

@@ -18,7 +18,7 @@
     "Exp": 86400,
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction.chinacloudsites.cn/api/",
-    "Version": "5.2406.12.1"
+    "Version": "5.2406.19.1"
   },
   "Azure": {
     "Storage": {